Audio Unit 基礎

如圖所示,全部 iOS 音頻技術都是基於 audio units。此處顯示的更高級別的技術,如 Media Player,AV Foundation,OpenAL,AudioToolbox,是對 audio units 的封裝,爲特定的任務提供專用且簡化的 API。ios

Figure 1

如在可控性、性能、靈活性有很是高的需求,或者須要實現特定的功能(例如迴音消除),直接使用 audio unit 是一個正確的選擇。編程

Audio Units 提供高效,模塊化音頻處理方案

當你須要實現如下需求時,不使用高級 API,直接使用 audio unitsapi

  • 低延時同步音頻輸入輸出,例如 VoIP 應用
  • 響應回放合成聲音,例如音樂遊戲或合成樂器
  • 使用特定的 audio unit 特徵,例如回聲消除,混音,色調均衡
  • 處理鏈結構讓你能夠將音頻處理模塊組裝到靈活的網絡中。這是 iOS 中惟一提供此功能的音頻 API

iOS 中的 Audio Units

根據不一樣功能分類,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 動態插件結構不支持第三方 audio units,也就是說,動態加載的 audio units 僅能經過操做系統提供。安全

Effect Unit

iOS 4 提供了一個效果單元,iPod Equalizer,與 iPod 內置應用使用相同的均衡器。查看這個 audio unit 的 iPod 應用用戶界面,進入設置 -> iPod -> EQ。當使用此 audio unit,必須提供本身的用戶界面。此 audio unit 提供了一組預設的均衡曲線,例如低音加強,Pop 和 Spoken Word。網絡

Mixer Units

iOS 提供兩個 mixer units。3D Mixer unit 是 OpenAL 的基礎,若是須要實現 3D Mixer unit 的特徵,能夠優先使用 OpenAL,它提供了高級 API,而且很是適合遊戲應用程序。關於如何使用 OpenAL,見示例代碼: oalTouch。數據結構

Multichannel Mixer unit 爲任意數量的單聲道或立體聲提供混音,立體聲輸出。能夠打開和關閉每個輸入,設置輸入增益,並設置立體聲平移位置。見示例代碼:MixerHost。app

I/O Units

iOS 提供了三個 I/O units,其中 Remote I/O unit 是最經常使用的。鏈接輸入輸出音頻硬件,對傳入和傳出的樣本值低延遲訪問,提供硬件音頻格式和應用音頻格式之間的格式轉化。見示例代碼:aurioTouch。異步

Voice-Processing I/O unit 是對 Remote I/O unit 的拓展,添加了語音聊天中的回聲消除,還提供了自動增益矯正,語音質量調整,靜音等特性。模塊化

Generic Output unit 不鏈接音頻硬件,而是提供了一種將處理鏈的輸出發送到應用程序的機制。一般會使用作離線音頻處理

Format Converter Unit

iOS 4 提供了 Format Converter Unit,一般經過 I/O unit 間接使用。

兩個 Audio Unit API

iOS 中兩個和 audio units 相關的 API,一個 API 直接處理 audio units ,另外一個處理 audio processing graphs,在應用中能夠同時使用兩個 API。

這兩個 API 之間有一些功能重疊,能夠根據本身編程風格自由組合和搭配,提供的功能以下:

  • 獲取對定義音頻單元動態連接庫的引用
  • 實例化 audio unit
  • audio units 互聯和附件回調函數
  • 開始和中止音頻流

Audio Unit 獲取

首先須要在音頻組件描述數據結構中肯定其類型、子類型和製造商密匙。下面指定了一個特定的 audio Unit,Remote I/O unit,對 componentManufacturer 字段,全部的 iOS audio units 使用 kAudioUnitManufacturer_Apple。如需建立一個通用描述,能夠將類型或者子類型設置爲0,例如爲了匹配全部的 I/O unit,能夠將 componentSubType 設置爲0。

AudioComponentDescription ioUnitDescription;
    ioUnitDescription.componentType = kAudioUnitType_Output;
    ioUnitDescription.componentSubType = kAudioUnitSubType_RemoteIO;
    ioUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
    ioUnitDescription.componentFlags = 0;
    ioUnitDescription.componentFlagsMask = 0;

使用 audio unit API 獲取 audio unit 實例,對於 AudioComponentFindNext ,若是第一個參數傳空,按照系統定義的排序,找到第一個符合的 audio unit ,若是該參數爲先前找到的音頻單元,則該功能找到與描述匹配的下一個 audio unit,例如此用法能夠經過重複調用 AudioComponentFindNext 來獲取全部 I/O 單元的引用。

AudioComponent foundIoUnitReference = AudioComponentFindNext(NULL, &ioUnitDescription);
    AudioUnit ioUnitInstance;
    AudioComponentInstanceNew(foundIoUnitReference, &ioUnitInstance);

