音視訊系列之iOS: 音訊採集 AudioUnit

檀志文發表於2017-12-14

AudioUnit是什麼? 它是ios端進行音視訊採集的框架,最全,最屌的!但是缺點就是學習成本大,但是大沒關係,既然您已經看到這裡,想必就是想搞音視訊,這點小的困難應該能克服的。


我這邊就先看怎麼用,用完在講講具體的是什麼東西比較好,這也是我一向學習新東西的習慣和方法,這個世界上的理論很多,真理也很多,我們可以選擇接收和不接受,如果你看看下面的實現結果如果不滿意就可以直接關閉,如果有興趣可以歡迎一直看下去咯!

廢話不多說了,我也沒時間了,直接介紹:

操作流程:

no1: 描述音訊元件: kAudioUnitType_Output。kAudioUnitSubType_RemoteIO/kAudioUnitManufacturerApple   這個知道就行,不需要了解

no2: 使用AudioComponentFindNext : 這個就當作是生產AudioUnit 的工廠

no3 : AudioComponentInstanceNew: 顧名思義,就是Audio Unit 的例項

no4:  AudioUnitSetProperty函式為錄製和回放開啟IO

no5: 使用 AudioStreamBasicDescription 結構體描述音訊格式,並使用AudioUnitSetProperty進行設定

no6: 使用 AudioUnitSetProperty 設定音訊錄製與放播的回撥函式

no7: 分配緩衝區

no8: 初始化Audio Unit

no9: 啟動Audio  Unit


理論:

Core Audio

數字音訊處理的基礎設施,它是應用程式用來處理音訊的一組軟體框架,所有關於iOS音訊開發的介面都是由Core Audio來提供或者經過它提供的介面來進行封裝的。Apple官方對Core Audio的框架分層圖示如下:


音視訊系列之iOS: 音訊採集 AudioUnit


音視訊系列之iOS: 音訊採集 AudioUnit

OutputOnlyWithRenderCallback_2x.png

較複雜的構建

輸入端有兩路音訊流,都是通過rendercallback方式抓取資料,其中一路音訊流直接給入到Mixer Unit中,另一路先經過EQ Unit處理後給入到Mixer Unit中,

音視訊系列之iOS: 音訊採集 AudioUnit

OutputOnlyWithRenderCallbackExtended_2x.png

Tips

1. 多執行緒及記憶體管理

儘可能的避免render callback方法內做加鎖及處理耗時較高的操作,這樣可以最大限度的提升實時效能,如果播放資料或者採集資料存在不同執行緒讀寫的情況,必需要加鎖保護,推薦pthread相關lock方法效能比其它鎖要高

音訊的輸入輸出一般都是一個持續的過程,在採集與播放的callback中,應儘量複用buffer及避免多次buffer拷貝,而不是每次回撥都重新申請和釋放,在適當的位置加上@autoreleasepool避免長時間執行記憶體不斷上漲

2. 格式

Core Audio Type中定義了AudioStreamBasicDescription結構,Audio Unit及其它很多音訊API對格式的配置都需要用到它,根據需要將該結構的資訊填充正確,下面是44.1K,stereo,16bit的填充例子

audioDescription.mSampleRate = 44100;

audioDescription.mChannelsPerFrame = 2;

audioDescription.mBitsPerChannel = 16;

audioDescription.mFramesPerPacket = 1;

audioDescription.mFormatID = kAudioFormatLinearPCM;

audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;

audioDescription.mBytesPerFrame = (audioDescription.mBitsPerChannel/8) * audioDescription.mChannelsPerFrame;

audioDescription.mBytesPerPacket = audioDescription.mBytesPerFrame ;

蘋果官方建議在整個Audio Processing Graph或者Unit之間儘量以相同的音訊格式流通,儘管Audio Unit的輸入輸出可以不同。另外在Unit之間輸入輸出連線點要保持一致。

3. 音質

在使用過程中,Audio Unit的format是可以動態改變的,但存在一種情況,Unit在銷燬前最好恢復到預設建立時的format,否則在銷燬後再重建Unit後,可能出現播放音質變差(音量變小,聲音粗糙)的情況。

在使用VoiceProcessing I/O Unit過程,遇到在有些iphone上開啟揚聲器後,Unit從Mic採集過來的資料為空或者噪音的情況,從APP STORE中下載了其它的VOIP型別的APP也同樣存在該問題,後來將AudioUnitSubType改成RemoteIO型別後,問題消失,懷疑蘋果在VoiceProcessing Unit上對回聲消除功能的處理上有bug

4. AudioSession

既然使用了音訊特性,就會用到AudioSession,隨著功能需求跟進,與它相關的問題也瞞多的,比如路由管理(聽筒揚聲器、線控耳機、藍芽耳機),打斷處理(interruption、iphone call)等,這裡以Audio Unit為主,就不對它進行詳細描述了,需要注意的是

音訊的路由變更(使用者挺拔耳機,或者程式碼呼叫強制切換)涉及到iOS硬體上輸入和輸出裝置的改變,I/O型別Unit的採集和播放執行緒在切換過程中會阻塞一定時間(200ms左右),如果是語音對講類對實時性要求較高的應用場景要考慮丟包策略。

在APP前臺工作時,iPhone來電或者使用者主動切換到其它音訊類APP後,要及時處理音訊的打斷機制,在恰當的時機停止及恢復Unit的工作,由於iOS平臺對資源的獨佔方式,iPhone在通話等操作時,APP中的Unit是無法初始化或者繼續工作的。

作者:MasonFu

連結:http://www.jianshu.com/p/5d18180c69b8

來源:簡書

著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

相關文章