天天看點

利用ALSA庫進行音頻重采樣一、ALSA介紹:二、配置檔案asound.conf:三、App調用方法:四、未盡之處:

一、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。

利用ALSA庫進行音頻重采樣一、ALSA介紹:二、配置檔案asound.conf:三、App調用方法:四、未盡之處:

                                         ALSA 架構圖

3、kernel driver層簡述:

Kernel driver 層,為核心驅動代碼,主要在核心源碼中的sound目錄下,負責對硬體進行控制與操作。驅動建立的裝置檔案,在檔案系統中的/dev/snd/目錄下。注意,應用層使用alsa-API中打開的裝置檔案,并不是/dev/snd/目錄下的檔案,而是alsa-lib對裝置的再一次封裝的産物,叫做plugins,如plughw:0,0 ,後面詳細解釋。

4、alsa-lib層簡述:

Alsa-lib層,為不同的驅動提供統一的接口alsa API,簡化了開發人員對于驅動層的調用開發。主要有如下接口

  • ALSA library API reference

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的功能,那勢必要用到這個功能,在這裡還沒有進行深究。