0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

alsa底層框架系統(tǒng)配置與插件

Linux閱碼場(chǎng) ? 來(lái)源:Linux閱碼場(chǎng) ? 作者:Linux閱碼場(chǎng) ? 2022-07-04 09:04 ? 次閱讀

作者簡(jiǎn)介

廖威雄 暨大物聯(lián)專(zhuān)業(yè)首批畢業(yè)生,手忙腳亂的新手奶爸,憧憬物聯(lián)未來(lái),為天貓精靈砌磚的逐夢(mèng)人

1. 背景

網(wǎng)上大多數(shù)是 alsa 底層框架、音頻驅(qū)動(dòng)的文章,應(yīng)用開(kāi)發(fā)的入門(mén)少得可憐。從業(yè)務(wù)需求出發(fā),摸索積累了一些 alsa 應(yīng)用開(kāi)發(fā)心得。出此文以便后來(lái)者快速入門(mén)。

本文不會(huì)涉及底層框架,也不會(huì)使用很高級(jí)的特性,適合需要做 alsa 應(yīng)用開(kāi)發(fā)的初學(xué)者。畢竟是半路出家,與沉浸多年對(duì) alsa 框架了如指掌的大牛沒(méi)得比。如果有理解不準(zhǔn)確的地方,希望指導(dǎo)共同進(jìn)步。

  • Alsa 主頁(yè):https://www.alsa-project.org/wiki/Main_Page

  • Alsa 文檔主頁(yè):https://www.alsa-project.org/alsa-doc/alsa-lib/index.html

  • Alsa PCM 接口說(shuō)明:https://www.alsa-project.org/alsa-doc/alsa-lib/group_pcm.html

  • Alsa HCTL 接口說(shuō)明:https://www.alsa-project.org/alsa-doc/alsa-lib/group_h_control.html

  • Alsa CTL 接口說(shuō)明:https://www.alsa-project.org/alsa-doc/alsa-lib/group_control.html

在學(xué)習(xí)過(guò)程中,有兩篇前人的分享給了我很多幫助,一并貼上:

  • 《學(xué)習(xí)Linux操作系統(tǒng)中Alsa音頻編程》:http://ttokpm.com/emb/20190402899220.html

  • 《【轉(zhuǎn)】Alsa音頻編程【精華】》:https://www.cnblogs.com/cslunatic/p/3677729.html

2. 基本概念

一些基本的概念還是要有理解的,不然無(wú)法理解 API 意義和參數(shù)作用。

我們知道聲音是靠震動(dòng)傳播的,自然界傳播的聲音都是連續(xù)的模擬信號(hào),經(jīng)過(guò)采樣轉(zhuǎn)換成數(shù)字信號(hào)。其實(shí)有不少概念都是在描述怎么采樣。

2.1 樣本長(zhǎng)度 Format

b5541a8c-fb2e-11ec-ba43-dac502259ad0.jpg

上圖中,每一個(gè)黑色小球就是采樣出來(lái)的數(shù)值,這個(gè)數(shù)值是多少比特位的,就是我們說(shuō)的采樣精度,也就是樣本長(zhǎng)度,常見(jiàn)的有 8 bit 和 16 bit,偶爾也有 32 bit。例如采樣值是 3,如果是 8 bit 位采樣結(jié)果就是 0x03,16 bit位采樣結(jié)果就是 0x0003。

2.2 通道數(shù) Channels

我們常說(shuō)的左聲道、右聲道,可以理解為左右各來(lái)一個(gè) mic 采樣,左 mic 采樣出來(lái)的樣本就是左聲道數(shù)據(jù),右邊 mic 采樣出來(lái)的樣本就是右聲道數(shù)據(jù)。而一個(gè)音頻既可以只有1個(gè)聲道,也可以有左右兩個(gè)聲道,后者也稱(chēng)為立體聲。而這個(gè)音頻究竟有幾個(gè)聲道,就是我們說(shuō)的通道數(shù)

2.3 幀 Frame

我們每一次采樣出來(lái)的結(jié)果,就是一幀。很明顯,一幀數(shù)據(jù)有多大,取決于我們采樣的精度以及通道數(shù)。

b56c28de-fb2e-11ec-ba43-dac502259ad0.jpg

2.4 交錯(cuò)模式 Interleaved

我們每一次采樣出的音頻幀,怎么保存呢?提供了兩種保存思路,也就是我們說(shuō)的交錯(cuò)模式和非交錯(cuò)模式。我們常用的也是交錯(cuò)模式。

b58f7d7a-fb2e-11ec-ba43-dac502259ad0.jpg

2.5 周期 Period

我們總不可能一次處理1幀數(shù)據(jù)吧,太低效了,那就做成批量處理吧。而一次處理多少幀就是我們說(shuō)的周期。

一次周期結(jié)束切到下一次周期,都是需要額外處理?yè)p耗的,就類(lèi)似于進(jìn)程切換。周期大,一次處理數(shù)據(jù)量就多,每次連續(xù)處理時(shí)間長(zhǎng),切換損耗就少,但也因?yàn)閿?shù)據(jù)要滿(mǎn)一個(gè)周期后才處理,導(dǎo)致數(shù)據(jù)處理延時(shí)長(zhǎng)。反之,如果周期設(shè)置的小,延時(shí)短了,但周期切換更頻繁,損耗就更大,更容易出現(xiàn)卡頓。

