一、什么是Audio Unit
iOS提供了音頻處理插件,支持混合、均衡、格式轉換和實時輸入/輸出用于錄制、播放、離線渲染和實時對話如VoIP(互聯網協議語音)。你可以從iOS應用動態加載和使用它,這些強大和靈活的插件叫做Audio Unit。
Audio units通常工作在一個封閉對象的上下文中,該對象為audio processing graph,如下圖。在此例中,你的app通過一個或多個callback functions發送audio到第一個audio unit,并對每個audio unit單獨控制。I/O輸出unit,直接連接輸出硬件。
Audio units提供非常有用的個性化功能,如立體聲像,混音,音量控制,音頻電平測量。
二、Audio unit用在哪些方面
1、低延遲的同時音頻I/O(輸入和輸出),例如VoIP應用
2、響應回放合成聲音,例如用于音樂游戲或或合成樂器
3、使用特定的音頻單元功能,例如回聲消除,混音,或者音調均衡
4、一種處理鏈架構,讓你靈活的將音頻處理模塊組裝起來,這是iOS中唯一提供此功能的音頻API
三、Audio Units in iOS
iOS根據功能提供了七種audio unit,分為四類,如下圖:
3.1 Effect Unit
iOS4提供了一個effect unit,即iPod Equalizer,與內置iPod應用程序使用的均衡器相同。要查看該audio unit的iPod應用程序用戶界面,請轉至Setting> iPod> EQ。 使用此audio unit時,您必須提供自己的UI。 該audio unit提供一組預設均衡曲線,如低音增強器,流行音樂和口語
3.2 Mixer Units
iOS提供兩個mixer units。3D Mixer unit是OpenAL構建的基礎。在大多數情況下,如果需要3D Mixer unit的功能,最佳選擇是使用OpenAL,它提供更適合游戲應用的更高級API。
Multichannel Mixer unit可以為任意數量的單聲道或立體聲流提供混音,并帶有立體聲輸出。你可以打開或關閉每個輸入,設置其輸入增益,并設置其立體聲平移位置。
3.3 I/O Units
iOS提供三個I/O unit。Remote I/O是最常用的。它連接輸入和輸出音頻硬件,并為你提供對各個傳入和傳出音頻樣品值的低延遲訪問。它提供硬件音頻格式和應用程序音頻格式之間的格式轉換,通過Format Converter unit進行格式轉換。
Voice-Processing I/O unit通過添加聲學回聲消除來擴展遠程I/O單元,以用于VoIP或語音聊天應用程序。它還提供自動增益校正,語音處理質量和靜音。
Generic Output unit不連接到音頻硬件,而是提供將處理鏈的輸出發送到應用程序。通常使用Generic Output unit 進行離線音頻處理
3.4 Format Converter Unit
iOS4提供,通常通過I/O單元間接使用
五、使用兩種方式來獲取audio unit
要在運行時查找audio unit,需要為AudioComponentDescription數據結構指定type,subtype,manufacturer。無論是audio unit還是audio process graph API。
AudioComponentDescription audioDesc = {0};
audioDesc.componentType = kAudioUnitType_Output;
audioDesc.componentSubType = kAudioUnitSubType_RemoteIO;
audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
不同的audio unit的AudioComponentDescription設置如下圖表:
5.1 使用AudioComponentDescription初始化Audio Unit:
// find component
AudioComponent compoent = AudioComponentFindNext(NULL, &audioDesc);
// create new instance
AudioComponentInstanceNew(compoent, &audioUnit);
5.2 使用AUGraph來初始化audio unit:
// Declare and instantiate an audio processing graph
AUGraph processingGraph;
NewAUGraph (&processingGraph);
// Add an audio unit node to the graph, then instantiate the audio unit
AUNode ioNode;
AUGraphAddNode (processingGraph, &audioDesc, &ioNode);
AUGraphOpen (processingGraph); // indirectly performs audio unit instantiation
// Obtain a reference to the newly-instantiated I/O unit
AudioUnit ioUnit;
AUGraphNodeInfo (processingGraph, ioNode, NULL, &ioUnit);
六、使用scope和elements來指定audio units的各個部分
Audio unit的各個部分組織成scopes and element,如下圖所示。當調用函數去配置和控制audio unit時,你可以指定scope和element以標識函數的特點目標。
scope是audio unit內的編程上下文。雖然global scope可能暗示,但這些上下文從不嵌套。一般是使用一個常量值來自AudioUnitScope枚舉。
element是嵌套在audio unit scope中的編程上下文。當element是輸入或輸出scope的一部分時,它類似于物理音頻設備中的信號總線,因此有時成為總線。
global scope適用于整個audio unit,不與任何特定音頻流相關聯。它只有一個元素,即0。某些屬性,如每個切片最大幀數(kAudioUnitProperty_MaximumFramesPerSlice),僅適用于global scope
輸入和輸出scopes直接參與通過audio unit移動一個或多個音頻流。正如你所期待的那樣,音頻輸入scope進入從輸出scope離開。屬性或參數可以作為整體應用于輸入scope或輸出scope,某些屬性只能應用于scope特定的element
七、AudioUnitSetProperty配置audio unit
AudioUnitProperty是一個鍵值對。以下是audio unit開發中常用的一些屬性:
kAudioOutputUnitProperty_EnableIO
:用于在I/O unit上啟用和禁用input or output。默認情況輸出已啟用,輸入已禁用
kAudioUnitProperty_ElementCount
:用于配置mixer unit上輸入elements的數量
kAudioUnitProperty_MaximumFramesPerSlice
:用于指定audio unit應準備響應于渲染調用而產生的音頻數據最大幀數。不需要為I/O unit設置該值,因為它們已預先配置為處理系統請求的任何切片大小。對于其它audio unit,你必須將此屬性設置為4096以處理屏幕睡眠,除非設備上正在運行音頻輸入。當音頻輸入運行時,系統保持切片大小為1024
kAudioUnitProperty_StreamFormat
:用于指定特定音頻單元輸出或輸出總線的音頻流數據格式
發現屬性的可用性,訪問其值以及監聽其值的更改使用以下函數
- AudioUnitGetPropertyInfo:發現屬性是否可用,則為你提供其值的數據大小以及是否可以更改該值
- AudioUnitGetProperty,AudioUnitSetProperty:獲取或設置屬性的值
- AudioUnitAddPropertyListener,AudioUnitRemovePropertyListenerWithUserData:安裝或刪除回調函數以監視屬性值的更改
八、設置和獲取parameter
audio unit parameter是用戶可調節的設置,可在audio unit產生音頻時改變。實際上,大多數parameters是在audio unit正在執行處理時,實時調整的。它也是鍵值對的形式。每個parameter的值是32位浮點類型。使用以下函數來設置或獲取parameter的值:
- AudioUnitGetParameter
- AudioUnitSetParameter
九、I/O Unit的特征
上圖I/O Unit有兩個element,但它們是獨立的,例如,你可以根據應用程序的需要使用enable I/O屬性(kAudioOutputUnitProperty_EnableIO)來獨立啟用或禁用某個element。每個element都有Input scope和Output scope。
I/O Unit的element 1
連接音頻的輸入硬件,在上圖中由麥克風表示。開發者只能訪問控制Output scope
I/O Unit的element 0
連接音頻的輸出硬件,在上圖中由揚聲器表示。開發者只能訪問控制Input scope
input element is element 1(單詞Input的字母“I”,類似1)
output element is element 0 (單詞Output的字母“O”,類型0)
十、Auio Processing Graphs Manage Audio Units
使用數據類型AUGraph,用于構建和管理audio unit處理鏈。它可以利用多個音頻單元和多個渲染回調函數的功能,允許你創建幾乎任何你能想象的音頻處理解決方案。
AUGraph是線程安全的,它能夠動態地重新配置處理鏈。例如,你可以安全的插入均衡器,甚至可以在播放時交換混音器輸入的不同渲染回調函數。事實上AUGraph是iOS唯一提供的API,用于在音頻應用中執行此類動態重新配置。
AUNode來表示graph上下文中的單個audio unit。當使用graph是,你通常與node交互,而不是直接與audio unit交互
當你將graph放在一起時,你必須配置每個audio unit。為此你必須通過audio unit API直接與audio unit進行交互。audio unit node本身是不可配置的
你還可以將AUNode實例作為復雜graph中的元素,通過定義node來表示完整audio processing subgraph。在這種情況下,subgraph末尾必須是Generic Output unit(一種不連接到硬件設備的I/O unit)
總而言之,構建audio processing graph需要三個任務:
1、添加node到graph
2、直接配置nodes表示的audio units
3、互連nodes
AUGraph提供了以下函數來重新配置:
AUGraphAddNode,AUGraphRemoveNode:添加或移除audio unit node
AUGraphConnectNodeInput,AUGraphDisconnectNodeInput:添加或移除nodes之間的connections
AUGraphSetNodeInputCallback:connecting一個渲染回調給audio unit的input bus
十一、一些設計模式
I/O Pass Through
I/O pass-through模式將傳入的音頻直接發送到硬件輸出,中間沒有處理音頻數據。
I/O Without a Render Callback Function
在Remote I/O unit的elements之間添加一個或多個其它audio unit,可以構建出更有用的應用,因為沒有回調函數,則無法直接操作音頻,限制了實用性。
I/O with a Render Callback Function
在Remote I/O unit之間添加一個回調函數,可以在傳入音頻到達輸出硬件之前對其進行操作。比如使用渲染回調函數調整輸出音量,添加顫音,鈴聲調制,回聲或其他效果。通過使用Accelerate框架中提供的傅立葉和卷積函數,你的可能性是無窮盡的
Output-Only with a Render Callback Function
適用于游戲和音樂合成app,將渲染回調函數直接連接到Remote I/O的Output element的input scope