AudioUnit框架詳細解析(二十二) —— 構(gòu)建您的應(yīng)用程序(一)

版本記錄

版本號 時間
V1.0 2018.07.05

前言

AudioUnit框架作為您的應(yīng)用程序添加復(fù)雜的音頻操作和處理功能。 創(chuàng)建在主機應(yīng)用程序中生成或修改音頻的音頻單元擴展花竞。接下來幾篇我們就一起看一下這個框架劲件,感興趣的看上面幾篇文章。
1. AudioUnit框架詳細解析(一) —— 基本概覽
2. AudioUnit框架詳細解析(二) —— 關(guān)于Audio Unit Hosting之概覽(一)
3. AudioUnit框架詳細解析(三) —— 關(guān)于Audio Unit Hosting之如何使用本文檔和參考資料(二)
4. AudioUnit框架詳細解析(四) —— 音頻單元提供快速的模塊化音頻處理之iOS中的Audio Units(一)
5. AudioUnit框架詳細解析(五) —— 音頻單元提供快速的模塊化音頻處理之在Concert中使用兩個音頻單元API(二)
6. AudioUnit框架詳細解析(六) —— 音頻單元提供快速的模塊化音頻處理之使用標識符來指定和獲取音頻單元(三)
7. AudioUnit框架詳細解析(七) —— 音頻單元提供快速的模塊化音頻處理之使用范圍和元素來指定音頻單元的部分(四)
8. AudioUnit框架詳細解析(八) —— 音頻單元提供快速的模塊化音頻處理之使用屬性來配置音頻單元(五)
9. AudioUnit框架詳細解析(九) —— 音頻單元提供快速的模塊化音頻處理之使用參數(shù)和UIKit為用戶提供控制(六)
10. AudioUnit框架詳細解析(十) —— 音頻單元提供快速的模塊化音頻處理之I / O單元的基本特性(七)
11. AudioUnit框架詳細解析(十一) —— 音頻處理圖管理音頻單元之音頻處理圖具有一個I / O單元(一)
12. AudioUnit框架詳細解析(十二) —— 音頻處理圖管理音頻單元之音頻處理圖提供線程安全性(二)
13. AudioUnit框架詳細解析(十三) —— 音頻處理圖管理音頻單元之音頻使用Pull通過圖表(三)
14. AudioUnit框架詳細解析(十四) —— 呈現(xiàn)回調(diào)函數(shù)將音頻饋送到音頻單元之了解音頻單元呈現(xiàn)回調(diào)函數(shù)(一)
15. AudioUnit框架詳細解析(十五) —— 音頻流格式啟用數(shù)據(jù)流之使用AudioStreamBasicDescription結(jié)構(gòu)(一)
16. AudioUnit框架詳細解析(十六) —— 音頻流格式啟用數(shù)據(jù)流之了解何處以及如何設(shè)置流格式(二)
17. AudioUnit框架詳細解析(十七) —— 從選擇設(shè)計模式開始之I / O傳遞(一)
18. AudioUnit框架詳細解析(十八) —— 從選擇設(shè)計模式開始之沒有渲染回調(diào)函數(shù)的I / O(二)
19. AudioUnit框架詳細解析(十九) —— 從選擇設(shè)計模式開始之具有渲染回調(diào)函數(shù)的I / O(三)
20. AudioUnit框架詳細解析(二十) —— 從選擇設(shè)計模式開始之僅具有渲染回調(diào)函數(shù)的輸出(四)
21. AudioUnit框架詳細解析(二十一) —— 從選擇設(shè)計模式開始之其他音頻單元Hosting設(shè)計模式(五)

Constructing Your App - 構(gòu)建您的應(yīng)用程序

無論您選擇哪種設(shè)計模式约急,構(gòu)建音頻單元hosting應(yīng)用程序的步驟基本相同:

    1. 配置音頻會話零远。
    1. 指定音頻單元。
    1. 創(chuàng)建音頻處理圖厌蔽,然后獲取音頻單元牵辣。
    1. 配置音頻單元。
    1. 連接音頻單元節(jié)點奴饮。
    1. 提供用戶界面纬向。
    1. 初始化然后啟動音頻處理圖。

Configure Your Audio Session - 配置音頻會話

接下來拐云,使用音頻會話對象請求系統(tǒng)使用您的首選采樣率作為設(shè)備硬件采樣率罢猪,如Listing 2-1所示。 這里的目的是避免硬件和您的應(yīng)用程序之間的采樣率轉(zhuǎn)換叉瘩。 這可以最大限度地提高CPU性能和音質(zhì)膳帕,并最大限度地減少電池消耗。