2.6 緩存大小 Buffer Size

這里說(shuō)的是 alsa 底層 DMA 搬運(yùn)數(shù)據(jù)的緩存大小,這是一個(gè)環(huán)形的緩存空間。我們?cè)O(shè)置 DMA 一次連續(xù)搬運(yùn) 1 個(gè)周期的數(shù)據(jù),搬運(yùn)期間如果又來(lái)數(shù)據(jù)怎么辦?我們就需要更大的緩存空間來(lái)保存更多的數(shù)據(jù)。緩存空間往往是周期的整數(shù)倍,例如設(shè)置了緩存 8 個(gè)周期,每個(gè)周期 6000 幀,那么最多可以緩存 8 * 6000 = 48000 幀的數(shù)據(jù)。

b5a52ce2-fb2e-11ec-ba43-dac502259ad0.jpg

2.7 采樣率 Rate

不同于周期是人為定義的一次處理多少幀,采樣率就是固定的 1s 時(shí)間內(nèi)會(huì)有多少次采樣,同時(shí)也表示 1s 播放需要多少幀。常用的采樣率如 8KHz 的人聲, 44.1KHz 的 mp3 音樂(lè), 96Khz 的藍(lán)光音頻。

假設(shè)一個(gè)周期是 6000 幀,采樣率是 48 Khz,那么一個(gè)周期的數(shù)據(jù)能播放 125 ms。

2.8 Xrun

錄音的應(yīng)用中,底層是持續(xù)不斷采樣的,如果應(yīng)用程序讀取數(shù)據(jù)不夠快,底層數(shù)據(jù)緩存區(qū)還沒(méi)被取走就被新的數(shù)據(jù)覆蓋,導(dǎo)致數(shù)據(jù)丟失,稱(chēng)為 over run。

播放的應(yīng)用中,底層是持續(xù)不斷從緩存中獲取數(shù)據(jù)播放的,如果應(yīng)用程序?qū)懭霐?shù)據(jù)慢了,緩存區(qū)已經(jīng)沒(méi)有有效數(shù)據(jù)了,導(dǎo)致播放“餓死”,稱(chēng)為 under run。

Xrun 是 under run 和 over run 的統(tǒng)稱(chēng),前者可以理解為播放卡頓,后者則是錄音卡頓。

當(dāng)出現(xiàn)卡頓的時(shí),大多情況調(diào)整周期、緩存大小,調(diào)整應(yīng)用進(jìn)程調(diào)度優(yōu)先級(jí)能解決問(wèn)題。

3. 框架初探與聲卡設(shè)備

以下是網(wǎng)上優(yōu)秀的文章:

《ALSA架構(gòu)簡(jiǎn)介》:http://t.zoukankan.com/-glb-p-13722212.html

Alsa 的架構(gòu)包括用戶(hù)空間的 Alsa Library,也包括內(nèi)核空間的 Alsa Core 和 ASoC Core,如下圖所示:

b5bbce7a-fb2e-11ec-ba43-dac502259ad0.jpg

  • APP:應(yīng)用程序通過(guò)調(diào)用 alsa 庫(kù) API 來(lái)實(shí)現(xiàn)聲卡播放、錄音、控制。此外,官方還提供了一些標(biāo)準(zhǔn)命令行程序,例如aplay/amixer。

  • Alsa-Library:alsa 庫(kù)封裝了底層復(fù)雜的系統(tǒng)調(diào)用,向上提供更直觀的 API。常見(jiàn)的 alsa 庫(kù)有 alsa-lib 和 tinyalsa。

  • Alsa Core:Alsa 的核心層在內(nèi)核,向上提供邏輯設(shè)備、系統(tǒng)調(diào)用,向下驅(qū)動(dòng)硬件設(shè)備。

  • ASoC Core:asoc是建立在標(biāo)準(zhǔn) alsa core 上為更好支持嵌入式系統(tǒng)和移動(dòng)設(shè)備音頻 codec 設(shè)計(jì)的軟件體系

Alsa 用戶(hù)空間的 API 庫(kù)主要通過(guò) open/read/write/ioctl 操作 /dev/snd/xxx 下的設(shè)備文件實(shí)現(xiàn)與內(nèi)核交互,常見(jiàn)的設(shè)備文件有:

文件名 用途
controlC0 第0號(hào)聲卡的控制設(shè)備,例如音量、混音等
pcmC0D0c 第0號(hào)聲卡第0個(gè)設(shè)備,用于錄音(Capture)的設(shè)備
pcmC0D0p 第0號(hào)聲卡第0個(gè)設(shè)備,用于播放(Playback)的設(shè)備
seq 音序器
timer 定時(shí)器

命名規(guī)則顯而易見(jiàn), pcm表示設(shè)備類(lèi)型, C0 表示聲卡0, D0表示設(shè)備0, c/p分別表示錄音、播放功能。

4. 系統(tǒng)配置與插件

最完整的介紹還是來(lái)自于官網(wǎng)原文:

《Asoundrc》配置文件:https://www.alsa-project.org/main/index.php/Asoundrc
《PCM (digital audio) plugins》:https://www.alsa-project.org/alsa-doc/alsa-lib/pcm_plugins.html

