1. 程式人生 > >音頻的采集和播放

音頻的采集和播放

接口 ndk 分享 包含 做成 動態 user 耦合 應用

音頻的采集和播放主要由專門的codec芯片完成,主流的codec芯片廠商有Circus Logic、Wolfson等。采集時codec芯片通過A/D采樣把聲音的模擬信號轉換成數字信號並通過I2S總線送給CPU處理,播放時CPU把處理好的數字信號通過I2S總線送給codec芯片並通過D/A轉換為模擬信號播放出來。codec芯片除了A/D, D/A功能外還有其他功能,主要有1)對音頻通路進行控制,比如播放音樂打電話等在codec芯片內部的流通線路是不一樣的。2)對音頻信號做相應的處理,比如音量控制、功率放大、EQ控制等。

音頻的采集和播放在軟件上主要是寫音頻的驅動程序,同時提供接口給上層調用。我主要用過linux和android,而這兩大系統又是嵌入式和手機上的主流系統,android又是基於linux的。本文主要講這兩大系統上的音頻采集和播放軟件開發。

1,linux

Linux中跟音頻相關的就是大名鼎鼎的ALSA(Advanced Linux Sound Architecture)了。它是linux上的音頻子系統,在kernel space和user space都有相應的代碼。kernel space裏主要是音頻的驅動程序,user space裏主要是alsa-lib,也就是提供接口給上層應用程序調用。 User space 和kernel space通過字符設備進行交互。

在kernel space裏ALSA相關的叫ASOC(ALSA System On Chip), 它有三大模塊組成:板載硬件(Machine)、Soc(Platform)、Codec,如下圖所示:

技術分享

Machine是指某一款具體的產品,由此可以看出Machine幾乎是不可重用的,每個Machine上的硬件實現可能都不一樣,CPU不一樣,Codec不一樣,音頻的輸入、輸出設備也不一樣,Machine為CPU、Codec、輸入輸出設備提供了一個載體。Platform一般是指某一個SoC平臺,只要指定了SoC,那麽我們可以認為它會有一個對應的Platform,它只與SoC相關,與Machine無關,這樣我們就可以把Platform抽象出來,使得同一款SoC不用做任何的改動,就可以用在不同的Machine中。Codec和Platform一樣,是可重用的部件,同一個Codec可以被不同的Machine使用。

這三個模塊都有相應的driver. Platform driver是cpu側的音頻驅動,主要由CPU芯片廠商負責編寫,主要作用是完成音頻數據的管理,通過CPU的數字音頻接口(DAI)把音頻數據傳送給Codec進行處理,最終由Codec輸出驅動耳機或者是喇叭的音信信號。在具體實現上,ASoC把Platform驅動分為兩個部分:snd_soc_platform_driver和snd_soc_dai_driver。其中,platform_driver負責管理音頻數據,把音頻數據通過dma或其他操作傳送至cpu dai中,dai_driver則主要完成cpu一側的dai的參數配置,同時也會通過一定的途徑把必要的dma等參數與snd_soc_platform_driver進行交互。

codec driver是codec芯片側的音頻驅動,主要由codec芯片廠商負責編寫,主要作用在上面已說過。ASoC中的一個重要設計原則就是要求Codec驅動是平臺無關的,它包含了一些音頻的控件(Controls),音頻接口,DAMP(動態音頻電源管理)的定義和某些Codec IO功能。同platform driver一樣,codec driver也分為兩個部分:snd_soc_codec_driver和snd_soc_dai_driver,作用也同platform driver類似。

Machine driver主要是做產品的廠商編寫(產品廠商會購買codec芯片CPU芯片做成一個能用的產品)。Machine驅動負責Platform和Codec之間的耦合以及部分和設備或板子特定的代碼。

ALSA 在User space裏以ALSA-Lib存在,即提供API給應用程序調用。應用時主要有兩種模式:block & nonblock,可以根據應用場景選擇合適的模式。

ALSA是個龐大復雜的子系統,網上關於ALSA的內容特別多,包括kernel space和user space的,這裏就不多敘述了。

2,Android

Android是基於linux的,即用的是linux的核,所以在音頻驅動部分跟linux是一樣的。不同的是在user space 部分不再用 ALSA-lib, 取而代之的是tinyalsa, 它是ALSA-Lib的裁剪。同時Android在Native層有media framework, 音頻相關的模塊有 AudioRecord/AudioTrack/AudioFlinger等,它們有層次關系,從上往下調用最終會調用tinyalsa的API跟kernel交互。

如果從事的是音頻類的APP開發,kernel以及media framework都是不可見的,他們可以調用JAVA層提供的API實現音頻功能,但這樣會存在JAVA層和Native層之間的音頻數據拷貝,效率較低,尤其是在實時通信類APP中。建議使用 Android NDK 提供的 OpenSL ES API 接口,它支持在 native 層直接處理音頻數據。OpenSL ES 調用Native層media framework中的AudioRecord/AudioTrack, 從而實現音頻數據的采集和播放,這樣音頻數據就不會到JAVA層了,效率較高。JAVA層跟Native層主要通過JNI實現一些控制功能。

技術分享

音頻的采集和播放