Listing 2-1 Configuring an audio session
    self.graphSampleRate = 44100.0; // Hertz
 
NSError *audioSessionError = nil;
AVAudioSession *mySession = [AVAudioSession sharedInstance]; //1 
[mySession setPreferredHardwareSampleRate: graphSampleRate //2
error: &audioSessionError]; 
[mySession setCategory: AVAudioSessionCategoryPlayAndRecord //3
error: &audioSessionError]; 
[mySession setActive: YES //4
error: &audioSessionError];
self.graphSampleRate = [mySession currentHardwareSampleRate]; //5

前面的行執(zhí)行以下操作:

    1. 獲取應(yīng)用程序的單例音頻會話對象的引用薇缅。
    1. 請求硬件采樣率危彩。 系統(tǒng)可能會或可能不會授予請求,具體取決于設(shè)備上的其他音頻活動泳桦。
    1. 請求所需的音頻會話類別汤徽。 此處指定的play and record類別支持音頻輸入和輸出。
    1. 請求激活您的音頻會話灸撰。
    1. 激活音頻會話后谒府,根據(jù)系統(tǒng)提供的實際采樣率更新您自己的采樣率變量拼坎。

您可能需要配置另一個硬件特性:音頻硬件I / O緩沖區(qū)持續(xù)時間。 在44.1 kHz采樣率下完疫,默認持續(xù)時間約為23 ms泰鸡,相當(dāng)于1,024個樣本的切片大小。 如果您的應(yīng)用中的I / O延遲至關(guān)重要壳鹤,您可以請求較小的持續(xù)時間盛龄,最低約0.005毫秒(相當(dāng)于256個樣本),如下所示:

self.ioBufferDuration = 0.005;
[mySession setPreferredIOBufferDuration: ioBufferDuration
                                  error: &audioSessionError];

有關(guān)如何配置和使用音頻會話對象的完整說明芳誓,請參閱Audio Session Programming Guide余舶。


Specify the Audio Units You Want - 指定您想要的音頻單元

在運行時,運行音頻會話配置代碼后锹淌,您的應(yīng)用尚未獲取音頻單元匿值。 您可以使用AudioComponentDescription結(jié)構(gòu)指定所需的每個。 有關(guān)如何執(zhí)行此操作赂摆,請參閱Use Identifiers to Specify and Obtain Audio Units千扔。 每個iOS音頻單元的標識符鍵列在Identifier Keys for Audio Units中。

獲取指定的音頻單元說明符库正,然后根據(jù)您選擇的模式構(gòu)建音頻處理圖。


Build an Audio Processing Graph - 構(gòu)建音頻處理圖

在此步驟中厘唾,您將創(chuàng)建本章第一部分中介紹的其中一種設(shè)計模式的框架褥符。 具體來說,你:

    1. 實例化AUGraph opaque類型抚垃。 該實例表示音頻處理圖喷楣。
    1. 實例化一個或多個AUNode不透明類型,每個類型代表圖中的一個音頻單元鹤树。
    1. 將節(jié)點添加到圖表中铣焊。
    1. 打開圖形并實例化音頻單元。
    1. 獲取音頻單元的引用罕伯。

Listing 2-2顯示了如何為包含遠程I / O單元和多通道混合器單元的圖形執(zhí)行這些步驟曲伊。 它假設(shè)您已經(jīng)為每個音頻單元定義了AudioComponentDescription結(jié)構(gòu)。

Listing 2-2 Building an audio processing graph

AUGraph processingGraph;
NewAUGraph (&processingGraph);

AUNode ioNode;
AUNode mixerNode;

AUGraphAddNode (processingGraph, &ioUnitDesc, &ioNode);
AUGraphAddNode (processingGraph, &mixerDesc, &mixerNode);

AUGraphAddNode函數(shù)調(diào)用使用音頻單元說明符ioUnitDescmixerDesc追他。 此時坟募,圖形將被實例化,并擁有您將在應(yīng)用程序中使用的節(jié)點邑狸。 要打開圖形并實例化音頻單元懈糯,請調(diào)用AUGraphOpen:

AUGraphOpen (processingGraph);

然后,通過AUGraphNodeInfo函數(shù)獲取對音頻單元實例的引用单雾,如下所示:

AudioUnit ioUnit;
AudioUnit mixerUnit;

AUGraphNodeInfo (processingGraph, ioNode, NULL, &ioUnit);
AUGraphNodeInfo (processingGraph, mixerNode, NULL, &mixerUnit);

ioUnitmixerUnit變量現(xiàn)在包含對圖形中音頻單元實例的引用赚哗,允許您配置并互連音頻單元她紫。


Configure the Audio Units - 配置音頻單元

