轉(zhuǎn)載請(qǐng)注明,F(xiàn)rom LXS, http://blog.csdn.net/uiop78uiop78/article/details/8796492
Android的音頻系統(tǒng)在很長(zhǎng)一段時(shí)間內(nèi)都是外界詬病的焦點(diǎn)。的確,早期的Android系統(tǒng)在音頻處理上相比于IOS有一定的差距,這也是很多專業(yè)的音樂播放軟件開發(fā)商沒有推出Android平臺(tái)產(chǎn)品的一個(gè)重要原因。但這并不代表它的音頻框架一無是處,相反,基于Linux系統(tǒng)的Android平臺(tái)有很多值得我們學(xué)習(xí)的地方。
在計(jì)算機(jī)發(fā)展的早期,電腦的聲音處理設(shè)備是由一個(gè)非常簡(jiǎn)易的loudspeaker外加發(fā)聲器(Tone Generator)構(gòu)成的,功能相對(duì)局限。后來人們想到了以plug-in的形式來擴(kuò)展音頻設(shè)備,“Sound blaster”就是其中很有名的一個(gè)。這種早期的聲卡以插件方式連接到電腦主板上,并提供了更多復(fù)雜的音頻設(shè)備??上攵?,獨(dú)立的硬件設(shè)計(jì)也意味著成本的增加,于是隨著技術(shù)的發(fā)展,便又出現(xiàn)了板載聲卡,也就是我們俗稱的“集成聲卡”。板載聲卡又分為“軟聲卡”和“硬聲卡”。如果聲卡本身沒有主處理芯片,而只有解碼芯片,需要通過CPU運(yùn)算來執(zhí)行處理工作,那么就是“軟聲卡”,反之就是“硬聲卡”。通常面向低端市場(chǎng)的計(jì)算機(jī)都會(huì)包含一個(gè)集成的聲卡設(shè)備以降低成本。
一個(gè)典型的聲卡通常包含三個(gè)部分:
· Connectors
用于聲卡與外放設(shè)備,如揚(yáng)聲器、耳機(jī)的連接,又被稱為“jacks”
· Audio Circuits
聲卡的主要實(shí)現(xiàn)體,它負(fù)責(zé)信號(hào)的放大、混音、以及模擬數(shù)字轉(zhuǎn)換等操作
· Interface
連接聲卡與計(jì)算機(jī)總線的單元,比如PCI總線
我們可以通過“cat/proc/asound/cards”命令來查看計(jì)算機(jī)中安裝的聲卡設(shè)備,如下例子所示:
目前市面上聲卡的種類眾多,既有復(fù)雜的高性能的,也有低端的簡(jiǎn)易的,那么對(duì)于一個(gè)操作系統(tǒng)來說,它如何管理這些音頻設(shè)備,并向上層應(yīng)用提供統(tǒng)一的接口呢?
Android嚴(yán)格來講只是一個(gè)Linux系統(tǒng),它依賴于內(nèi)核提供的各種驅(qū)動(dòng)支持,包括音頻驅(qū)動(dòng)。因此我們有必要先花點(diǎn)時(shí)間來學(xué)習(xí)下Linux平臺(tái)下的兩種主要的音頻驅(qū)動(dòng)架構(gòu):
· OSS (Open Sound System)
早期Linux版本采用的是OSS框架,它也是Unix及類Unix系統(tǒng)中廣泛使用的一種音頻體系。OSS既可以指OSS接口本身,也可以用來表示接口的實(shí)現(xiàn)。OSS的作者是Hannu Savolainen,就職于4Front Technologies公司。由于涉及到知識(shí)產(chǎn)權(quán)問題,OSS后期的支持與改善不是很好,這也是Linux內(nèi)核最終放棄OSS的一個(gè)原因。
另外,OSS在某些方面也遭到了人們的質(zhì)疑,比如:
對(duì)新音頻特性的支持不足;
缺乏對(duì)最新內(nèi)核特性的支持等等。
當(dāng)然,OSS做為Unix下統(tǒng)一音頻處理操作的早期實(shí)現(xiàn),本身算是比較成功的。它符合“一切都是文件”的設(shè)計(jì)理念,而且做為一種體系框架,其更多地只是規(guī)定了應(yīng)用程序與操作系統(tǒng)音頻驅(qū)動(dòng)間的交互,因而各個(gè)系統(tǒng)可以根據(jù)實(shí)際的需求進(jìn)行定制開發(fā)??偟膩碚f,OSS使用了如下表所示的設(shè)備節(jié)點(diǎn):
表格 13?1 OSS采用的設(shè)備節(jié)點(diǎn)
設(shè)備節(jié)點(diǎn) | 說明 |
/dev/dsp | 向此文件寫數(shù)據(jù)à輸出到外放Speaker 向此文件讀數(shù)據(jù)à從Microphone進(jìn)行錄音 |
/dev/mixer | 混音器,用于對(duì)音頻設(shè)備進(jìn)行相關(guān)設(shè)置,比如音量調(diào)節(jié) |
/dev/midi00 | 第一個(gè)MIDI端口,還有midi01,midi02等等 |
/dev/sequencer | 用于訪問合成器(synthesizer),常用于游戲等效果的產(chǎn)生 |
更多詳情,可以參考OSS的官方說明:http://www.opensound.com/
· ALSA(Advanced Linux Sound Architecture)
ALSA是Linux社區(qū)為了取代OSS而提出的一種框架,是一個(gè)源代碼完全開放的系統(tǒng)(遵循GNU GPL和GNU LGPL)。ALSA在Kernel 2.5版本中被正式引入后,OSS就逐步被排除在內(nèi)核之外。當(dāng)然,OSS本身還是在不斷維護(hù)的,只是不再為Kernel所采用而已。
ALSA相對(duì)于OSS提供了更多,也更為復(fù)雜的API接口,因而開發(fā)難度相對(duì)來講加大了一些。為此,ALSA專門提供了一個(gè)供開發(fā)者使用的工具庫,以幫助他們更好地使用ALSA的API。根據(jù)官方文檔的介紹,ALSA有如下特性:
高效支持大多數(shù)類型的audio interface(不論是消費(fèi)型或者是專業(yè)型的多聲道聲卡)
高度模塊化的聲音驅(qū)動(dòng)
SMP及線程安全(thread-safe)設(shè)計(jì)
在用戶空間提供了alsa-lib來簡(jiǎn)化應(yīng)用程序的編寫
與OSS API保持兼容,這樣子可以保證老的OSS程序在系統(tǒng)中正確運(yùn)行
ALSA主要由下表所示的幾個(gè)部分組成:
表格 13?2 Alsa-project Package
Element | Description |
alsa-driver | 內(nèi)核驅(qū)動(dòng)包 |
alsa-lib | 用戶空間的函數(shù)庫 |
alsa-utils | 包含了很多實(shí)用的小程序,比如 alsactl:用于保存設(shè)備設(shè)置 amixer:是一個(gè)命令行程序,用于聲量和其它聲音控制 alsamixer:amixer的ncurses版 acconnect和aseqview:制作MIDI連接,以及檢查已連接的端口列表 aplay和arecord:兩個(gè)命令行程序,分別用于播放和錄制多種格式的音頻 |
alsa-tools | 包含一系列工具程序 |
alsa-firmware | 音頻固件支持包 |
alsa-plugins | 插件包,比如jack,pulse,maemo |
alsa-oss | 用于兼容OSS的模擬包 |
pyalsa | 用于編譯Python版本的alsa lib |
Alsa主要的文件節(jié)點(diǎn)如下:
關(guān)于ALSA的更多知識(shí),建議大家可以自行參閱相關(guān)文檔,這對(duì)于后面理解整個(gè)Audio系統(tǒng)是不無裨益的。
一看“Tiny”這個(gè)詞,大家應(yīng)該能猜到這是一個(gè)ALSA的縮減版本。實(shí)際上在Android系統(tǒng)的其它地方也可以看到類似的做法——既想用開源項(xiàng)目,又嫌工程太大太繁瑣,怎么辦?那就只能瘦身了,于是很多Tiny-XXX就出現(xiàn)了。
在早期版本中,Android系統(tǒng)的音頻架構(gòu)主要是基于ALSA的,其上層實(shí)現(xiàn)可以看做是ALSA的一種“應(yīng)用”。后來可能是由于ALSA所存在的一些不足,Android后期版本開始不再依賴于ALSA提供的用戶空間層的實(shí)現(xiàn),因而我們?cè)谒膸煳募A中已經(jīng)找不到alsa相關(guān)的lib了,如下圖所示:
圖 13?7 Android4.1與早期版本在音頻庫上的區(qū)別
而取代它的是tinyalsa相關(guān)的庫文件,如下圖所示:
同時(shí)我們可以看到externl目錄下多了一個(gè)“tinyalsa”文件夾,其中包含了為數(shù)不多的幾個(gè)源碼文件,如下所示:
表格 13?3 Tiny-alsa工程文件
Source File | Description |
Android.mk | makefile |
mixer.c | Mixer Interface實(shí)現(xiàn) |
pcm.c | PCM Interface實(shí)現(xiàn) |
tinycap.c | Caputer工具 |
tinymix.c | Mixer工具 |
tinyplay.c | Play工具 |
include/tinyalsa/asoundlib.h | 頭文件 |
可見TinyAlsa與原版Alsa的差異還是相當(dāng)大的,它只是部分支持了其中的兩種Interface,而像Raw MIDI、Sequencer、Timer等Interface則沒有涉及到——當(dāng)然這對(duì)于一般的嵌入式設(shè)備還是足夠了。
TinyAlsa作為Alsa-lib的一個(gè)替代品,自面世已來得到的公眾評(píng)價(jià)有褒有貶,不能一概而論——對(duì)于每個(gè)廠商來說,合適自己的就是最好的。而且各廠商也可以在此基礎(chǔ)上擴(kuò)展自己的功能,真正的把ALSA利用到極致。
一個(gè)好的系統(tǒng)架構(gòu),需要盡可能地降低上層與具體硬件的耦合,這既是操作系統(tǒng)的設(shè)計(jì)目的,對(duì)于音頻系統(tǒng)也是如此。音頻系統(tǒng)的雛形框架可以簡(jiǎn)單的用下圖來表示:
圖 13?8 音頻系統(tǒng)的雛形框架
在這個(gè)圖中,除去Linux本身的Audio驅(qū)動(dòng)外,整個(gè)Android音頻實(shí)現(xiàn)都被看成了User。因而我們可以認(rèn)為Audio Driver就是上層與硬件間的“隔離板”。但是如果單純采用上圖所示的框架來設(shè)計(jì)音頻系統(tǒng),對(duì)上層應(yīng)用使用音頻功能是不小的負(fù)擔(dān),顯然Android開發(fā)團(tuán)隊(duì)還會(huì)根據(jù)自身的實(shí)際情況來進(jìn)一步細(xì)化“User”部分。
細(xì)化的根據(jù)自然還是Android的幾個(gè)層次結(jié)構(gòu),包括應(yīng)用層、framework層、庫層以及HAL層,如下圖所示:
圖 13?9 音頻框架在Android系統(tǒng)中的進(jìn)一步細(xì)化
我們可以結(jié)合目前已有的知識(shí),想一下每一個(gè)層次都會(huì)包含哪些模塊(先不考慮藍(lán)牙音頻部分)?
· APP
這是整個(gè)音頻體系的最上層,因而并不是Android系統(tǒng)實(shí)現(xiàn)的重點(diǎn)。比如廠商根據(jù)特定需求自己寫的一個(gè)音樂播放器,游戲中使用到聲音,或者調(diào)節(jié)音頻的一類軟件等等。
· Framework
相信大家可以馬上想到MediaPlayer和MediaRecorder,因?yàn)檫@是我們?cè)陂_發(fā)音頻相關(guān)產(chǎn)品時(shí)使用最廣泛的兩個(gè)類。實(shí)際上,Android也提供了另兩個(gè)相似功能的類,即AudioTrack和AudioRecorder,MediaPlayerService內(nèi)部的實(shí)現(xiàn)就是通過它們來完成的,只不過MediaPlayer/MediaRecorder提供了更強(qiáng)大的控制功能,相比前者也更易于使用。我們后面還會(huì)有詳細(xì)介紹。
除此以外,Android系統(tǒng)還為我們控制音頻系統(tǒng)提供了AudioManager、AudioService及AudioSystem類。這些都是framework為便利上層應(yīng)用開發(fā)所設(shè)計(jì)的。
· Libraries
我們知道,framework層的很多類,實(shí)際上只是應(yīng)用程序使用Android庫文件的“中介”而已。因?yàn)樯蠈討?yīng)用采用java語言編寫,它們需要最直接的java接口的支持,這就是framework層存在的意義之一。而作為“中介”,它們并不會(huì)真正去實(shí)現(xiàn)具體的功能,或者只實(shí)現(xiàn)其中的一部分功能,而把主要重心放在庫中來完成。比如上面的AudioTrack、AudioRecorder、MediaPlayer和MediaRecorder等等在庫中都能找到相對(duì)應(yīng)的類。
這一部分代碼集中放置在工程的frameworks/av/media/libmedia中,多數(shù)是C++語言編寫的。
除了上面的類庫實(shí)現(xiàn)外,音頻系統(tǒng)還需要一個(gè)“核心中控”,或者用Android中通用的實(shí)現(xiàn)來講,需要一個(gè)系統(tǒng)服務(wù)(比如ServiceManager、LocationManagerService、ActivityManagerService等等),這就是AudioFlinger和AudioPolicyService。它們的代碼放置在frameworks/av/services/audioflinger,生成的最主要的庫叫做libaudioflinger。
音頻體系中另一個(gè)重要的系統(tǒng)服務(wù)是MediaPlayerService,它的位置在frameworks/av/media/libmediaplayerservice。
因?yàn)樯婕暗降膸旌拖嚓P(guān)類是非常多的,建議大家在理解的時(shí)候分為兩條線索。
其一,以庫為線索。比如AudioPolicyService和AudioFlinger都是在libaudioflinger庫中;而AudioTrack、AudioRecorder等一系列實(shí)現(xiàn)則在libmedia庫中。
其二,以進(jìn)程為線索。庫并不代表一個(gè)進(jìn)程,進(jìn)程則依賴于庫來運(yùn)行。雖然有的類是在同一個(gè)庫中實(shí)現(xiàn)的,但并不代表它們會(huì)在同一個(gè)進(jìn)程中被調(diào)用。比如AudioFlinger和AudioPolicyService都駐留于名為mediaserver的系統(tǒng)進(jìn)程中;而AudioTrack/AudioRecorder和MediaPlayer/MediaRecorder一樣實(shí)際上只是應(yīng)用進(jìn)程的一部分,它們通過binder服務(wù)來與其它系統(tǒng)進(jìn)程通信。
在分析源碼的過程中,一定要緊抓這兩條線索,才不至于覺得混亂。
· HAL
從設(shè)計(jì)上來看,硬件抽象層是AudioFlinger直接訪問的對(duì)象。這說明了兩個(gè)問題,一方面AudioFlinger并不直接調(diào)用底層的驅(qū)動(dòng)程序;另一方面,AudioFlinger上層(包括和它同一層的MediaPlayerService)的模塊只需要與它進(jìn)行交互就可以實(shí)現(xiàn)音頻相關(guān)的功能了。因而我們可以認(rèn)為AudioFlinger是Android音頻系統(tǒng)中真正的“隔離板”,無論下面如何變化,上層的實(shí)現(xiàn)都可以保持兼容。
音頻方面的硬件抽象層主要分為兩部分,即AudioFlinger和AudioPolicyService。實(shí)際上后者并不是一個(gè)真實(shí)的設(shè)備,只是采用虛擬設(shè)備的方式來讓廠商可以方便地定制出自己的策略。
抽象層的任務(wù)是將AudioFlinger/AudioPolicyService真正地與硬件設(shè)備關(guān)聯(lián)起來,但又必須提供靈活的結(jié)構(gòu)來應(yīng)對(duì)變化——特別是對(duì)于Android這個(gè)更新相當(dāng)頻繁的系統(tǒng)。比如以前Android系統(tǒng)中的Audio系統(tǒng)依賴于ALSA-lib,但后期就變?yōu)榱藅inyalsa,這樣的轉(zhuǎn)變不應(yīng)該對(duì)上層造成破壞。因而Audio HAL提供了統(tǒng)一的接口來定義它與AudioFlinger/AudioPolicyService之間的通信方式,這就是audio_hw_device、audio_stream_in及audio_stream_out等等存在的目的,這些Struct數(shù)據(jù)類型內(nèi)部大多只是函數(shù)指針的定義,是一些“殼”。當(dāng)AudioFlinger/AudioPolicyService初始化時(shí),它們會(huì)去尋找系統(tǒng)中最匹配的實(shí)現(xiàn)(這些實(shí)現(xiàn)駐留在以audio.primary.*,audio.a2dp.*為名的各種庫中)來填充這些“殼”。
根據(jù)產(chǎn)品的不同,音頻設(shè)備存在很大差異,在Android的音頻架構(gòu)中,這些問題都是由HAL層的audio.primary等等庫來解決的,而不需要大規(guī)模地修改上層實(shí)現(xiàn)。換句話說,廠商在定制時(shí)的重點(diǎn)就是如何提供這部分庫的高效實(shí)現(xiàn)了。
基于上面的分析,我們給出一個(gè)完整的Android音頻系統(tǒng)框架來給大家參考(沒有列出Linux層的實(shí)現(xiàn),比如ALSADriver等等),如下所示:
圖 13?10 Android音頻系統(tǒng)框架全圖
接下來的小節(jié),我們將分別介紹上述框架圖中的幾個(gè)重點(diǎn)模塊,包括AudioFlinger,AudioTrack/AudioRecorder,AudioManager/AudioPolicyService,并簡(jiǎn)單地介紹上層的一些模塊如MediaPlayerService等等。
http://blog.csdn.net/xuesen_lin/article/details/8796492
聯(lián)系客服