alsa-lib 會(huì)從 /usr/share/alsa/alsa.conf 開(kāi)始加載,進(jìn)而根據(jù) alsa.conf 的記錄加載 /etc/asond.conf~/.asoundrc。前者是系統(tǒng)級(jí)別的配置,后者是用戶(hù)級(jí)別的配置,兩者的語(yǔ)法是一致的。

我們從配置默認(rèn)聲卡開(kāi)始,以下是一個(gè)標(biāo)準(zhǔn)示例:

pcm.!default { type hw card 0}ctl.!default { type hw  card 0}

一般情況下,我們配置的格式 pcm.{...},而關(guān)鍵字 !default 可以理解為保留字。pcm.!default 配置的是默認(rèn)錄播聲卡, ctl.!default 配置的是默認(rèn)控制聲卡。如此配置后,我們可以用 "default" 做聲卡名指代 "hw:0,0",所以下兩個(gè)命令就是等效的了。

aplay -D hw:0,0 test.wavaplay -D default test.wav

此時(shí) "default" 聲卡不管是播放還是錄音,都指向 "hw:0,0" 設(shè)備。如果我希望 "default" 錄音和播放指向不同(虛擬)聲卡,我們可以用 asym 插件,例如:

pcm.!default { type asym playback.pcm "Playback" capture.pcm "Capture"}pcm.Playback { ...}pcm.Capture { ...}

當(dāng)然,我們可以跳過(guò) "default" 直接用 "Playback" 的虛擬聲卡播放,例如

aplay -D Playback test.wav

Alsa 配置的節(jié)點(diǎn)是一個(gè)個(gè)聲卡節(jié)點(diǎn)串聯(lián)起來(lái)的,例如下面的配置,實(shí)現(xiàn)了從插件 A 開(kāi)始串上插件 B ,用插件實(shí)現(xiàn)各種音效功能,最后到物理聲卡播放。

pcm.A { type XXX # 下?個(gè)節(jié)點(diǎn)是聲卡 B slave.pcm B ...}pcm.B { type XXX # 下?個(gè)節(jié)點(diǎn)是物理聲卡 salve.pcm "hw:0,0"}

type 字段就標(biāo)識(shí)此節(jié)點(diǎn)使?什么插件。我們可以??實(shí)現(xiàn)插件,也可以?官?提供的插件,詳?官? PCM (digital audio)plugins。其中有?個(gè)?常有意思的插件,這?簡(jiǎn)單介紹下。

b5d96afc-fb2e-11ec-ba43-dac502259ad0.png

例如 "default" 聲卡?持分流,播放時(shí)?持?量調(diào)節(jié),且?持混?。

pcm.!default { type asym playback.pcm "Playback" capture.pcm "..."}pcm.Playback { type softvol slave.pcm PlaybackDmix ...}pcm.PlaybackDmix { type plug # dmix 再套?層plug,實(shí)現(xiàn)重采樣 slave.pcm { type dmix ... slave { pcm "hw:0,0" format S16_LE ... } }}

5.基本錄播

官?上有個(gè)最最最精簡(jiǎn)的示例 pcm_mini,其作?僅僅是播放?段隨機(jī)數(shù)據(jù)。

精煉核?邏輯如下:

int main(void){ ... /* 打開(kāi)alsa設(shè)備,類(lèi)型為 PlayBack */ if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { ... } /* 設(shè)置alsa設(shè)備基本屬性 */ if ((err = snd_pcm_set_params(handle, SND_PCM_FORMAT_U8, SND_PCM_ACCESS_RW_INTERLEAVED, 1, 48000, 1, 500000)) < 0) { ... } /* 播放?頻數(shù)據(jù) */ frames = snd_pcm_writei(handle, buffer, sizeof(buffer)); /* 關(guān)閉聲卡設(shè)備 */ snd_pcm_close(handle); return 0;}

錄?跟播放?常相似,播放調(diào)? snd_pcm_writei() ,錄?則調(diào)? snd_pcm_readi()

總的來(lái)說(shuō),?個(gè)簡(jiǎn)單的錄播包括以下 4 個(gè)步驟:

  • 1. 打開(kāi)聲卡設(shè)備

  • 2. 初始化設(shè)備

  • 3. 錄?、播放

  • 4. 關(guān)閉聲卡設(shè)備

圍繞這 4 個(gè)步驟,介紹下常?的 API,更多的介紹請(qǐng)看官?:pcm api

5.1 打開(kāi)聲卡設(shè)備

int snd_pcm_open( snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)

  • pcmp:聲卡設(shè)備句柄,類(lèi)似于?件句柄

  • name:聲卡設(shè)備名,類(lèi)似于?件名,聲卡設(shè)備名參考第3章節(jié)

  • stream:數(shù)據(jù)流向,指定?于錄?還是播放

  • mode:打開(kāi)模式,例如nonBlock,async等,?多數(shù)情況? 0 即可

數(shù)據(jù)流向有兩種,分別指代錄? or 播放。

b5f8750a-fb2e-11ec-ba43-dac502259ad0.png

?個(gè)簡(jiǎn)單的示例如下,從 default 設(shè)備錄?:

#include snd_pcm_t *snd_handle;err = snd_pcm_open(&snd_handle, "default", SND_PCM_STREAM_CAPTURE, 0)

5.2初始化設(shè)備

alsa 設(shè)置聲卡參數(shù)的接??常多,可以分為軟件參數(shù)(software parameters)和硬件參數(shù)(software parameters)兩類(lèi)。上?例?調(diào)?的 snd_pcm_set_params() 如官?API?檔所說(shuō),只是簡(jiǎn)單設(shè)置軟件、硬件參數(shù)的?法,實(shí)際項(xiàng)?中很少這么?。

5.2.1 設(shè)置硬件參數(shù)

官?有?常多的例?,以 pcm 為例,設(shè)置硬件參數(shù)常?以下步驟:

int set_hwparams(...){ /* 從棧?分配硬件參數(shù)對(duì)象內(nèi)存 */ snd_pcm_hw_params_alloca(¶ms); /* 初始化參數(shù)對(duì)象 */ err = snd_pcm_hw_params_any(handle, params); /* 設(shè)置采樣率 */ err = snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0); /* 設(shè)置交錯(cuò)模式 */ err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); /* 設(shè)置采樣格式,例如樣本?度、有?符號(hào) */ err = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); /* 設(shè)置通道數(shù) */ err = snd_pcm_hw_params_set_channels(handle, params, 2); /* 設(shè)置緩存?? */ err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir); /* 設(shè)置周期?? */ err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir); /* 把上述設(shè)置值寫(xiě)?設(shè)備 */ err = snd_pcm_hw_params(handle, params);}