每個iOS音頻設(shè)備都需要自己的配置,如Using Specific Audio Units中所述屿储。 但是贿讹,有些配置很常見,所有iOS音頻開發(fā)人員都應(yīng)該熟悉它們扩所。

默認情況下围详,遠程I / O單元已啟用輸出并禁用輸入。 如果您的應(yīng)用程序同時執(zhí)行I / O或僅使用輸入祖屏,則必須相應(yīng)地重新配置I / O單元助赞。 有關(guān)詳細信息,請參閱Audio Unit Properties Reference中的kAudioOutputUnitProperty_EnableIO屬性袁勺。

除了遠程I/O和語音處理I/O單元之外雹食,所有iOS音頻單元都需要配置它們的kAudioUnitProperty_MaximumFramesPerSlice屬性。此屬性確保音頻單元準備生成足夠數(shù)量的音頻數(shù)據(jù)幀以響應(yīng)呈現(xiàn)調(diào)用期丰。有關(guān)詳細信息群叶,請參見Audio Unit Properties Reference中的kAudioUnitProperty_MaximumFramesPerSlice

所有音頻單元都需要在輸入钝荡、輸出或兩者上定義它們的音頻流格式街立。有關(guān)音頻流格式的解釋,請參閱Audio Stream Formats Enable Data Flow埠通。對于各種iOS音頻單元的特定流格式要求赎离,請參見Using Specific Audio Units


Write and Attach Render Callback Functions - 編寫并附加呈現(xiàn)回調(diào)函數(shù)

對于采用渲染回調(diào)函數(shù)的設(shè)計模式端辱,您必須編寫這些函數(shù)梁剔,然后將它們附加到正確的點。Render Callback Functions Feed Audio to Audio Units介紹了這些回調(diào)的作用并說明了它們的工作原理舞蔽。 有關(guān)工作回調(diào)的示例荣病,請查看iOS參考庫中的各種音頻單元示例代碼項目,包括音頻混合器(MixerHost)aurioTouch以及SynthHost渗柿。

當(dāng)音頻不流動時个盆,您可以使用音頻單元API立即附加渲染回調(diào),如Listing 2-3所示做祝。

Listing 2-3 Attaching a render callback immediately

AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc        = &renderCallback;
callbackStruct.inputProcRefCon  = soundStructArray;
AudioUnitSetProperty (
    myIOUnit,
    kAudioUnitProperty_SetRenderCallback,
    kAudioUnitScope_Input,
    0,                 // output element
    &callbackStruct,
    sizeof (callbackStruct)
);

通過使用音頻處理圖API砾省,您可以以線程安全的方式附加渲染回調(diào),即使在音頻流動時也是如此混槐。 Listing 2-4顯示了如何做编兄。

Listing 2-4 Attaching a render callback in a thread-safe manner
 
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc        = &renderCallback;
callbackStruct.inputProcRefCon  = soundStructArray;
AUGraphSetNodeInputCallback (
    processingGraph,
    myIONode,
    0,                 // output element
    &callbackStruct
);
// ... some time later
Boolean graphUpdated;
AUGraphUpdate (processingGraph, &graphUpdated);

Connect the Audio Unit Nodes - 連接音頻單元節(jié)點

在大多數(shù)情況下,使用音頻處理圖API中的AUGraphConnectNodeInputAUGraphDisconnectNodeInput函數(shù)建立或斷開音頻單元之間的連接是最好和最容易的声登。 這些函數(shù)是線程安全的狠鸳,可以避免顯式定義連接的編碼開銷揣苏,因為在不使用圖形時必須這樣做。

Listing 2-5顯示了如何使用音頻處理圖API將混合器節(jié)點的輸出連接到I / O單元輸出element的輸入件舵。

Listing 2-5 Connecting two audio unit nodes using the audio processing graph API

AudioUnitElement mixerUnitOutputBus  = 0;
AudioUnitElement ioUnitOutputElement = 0;
AUGraphConnectNodeInput (
    processingGraph,
    mixerNode,           // source node
    mixerUnitOutputBus,  // source node bus
    iONode,              // destination node
    ioUnitOutputElement  // desinatation node element
);

或者卸察,您可以使用音頻單元屬性機制直接建立和斷開音頻單元之間的連接。 為此铅祸,請使用AudioUnitSetProperty函數(shù)以及kAudioUnitProperty_MakeConnection屬性坑质,如Listing 2-6所示。 此方法要求您為每個連接定義AudioUnitConnection結(jié)構(gòu)以用作其屬性值临梗。

Listing 2-6 Connecting two audio units directly
 
