使用Core Audio實現VoIP通用音頻模塊

項目背景

最近一直在做iOS音頻技術相關的項目,由于單項直播SDK摆昧,互動直播SDK(iOS/Mac)撩满,短視頻SDK,都會用到音頻技術绅你,因此在這里收集三個SDK的音頻技術需求伺帘,開發(fā)一個通用的音頻模塊用于三個SDK,同時支持iOS和Mac忌锯。

需求實現

主要包括音頻采集伪嫁,音頻格式轉換,音頻多路混音(本地文件和網絡文件)偶垮,寫WAV/AAC音頻文件张咳,通話錄制帝洪,音頻文件播放,耳返脚猾,自定義音頻輸入葱峡,音視頻設備管理等功能。

本文大部分圖片和技術概念闡述均來自Apple官網婚陪。

概念介紹

Core Audio是iOS和 Mac的關于數字音頻處理的基礎族沃,它提供應用程序用來處理音頻的一組軟件框架频祝,所有關于iOS音頻開發(fā)的接口都是由Core Audio來提供或者經過它提供的接口來進行封裝的泌参,按照官方的說法是集播放、音頻處理常空、錄制為一體的專業(yè)技術沽一,通過它我們的程序可以同時錄制,播放一個或者多個音頻流漓糙,自動適應耳機铣缠,藍牙耳機等硬件,響應各種電話中斷昆禽,靜音蝗蛙,震動等。

Low-Level

I/O Kit:與硬件驅動交互Audio HAL:音頻硬件抽象層醉鳖,使API調用與實際硬件相分離捡硅,保持獨立Core MIDI:為MIDI流和設備提供軟件抽象工作層Host Time Services:訪問電腦硬件時鐘

Mid-Level

Audio Convert Services負責音頻數據格式的轉換Audio File Services負責音頻數據的讀寫Audio Unit Services和?Audio Processing Graph Services?支持均衡器和混音器等數字信號處理的插件Audio File Scream Services負責流解析Core Audio Clock Services負責音頻時鐘同步

High-Level

Audio Queue Services提供錄制、播放盗棵、暫停壮韭、循環(huán)、和同步音頻纹因,它自動采用必要的編解碼器處理壓縮的音頻格式AVAudioPlayer是專為iOS平臺提供的基于Objective-C接口的音頻播放類喷屋,可以支持iOS所支持的所有音頻的播放Extended Audio File Services由Audio File與Audio Converter組合而成,提供壓縮及無壓縮音頻文件的讀寫能力OpenAL是CoreAudio對OpenAL標準的實現瞭恰,可以播放3D混音效果

OS X和 iOS 的核心音頻架構

Audio Unit

iOS提供了混音屯曹、均衡、格式轉換惊畏、實時IO錄制恶耽、回放、離線渲染陕截、語音對講(VoIP)等音頻處理插件驳棱,它們都屬于不同AudioUnit,支持動態(tài)載入和使用农曲。AudioUnit可以單獨創(chuàng)建使用社搅,但更多的是被組合使用在Audio Processing Graph容器中以達到多樣的處理需要驻债。

一個I/O Unit包含兩個實體對象,兩個實體對象(Element 0形葬、Element 1)相互獨立合呐,根據需求可通過kAudioOutputUnitProperty_EnableIO屬性去開關它們。Element 1與硬件輸入連接笙以,并且Element 1的輸入域(input scope)對你不可見淌实,你只能讀取它的輸出域的數據及設置其輸出域的音頻格式;Element 0與硬件輸出連接猖腕,并且Element 0的輸出域(ouput scope)對你不可見拆祈,你只能寫入它的輸入域的數據及設置其輸入域的音頻格式。

Audio Session

AVAudioSession構建了一個音頻使用生命周期的上下文倘感。當前狀態(tài)是否可以錄音放坏、對其他App有怎樣的影響、是否響應系統的靜音鍵老玛、如何感知來電話了等都可以通過它來實現淤年。

Audio Processing Graphs

AUGraph可以用來構建和管理一個音頻單元處理鏈。能夠利用多個音頻單元的功能和多個渲染回調函數,允許您創(chuàng)建幾乎任何你可以想象的音頻處理的解決方案蜡豹。同時它也是線程安全的麸粮。

Audio Flows Through a Graph Using “Pull”

在一個音頻處理圖,當需要更多的音頻數據時,使用者調用提供者镜廉。有源源不斷的音頻數據流的請求,這個控制流的方向和音頻流方向相反弄诲。

