本文基于Android音頻API提供的四個(gè)層面的音頻API夜矗,說說Android系統(tǒng)的音頻架構(gòu)泛范。
下面先上這張經(jīng)典的Android系統(tǒng)架構(gòu)圖:
從圖上看Andorid整個(gè)系統(tǒng)層面從下到上分以下四層:
- Linux Kernel
- 硬件適配層
- Framework層(可分為Java層與C++層)
- APP層
我們上面介紹的四個(gè)層面的音頻API實(shí)現(xiàn)均在Framework層,其他各層音頻相關(guān)有哪些功能紊撕?當(dāng)我們調(diào)用某一API時(shí)最終是怎么驅(qū)動(dòng)硬件工作的呢罢荡?下面我們先看看系統(tǒng)各層音頻相關(guān)模塊及功能。
1. 各層音頻模塊
1.1 Java層
Java層提供了 android.media API 與音頻硬件進(jìn)行交互对扶。在內(nèi)部柠傍,此代碼會(huì)調(diào)用相應(yīng)的 JNI 類,以訪問與音頻硬件交互的原生代碼辩稽。
源代碼目錄:frameworks/base/media/java/android/media/
AudioManager:音頻管理器,包括音量管理从媚、AudioFocus管理逞泄、音頻設(shè)備管理、模式管理拜效;
錄音:AudioRecord喷众、MediaRecorder;
播放:AudioTrack紧憾、MedaiPlayer到千、SoundPool、ToneGenerator;
編解碼:MediaCodec赴穗,音視頻數(shù)據(jù) 編解碼接口憔四。
1.2 JNI層
與 android.media 關(guān)聯(lián)的 JNI 代碼可調(diào)用較低級(jí)別的原生代碼,以訪問音頻硬件般眉。JNI 位于 frameworks/base/core/jni/ 和 frameworks/base/media/jni 中了赵。
在這里可以調(diào)用我們上篇文章介紹的AAudio和OpenSLES接口。
1.3 Native framework 原生框架層
不管是Java層還是JNI層都只是對(duì)外提供的接口甸赃,真正的實(shí)現(xiàn)在原生框架層柿汛。原生框架可提供相當(dāng)于 android.media 軟件包的原生軟件包,從而調(diào)用 Binder IPC 代理以訪問媒體服務(wù)器的特定于音頻的服務(wù)埠对。原生框架代碼位于 frameworks/av/media/libmedia
或frameworks/av/media/libaudioclient
中(不同版本络断,位置有所改變)裁替。
1.4 Binder IPC
Binder IPC 代理用于促進(jìn)跨越進(jìn)程邊界的通信。代理位于 frameworks/av/media/libmedia
或frameworks/av/media/libaudioclient
中貌笨,并以字母“I”開頭弱判。
1.5 Audio Server
Audio系統(tǒng)在Android中負(fù)責(zé)音頻方面的數(shù)據(jù)流傳輸和控制功能,也負(fù)責(zé)音頻設(shè)備的管理躁绸。這個(gè)部分作為Android的Audio系統(tǒng)的輸入/輸出層次裕循,一般負(fù)責(zé)播放PCM聲音輸出和從外部獲取PCM聲音,以及管理聲音設(shè)備和設(shè)置(注意:解碼功能不在這里實(shí)現(xiàn)净刮,在android系統(tǒng)里音頻視頻的解碼是opencore或stagefright完成的剥哑,在解碼之后才調(diào)用音頻系統(tǒng)的接口,創(chuàng)建音頻流并播放)淹父。Audio服務(wù)在Android N(7.0)之前存在于mediaserver中株婴,Android N開始以audioserver形式存在,這些音頻服務(wù)是與HAL 實(shí)現(xiàn)進(jìn)行交互的實(shí)際代碼暑认。媒體服務(wù)器位于 frameworks/av/services/audioflinger
和frameworks/av/services/audiopolicy
中困介。
Audio服務(wù)包含AudioFlinger 和AudioPolicyService:
AudioFlinger:主要負(fù)責(zé)音頻流設(shè)備的管理以及音頻流數(shù)據(jù)的處理傳輸,?量計(jì)算蘸际,重采樣座哩、混?、?效等粮彤。
AudioPolicyService:主要負(fù)責(zé)?頻策略相關(guān)根穷,?量調(diào)節(jié)?效,設(shè)備選擇导坟,?頻通路選擇等屿良。
1.6 HAL層
HAL 定義了由音頻服務(wù)調(diào)用且手機(jī)必須實(shí)現(xiàn)以確保音頻硬件功能正常運(yùn)行的標(biāo)準(zhǔn)接口。音頻 HAL 接口位于 hardware/libhardware/include/hardware
中惫周。詳情可參閱 audio.h睡汹。
1.7 內(nèi)核驅(qū)動(dòng)層
音頻驅(qū)動(dòng)程序可與硬件和 HAL 實(shí)現(xiàn)進(jìn)行交互阶冈。我們可以使用高級(jí) Linux 音頻架構(gòu) (ALSA)、開放聲音系統(tǒng) (OSS) 或自定義驅(qū)動(dòng)程序(HAL 與驅(qū)動(dòng)程序無關(guān))。
注意:如果使用的是 ALSA浮庐,建議將 external/tinyalsa
用于驅(qū)動(dòng)程序的用戶部分硼砰,因?yàn)樗哂屑嫒莸脑S可(標(biāo)準(zhǔn)的用戶模式庫已獲得 GPL 許可)乎婿。
2. 音頻系統(tǒng)架構(gòu)的演進(jìn)
一個(gè)好的系統(tǒng)架構(gòu)今阳,需要盡可能地降低上層與具體硬件的耦合,這既是操作系統(tǒng)的設(shè)計(jì)目的逊躁,對(duì)于音頻系統(tǒng)也是如此似踱。音頻系統(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ì)化呢?如果是讓我們?nèi)ゼ?xì)化我們?cè)撛趺醋瞿兀?/p>
首先作為一個(gè)操作系統(tǒng)要對(duì)外提供可用的API哮独,供應(yīng)用開發(fā)者調(diào)用拳芙。APP開發(fā)者開發(fā)的應(yīng)用我們稱APP,我們提供的API姑且叫Framework皮璧。如果Framework直接和驅(qū)動(dòng)交互有什么問題呢舟扎?
- 首先是耦合問題,接口和實(shí)現(xiàn)耦合悴务,硬件層有任何變動(dòng)都需要接口層適配睹限,我們?cè)黾右粚佑布m配層;
- 資源統(tǒng)一管理的問題讯檐,如果多個(gè)APP調(diào)用相同API使用硬件資源羡疗,改怎么分配?增加統(tǒng)一資源管理器别洪,其實(shí)就是對(duì)應(yīng)Android系統(tǒng)的Audio Lib層叨恨。
細(xì)化后我們發(fā)現(xiàn),整個(gè)結(jié)構(gòu)對(duì)應(yīng)的就就是Android的幾個(gè)層次結(jié)構(gòu)挖垛,包括應(yīng)用層特碳、framework層、庫層以及HAL層晕换,如下圖所示:
我們可以結(jié)合目前已有的知識(shí),我們分析Lib層和HAL層架構(gòu)主要設(shè)計(jì)思路站宗。
2.1 Lib層
framework層的大多數(shù)類闸准,其實(shí)只是應(yīng)用程序使用Android庫文件的“中介”,它只是個(gè)殼子梢灭。因?yàn)锳ndroid應(yīng)用采用java語言編寫夷家,它們需要最直接的java接口的支持,如果我們的Android系統(tǒng)支持另一種語言的運(yùn)行時(shí)敏释,那么可以提供另一種語言的接口支持(比如Go)库快,這就是framework層存在的意義之一。但是作為“中介”钥顽,它們并不會(huì)真正去實(shí)現(xiàn)具體的功能义屏,或者只實(shí)現(xiàn)其中的一部分功能,而把主要重心放在核心庫中來完成。比如上面的AudioTrack闽铐、AudioRecorder蝶怔、MediaPlayer和MediaRecorder等等在庫中都能找到相對(duì)應(yīng)的類,這些多數(shù)是C++語言編寫的兄墅。
我們?cè)購牧硪粋€(gè)線索來思考這個(gè)問題:我們提供的API供應(yīng)用層調(diào)用踢星,那么這個(gè)API最終運(yùn)行在應(yīng)用的進(jìn)程中。如果多個(gè)應(yīng)用同時(shí)使用這個(gè)功能就會(huì)沖突隙咸;再一個(gè)允許任何一個(gè)進(jìn)程操作硬件也是個(gè)危險(xiǎn)的行為沐悦。那么真相就浮出了水面:我們需要一個(gè)有權(quán)限管理和硬件交互的進(jìn)程,需要調(diào)用某個(gè)硬件服務(wù)必須和我這個(gè)服務(wù)打交道五督。這就是Android系統(tǒng)的很常用的C/S結(jié)構(gòu)以及Binder存在的主要原因藏否。Android系統(tǒng)中的Server就是一個(gè)個(gè)系統(tǒng)服務(wù),比如ServiceManager概荷、LocationManagerService秕岛、ActivityManagerService等等,以及管理圖像合成的SurfaceFlinger误证,和今天我們今天介紹的音頻服務(wù)AudioFlinger和AudioPolicyService继薛。它們的代碼放置在frameworks/av/services/audioflinger
,生成的最主要的庫叫做libaudioflinger愈捅。
這里也提到了分析源碼除以模塊為線索外的另一種線索以進(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只是應(yīng)用進(jìn)程的一部分譬巫,它們通過binder服務(wù)來與其它audioflinger等系統(tǒng)進(jìn)程通信咖楣。
2.2 HAL層
硬件抽象層顧名思義為適配不同硬件而獨(dú)立封裝的一層,音頻硬件抽象層的任務(wù)是將AudioFlinger/AudioPolicyService真正地與硬件設(shè)備關(guān)聯(lián)起來芦昔,但又必須提供靈活的結(jié)構(gòu)來應(yīng)對(duì)變化诱贿。
從設(shè)計(jì)上來看,硬件抽象層是AudioFlinger直接訪問的對(duì)象咕缎。這里體現(xiàn)了兩方面的考慮:
- 一方面AudioFlinger并不直接調(diào)用底層的驅(qū)動(dòng)程序;
- 另一方面珠十,AudioFlinger上層(包括和它同一層的MediaPlayerService)的模塊只需要與它進(jìn)行交互就可以實(shí)現(xiàn)音頻相關(guān)的功能了。
AudioFlinger和HAL是整個(gè)架構(gòu)解耦的核心層凭豪,通過HAL層的audio.primary等庫抹平音頻設(shè)備間的差異焙蹭,無論硬件如何變化,不需要大規(guī)模地修改上層實(shí)現(xiàn)嫂伞,保證系統(tǒng)對(duì)外暴露的上層API不需要修改孔厉,達(dá)成高內(nèi)聚低耦合拯钻。而對(duì)廠商而言,在定制時(shí)的重點(diǎn)就是如何在這部分庫中進(jìn)行高效實(shí)現(xiàn)了烟馅。
舉個(gè)例子说庭,以前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ù)指針的定義,是一個(gè)個(gè)句柄梭纹。當(dāng)AudioFlinger/AudioPolicyService初始化時(shí)躲惰,它們會(huì)去尋找系統(tǒng)中最匹配的實(shí)現(xiàn)(這些實(shí)現(xiàn)駐留在以audio.primary.,audio.a2dp.為名的各種庫中)來填充這些“殼”,可以理解成是一種“多態(tài)”的實(shí)現(xiàn)变抽。
3. Linux平臺(tái)下的兩種主要的音頻驅(qū)動(dòng)架構(gòu)介紹
上面我們的示例提到了ALSA础拨,這個(gè)其實(shí)是Linux平臺(tái)的一種音頻驅(qū)動(dòng)架構(gòu)。下面介紹兩種常見的Linux音頻驅(qū)動(dòng)架構(gòu)绍载。
3.1 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ā)∫馀遥總的來說樱调,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的官方說明
3.2 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來簡化應(yīng)用程序的編寫
- 與OSS API保持兼容写半,這樣子可以保證老的OSS程序在系統(tǒng)中正確運(yùn)行
ALSA主要由下表所示的幾個(gè)部分組成:
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)如下:
- 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)
Android的TinyALSA是基于Linux ALSA基礎(chǔ)改造而來蟆肆。一看“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)更啄。HAL層最終依賴alsa-lib庫與驅(qū)動(dòng)層交互。
4. 一種新的錄音方式實(shí)現(xiàn)
除了之前提到的系統(tǒng)API居灯,我們還有其他的錄音方式嗎祭务?答案是肯定的内狗。上面我們提到HAL層依賴alsa-lib庫與驅(qū)動(dòng)層交互,我們直接使用alsa-lib义锥,繞開HAL層和Framework層不也可以做到嗎(當(dāng)然前提是要有系統(tǒng)權(quán)限)柳沙?
為什么會(huì)有這種述求呢?在做家居和車載產(chǎn)品時(shí)拌倍,會(huì)有四麥赂鲤、六麥、甚至八麥的場景贰拿。錄制大于2麥的設(shè)備時(shí)需要在HAL層以及Framework層做適配蛤袒,基于AOSP的修改會(huì)顯得特別重,特別是一些像回聲抑制膨更,聲源定位等信號(hào)處理算法妙真,如果集成在操作系統(tǒng),會(huì)有更新升級(jí)麻煩的問題荚守,我們可以基于alsa-lib在應(yīng)用層拿到多路數(shù)據(jù)調(diào)用信號(hào)處理算法珍德,這樣算法模塊升級(jí)只需要升級(jí)APP即可,不需要升級(jí)整個(gè)系統(tǒng)矗漾。
我們先來看看Android系統(tǒng)自帶的tinyX系列工具锈候。
4.1 tinymix混響器
在root用戶下調(diào)用tinymix可以查看硬件驅(qū)動(dòng)支持的混響配置
root@android:/ # tinymix
Number of controls: 7
ctl type num name value
0 ENUM 1 Playback Path OFF
1 ENUM 1 Capture MIC Path MIC OFF
2 ENUM 1 Voice Call Path OFF
3 ENUM 1 Voip Path OFF
4 INT 2 Speaker Playback Volume 0 0
5 INT 2 Headphone Playback Volume 0 0
6 ENUM 1 Modem Input Enable ON
root@android:/ #
復(fù)制代碼
那么它里面的內(nèi)容是什么意思呢?
- 首先我們要知道敞贡,一個(gè)mixer通常有多個(gè)controler泵琳,像這個(gè),里面有7個(gè)誊役,然后就分別列出每一個(gè)controller的信息获列;
- 首先看第一個(gè):它的編號(hào)為0,類型是ENUM型蛔垢,它目前的值是OFF击孩,它是用來控制音頻輸出通道;
- 同理鹏漆,第二個(gè)也控制音頻輸入通道巩梢;
- 第三個(gè),通話音頻通道艺玲;
- 第四個(gè)IP電話音頻通道括蝠;
- 第五個(gè)揚(yáng)聲器音量,和上層音量值無關(guān)饭聚;
- 第六個(gè)耳機(jī)音量忌警,和上層音量值無關(guān);
一般Playback Path對(duì)應(yīng)的枚舉值有:
- OFF:關(guān)閉
- RCV
- SPK:揚(yáng)聲器
- HP:耳機(jī)帶麥
- HP_NO_MIC:耳機(jī)無麥
- BT:藍(lán)牙
那么我如果像改變某一項(xiàng)的時(shí)候若治,要怎么設(shè)置呢慨蓝?方法是tinymix ctl value;如果tinymix只跟上控制器的編號(hào)端幼,就會(huì)把控制器的當(dāng)前狀態(tài)顯示出來:
# tinymix 7
Audio linein in: On
# tinymix 7 0
root@dolphin-fvd-p1:/ # **tinymix 7**
Audio linein in: Off
復(fù)制代碼
4.2 tinycap采集器
使用下面命令即可實(shí)現(xiàn)錄制并保存到sd卡:
tinycap
Usage: tinycap file.wav [-D card] [-d device] [-c channels] [-r rate] [-b bits] [-p period_size] [-n n_periods]
tinycap /sdcard/rec.wav -D 0 -d 0 –c 4 –r 16000 –b 16 –p 1024 –n 3
復(fù)制代碼
4.3 tinyplay播放
tinyplay
Usage: tinyplay file.wav [-D card] [-d device] [-p period_size] [-n n_periods]
tinyplay /sdcard/test44.wav -D 0 -d 0 -p 1024 -n 3
復(fù)制代碼
4.4 程序中集成
現(xiàn)在我們已經(jīng)通過命令的方式實(shí)現(xiàn)了繞開framework的音頻采集礼烈,我們?cè)谧约旱腶pp中怎么使用呢?如果還是通過命令的方式只能錄制到文件婆跑,無法實(shí)現(xiàn)流式錄制此熬。
解決辦法是我們的app依賴tinyalsa庫
struct pcm_config config;
config.channels = 4;
config.rate = 16000;
config.period_size = 1024;
config.period_count = 4;
config.start_threshold = 0;
config.stop_threshold = 0;
config.silence_threshold = 0;
if (bitDepth == 32)
config.format = PCM_FORMAT_S32_LE;
else if (bitDepth == 16)
config.format = PCM_FORMAT_S16_LE;
pcm = pcm_open(0, device, PCM_IN, &config);
if (!pcm || !pcm_is_ready(pcm)) {
return -1;
}
int bufferSize = pcm_get_buffer_size(pcm);
char *buffer = (char*)malloc(bufferSize);
int i = pcm_read(pcm, buffer, bufferSize);
if(i ==0){
//success
}
復(fù)制代碼
5. 總結(jié)
本文介紹了Andorid系統(tǒng)的整套音頻架構(gòu),以及架構(gòu)各層級(jí)的功能及作用滑进。并介紹了一種繞開framework層的新的音頻采集方式犀忱。其實(shí)Andorid的音頻架構(gòu)實(shí)現(xiàn)是更復(fù)雜的一個(gè)過程,本文只是簡略的對(duì)各個(gè)模塊做了一些介紹扶关,以助于更深入理解上一篇提到的各個(gè)API的實(shí)現(xiàn)阴汇。其實(shí)API提供出來的音頻接口,都是屬于接口層节槐,不論是Java接口還是C++接口搀庶,都隸屬于應(yīng)用進(jìn)程。以采集為例铜异,不論我們調(diào)用哪個(gè)API哥倔,我們都會(huì)發(fā)現(xiàn)啟動(dòng)后應(yīng)用進(jìn)程會(huì)多出一個(gè)AudioRecord的線程:
我們啟動(dòng)的錄制線程調(diào)用API只是從AudioRecord線程寫入到Buffer的數(shù)據(jù)的讀取。
更多Android技術(shù)分享可以關(guān)注@我,也可以加入QQ群號(hào):1078469822揍庄,學(xué)習(xí)交流Android開發(fā)技能咆蒿。
作者:輕口味
鏈接:https://juejin.cn/post/7011154855590887437
來源:掘金
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán)蚂子,非商業(yè)轉(zhuǎn)載請(qǐng)注明出處沃测。