使用 audio processing graph API 獲取 audio unit

AUGraph processingGraph;
    NewAUGraph(&processingGraph);
    
    AUNode ioNode;
    AUGraphAddNode(processingGraph, &ioUnitDescription, &ioNode);
    AUGraphOpen(processingGraph);
    
    AudioUnit ioUnit;
    AUGraphNodeInfo(processingGraph, ioNode, NULL, &ioUnit);

Audio Units 結構

如圖所示,Audio Unit 中有一個 input element,一個 output element,這種結構比較常見,但這並不適合全部情況。例如在 mixer unit 中,會存在多個 input element,一個 output element的狀況。

element 1 能夠理解爲 input element(bus),element 0 理解爲output element。Input scope 和 Output scope,直接參與音頻流的流程,音頻從 Input scope 輸入,從 Output scope 輸出,一些參數或屬性適用於 Input scope 或 Output scope。Global scope,應用於整個 audio unit,不與音頻流關聯,它有一個 element,命名爲 element 0,一些屬性,像 kAudioUnitProperty_MaximumFramesPerSlice 應用於 Global scope。

Audio Units 屬性

設置屬性,可使用函數 AudioUnitSetProperty

UInt32 busCount = 2;
    OSStatus result = AudioUnitSetProperty(mixerUnit, kAudioUnitProperty_ElementCount, kAudioUnitScope_Input, 0, &busCount, sizeof(busCount));

下面是一些經常使用的屬性:

  • kAudioOutputUnitProperty_EnableIO 啓用或禁止 I/O,默認輸出開啓,輸入禁止。
  • kAudioUnitProperty_ElementCount 配置元素個數
  • kAudioUnitProperty_MaximumFramesPerSlice 設置 audio unit 的最大幀數
  • kAudioUnitProperty_StreamFormat 指定輸入 audio unit 輸入輸出元素的數據格式

大部分屬性能夠在 audio unit 未初始化的時候設置,由於這些屬性通常不會發生改變,有些屬性像 iPod EQ unit 中的 kAudioUnitProperty_PresentPreset和 Voice-Processing I/O unit 中的 kAUVoiceIOProperty_MuteOutput 這些屬性會在播放音頻的時候也會發生改變

查找屬性是否可得,訪問屬性值,監聽改變,可使用一下函數:

  • AudioUnitGetPropertyInfo 查看屬性是否可得,若是能夠,會獲得值大小和值是否能夠改變
  • AudioUnitGetProperty, AudioUnitSetProperty 獲取或設置屬性
  • AudioUnitAddPropertyListener, AudioUnitRemovePropertyListenerWithUserData 安裝或者移除監聽屬性變化回調函數

Audio Units 參數

audio unit 參數是用戶能夠在音頻生成的過程當中更改,事實上,大部分參數能夠在 audio unit 正在執行時實時調整的,例如音量。

  • AudioUnitGetParameter
  • AudioUnitSetParameter

I/O Units 的基本特性

  • Input element 和 Output element 都是 I/O unit 的一部分,能夠將它們視爲一個獨立的個體,單獨啓動或禁止每個 Element,默認狀況下,Element 1 禁用,Element 0 開啓。
  • 音頻輸入硬件麥克風直接連着 Element 1, Element 1 的 Input scope 對你是不可見的,你首次訪問硬件輸入的音頻數據是位於 Element 1 的 Output scope。
  • 音頻輸出硬件揚聲器直接連着 Element 0,Element 0 的 Output scope 對你是不可見的,數據從 Element 1 的 Output scope 傳遞到 Element 0 的 Input scope。

每個 Element都有本身的 input scope 和 output scope,當描述 I/O unit 的時候可能會有困惑,至關於這樣描述,你收到收據來自 input element 的 output scope,發送數據到 output element 的 input scope。
I/O unit 是惟一可以在 audio processing graph 中啓動和中止音頻流的 audio unit。I/O unit 負責在音頻單元APP中的音頻流。

Audio Processing Graphs 管理 Audio Units

AUGraph 用於構建和管理 audio units 處理鏈,能夠利用多個 audio units 和多個回調函數功能,建立幾乎任何你能夠想象的音頻處理解決方案。
AUGraph 增長了線程安全,讓你能夠即時從新配置處理鏈,例如你能夠安全插入一個均衡器,甚至在音頻播放時能夠交換混音器輸入的其它回調函數。實際上,AUGraph 提供了 iOS 中惟一能夠在音頻應用程序中執行這種動態從新配置的 API 。
Audio Processing Graph 使用了 AUNode 表示上 graph 中 一個單獨的 audio unit ,當使用 Audio Processing Graphs,一般與包含 audio units 的代理 AUNode 交互,而不是直接使用 audio unit。
當將 graph 組合時,須要配置每個 audio unit ,而且必須經過 audio unit API 直接與 audio unit 交互,節點單元自己是不能夠配置的,經過這種方式,須要使用這兩種 API。
一般狀況下,Audio Processing Graphs 一般須要三個任務,將節點添加到 Graph 中,直接配置由節點表示的 audio unit,互連節點。