具體實現

一、音頻采集

iOS采集:

kAudioUnitSubType_RemoteIO

kAudioUnitSubType_VoiceProcessingIO

Mac采集:

kAudioUnitSubType_VoiceProcessingIO

一個I/O Unit包含兩個實體對象桨吊,兩個實體對象(Element 0威根、Element 1)相互獨立。Element 1與硬件輸入(麥克風或者聽筒)連接视乐,并且Element 1的輸入域(input scope)對你不可見洛搀,你只能讀取它的輸出域的數據及設置其輸出域的音頻格式;Element 0與硬件輸出(揚聲器或者聽筒)連接佑淀,并且Element 0的輸出域(ouput scope)對你不可見留美,你只能寫入它的輸入域的數據及設置其輸入域的音頻格式。

操作步驟:

第一伸刃,創(chuàng)建AudioUnit谎砾。

第二,開啟麥克風或者聽筒的輸入開關捧颅;開啟揚聲器或者聽筒的輸出開關景图。

第三,設置輸入和輸出的采集回調和播放回調碉哑。

第四挚币, 設置輸入和輸出的音頻格式亮蒋。

第五, 初始化AudioUnit妆毕。

第六慎玖, 開啟AudioUnit。


Mac采集:

kAudioUnitSubType_HALOutput

Mac的音頻采集使用的是kAudioUnitSubType_HALOutput,音頻硬件抽象層HAL笛粘。因此它使用的是2個I/O Uint串聯趁怔,前一個I/O Uint的輸出作為后一個I/O Uint的輸入。


操作步驟:

第一薪前, 創(chuàng)建2個AudioUnit润努。

第二,開啟第一個I/O Uint的麥克風或者聽筒的輸入開關序六,關閉第一個I/O Uint的揚聲器或者聽筒的輸出開關任连;開啟第二個I/O Uint的揚聲器或者聽筒的輸出開關,關閉第二個I/O Uint的麥克風或者聽筒的輸入開關例诀。

第三,將第一個I/O Unit設為Mac的

kAudioHardwarePropertyDefaultInputDevice裁着,

第二個I/O Unit設為Mac的

kAudioHardwarePropertyDefaultOutputDevice繁涂,

第四,設置第二個I/O Uint的輸入和第一個I/O Uint的輸出的采集回調和播放回調二驰。

第五扔罪,設置第二個I/O Uint的輸入和第一個I/O Uint的輸出的音頻格式。

第六桶雀,初始化2個AudioUnit矿酵。

第七, 開啟2個AudioUnit矗积。


二全肮、音頻架構

從圖中可以看出,我們使用了一個I/O Unit作為最核心的部件棘捣,用于驅動整個流程辜腺,同時使用三個Audio Processing Graphs作為混音器。三個Audio Processing Graphs分別代表播放混音器乍恐,發(fā)送混音器评疗,錄制混音器。每個混音器有三個Unit最為其部件茵烈,音頻混音Mixing(kAudioUnitSubType_MultiChannelMixer)百匆,音頻格式轉換(kAudioUnitSubType_AUConverter),音頻通用輸出(kAudioUnitSubType_GenericOutput)呜投。同時支持多路輸入加匈,一路輸出寄症。

1.播放混音器支持來自服務器的多路音頻流和一路本地伴音以及一路耳返音頻,每一路輸入都會接一個音頻格式轉換矩动,同時設置一個輸入回調有巧,用于音頻數據的主動拉取。并將混音器的輸出作為Audio Unit的輸入悲没。

2.發(fā)送混音器支持一路Audio Unit的采集和本地多路音頻伴音的輸入篮迎,每一路輸入都會接一個音頻格式轉換,同時設置一個輸入回調示姿,用于音頻數據的主動拉取甜橱。并將混音器的輸出作為音頻編碼和發(fā)送的輸入。

3.錄制混音器支持Audio Unit的一路采集和Audio Unit的一路播放栈戳,將整個通話過程涉及到的音頻數據都合成一路岂傲。每一路輸入都會接一個音頻格式轉換,同時設置一個輸入回調子檀,用于音頻數據的主動拉取镊掖。并將混音器的輸出作為通話錄制的輸入,并寫WAV/AAC文件褂痰。

4.Audio Unit的采集回調驅動音頻編碼亩进,從而驅動整個發(fā)送混音器;Audio Unit的采集回調驅動通話錄制缩歪,從而驅動整個錄制混音器归薛;