不妨回顧章節(jié)2的基本概念,可以發(fā)現(xiàn)硬件參數(shù)基本都是圍繞這些概念設(shè)置的。不管是交錯(cuò)模式、采樣率,還是樣本?度、通道數(shù)都?較直觀,如果設(shè)置錯(cuò)?概率?法正常運(yùn)?。?緩存??和周期??往往跟卡頓、延時(shí)有關(guān),且有好?種設(shè)置維度,值得展開(kāi)介紹。

調(diào)整卡頓、延時(shí)參數(shù)時(shí),我們需要記住?個(gè)核?的關(guān)系:

緩存?? = 周期?? * 周期數(shù),即 buffer size = period size * periods

3 個(gè)參數(shù)知其2 就可以換算出另外?個(gè)參數(shù)。例如我們可以設(shè)置 周期?? 和 周期數(shù),alsa 會(huì)?動(dòng)換算出 緩存??。同理,我們可以設(shè)置緩存??和周期??,alsa 也能?動(dòng)換算出周期數(shù)。在上述的例?中,就是設(shè)置了緩存??和周期??。

在?定的采樣率下,緩存??也可以換算成時(shí)間,畢竟有些?需要從時(shí)間維度設(shè)置緩存。

播放時(shí)間 = 緩存?? / 采樣率

因此我們可以發(fā)現(xiàn),除了 set_buffer/period_size() 之外,我們還可以set_buffer/period_time() ,他們是等效的。

更多的 pcm 硬件參數(shù)設(shè)置API,可以看官? hw參數(shù)API?檔,這?再補(bǔ)充?點(diǎn)。

同樣是設(shè)置周期??,我們可以? snd_pcm_hw_params_set_period_size() ,但更多會(huì)選擇?

snd_pcm_hw_params_set_period_size_near() 。這?的 near 后綴表示就近設(shè)置,因?yàn)椴还苁蔷彺??還是周期??、周期數(shù),有時(shí)候會(huì)受其他配置制約,這時(shí)候就采?可?的接近的值。例如聲卡設(shè)備在系統(tǒng)配置中限制了周期??不超過(guò) 1024 幀,此時(shí)如果設(shè)置 6000 幀,就會(huì)就近復(fù)位為1024

5.2.2 設(shè)置軟件參數(shù)

同樣在 pcm 的例?中提取軟件參數(shù)設(shè)置步驟:

int set_swparams(...){ /* 從棧?分配軟件參數(shù)對(duì)象內(nèi)存 */ snd_pcm_sw_params_alloca(¶ms); /* 獲取當(dāng)前的軟件參數(shù)配置以初始化對(duì)象 */ err = snd_pcm_sw_params_current(handle, swparams); /* 設(shè)置起播閾值 */ err = snd_pcm_sw_params_set_start_threshold(...); /* 設(shè)置最?可? */ err = snd_pcm_sw_params_set_avail_min(...); /* 把上述設(shè)置值寫(xiě)?設(shè)備 */ err = snd_pcm_sw_params(handle, swparams);}

軟件參數(shù)設(shè)置我?的也不多,更多時(shí)候?脆不設(shè)置軟件參數(shù)采?默認(rèn)值。為了不誤??弟,每個(gè)參數(shù)的具體作?不展開(kāi)介紹。以下是相關(guān)的?檔鏈接,請(qǐng)讀者辨證分析。

https://blog.csdn.net/weixin_39560924/article/details/110569666

https://blog.csdn.net/zz2862625432/article/details/101787316

https://www.cnblogs.com/cslunatic/p/3677729.html

5.3錄音與播放

本?只講常?的讀寫(xiě),不展開(kāi) mmap 等?法。