#Audio Processing Graph 有一個 I/O Unit

每個 audio processing graph 有一個 I/O unit,不管你是錄音,播放,同步 I/O。Graphs 經過 AUGraphStart 和 AUGraphStop 啓動和中止音頻流,經過函數 AudioOutputUnitStart 和 AudioOutputUnitStop 傳遞開始和中止消息到 I/O unit。

Audio Processing Graphs 提供線程安全

audio processing graph 使用「待辦事項列表」提供線程安全,API 的一些函數添加工做單元到稍後執行的更改列表中,在你指定完整的更改好,讓 graph 實現他們。
這是一些 audio processing graph 支持的重配置函數

  • 添加或刪除音頻單元節點(AUGraphAddNode,AUGraphRemoveNode)
  • 添加或刪除節點間的鏈接(AUGraphConnectNodeInput,AUGraphDisconnectNodeInput)
  • 渲染回調函數鏈接到 aduio unit 的輸入總線(AUGraphSetNodeInputCallback)

下面看一個重配置 audio processing graph 的例子,構建一個 graph 包含 Multichannel Mixer unit 和 Remote I/O unit,將聲音輸入到混頻器的兩個輸入總線上。從混合器輸出數據到 I/O unit 的 Output element 上。

如今用戶想插入均衡器到其中一個音頻流上,如何完成動態配置

  • 使用 AUGraphDisconnectNodeInput 斷掉 input 1 到 mixer unit 的回調
  • 添加一個 iPod EQ unit 到 graph 中,須要使用 AudioComponentDescription 指定 iPod EQ unit 的結構,接着調用 AUGraphAddNode,至此,iPod EQ unit 被安裝可是沒有初始化,被 graph 擁有可是沒有參與到音頻流中
  • 重配置和初始化 iPod EQ unit,詳情以下:

調用 AudioUnitGetProperty 函數獲得 mixer input 的流格式(kAudioUnitProperty_StreamForamt)
調用 AudioUnitSetProperty 函數兩次,一次設置 iPod EQ unit 的輸入格式,一次設置它的輸出格式
調用 AudioUnitInitialize 函數,給 iPod EQ 分配資源和準備處理音頻,這個函數調用時線程安全的
調用 AUGraphSetNodeInputCallback 函數,設置鼓的回調函數到 iPod EQ unit 的輸入

回調函數提供數據給 Audio Units

爲了給 audio unit 的輸入總線提供數據,使用聽從 AURenderCallback 原型的回調函數,音頻輸入單元須要一幀數據的時候觸發回調。在處理 audio unit 應用中,寫回調函數多是最具備創意的工做,你能根據你的意願產生和改變聲音。
回調函數有嚴格的性能要求,回調存在於實時線程上,隨後回調異步到達,回調函數內部全部的工做發生在時間有限的環境中,當下一幀數據到達,你仍在處理以前的回調產生的幀,聲音則會產生間隙,出於這個緣由,不得在回調函數主體中執行耗時操做,例如鎖定,分配內存,訪問文件系統,網絡鏈接等。

理解音頻單元的回調函數

回調函數頭部

static OSStatus MyAURenderCallBack(void                                    *inRefCon,
                                                      AudioUnitRenderActionFlags  *ioActionFlags,
                                                      const AudioTimeStamp         *inTimeStamp,
                                                      UInt32                                inBusNumber,
                                                      UInt32                                inNumberFrames,
                                                      AudioBufferList                   *ioData);
  • inRefCon,參數指向回調附加到 audio unit 輸入時指定的編程上下文

  • ioActionFlags,參數容許提供提示當沒有音頻數據處理時,例如當你的應用程序是合成吉他,用戶當面沒有播放,請執行此操做。當你想要輸出靜音,能夠在回調主體中使用以下語句:*ioActionFlags |= kAudioUnitRenderAction_OutputIsSilence,而且你必須明確地將 ioData 參數指向的緩衝區設置爲0。
  • inTimeStamp,回調函數被觸發時間,包含一個 AudioTimeStamp 結構體。
  • inBusNumber,參數指示調用回調的音頻單元總線
  • inNumberFrames,當前調用的音頻採樣數
  • ioData,指向音頻數據緩存區

相關文章
相關標籤/搜索