使用Core Audio實現VoIP通用音訊模組
最近一直在做c音訊技術相關的專案,由於單項直播SDK,互動直播SDK(iOS/Mac),短視訊SDK,都會用到音訊技術,因此在這裡收集三個SDK的音訊技術需求,開發一個通用的音訊模組用於三個SDK,同時支援iOS和Mac。
想要閱讀更多技術乾貨、行業洞察,歡迎關注網易雲信部落格。
瞭解網易雲信,來自網易核心架構的通訊與視訊雲服務。
需求實現
主要包括音訊採集,音訊格式轉換,音訊多路混音(本地檔案和網路檔案),寫WAV/AAC音訊檔案,通話錄製,音訊檔案播放,耳返,自定義音訊輸入,音視訊裝置管理等功能。
本文大部分圖片和技術概念闡述均來自Apple官網。
概念介紹
Core Audio 是iOS和 Mac 的關於數字音訊處理的基礎,它提供應用程式用來處理音訊的一組軟體框架,所有關於iOS音訊開發的介面都是由Core Audio來提供或者經過它提供的介面來進行封裝的,按照官方的說法是集播放、音訊處理、錄製為一體的專業技術,通過它我們的程式可以同時錄製,播放一個或者多個音訊流,自動適應耳機,藍芽耳機等硬體,響應各種電話中斷,靜音,震動等。
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 提供錄製、播放、暫停、迴圈、和同步音訊,它自動採用必要的編解碼器處理壓縮的音訊格式 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,支援動態載入和使用。AudioUnit可以單獨建立使用,但更多的是被組合使用在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構建了一個音訊使用生命週期的上下文。當前狀態是否可以錄音、對其他App有怎樣的影響、是否響應系統的靜音鍵、如何感知來電話了等都可以通過它來實現。
Audio Processing Graphs
AUGraph可以用來構建和管理一個音訊單元處理鏈。能夠利用多個音訊單元的功能和多個渲染回撥函式,允許您建立幾乎任何你可以想象的音訊處理的解決方案。同時它也是執行緒安全的。
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)對你不可見,你只能寫入它的輸入域的資料及設定其輸入域的音訊格式。
操作步驟:
第一, 建立AudioUnit。
第二, 開啟麥克風或者聽筒的輸入開關;開啟揚聲器或者聽筒的輸出開關。
第三, 設定輸入和輸出的採集回撥和播放回調。
第四, 設定輸入和輸出的音訊格式。
第五, 初始化AudioUnit。
第六, 開啟AudioUnit。
Mac採集:
kAudioUnitSubType_HALOutput
Mac的音訊採集使用的是kAudioUnitSubType_HALOutput,音訊硬體抽象層HAL。因此它使用的是2個I/O Uint串聯,前一個I/O Uint的輸出作為後一個I/O Uint的輸入。
操作步驟:
第一, 建立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分別代表播放混音器,傳送混音器,錄製混音器。每個混音器有三個Unit最為其部件,音訊混音Mixing(kAudioUnitSubType_MultiChannelMixer),音訊格式轉換(kAudioUnitSubType_AUConverter),音訊通用輸出(kAudioUnitSubType_GenericOutput)。同時支援多路輸入,一路輸出。
1.播放混音器支援來自伺服器的多路音訊流和一路本地伴音以及一路耳返音訊,每一路輸入都會接一個音訊格式轉換,同時設定一個輸入回撥,用於音訊資料的主動拉取。並將混音器的輸出作為Audio Unit的輸入。
2.傳送混音器支援一路Audio Unit的採集和本地多路音訊伴音的輸入,每一路輸入都會接一個音訊格式轉換,同時設定一個輸入回撥,用於音訊資料的主動拉取。並將混音器的輸出作為音訊編碼和傳送的輸入。
3.錄製混音器支援Audio Unit的一路採集和Audio Unit的一路播放,將整個通話過程涉及到的音訊資料都合成一路。每一路輸入都會接一個音訊格式轉換,同時設定一個輸入回撥,用於音訊資料的主動拉取。並將混音器的輸出作為通話錄製的輸入,並寫WAV/AAC檔案。
4.Audio Unit的採集回撥驅動音訊編碼,從而驅動整個傳送混音器;Audio Unit的採集回撥驅動通話錄製,從而驅動整個錄製混音器;
Audio Unit的播放回調驅動播放,從而驅動整個播放混音器。
5.目前最新的音訊架構,我們使用了兩個I/O Unit作為最核心的部件,用於驅動整個流程。同時統一了iOS和Mac 2個版本,也解決了採集和播放同一個執行緒的問題,為我們的音訊前處理提供了安全的執行緒保障。
三、AVAudioSeeion管理
AVAudioSession 的主要功能包括以下幾點功能:
向系統說明你的app使用音訊的模式(比如是播放還是錄音,是否支援藍芽播放,是否支援後臺播放)
為你的app選擇音訊的輸入輸出裝置(比如輸入用的麥克風,輸出是耳機、手機功放或者airplay)
協助管理多個音源需要播放時的行為(例如同時使用多個音樂播放app,或者突然有電話接入)
如果需要音訊支援後臺執行,需要按下圖配置:
在需要完成上述功能點的前提下,我們需要監聽中斷響應,外設改變,媒體伺服器終止,媒體伺服器重新啟動,前後臺切換的通知。在不同的通知下,做出相應的調整。
系統中斷響應:
AVAudioSession提供了多種Notifications來進行此類狀況的通知。其中將來電話、鬧鈴響等都歸結為一般性的中斷,用AVAudioSessionInterruptionNotification來通知。其回調回來的userInfo主要包含兩個鍵:AVAudioSessionInterruptionTypeKey: 取值為AVAudioSessionInterruptionTypeBegan表示中斷開始,我們應該暫停播放和採集,取值為AVAudioSessionInterruptionTypeEnded表示中斷結束,我們可以繼續播放和採集。
AVAudioSessionInterruptionOptionKey: 當前只有一種值AVAudioSessionInterruptionOptionShouldResume表示此時也應該恢復繼續播放和採集。
外設改變:
在NSNotificationCenter中對AVAudioSessionRouteChangeNotification進行註冊。在其userInfo中有鍵:AVAudioSessionRouteChangeReasonKey : 表示改變的原因
網易雲信(NeteaseYunXin)是集網易18年IM以及音視訊技術打造的PaaS服務產品,來自網易核心技術架構的通訊與視訊雲服務,穩定易用且功能全面,致力於提供全球領先的技術能力和場景化解決方案。開發者通過整合客戶端SDK和雲端OPEN API,即可快速實現包含IM、音視訊通話、直播、點播、互動白板、簡訊等功能。