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

最近一直在作iOS音頻技術相關的項目,因爲單項直播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:訪問電腦硬件時鐘html

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」

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

具體實現

1、音頻採集

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。

2、音頻架構

從圖中能夠看出,咱們使用了一個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個版本,也解決了採集和播放同一個線程的問題,爲咱們的音頻前處理提供了安全的線程保障。
 

3、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、音視頻通話、直播、點播、互動白板、短信等功能。網絡

相關文章
相關標籤/搜索