AudioUnitElement mixerUnitOutputBus  = 0;
AudioUnitElement ioUnitOutputElement = 0;
AudioUnitConnection mixerOutToIoUnitIn;
mixerOutToIoUnitIn.sourceAudioUnit    = mixerUnitInstance;
mixerOutToIoUnitIn.sourceOutputNumber = mixerUnitOutputBus;
mixerOutToIoUnitIn.destInputNumber    = ioUnitOutputElement;
AudioUnitSetProperty (
    ioUnitInstance,                     // connection destination
    kAudioUnitProperty_MakeConnection,  // property key
    kAudioUnitScope_Input,
    ioUnitOutputElement,
    &mixerOutToIoUnitIn,
    sizeof (mixerOutToIoUnitIn)
);
// destination scope
// destination element
// connection definition

Provide a User Interface - 提供一個用戶界面

此時涡扼,在構(gòu)建應(yīng)用程序時,音頻單元(通常是音頻處理圖形)已完全構(gòu)建和配置盟庞。在許多情況下吃沪,您需要提供一個用戶界面,讓您的用戶微調(diào)音頻行為什猖。您可以定制用戶界面以允許用戶調(diào)整特定的音頻單元參數(shù)票彪,并在某些特殊情況下調(diào)整音頻單元屬性。在任何一種情況下不狮,用戶界面還應(yīng)提供有關(guān)當(dāng)前設(shè)置的視覺反饋降铸。

Use Parameters and UIKit to Give Users Control介紹了構(gòu)建用戶界面以讓用戶控制參數(shù)值的基礎(chǔ)知識。有關(guān)工作示例摇零,請查看示例代碼項目Audio Mixer(MixerHost)垮耳。

iPod EQ單元是一種不尋常的情況,為了更改其活動均衡曲線遂黍,您可以更改kAudioUnitProperty_PresentPreset屬性的值。無論音頻是否正在運行俊嗽,您都可以執(zhí)行此操作雾家。有關(guān)工作示例,請查看示例代碼項目iPhoneMixerEQGraphTest绍豁。


Initialize and Start the Audio Processing Graph - 初始化并啟動音頻處理圖

在開始音頻流之前芯咧,必須通過調(diào)用AUGraphInitialize函數(shù)來初始化音頻處理圖。 這個關(guān)鍵步驟:

  • 通過為每個音頻單獨自動調(diào)用AudioUnitInitialize函數(shù)來初始化圖形所擁有的音頻單元竹揍。 (如果要在不使用圖形的情況下構(gòu)建處理鏈敬飒,則必須依次顯式初始化每個音頻單元。)
  • 驗證圖形的連接和音頻數(shù)據(jù)流格式芬位。
  • 在音頻單元連接上傳播流格式无拗。

Listing 2-7顯示了如何使用AUGraphInitialize。

Listing 2-7 Initializing and starting an audio processing graph

OSStatus result = AUGraphInitialize (processingGraph);
// Check for error. On successful initialization, start the graph...
AUGraphStart (processingGraph);
// Some time later
AUGraphStop (processingGraph);

后記

本篇主要講述了構(gòu)建您的應(yīng)用程序昧碉,感興趣的給個贊或者關(guān)注~~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末英染,一起剝皮案震驚了整個濱河市揽惹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌四康,老刑警劉巖搪搏,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異闪金,居然都是意外死亡疯溺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門哎垦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來囱嫩,“玉大人,你說我怎么就攤上這事撼泛∧铀担” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵愿题,是天一觀的道長损俭。 經(jīng)常有香客問我,道長潘酗,這世上最難降的妖魔是什么杆兵? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮仔夺,結(jié)果婚禮上琐脏,老公的妹妹穿的比我還像新娘。我一直安慰自己缸兔,他們只是感情好日裙,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著惰蜜,像睡著了一般昂拂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抛猖,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天格侯,我揣著相機與錄音,去河邊找鬼财著。 笑死联四,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的撑教。 我是一名探鬼主播朝墩,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼伟姐!你這毒婦竟也來了鱼辙?” 一聲冷哼從身側(cè)響起廉嚼,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎倒戏,沒想到半個月后怠噪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡杜跷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年傍念,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片葛闷。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡憋槐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出淑趾,到底是詐尸還是另有隱情阳仔,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布扣泊,位于F島的核電站近范,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏延蟹。R本人自食惡果不足惜评矩,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阱飘。 院中可真熱鬧斥杜,春花似錦、人聲如沸沥匈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽高帖。三九已至弱恒,卻和暖如春沸版,著一層夾襖步出監(jiān)牢的瞬間莽红,已是汗流浹背镶蹋。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留爪飘,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓拉背,卻偏偏與公主長得像师崎,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子椅棺,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容