交錯(cuò)模式和?交錯(cuò)模式?的讀(錄?)和寫(xiě)(播放)接?不?樣。

# 交錯(cuò)模式snd_pcm_sframes_t snd_pcm_readi (snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)snd_pcm_sframes_t snd_pcm_writei (snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)# ?交錯(cuò)模式snd_pcm_sframes_t snd_pcm_readn (snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)snd_pcm_sframes_t snd_pcm_writen (snd_pcm_t *pcm, void **bufs, snd_pcm_uframes_t size)
  • pcm:聲卡設(shè)備句柄

  • buffer:讀/寫(xiě)的buffer指針

  • size:指代buffer??,單位幀

?個(gè)簡(jiǎn)單的轉(zhuǎn)播(讀->寫(xiě))示例如下:

frames = 6000; # 假設(shè)?個(gè)周期 6000 幀buffer = malloc( frames * 4 ); # 雙通道16Bit采樣精度,因此?幀 4Bwhile (true) { ret = snd_pcm_readi(chandle, buffer, frames); snd_pcm_writei(phandle, buffer, ret);}

5.4關(guān)閉聲卡設(shè)備

int snd_pcm_close(snd_pcm_t *pcm)

關(guān)閉聲卡設(shè)備的接??常簡(jiǎn)單,類(lèi)似于關(guān)閉?件句柄。

6. 設(shè)置音量

錄播? pcm APIs,?設(shè)置?量需要使? ctrl APIsAlsa 有兩類(lèi)控制接?,?個(gè)是 ctrl,?個(gè)則是更?層抽象的 hctrl,以下是官?兩個(gè)類(lèi)型接??檔:

Alsa HCTL 接?說(shuō)明:https://www.alsa-project.org/alsa-doc/alsa-lib/grouphcontrol.html

Alsa CTL 接?說(shuō)明:https://www.alsa-project.org/alsa-doc/alsa-lib/group_control.html

以及下?鏈接是官?關(guān)于控制的?些概念介紹:

Control interface 概述:https://www.alsa-project.org/alsa-doc/alsa-lib/control.html

下?會(huì)先介紹關(guān)于 ctrl 的基本概念,再參考 Alsa Utils amixer 命令學(xué)習(xí)如何獲取、設(shè)置?量。

6.1控制基本概念

不管是實(shí)體聲卡還是虛擬聲卡,每?個(gè)聲卡都會(huì)提供?個(gè)控制?法,我們需要設(shè)置聲卡屬性,就必須要先打開(kāi)丟應(yīng)的聲卡控制。打開(kāi)聲卡設(shè)置需要使? snd_ctl_open() ,并?以下?種?法可以指定聲卡:

1. 使?聲卡編號(hào),例如: hw:1

2. 使?聲卡名,例如: hw:sndtasXXXX 或者 hw:CARD=sndtasXXXX

3. 使?設(shè)備?件,例如:hw:/dev/snd/controlC0

每個(gè)聲卡可以有很多控制項(xiàng),在 Alsa ?叫做 要素(Elements)。要素可以有多個(gè)成員(Member),例如?體聲有左右聲道?量?jī)蓚€(gè)成員。?個(gè)要素的所有成員共享?樣的屬性,例如最?、最??量。此外,要素?cái)?shù)據(jù)也區(qū)分類(lèi)型,例如?量是整型。以下是所有?持的要素類(lèi)型:

b60d263a-fb2e-11ec-ba43-dac502259ad0.png

既然?個(gè)聲卡可以有很多要素(控制項(xiàng)),我們?cè)O(shè)置要素需要先定位哪個(gè)要素吧。要定位每個(gè)要素,可以有以下?法:

1. 使?numid:當(dāng)聲卡被檢測(cè)到的時(shí)候就會(huì)賦予?個(gè)編號(hào),但每次開(kāi)機(jī)可能都不?樣。使?此編號(hào)主要是減少根據(jù)屬性遍歷時(shí)間。

2. 使?固定屬性:固定屬性包括?法類(lèi)型(interface type)、設(shè)備(device)、?設(shè)備(subname)、名字(name)或者編號(hào)index)??梢?次指定多個(gè)屬性以便準(zhǔn)確定位要素。

6.2獲取設(shè)置音量

Alsa Libs 關(guān)于設(shè)置?量的示例不多,這時(shí)候我們不妨看看 Alsa Utils ? amixer 命令的實(shí)現(xiàn),畢竟其我們通過(guò)命令?設(shè)置?量往往是通過(guò) amixer 命令,例如:

amixer -D default cset name='Master Volume' 60 # 設(shè)置默認(rèn)聲卡?量為60(要素名為:Master Volume)

6.2.1 關(guān)鍵數(shù)據(jù)類(lèi)型

在了解相關(guān)代碼實(shí)現(xiàn)前,需要先了解?個(gè)很重要的數(shù)據(jù)類(lèi)型。

1. snd_ctl_elem_id_t :記錄了定位要素的屬性,例如設(shè)備、numid

2. snd_ctl_elem_value_t :存儲(chǔ)了要素值,需要根據(jù)不同類(lèi)型?不同接?獲取具體值

3. snd_ctl_elem_info_t :要素的信息

