iOS 音頻處理總結(jié)

前言

前段時(shí)間在閱讀蘋果音頻文檔(均列在參考資料一節(jié)里面了),并做了一些音頻相關(guān)的開發(fā)(主要是帶回音消除的錄音)。這里做一個(gè)總結(jié)。

關(guān)于 Audio Session

每一個(gè) app 帶有一個(gè) AVAudioSession 的單例(也就是說正常情況下你無法獲得第二個(gè) AVAudioSession 實(shí)例)。iOS 系統(tǒng)上每個(gè) app 有各自不同的 AVAudioSession 實(shí)例。通過使用這個(gè)實(shí)例的方法可以告訴系統(tǒng)當(dāng)前的 app 是怎樣使用手機(jī)的音頻服務(wù)的,然后系統(tǒng)會(huì)根據(jù)每個(gè) app 的配置進(jìn)行相應(yīng)的協(xié)調(diào),盡量滿足所有 app 的請(qǐng)求,當(dāng)無法滿足的時(shí)候,系統(tǒng)盡量滿足前臺(tái) app 的要求或者系統(tǒng)電話服務(wù)等。比如說,如果當(dāng)前另外一個(gè) app 正在播放的話,當(dāng)前 app 可能希望能將其播放的音頻和其他 app 的音頻一起播放,而不是暫停其他 app 的音頻服務(wù);又比如說當(dāng)前 app 需要播放音頻或者進(jìn)行錄音;比如當(dāng)前 app 只是播放音頻;比如當(dāng)前 app 只是錄音;比如當(dāng)前 app 播放音頻時(shí)候屏蔽所有其他 app 的音頻等等,總之就是告訴系統(tǒng)當(dāng)前 app 是如何使用它的音頻服務(wù)的。

Audio Session 有三個(gè)比較重要的概念:

  1. category
  2. mode
  3. option

通過配置這三個(gè)內(nèi)容,表達(dá)了當(dāng)前 app 的使用音頻服務(wù)的具體意圖。

在某些情況下,我們不需要配置 Audio Session 的 category,比如如果使用 AVAudioRecorder 來錄音,并不需要配置 category 為 AVAudioSessionCategoryRecord,因?yàn)橄到y(tǒng)在我們使用 AVAudioRecorder 的錄音服務(wù)的時(shí)候已經(jīng)為我們配置了。同時(shí) Audio Session 有默認(rèn)配置(如果當(dāng)前 app 不進(jìn)行配置的話)。當(dāng)默認(rèn)配置無法滿足需求的時(shí)候,就可以手動(dòng)配置 Audio Session

Audio Session 另一個(gè)重要功能是配置系統(tǒng)音頻服務(wù)硬件參數(shù),比如配置輸入的聲道數(shù),采樣率,IO 緩存時(shí)間等等。其 API 中 setPreferred__ 開頭的方法作用就是這些。

配置完 Audio Session 以后,當(dāng)我們要求的音頻服務(wù)受到打斷(比如,電話來了,則系統(tǒng)要停止錄音和播放;比如,app 退到后臺(tái)運(yùn)行了,如果沒有配置后臺(tái)運(yùn)行的話,系統(tǒng)也會(huì)停止當(dāng)前 app 的音頻服務(wù);),我們可以使用通知中心的方式來監(jiān)聽,并做一下相應(yīng)的處理。音頻服務(wù)中斷有兩個(gè)概念比較重要,就是中斷開始以及中斷結(jié)束,我們可以在中斷開始的時(shí)候記錄當(dāng)前播放時(shí)間點(diǎn),中斷結(jié)束的時(shí)候重新開始播放(當(dāng)然系統(tǒng)默認(rèn)行為是會(huì)在中斷結(jié)束時(shí)重新開始播放音頻,但是如果默認(rèn)行為無法滿足需求時(shí)候,就需要自行處理了)。

Audio Session 另一個(gè)重要我們需要監(jiān)聽的變化是路由變化 (Route Change)。比如有新的輸出源來了(比如用戶把耳機(jī)插進(jìn)去或者是用戶開始使用藍(lán)牙耳機(jī)),或者原來的輸出源不可用了(用戶拔掉耳機(jī)等)。

還有一些其他的功能,比如當(dāng)前其他 app 是否在播放音頻,請(qǐng)求麥克風(fēng)權(quán)限等,可以查看具體的 API 文檔 AVAudioSession。

Audio Queue Service

使用 Audio Queue Service 我們可以做到錄音或者播放音頻。當(dāng)然我們使用 AVAudioPlayer 也能很簡(jiǎn)單的做播放音頻功能,那為什么要用到 Audio Queue Service 呢?它有幾個(gè)優(yōu)點(diǎn)

  1. 設(shè)想你的要嚴(yán)格同步不同音頻的播放。 Audio Queue Service 的回調(diào)函數(shù)包含相應(yīng)的時(shí)間,來滿足你的需求。
  2. 如果是播放音頻用 Audio Queue Service,在將音頻數(shù)據(jù)給它的回調(diào)函數(shù)之前做一些處理,比如變聲等。
  3. 如果是錄音,可以對(duì)回調(diào)函數(shù)傳回來的音頻數(shù)據(jù)做處理,比如寫到文件或者對(duì)這些音頻數(shù)據(jù)進(jìn)行其他任何處理

