轉(zhuǎn)自:https://www.cnblogs.com/wangyaoguo/p/8392660.html
Audio Unit 基礎(chǔ)
如圖所示饮六,所有 iOS 音頻技術(shù)都是基于 audio units其垄。此處顯示的更高級別的技術(shù),如 Media Player卤橄,AV Foundation绿满,OpenAL,AudioToolbox窟扑,是對 audio units 的封裝喇颁,為特定的任務提供專用且簡化的 API。
如在可控性嚎货、性能橘霎、靈活性有非常高的需求,或者需要實現(xiàn)特定的功能(例如回音消除)厂抖,直接使用 audio unit 是一個正確的選擇茎毁。
Audio Units 提供高效克懊,模塊化音頻處理方案
當你需要實現(xiàn)以下需求時忱辅,不使用高級 API,直接使用 audio units
- 低延時同步音頻輸入輸出谭溉,例如 VoIP 應用
- 響應回放合成聲音墙懂,例如音樂游戲或合成樂器
- 使用特定的 audio unit 特征,例如回聲消除扮念,混音损搬,色調(diào)均衡
- 處理鏈結(jié)構(gòu)讓你可以將音頻處理模塊組裝到靈活的網(wǎng)絡中。這是 iOS 中唯一提供此功能的音頻 API
iOS 中的 Audio Units
根據(jù)不同功能分類柜与,iOS 提供了七種 audio units
- Effect - iPod Equalizer
- Mixing - 3D Mixer
- Mixing - Multichannel Mixer
- I/O - Remote I/O
- I/O - Voice-Processing I/O
- I/O - Generic Output
- Format conversion - Format Converter
注意:iOS 動態(tài)插件結(jié)構(gòu)不支持第三方 audio units巧勤,也就是說,動態(tài)加載的 audio units 僅能通過操作系統(tǒng)提供弄匕。
Effect Unit
iOS 4 提供了一個效果單元颅悉,iPod Equalizer,與 iPod 內(nèi)置應用使用相同的均衡器迁匠。查看這個 audio unit 的 iPod 應用用戶界面剩瓶,進入設置 -> iPod -> EQ。當使用此 audio unit城丧,必須提供自己的用戶界面延曙。此 audio unit 提供了一組預設的均衡曲線,例如低音增強亡哄,Pop 和 Spoken Word枝缔。
Mixer Units
iOS 提供兩個 mixer units。3D Mixer unit 是 OpenAL 的基礎(chǔ)蚊惯,如果需要實現(xiàn) 3D Mixer unit 的特征愿卸,可以優(yōu)先使用 OpenAL国夜,它提供了高級 API,并且非常適合游戲應用程序克蚂。關(guān)于如何使用 OpenAL垂攘,見示例代碼: oalTouch。
Multichannel Mixer unit 為任意數(shù)量的單聲道或立體聲提供混音赊舶,立體聲輸出睁搭。可以打開和關(guān)閉每一個輸入笼平,設置輸入增益园骆,并設置立體聲平移位置。見示例代碼:MixerHost寓调。
I/O Units
iOS 提供了三個 I/O units锌唾,其中 Remote I/O unit 是最常用的。連接輸入輸出音頻硬件夺英,對傳入和傳出的樣本值低延遲訪問晌涕,提供硬件音頻格式和應用音頻格式之間的格式轉(zhuǎn)化。見示例代碼:aurioTouch痛悯。
Voice-Processing I/O unit 是對 Remote I/O unit 的拓展余黎,添加了語音聊天中的回聲消除,還提供了自動增益矯正载萌,語音質(zhì)量調(diào)整惧财,靜音等特性。
Generic Output unit 不連接音頻硬件扭仁,而是提供了一種將處理鏈的輸出發(fā)送到應用程序的機制垮衷。通常會使用做離線音頻處理
Format Converter Unit
iOS 4 提供了 Format Converter Unit,通常通過 I/O unit 間接使用乖坠。
兩個 Audio Unit API
iOS 中兩個和 audio units 相關(guān)的 API搀突,一個 API 直接處理 audio units ,另一個處理 audio processing graphs瓤帚,在應用中可以同時使用兩個 API描姚。
- 直接使用 audio units
- 創(chuàng)建配置 audio processing graph
這兩個 API 之間有一些功能重疊,可以根據(jù)自己編程風格自由組合和搭配戈次,提供的功能如下:
- 獲取對定義音頻單元動態(tài)鏈接庫的引用
- 實例化 audio unit
- audio units 互聯(lián)和附件回調(diào)函數(shù)
- 開始和停止音頻流
Audio Unit 獲取
首先需要在音頻組件描述數(shù)據(jù)結(jié)構(gòu)中確定其類型轩勘、子類型和制造商密匙。下面指定了一個特定的 audio Unit怯邪,Remote I/O unit绊寻,對 componentManufacturer 字段,所有的 iOS audio units 使用 kAudioUnitManufacturer_Apple。如需創(chuàng)建一個通用描述澄步,可以將類型或者子類型設置為0冰蘑,例如為了匹配所有的 I/O unit,可以將 componentSubType 設置為0村缸。
使用 audio unit API 獲取 audio unit 實例祠肥,對于 AudioComponentFindNext ,如果第一個參數(shù)傳空梯皿,按照系統(tǒng)定義的排序仇箱,找到第一個符合的 audio unit ,如果該參數(shù)為先前找到的音頻單元东羹,則該功能找到與描述匹配的下一個 audio unit剂桥,例如此用法可以通過重復調(diào)用 AudioComponentFindNext 來獲取所有 I/O 單元的引用。
使用 audio processing graph API 獲取 audio unit
Audio Units 結(jié)構(gòu)
如圖所示属提,Audio Unit 中有一個 input element权逗,一個 output element,這種結(jié)構(gòu)比較常見冤议,但這并不適合所有狀況斟薇。例如在 mixer unit 中,會存在多個 input element求类,一個 output element的情況奔垦。
element 1 可以理解為 input element(bus),element 0 理解為output element尸疆。Input scope 和 Output scope,直接參與音頻流的流程惶岭,音頻從 Input scope 輸入寿弱,從 Output scope 輸出,一些參數(shù)或?qū)傩赃m用于 Input scope 或 Output scope按灶。Global scope症革,應用于整個 audio unit,不與音頻流關(guān)聯(lián)鸯旁,它有一個 element噪矛,命名為 element 0,一些屬性铺罢,像 kAudioUnitProperty_MaximumFramesPerSlice 應用于 Global scope艇挨。
Audio Units 屬性
設置屬性,可以使用函數(shù) AudioUnitSetProperty
下面是一些常用的屬性:
- kAudioOutputUnitProperty_EnableIO 啟用或禁止 I/O韭赘,默認輸出開啟缩滨,輸入禁止。
- kAudioUnitProperty_ElementCount 配置元素個數(shù)
- kAudioUnitProperty_MaximumFramesPerSlice 設置 audio unit 的最大幀數(shù)
- kAudioUnitProperty_StreamFormat 指定輸入 audio unit 輸入輸出元素的數(shù)據(jù)格式
大部分屬性可以在 audio unit 未初始化的時候設置,因為這些屬性一般不會發(fā)生改變脉漏,有些屬性像 iPod EQ unit 中的 kAudioUnitProperty_PresentPreset和 Voice-Processing I/O unit 中的 kAUVoiceIOProperty_MuteOutput 這些屬性會在播放音頻的時候也會發(fā)生改變
查找屬性是否可得苞冯,訪問屬性值,監(jiān)聽改變侧巨,可以使用一下函數(shù):
- AudioUnitGetPropertyInfo 查看屬性是否可得舅锄,如果可以,會得到值大小和值是否可以改變
- AudioUnitGetProperty, AudioUnitSetProperty 獲取或設置屬性
- AudioUnitAddPropertyListener, AudioUnitRemovePropertyListenerWithUserData 安裝或者移除監(jiān)聽屬性變化回調(diào)函數(shù)
Audio Units 參數(shù)
audio unit 參數(shù)是用戶可以在音頻生成的過程中更改司忱,事實上巧娱,大部分參數(shù)可以在 audio unit 正在執(zhí)行時實時調(diào)整的,例如音量烘贴。
- AudioUnitGetParameter
- AudioUnitSetParameter
I/O Units 的基本特性
- Input element 和 Output element 都是 I/O unit 的一部分禁添,可以將它們視為一個獨立的個體,單獨啟動或禁止每一個 Element桨踪,默認情況下老翘,Element 1 禁用,Element 0 開啟锻离。
- 音頻輸入硬件麥克風直接連著 Element 1铺峭, Element 1 的 Input scope 對你是不可見的,你首次訪問硬件輸入的音頻數(shù)據(jù)是位于 Element 1 的 Output scope汽纠。
- 音頻輸出硬件揚聲器直接連著 Element 0卫键,Element 0 的 Output scope 對你是不可見的,數(shù)據(jù)從 Element 1 的 Output scope 傳遞到 Element 0 的 Input scope虱朵。
每一個 Element都有自己的 input scope 和 output scope莉炉,當描述 I/O unit 的時候可能會有困惑,相當于這樣描述碴犬,你收到收據(jù)來自 input element 的 output scope絮宁,發(fā)送數(shù)據(jù)到 output element 的 input scope。
I/O unit 是唯一能夠在 audio processing graph 中啟動和停止音頻流的 audio unit服协。I/O unit 負責在音頻單元APP中的音頻流绍昂。
Audio Processing Graphs 管理 Audio Units
AUGraph 用于構(gòu)建和管理 audio units 處理鏈,可以利用多個 audio units 和多個回調(diào)函數(shù)功能偿荷,創(chuàng)建幾乎任何你可以想象的音頻處理解決方案窘游。
AUGraph 增加了線程安全,讓你可以即時重新配置處理鏈跳纳,例如你可以安全插入一個均衡器忍饰,甚至在音頻播放時可以交換混音器輸入的其它回調(diào)函數(shù)。實際上棒旗,AUGraph 提供了 iOS 中唯一可以在音頻應用程序中執(zhí)行這種動態(tài)重新配置的 API 喘批。
Audio Processing Graph 使用了 AUNode 表示上 graph 中 一個單獨的 audio unit 撩荣,當使用 Audio Processing Graphs,通常與包含 audio units 的代理 AUNode 交互饶深,而不是直接使用 audio unit餐曹。
當將 graph 組合時,需要配置每一個 audio unit 敌厘,并且必須通過 audio unit API 直接與 audio unit 交互台猴,節(jié)點單元本身是不可以配置的,通過這種方式俱两,需要使用這兩種 API饱狂。
通常情況下,Audio Processing Graphs 通常需要三個任務宪彩,將節(jié)點添加到 Graph 中休讳,直接配置由節(jié)點表示的 audio unit,互連節(jié)點尿孔。
#Audio Processing Graph 有一個 I/O Unit
每一個 audio processing graph 有一個 I/O unit俊柔,無論你是錄音,播放活合,同步 I/O雏婶。Graphs 通過 AUGraphStart 和 AUGraphStop 啟動和停止音頻流,通過函數(shù) AudioOutputUnitStart 和 AudioOutputUnitStop 傳遞開始和停止消息到 I/O unit白指。
Audio Processing Graphs 提供線程安全
audio processing graph 使用“待辦事項列表”提供線程安全留晚,API 的一些函數(shù)添加工作單元到稍后執(zhí)行的更改列表中,在你指定完整的更改好告嘲,讓 graph 實現(xiàn)他們错维。
這是一些 audio processing graph 支持的重配置函數(shù)
- 添加或刪除音頻單元節(jié)點(AUGraphAddNode,AUGraphRemoveNode)
- 添加或刪除節(jié)點間的連接(AUGraphConnectNodeInput状蜗,AUGraphDisconnectNodeInput)
- 渲染回調(diào)函數(shù)連接到 aduio unit 的輸入總線(AUGraphSetNodeInputCallback)
下面看一個重配置 audio processing graph 的例子需五,構(gòu)建一個 graph 包含 Multichannel Mixer unit 和 Remote I/O unit,將聲音輸入到混頻器的兩個輸入總線上轧坎。從混合器輸出數(shù)據(jù)到 I/O unit 的 Output element 上。
現(xiàn)在用戶想插入均衡器到其中一個音頻流上泽示,如何完成動態(tài)配置
- 使用 AUGraphDisconnectNodeInput 斷掉 input 1 到 mixer unit 的回調(diào)
- 添加一個 iPod EQ unit 到 graph 中缸血,需要使用 AudioComponentDescription 指定 iPod EQ unit 的結(jié)構(gòu),接著調(diào)用 AUGraphAddNode械筛,至此捎泻,iPod EQ unit 被安裝但是沒有初始化,被 graph 擁有但是沒有參與到音頻流中
- 重配置和初始化 iPod EQ unit埋哟,詳情如下:
調(diào)用 AudioUnitGetProperty 函數(shù)得到 mixer input 的流格式(kAudioUnitProperty_StreamForamt)
調(diào)用 AudioUnitSetProperty 函數(shù)兩次笆豁,一次設置 iPod EQ unit 的輸入格式郎汪,一次設置它的輸出格式
調(diào)用 AudioUnitInitialize 函數(shù),給 iPod EQ 分配資源和準備處理音頻闯狱,這個函數(shù)調(diào)用時線程安全的
調(diào)用 AUGraphSetNodeInputCallback 函數(shù)煞赢,設置鼓的回調(diào)函數(shù)到 iPod EQ unit 的輸入
回調(diào)函數(shù)提供數(shù)據(jù)給 Audio Units
為了給 audio unit 的輸入總線提供數(shù)據(jù),使用遵從 AURenderCallback 原型的回調(diào)函數(shù)哄孤,音頻輸入單元需要一幀數(shù)據(jù)的時候觸發(fā)回調(diào)照筑。在處理 audio unit 應用中,寫回調(diào)函數(shù)可能是最具有創(chuàng)意的工作瘦陈,你能根據(jù)你的意愿產(chǎn)生和改變聲音凝危。
回調(diào)函數(shù)有嚴格的性能要求,回調(diào)存在于實時線程上晨逝,隨后回調(diào)異步到達蛾默,回調(diào)函數(shù)內(nèi)部所有的工作發(fā)生在時間有限的環(huán)境中,當下一幀數(shù)據(jù)到達捉貌,你仍在處理之前的回調(diào)產(chǎn)生的幀支鸡,聲音則會產(chǎn)生間隙,出于這個原因昏翰,不得在回調(diào)函數(shù)主體中執(zhí)行耗時操作苍匆,例如鎖定,分配內(nèi)存棚菊,訪問文件系統(tǒng)浸踩,網(wǎng)絡連接等。
理解音頻單元的回調(diào)函數(shù)
回調(diào)函數(shù)頭部
inRefCon统求,參數(shù)指向回調(diào)附加到 audio unit 輸入時指定的編程上下文
ioActionFlags检碗,參數(shù)允許提供提示當沒有音頻數(shù)據(jù)處理時,例如當你的應用程序是合成吉他码邻,用戶當面沒有播放折剃,請執(zhí)行此操作。當你想要輸出靜音像屋,可以在回調(diào)主體中使用如下語句:*ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence怕犁,并且你必須明確地將 ioData 參數(shù)指向的緩沖區(qū)設置為0。
inTimeStamp己莺,回調(diào)函數(shù)被觸發(fā)時間奏甫,包含一個 AudioTimeStamp 結(jié)構(gòu)體。
inBusNumber凌受,參數(shù)指示調(diào)用回調(diào)的音頻單元總線
inNumberFrames阵子,當前調(diào)用的音頻采樣數(shù)
ioData,指向音頻數(shù)據(jù)緩存區(qū)