對(duì) hctl API,還有 snd_hctl_elem_t 描述具體的要素對(duì)象。

  • id 唯?標(biāo)識(shí)了要素,在定位要素時(shí)可以賦值部分已知屬性到 id,?于遍歷要素。

  • 通過(guò)綁定 id 后獲取要素的 infoinfo包含了要素的所有屬性,例如類(lèi)型、完整要素 id 信息。

  • 通過(guò)綁定 id 后讀取要素的 value,最后根據(jù)類(lèi)型調(diào)?對(duì)應(yīng)接?從 value 中獲取具體值。

6.2.2 代碼實(shí)現(xiàn)

以下是精簡(jiǎn)后設(shè)置?量的實(shí)現(xiàn)(為了?便理解跟源代碼 amixer 的調(diào)?API不完全相同):

int cset(...){ /* 從棧申請(qǐng) info/id/value 對(duì)象空間 */ snd_ctl_elem_info_alloca(&info); snd_ctl_elem_id_alloca(&id); snd_ctl_elem_value_alloca(&control); /* 根據(jù)命令?指定的要素信息來(lái)初始化 id (id 記錄了定位要素的信息) */ snd_ctl_ascii_elem_id_parse(id, "name='Master Volume'"); /* 打開(kāi)默認(rèn)聲卡,獲取控制句柄 */ snd_ctl_open(&handle, "default", 0); /* 綁定要素 id 到 info 對(duì)象,此處僅僅是把 id 賦值到 info 的成員 */ snd_ctl_elem_info_set_id(info, id); /* 從聲卡中,依據(jù)綁定的 id,獲取要素完整的 info 信息 */ snd_ctl_elem_info(handle, info); /* 讀取當(dāng)前?量 */ /* 綁定要素 id 到 value 對(duì)象,此處僅僅是把 id 復(fù)制到 value 的成員 */ snd_ctl_elem_value_set_id(control, id); /* 從聲卡中,依據(jù)綁定的 id,獲取要素完整的 value 信息 */ snd_ctl_elem_read(handle, control); /* 從 value 對(duì)象中,獲取通道 idx 的整型?量值 */ vol = snd_ctl_elem_value_get_integer(control, idx); /* 設(shè)置新?量 */ /* * info ?記錄了要素類(lèi)型、成員數(shù)量等屬性,此接?根據(jù)要素屬性, * 解析命令?設(shè)置字符串的值,獲取新的的 value 信息。 * 此?法?于命令?字符串解析,如果是??編程實(shí)現(xiàn),應(yīng)該? snd_ctl_elem_value_set_xxxx()。 */ snd_ctl_ascii_value_parse(handle, control, info, "60"); /* 把最終的 value 設(shè)置?聲卡 */ snd_ctl_elem_write(handle, control); /* 關(guān)閉聲卡控制 */ snd_ctl_close(handle);}

以獲取?量為例,就以下?個(gè)關(guān)鍵的步驟:

1. 初始化 id ,賦值已知的要素屬性,?便遍歷定位要素。

  • snd_ctl_ascii_elem_id_parse()

2. 綁定 id,根據(jù) id 獲取要素 value

  • snd_ctl_elem_value_set_id()

  • snd_ctl_elem_read()

3. (默認(rèn)?量是int類(lèi)型)調(diào)? int 類(lèi)型獲取接?,從 value 對(duì)象獲取實(shí)際?量值

  • snd_ctl_elem_value_get_integer()

設(shè)置?量與獲取?量相?,多了以下?個(gè)步驟:

1. (默認(rèn)?量是int類(lèi)型)調(diào)? int 類(lèi)型設(shè)置接?,設(shè)置 value 對(duì)象新?量值

  • snd_ctl_elem_value_set_integer()

2. value 對(duì)象寫(xiě)?聲卡

  • snd_ctl_elem_write()

當(dāng)然,如果想要做的兼容性更好,我們還需要獲取要素 info,以根據(jù) info 記錄的要素類(lèi)型調(diào)?不同接?:

1. 綁定 id,根據(jù) id 獲取要素 info

  • snd_ctl_elem_info_set_id()

  • snd_ctl_elem_info()

2. info 獲取要素類(lèi)型、要素成員數(shù)量、完整的id信息等

  • snd_ctl_elem_info_get_type()

  • snd_ctl_elem_info_get_count()

  • snd_ctl_elem_info_get_id()

補(bǔ)充?點(diǎn),我們可以直接? snd_ctl_elem_id_set_numid/name/index/... 直接初始化 id,也可以參考 amixer 通過(guò)字符串??解析初始化 id,調(diào)? snd_ctl_ascii_elem_id_parse() 。??解析字符串?持以下格式:

[[iface=,][name='name',][index=,][device=,][subdevice=]]|[numid=]

7. 調(diào)試信息

調(diào)試信息用于打印聲卡詳細(xì)的屬性,類(lèi)似于 aplay 命令的 -v 選項(xiàng)。

alsa debug API文檔:https://www.alsa-project.org/alsa-doc/alsa-lib/grouppcmdump.html

以下是我常用的一個(gè)例子:

