轉自:http://www.voidcn.com/article/p-snamarwr-p.html
一、ALSA介紹:
1、簡介:
高級Linux聲音體系(英語:Advanced LinuxSound Architecture,縮寫為ALSA)是Linux內核中,為聲卡提供的驅動組件,以替代原先的OSS(開放聲音系統)。 一部分的目的是支持聲卡的自動配置,以及完美的處理系統中的多個聲音設備,這些目的大多都已達到。另一個聲音框架JACK使用ALSA提供低延遲的專業級音頻編輯和混音能力。
Jaroslav Kysela過去是這個項目的領導者,這個項目開始於為1998年Gravis Ultrasound所開發的驅動,它一直作為一個單獨的軟件包開發,直到2002年他被引進入Linux內核的開發版本 (2.5.4-2.5.5)。從2.6版本開始ALSA成為Linux內核中默認的標准音頻驅動程序集,OSS則被標記為廢棄。
ALSA是一個完全開放源代碼的音頻驅動程序集,除了像OSS那樣提供了一組內核驅動程序模塊之外,ALSA還專門為簡化應用程序的編寫提供了相應的函數庫,與OSS提供的基於ioctl的原始編程接口相比,ALSA函數庫使用起來要更加方便一些。利用該函數庫,開發人員可以方便快捷的開發出自己的應用程序,細節則留給函數庫內部處理。當然ALSA也提供了類似於OSS的系統接口,不過ALSA的開發者建議應用程序開發者使用音頻函數庫而不是驅動程序的API。
2、分層
ALSA體系主要分為三層,按照調用關系依次是,app、alsa-lib、kerneldriver。
3、kernel driver層簡述:
Kernel driver 層,為內核驅動代碼,主要在內核源碼中的sound目錄下,負責對硬件進行控制與操作。驅動創建的設備文件,在文件系統中的/dev/snd/目錄下。注意,應用層使用alsa-API中打開的設備文件,並不是/dev/snd/目錄下的文件,而是alsa-lib對設備的再一次封裝的產物,叫做plugins,如plughw:0,0 ,后面詳細解釋。
alsa驅動的設備文件結構: 字符設備
# ls /dev/snd/ -lh
total 0
crw-rw---- 1 root root 116, 0 Aug 21 16:01 controlC0
crw-rw---- 1 root root 116, 24 Aug 21 16:01 pcmC0D0c
crw-rw---- 1 root root 116, 16 Aug 21 16:01 pcmC0D0p
crw-rw---- 1 root root 116, 25 Aug 21 16:01 pcmC0D1c
crw-rw---- 1 root root 116, 17 Aug 21 16:01 pcmC0D1p
crw-rw---- 1 root root 116, 26 Aug 21 16:01 pcmC0D2c
crw-rw---- 1 root root 116, 33 Aug 21 16:01 timer
controlC0 用於聲卡的控制,例如通道選擇,混音,麥克風的控制等
pcmC0D0c 用於錄音的pcm設備
pcmC0D0p 用於播放的pcm設備
timer 定時器
C0D0代表的是聲卡0中的設備0,pcmC0D0c最后一個c代表capture,pcmC0D0p最后一個p代表playback,這些都是alsa-driver中的命名規則。
4、alsa-lib層簡述:
Alsa-lib層,為不同的驅動提供統一的接口alsa API,簡化了開發人員對於驅動層的調用開發。主要有如下接口
網址:https://www.alsa-project.org/alsa-doc/alsa-lib/
The currently designed interfaces are listed below:
Information Interface (/proc/asound)
Control Interface (/dev/snd/controlCX)
Mixer Interface (/dev/snd/mixerCXDX)
PCM Interface (/dev/snd/pcmCXDX)
Raw MIDI Interface (/dev/snd/midiCXDX)
Sequencer Interface (/dev/snd/seq)
Timer Interface (/dev/snd/timer)
我們在應用中,主要使用的是 PCM 接口。如Snd_pcm_open()函數。
除了Alsa-API接口以外,alsa-lib還可以通過配置文件,開放其附加功能,如采樣率轉換、軟件混音等。
我們就是利用alsa-lib的附加功能實現我們的重采樣功能,修改的地方主要包括alsa-lib的配置和APP調用兩方面。下一章對如何利用alsa-lib的配置文件開放其采樣率轉換功能進行描述。
二、配置文件asound.conf:
asound.conf配置文件,是alsa-lib的默認配置文件,路徑在 /etc/,可以用來配置alsa庫的一些附加功能。這個文件不是alsa庫運行時所必須的,沒有它alsa庫也可以正常運行。
關於asound.conf的配置,可以參考以下文檔:
http://www.alsa-project.org/main/index.php/Asoundrc
先闡述一些重要的名詞:
Card:聲卡,直接對應硬件,ID從0開始計數。
Device:設備,在一個card上,可以有多個device,每個device可以獨立被打開和使用,ID從0開始計數。
Plugin:插件,前文說過,應用層調用alsa庫時,操作的並不是驅動層創建的設備文件,而是這個plugins,plugin是alsa庫對音頻處理設備的抽象,hw plugin為硬件設備抽象出的plugin,是最基礎的模塊,不需要對alsa-lib進行配置即可使用,我們常見的plughw:0,0含義就是類型為hw的plugin,編號聲卡0上面的設備0。除了hw類型的plugin外,還有一些純軟件實現的模塊,可以用來進行音頻處理,例如,可以實現音頻采樣率轉換的rate plugin,可以用來混音的dmix plugin等等。
Slave:從屬設備,可以把幾個plugin連接起來,sink端的設備就是source端設備的slave。
需要使用這些附加的plugin,就要對配置文件(asound.conf)進行配置,這個配置是實時生效的,所以我們不必修改文件系統中的文件,而是在運行我們的應用程序之前,將自己的配置文件拷貝到/etc/下,對默認的配置文件進行覆蓋就行了。
具體如何配置,書寫格式,請參看Asoundrc文檔。
以下就是我的配置,
pcm_slave.sl2 {
pcm"plughw:0,1"
rate48000
}
pcm.rate_convert {
typerate
slavesl2
}
這個配置的含義是,
下面一段:創建一個使用pcm API接口的設備,叫做rate_convert,它的類型是rate(可以實現采樣率轉換的plugin),它有一個slave叫做sl2;
上面一段:定義一個使用pcm接口的slave,叫做sl2,他實際上是plughw:0,1這個設備的別名,即等同於plughw:0,1(對應我用於播放的AIC3104芯片),這個設備需要的采樣率是48KHz。
通過這個配置,就可以在app中,使用pcm API打開rate_convert這個設備,並把解碼后的8K采樣率的PCM數據,直接使用snd_pcm_writei寫入設備,rate_convert這個設備就可以自動將PCM數據重采樣至48KHz,然后自動傳遞給plughw:0,1進行播放。
在看Asoundrc的文檔中,一直不明白,為什么在配置文件中,只有輸出的采樣率配置,而沒有輸入的采樣率配置,要重采樣,alsa-lib總得知道把啥轉換成48K吧,
在實踐中發現,可以通過APP調用alsa-API中的snd_pcm_hw_params_set_rate_near()函數將數據源的采樣率為8K傳遞給alsa-lib。下面一章對app調用alsa-API進行說明。
三、App調用方法:
在app調用這塊兒,其他的通用調用流程在這里就不累述了,使用個項目原來的那套代碼就行,只有三塊兒需要修改和注意:
1、使用snd_pcm_open()打開的設備文件rate_convert(不需再打開plughw:0,1了),PCM數據的原始采樣率,用snd_pcm_hw_params_set_rate_near()對rate_convert進行配置。
2、重要的參數Period_size,即播放周期大小,單位為Byte,需使用snd_pcm_hw_params_set_period_size_near()進行配置,如果period_size配的不對,或者不配置,會發生underRun,播放聲音斷斷續續。
8K pcm, 配置sample_rate為8000,配置period_size為256
48K pcm, 配置sample_rate為48000,配置period_size為1024
3、配置負責playback的AIC3104的采樣率為48K
四、未盡之處:
在研究alsa-lib的調用時,還有一些沒有搞明白的地方,這里記錄下來,將來大家有時間可以研究研究。
1、我的設備上音頻輸入輸出分開使用了兩塊AIC3104,這樣重采樣后G711的自編自解就不成問題,因為輸入的AIC3104設為8K,輸出的AIC3104設為48K播放重采樣后的數據,如果系統中只使用一塊AIC3104,就必須對輸入的PCM數據也進行一次重采樣,這里沒有進行研究。
2、多設備綁定,假如我們系統中有多個playback設備,現在的做法是啟兩個線程,分別寫入數據,如果可以使用alsa-lib的slave配置將多個設備進行綁定,例如一個rate plugin綁定兩個 hw plugin,然后只需向這一個rate plugin寫入數據即可,不會遇到兩個播放線程同步的問題,我試了一下,只能綁定一個slave,再多綁一個,第一個slave就會沒有播放聲音。
3、混音功能,這個混音功能看似是非常強大的,它可以把多個不同采樣率的通道,混合成一路統一采樣率的數據進行播放,如果我們以后可以進行多路解碼,或者要實現視頻會議中MCU的功能,那勢必要用到這個功能,在這里還沒有進行深究。