理解 Audio Queue Service 比較重要的是它的 buffer queue。拿錄音來說,一般設(shè)置的緩存是3個(gè)。首先通過 AudioQueueEnqueueBuffer 將可用緩存提供給相應(yīng)的 queue。然后系統(tǒng)開始將記錄下的音頻數(shù)據(jù)放到第一個(gè)緩存,當(dāng)緩存滿的時(shí)候,回調(diào)函數(shù)會(huì)將該 buffer 返回給你并將該緩存出列,在回調(diào)函數(shù)中我們可以對(duì)這些數(shù)據(jù)進(jìn)行處理,與此同時(shí)系統(tǒng)開始將數(shù)據(jù)寫到第二個(gè)緩存,當(dāng)我們的回調(diào)函數(shù)處理完第一個(gè)返回的緩存時(shí)候,我們需要重新使用 AudioQueueEnqueueBuffer 將該緩存入列,以便系統(tǒng)再次使用。當(dāng)?shù)诙€(gè)緩存返回的時(shí)候,系統(tǒng)開始往第三個(gè)緩存寫數(shù)據(jù),寫完之后返回第三個(gè)緩存,并開始往之前返回的第一個(gè)緩存寫數(shù)據(jù)。這就是一個(gè)典型的隊(duì)列結(jié)構(gòu)(先進(jìn)先出,后進(jìn)后出)。

Audio Unit

Audio Unit 是所有 iOS 以及 macOS 上音頻框架的最底層,無論使用的是 AVAudioRecorder、AVAudioPlayer、或者 Audio Queue Service、OpenAL 等,最終底層實(shí)現(xiàn)都是通過 Audio Unit 來完成的。

在 iOS 上可用的 audio unit 是有限的,macOS 上面可以自定義一個(gè) audio unit 但是 iOS 上不行,只能使用系統(tǒng)提供的 audio unit。

什么時(shí)候使用 Audio Unit ?官方的說法是,當(dāng)你需要高度可控的、高性能、高靈活性或者需要某種特別的功能(比如回音消除,只在 audio unit 提供支持,所有高層 API 均不支持回音消除)的時(shí)候,才需要使用 audio unit。

有4類 audio unit(具體用途看名字就能理解):

  1. Effect
  2. Mixing
  3. I/O
  4. Format convert

使用 audio unit 有兩種方式:

  1. 直接使用
  2. 混合構(gòu)建使用,AUGraph

第一種方式是對(duì)于比較簡(jiǎn)單的結(jié)構(gòu)。
第二種方式是用于構(gòu)建復(fù)雜的音頻處理流程。配置具體的 audio unit 的屬性的時(shí)候還是會(huì)用到直接使用種的方法。

Audio Unit 重要概念

audio unit 重要的概念是 scope 和 element。scope 包含 element。

scope 分三種:

  1. Input scope
  2. Output scope
  3. global scope

scope 概念有一點(diǎn)抽象,可以這樣理解 scope,比如 input scope 表示里面所有的 element 都需要一個(gè)輸入。output scope 表示里面所有的 element 都會(huì)輸出到某個(gè)地方。至于 global scope,應(yīng)該是用來配置一些和輸入輸出概念無關(guān)的屬性。

element 官方的解釋是可以理解成 bus,就是將數(shù)據(jù)從 element 的一頭傳到另一頭。

其他

  1. 音頻格式轉(zhuǎn)換
  2. 音頻(流)讀寫

iOS 錄音的幾種方式

  1. 使用 AVAudioRecorder
  2. 使用 Audio Queue Service
  3. 使用 Audio Unit
  4. 使用 OpenAL

iOS 播放音頻的方式

  1. 使用 AVAudioPlayer
  2. 使用 AVPlayer
  3. 使用 System Sound Services
  4. 使用 Audio Queue Service
  5. 使用 Audio Unit
  6. 使用 OpenAL

一些需要思考的問題

  1. 如何獲取當(dāng)前揚(yáng)聲器播放的音頻數(shù)據(jù)?(包括其他 app)
  2. 如何實(shí)時(shí)錄音,同時(shí)當(dāng)前手機(jī)正在播放音頻
  3. 如何做回音消除,或者不借助系統(tǒng)提供的回音消除功能來完成回音消除的需求?

這里有些問題我也不知道如何解答,若有了解的,請(qǐng)多多指教一下。

一些有用的開源代碼

  1. aurioTouch 官方的關(guān)于 audio unit 使用 demo 代碼。注意其中關(guān)于 AVAudioSession 配置的順序是錯(cuò)的,你可以看它的代碼和 AVAudioSession Api 的說明來知道錯(cuò)誤的地方
  2. XBEchoCancellation 可以學(xué)習(xí)其中關(guān)于回音消除的使用。官方的 aurioTouch demo 簡(jiǎn)單的改 audio unit 類型為 voiceprocess 也可以做回音消除,但是當(dāng)涉及到同時(shí)播放音頻時(shí),官方 demo 在某些 iPhone 上會(huì)失敗,所以建議參考這個(gè)源碼

參考資料

  1. Core Audio Overview
  2. Audio Session Programming Guide
  3. Audio Queue Services Programming Guide
  4. Audio Unit Programming Guide
  5. Audio Unit Hosting Guide for iOS
  6. Multimedia Programming Guide
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容