Audio Unit的播放回調驅動播放,從而驅動整個播放混音器匪蝙。

5.目前最新的音頻架構主籍,我們使用了兩個I/O Unit作為最核心的部件,用于驅動整個流程逛球。同時統一了iOS和Mac 2個版本千元,也解決了采集和播放同一個線程的問題,為我們的音頻前處理提供了安全的線程保障需忿。


三诅炉、AVAudioSeeion管理

AVAudioSession的主要功能包括以下幾點功能:

向系統說明你的app使用音頻的模式(比如是播放還是錄音,是否支持藍牙播放屋厘,是否支持后臺播放)

為你的app選擇音頻的輸入輸出設備(比如輸入用的麥克風涕烧,輸出是耳機、手機功放或者airplay)

協助管理多個音源需要播放時的行為(例如同時使用多個音樂播放app汗洒,或者突然有電話接入)

如果需要音頻支持后臺運行议纯,需要按下圖配置:

在需要完成上述功能點的前提下,我們需要監(jiān)聽中斷響應溢谤,外設改變瞻凤,媒體服務器終止憨攒,媒體服務器重新啟動,前后臺切換的通知阀参。在不同的通知下肝集,做出相應的調整。


系統中斷響應:

AVAudioSession提供了多種Notifications來進行此類狀況的通知蛛壳。其中將來電話杏瞻、鬧鈴響等都歸結為一般性的中斷,用AVAudioSessionInterruptionNotification來通知衙荐。其回調回來的userInfo主要包含兩個鍵:

AVAudioSessionInterruptionTypeKey: 取值為AVAudioSessionInterruptionTypeBegan表示中斷開始捞挥,我們應該暫停播放和采集,取值為AVAudioSessionInterruptionTypeEnded表示中斷結束忧吟,我們可以繼續(xù)播放和采集砌函。

AVAudioSessionInterruptionOptionKey: 當前只有一種值AVAudioSessionInterruptionOptionShouldResume表示此時也應該恢復繼續(xù)播放和采集。


外設改變:

在NSNotificationCenter中對AVAudioSessionRouteChangeNotification進行注冊溜族。在其userInfo中有鍵:AVAudioSessionRouteChangeReasonKey : 表示改變的原因

參考文檔:

https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/AudioUnitHostingGuide_iOS/AudioUnitHostingFundamentals/AudioUnitHostingFundamentals.html#//apple_ref/doc/uid/TP40009492-CH3-SW11

https://developer.apple.com/library/content/documentation/MusicAudio/Conceptual/CoreAudioOverview/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003577-CH1-SW1

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末讹俊,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子斩祭,更是在濱河造成了極大的恐慌劣像,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摧玫,死亡現場離奇詭異,居然都是意外死亡绑青,警方通過查閱死者的電腦和手機诬像,發(fā)現死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闸婴,“玉大人坏挠,你說我怎么就攤上這事⌒罢В” “怎么了降狠?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長庇楞。 經常有香客問我榜配,道長,這世上最難降的妖魔是什么吕晌? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任蛋褥,我火速辦了婚禮,結果婚禮上睛驳,老公的妹妹穿的比我還像新娘烙心。我一直安慰自己膜廊,他們只是感情好,可當我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布淫茵。 她就那樣靜靜地躺著爪瓜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪匙瘪。 梳的紋絲不亂的頭發(fā)上铆铆,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機與錄音辆苔,去河邊找鬼算灸。 笑死,一個胖子當著我的面吹牛驻啤,可吹牛的內容都是我干的菲驴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼骑冗,長吁一口氣:“原來是場噩夢啊……” “哼赊瞬!你這毒婦竟也來了?” 一聲冷哼從身側響起贼涩,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤巧涧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后遥倦,有當地人在樹林里發(fā)現了一具尸體谤绳,經...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年袒哥,在試婚紗的時候發(fā)現自己被綠了缩筛。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡堡称,死狀恐怖瞎抛,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情却紧,我是刑警寧澤桐臊,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站晓殊,受9級特大地震影響断凶,放射性物質發(fā)生泄漏。R本人自食惡果不足惜挺物,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一懒浮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦砚著、人聲如沸次伶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瑞凑。三九已至入蛆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背朴沿。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工伸辟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留咽筋,地道東北人堕扶。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像否灾,于是被迫代替她去往敵國和親卖擅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內容