/* 定義dump輸出對(duì)象 */snd_output_t *output = NULL;/* 綁定輸出對(duì)象到 stdout */snd_output_stdio_attach(&output, stdout, 0);/* dump 出聲卡 handle (pcm)的信息 */snd_pcm_dump(handle, output);/* 關(guān)閉輸出對(duì)象 */snd_output_close(output);

snd_pcm_dump() 可以dump出播放鏈路中每?個(gè)節(jié)點(diǎn)的配置信息,例如 dmix 插件的信息:

Slave: Direct Stream Mixing PCMIts setup is: stream : PLAYBACK access : MMAP_INTERLEAVED format : S16_LE subformat : STD channels : 2 rate : xxxx exact rate : xxxx (xxxx/1) msbits : xxx buffer_size : xxx period_size : xxx period_time : xxx tstamp_mode : NONE tstamp_type : GETTIMEOFDAY period_step : 1 avail_min : 6000 period_event : 0 start_threshold : xxx stop_threshold : xxxx silence_threshold: 0 silence_size : 0 boundary : 5066549580791808000

當(dāng)然,如果想看聲卡的 hw/sw_params,也可以直接讀 proc 的?件,例如聲卡0的播放設(shè)備0節(jié)點(diǎn):

cat /proc/asound/card0/pcm0p/sub0/{hw_params,sw_params}

8. 命令工具集

Alsa Utils 提供了?系列?常有?的?具集,常?的包括 arecord 錄?、aplay 播放、amixer 設(shè)置。

每個(gè)命令都有詳細(xì)的 --help 信息,本?只提供?個(gè)簡(jiǎn)單的例?。

# 從 default 設(shè)備錄?,采樣精度為 16 bit,采樣率為16K,1通道arecord -D default -f S16_LE -r 16000 -c 1 ./record.wav# 向 default 設(shè)備播放# wav 可以??從頭信息讀取,PCM格式需要指定更多參數(shù),不?持mp3等需要解碼的?頻格式aplay -D default ./record.wav# 修改系統(tǒng)?量為90amixer -D default cset name='xxxxx Volume' 90

原文標(biāo)題:8. 命令工具集

文章出處:【微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

審核編輯:湯梓紅
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8449

    瀏覽量

    150726
  • 框架
    +關(guān)注

    關(guān)注

    0

    文章

    398

    瀏覽量

    17405
  • alsa
    +關(guān)注

    關(guān)注

    0

    文章

    19

    瀏覽量

    3604

原文標(biāo)題:8. 命令工具集

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    嵌入式 Linux 操作系統(tǒng)配置

    隨著物聯(lián)網(wǎng)(IoT)和智能設(shè)備的快速發(fā)展,嵌入式系統(tǒng)在各個(gè)領(lǐng)域扮演著越來(lái)越重要的角色。Linux因其開(kāi)源、靈活和穩(wěn)定的特性,成為嵌入式系統(tǒng)的首選操作系統(tǒng)。 1. 硬件選擇 在配置嵌入式
    的頭像 發(fā)表于 11-06 10:22 ?137次閱讀

    基于DM816x C6A816x和AM389x系列SOC的最小系統(tǒng)配置

    電子發(fā)燒友網(wǎng)站提供《基于DM816x C6A816x和AM389x系列SOC的最小系統(tǒng)配置.pdf》資料免費(fèi)下載
    發(fā)表于 09-29 10:23 ?0次下載
    基于DM816x C6A816x和AM389x系列SOC的最小<b class='flag-5'>系統(tǒng)配置</b>

    C2000系統(tǒng)配置應(yīng)用說(shuō)明

    電子發(fā)燒友網(wǎng)站提供《C2000系統(tǒng)配置應(yīng)用說(shuō)明.pdf》資料免費(fèi)下載
    發(fā)表于 09-14 10:12 ?0次下載
    C2000<b class='flag-5'>系統(tǒng)配置</b>應(yīng)用說(shuō)明

    百問(wèn)網(wǎng)全志系列開(kāi)發(fā)板音頻ALSA配置步驟詳解

    的選擇,因?yàn)樗哂懈佑押玫木幊探涌?并且完全兼容于OSS。 ?ALSA系統(tǒng)包括7個(gè)子項(xiàng)目: 驅(qū)動(dòng)包alsa-driver 開(kāi)發(fā)包alsa-libs 開(kāi)發(fā)包
    發(fā)表于 08-13 09:56

    Modbus協(xié)議轉(zhuǎn)Profinet協(xié)議網(wǎng)關(guān)與氣體監(jiān)測(cè)系統(tǒng)配置案例

    Modbus協(xié)議轉(zhuǎn)換為Profinet協(xié)議,以實(shí)現(xiàn)不同設(shè)備之間的數(shù)據(jù)交換和通訊。本文將結(jié)合Modbus協(xié)議轉(zhuǎn)Profinet協(xié)議網(wǎng)關(guān)與氣體監(jiān)測(cè)系統(tǒng)配置的成功案例。
    的頭像 發(fā)表于 06-13 17:50 ?1341次閱讀
    Modbus協(xié)議轉(zhuǎn)Profinet協(xié)議網(wǎng)關(guān)與氣體監(jiān)測(cè)<b class='flag-5'>系統(tǒng)配置</b>案例

    教學(xué)一體機(jī)系統(tǒng)配置怎么選

    教學(xué)一體機(jī)作為現(xiàn)代教學(xué)的重要工具,其系統(tǒng)配置的選擇直接關(guān)系到教學(xué)質(zhì)量和學(xué)生的學(xué)習(xí)體驗(yàn)。因此,在選購(gòu)教學(xué)一體機(jī)時(shí),我們需要仔細(xì)考慮其系統(tǒng)配置,確保其能夠滿(mǎn)足教學(xué)需求并具備良好的性能和穩(wěn)定性。
    的頭像 發(fā)表于 05-16 14:09 ?632次閱讀

    鴻蒙OpenHarmony開(kāi)發(fā)板:【產(chǎn)品配置規(guī)則】

    產(chǎn)品解決方案為基于開(kāi)發(fā)板的完整產(chǎn)品,主要包含產(chǎn)品對(duì)OS的適配、部件拼裝配置、啟動(dòng)配置和文件系統(tǒng)配置等。產(chǎn)品解決方案的源碼路徑規(guī)則為:**vendor/{產(chǎn)品解決方案廠商}/{產(chǎn)品名稱(chēng)}** _。
    的頭像 發(fā)表于 05-09 10:32 ?989次閱讀
    鴻蒙OpenHarmony開(kāi)發(fā)板:【產(chǎn)品<b class='flag-5'>配置</b>規(guī)則】

    鴻蒙OpenHarmony開(kāi)發(fā)板:【子系統(tǒng)配置規(guī)則】

    通過(guò)build倉(cāng)下的subsystem_config.json可以查看所有子系統(tǒng)配置規(guī)則。
    的頭像 發(fā)表于 05-08 22:07 ?243次閱讀
    鴻蒙OpenHarmony開(kāi)發(fā)板:【子<b class='flag-5'>系統(tǒng)配置</b>規(guī)則】

    TYPE B型微電網(wǎng)結(jié)構(gòu)及工作原理圖

    TYPE B型微電網(wǎng)是一種特定的微電網(wǎng)系統(tǒng)配置。在這種配置中,系統(tǒng)包含光伏系統(tǒng)、儲(chǔ)能系統(tǒng)和柴油發(fā)電機(jī)組。
    的頭像 發(fā)表于 04-17 16:27 ?1802次閱讀
    TYPE B型微電網(wǎng)結(jié)構(gòu)及工作原理圖

    系統(tǒng)配置清單和設(shè)備選型(輸電線路分布式故障定位監(jiān)測(cè)裝置)

    下面,深圳鼎信智慧跟大家探討輸電線路分布式故障定位監(jiān)測(cè)裝置的系統(tǒng)配置清單和設(shè)備選型: 在系統(tǒng)配置清單方面,我們需要關(guān)注監(jiān)測(cè)裝置的核心組件,包括傳感器、數(shù)據(jù)采集器、通信模塊等。這些組件就如同電網(wǎng)
    的頭像 發(fā)表于 04-01 18:24 ?1156次閱讀

    消防報(bào)警主機(jī)的升級(jí)利器:貼片式TF卡的應(yīng)用與優(yōu)勢(shì)

    SD NAND在消防報(bào)警主機(jī)上可以用于存儲(chǔ)重要的監(jiān)控?cái)?shù)據(jù)、日志信息和系統(tǒng)配置文件。
    的頭像 發(fā)表于 01-24 10:43 ?429次閱讀
    消防報(bào)警主機(jī)的升級(jí)利器:貼片式TF卡的應(yīng)用與優(yōu)勢(shì)

    Profinet轉(zhuǎn)EthernetIP網(wǎng)關(guān)連接HCS-6100系統(tǒng)配置

    本案例主要涉及西門(mén)子1200PLC通過(guò)Profinet轉(zhuǎn)EthernetIP網(wǎng)關(guān)與HCS-6100系統(tǒng)進(jìn)行連接的配置過(guò)程。所需設(shè)備清單如下:西門(mén)子1200PLC、Profinet轉(zhuǎn)
    發(fā)表于 01-11 10:29

    Profinet轉(zhuǎn)EthernetIP網(wǎng)關(guān)連接HCS-6100系統(tǒng)配置

    本案例主要涉及西門(mén)子1200PLC通過(guò)Profinet轉(zhuǎn)EthernetIP網(wǎng)關(guān)與HCS-6100系統(tǒng)進(jìn)行連接的配置過(guò)程。所需設(shè)備清單如下:西門(mén)子1200PLC、Profinet轉(zhuǎn)EthernetIP網(wǎng)關(guān)以及HCS-6100系統(tǒng)
    的頭像 發(fā)表于 01-08 16:07 ?440次閱讀
    Profinet轉(zhuǎn)EthernetIP網(wǎng)關(guān)連接HCS-6100<b class='flag-5'>系統(tǒng)配置</b>

    怎么通過(guò)alsa配置和開(kāi)發(fā)AD1937的多路音頻?

    控制和使用。驅(qū)動(dòng)介紹的內(nèi)容中有提到alsa的控制,之前用過(guò)TI的tlv320aic3106通過(guò)alsa去實(shí)現(xiàn)了單路音頻的開(kāi)發(fā),但具體怎么通過(guò)alsa配置和開(kāi)發(fā)1937的多路音頻沒(méi)有找
    發(fā)表于 11-29 07:17