iOS 音頻-AVAudioSession

1. AVAudioSession 概述

最近一年一直在做IPC Camera的iOS客戶端開發(fā)。和音頻打交道,必須要弄清楚
AVAudioSession。
先看下蘋果的官方圖:


Audio Session

可以看到AVAudioSession就是用來管理多個APP對音頻硬件設備(麥克風,揚聲器)的資源使用。

舉例一下AVAudioSession可以做這些事情

  • 設置自己的APP是否和其他APP音頻同時存在,還是中斷其他APP聲音
  • 在手機調(diào)到靜音模式下,自己的APP音頻是否可以播放出聲音
  • 電話或者其他APP中斷自己APP的音頻的事件處理
  • 指定音頻輸入和輸出的設備(比如是聽筒輸出聲音,還是揚聲器輸出聲音)
  • 是否支持錄音,錄音同時是否支持音頻播放

2. AVAudioSession Category

AVAudioSession的接口比較簡單。APP啟動的時候會自動幫激活AVAudioSession,當然我們可以手動激活代碼如下。

    //導入頭文件
    #import <AVFoundation/AVFoundation.h>

    //AVAudioSession是一個單例類
    AVAudioSession *session = [AVAudioSession sharedInstance];
    //AVAudioSessionCategorySoloAmbient是系統(tǒng)默認的category
    [session setCategory:AVAudioSessionCategorySoloAmbient error:nil];
    //激活AVAudioSession
    [session setActive:YES error:nil];

可以看到設置session這里有兩個參數(shù),category和options
Category iOS下目前有七種,每種Category都對應是否支持下面四種能力

  • Interrupts non-mixable apps audio:是否打斷不支持混音播放的APP
  • Silenced by the Silent switch:是否會響應手機靜音鍵開關
  • Supports audio input:是否支持音頻錄制
  • Supports audio output:是否支持音頻播放

下面用圖表來直觀的看下每種category具體的能力集

Category 是否允許音頻播放/錄音 是否打斷其他不支持混音APP 是否會被靜音鍵或鎖屏鍵靜音
AVAudioSessionCategoryAmbient 只支持播放
AVAudioSessionCategoryAudioProcessing 不支持播放,不支持錄制
AVAudioSessionCategoryMultiRoute 支持播放,支持錄制
AVAudioSessionCategoryPlayAndRecord 支持播放,支持錄制 默認YES,可以重寫為NO
AVAudioSessionCategoryPlayback 只支持播放 默認YES,可以重寫為NO
AVAudioSessionCategoryRecord 只支持錄制 否(鎖屏下仍可錄制)
AVAudioSessionCategorySoloAmbient 只支持播放
  • AVAudioSessionCategoryAmbient,只支持音頻播放。這個 Category,音頻會被靜音鍵和鎖屏鍵靜音。并且不會打斷其他應用的音頻播放。

  • AVAudioSessionCategorySoloAmbient,這個是系統(tǒng)默認使用的 Category,只支持音頻播放。音頻會被靜音鍵和鎖屏鍵靜音。和AVAudioSessionCategoryAmbient不同的是,這個會打斷其他應用的音頻播放

  • AVAudioSessionCategoryPlayback,只支持音頻播放。你的音頻不會被靜音鍵和鎖屏鍵靜音。適用于音頻是主要功能的APP,像網(wǎng)易云這些音樂app,鎖屏后依然可以播放。

需要注意一下,選擇支持在靜音鍵切到靜音狀態(tài)以及鎖屏鍵切到鎖屏狀態(tài)下仍然可以播放音頻 Category 時,必須在應用中開啟支持后臺音頻功能,詳見 UIBackgroundModes。

  • AVAudioSessionCategoryRecord,只支持音頻錄制。不支持播放。
  • AVAudioSessionCategoryPlayAndRecord,支持音頻播放和錄制。音頻的輸入和輸出不需要同步進行,也可以同步進行。需要音頻通話類應用,可以使用這個 Category。
  • AVAudioSessionCategoryAudioProcessing,只支持本地音頻編解碼處理。不支持播放和錄制。
  • AVAudioSessionCategoryMultiRoute,支持音頻播放和錄制。允許多條音頻流的同步輸入和輸出。(比如USB連接外部揚聲器輸出音頻,藍牙耳機同時播放另一路音頻這種特殊需求)

我們也可以通過AVAudioSession的屬性來讀取當前設備支持的Category

@property(readonly) NSArray<NSString *> *availableCategories;

這樣可以保證設備兼容性。

設置Category的代碼示例如下

NSError *setCategoryError = nil;
BOOL isSuccess = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&setCategoryError];
if (!success) { 
    //這里可以讀取setCategoryError.localizedDescription查看錯誤原因
}

3. AVAudioSession Mode&&Options

剛剛介紹的Category定義了七種主場景,實際開發(fā)需求中有時候需要對Category進行微調(diào)整,我們發(fā)現(xiàn)這個接口還有兩個參數(shù)Mode和Options。

/* set session category and mode with options */
- (BOOL)setCategory:(NSString *)category mode:(NSString *)mode options:(AVAudioSessionCategoryOptions)options error:(NSError **)outError API_AVAILABLE(ios(10.0), watchos(3.0), tvos(10.0));

AVAudioSession Mode

我們通過讀取下面這條屬性獲取當前設備支持的Mode

@property(readonly) NSArray<NSString *> *availableModes;

iOS下有七種mode來定制我們的Category行為

模式 兼容的 Category 場景
AVAudioSessionModeDefault All 默認模式
AVAudioSessionModeVoiceChat AVAudioSessionCategoryPlayAndRecord VoIP
AVAudioSessionModeGameChat AVAudioSessionCategoryPlayAndRecord 游戲錄制,GKVoiceChat自動設置
AVAudioSessionModeVideoRecording AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryRecord 錄制視頻
AVAudioSessionModeMoviePlayback AVAudioSessionCategoryPlayback 視頻播放
AVAudioSessionModeMeasurement AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryRecord AVAudioSessionCategoryPlayback 最小系統(tǒng)
AVAudioSessionModeVideoChat AVAudioSessionCategoryPlayAndRecord 視頻通話

下面逐一介紹下每個Mode

  • AVAudioSessionModeDefault,默認模式,與所有的 Category 兼容

  • AVAudioSessionModeVoiceChat,適用于VoIP 類型的應用。只能是 AVAudioSessionCategoryPlayAndRecord Category下。在這個模式系統(tǒng)會自動配置AVAudioSessionCategoryOptionAllowBluetooth 這個選項。系統(tǒng)會自動選擇最佳的內(nèi)置麥克風組合支持語音聊天。

  • AVAudioSessionModeVideoChat,用于視頻聊天類型應用,只能是 AVAudioSessionCategoryPlayAndRecord Category下。適在這個模式系統(tǒng)會自動配置 AVAudioSessionCategoryOptionAllowBluetooth 和 AVAudioSessionCategoryOptionDefaultToSpeaker 選項。系統(tǒng)會自動選擇最佳的內(nèi)置麥克風組合支持視頻聊天。

  • AVAudioSessionModeGameChat,適用于游戲類應用。使用 GKVoiceChat 對象的應用會自動設置這個模式和 AVAudioSessionCategoryPlayAndRecord Category。實際參數(shù)和AVAudioSessionModeVideoChat一致

  • AVAudioSessionModeVideoRecording,適用于使用攝像頭采集視頻的應用。只能是 AVAudioSessionCategoryPlayAndRecord 和 AVAudioSessionCategoryRecord 這兩個 Category下。這個模式搭配 AVCaptureSession API 結(jié)合來用可以更好地控制音視頻的輸入輸出路徑。(例如,設置 automaticallyConfiguresApplicationAudioSession 屬性,系統(tǒng)會自動選擇最佳輸出路徑。

  • AVAudioSessionModeMeasurement,最小化系統(tǒng)。只用于 AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryRecord、AVAudioSessionCategoryPlayback 這幾種 Category。

  • AVAudioSessionModeMoviePlayback,適用于播放視頻的應用。只用于 AVAudioSessionCategoryPlayback 這個Category。

AVAudioSession Options

我們還可以使用options去微調(diào)Category行為,如下表

Option Option功能說明 兼容的 Category
AVAudioSessionCategoryOptionMixWithOthers 支持和其他APP音頻 mix AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryPlayback AVAudioSessionCategoryMultiRoute
AVAudioSessionCategoryOptionDuckOthers 系統(tǒng)智能調(diào)低其他APP音頻音量 AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryPlayback AVAudioSessionCategoryMultiRoute
AVAudioSessionCategoryOptionAllowBluetooth 支持藍牙音頻輸入 AVAudioSessionCategoryRecord AVAudioSessionCategoryPlayAndRecord
AVAudioSessionCategoryOptionDefaultToSpeaker 設置默認輸出音頻到揚聲器 AVAudioSessionCategoryPlayAndRecord

調(diào)優(yōu)我們的Category

通過Category和合適的Mode和Options的搭配我們可以調(diào)優(yōu)出我們的效果,下面舉兩個應用場景:

用過高德地圖的都知道,在后臺播放QQ音樂的時候,如果導航語音出來,QQ音樂不會停止,而是被智能壓低和混音,等導航語音播報完后,QQ音樂正常播放,這里我們需要后臺播放音樂,所以Category使用AVAudioSessionCategoryPlayback,需要混音和智能壓低其他APP音量,所以Options選用 AVAudioSessionCategoryOptionMixWithOthers和AVAudioSessionCategoryOptionDuckOthers

代碼示例如下

 BOOL isSuccess = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionDuckOthers error:&setCategoryError];

又或者我希望AVAudioSessionCategoryPlayAndRecord這個Category默認的音頻由揚聲器播放,那么可以調(diào)用這個接口去調(diào)整Category

- (BOOL)setCategory:(NSString *)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError

通過選擇合適和Category,mode和options,就可以調(diào)優(yōu)音頻的輸入輸出,來滿足日常開發(fā)需求(需要注意的是Category,mode,option是搭配使用的,而不是簡單組合,也就是說某種Category支持某些mode和option,從上面的表中也可以看出這一點)

4. 音頻中斷處理

其他APP或者電話會中斷我們的APP音頻,所以相應的我們要做出處理。
我們可以通過監(jiān)聽AVAudioSessionInterruptionNotification這個key獲取音頻中斷事件

回調(diào)回來Userinfo有鍵值

  • AVAudioSessionInterruptionTypeKey:
    取值AVAudioSessionInterruptionTypeBegan表示中斷開始
    取值AVAudioSessionInterruptionTypeEnded表示中斷結(jié)束

中斷開始:我們需要做的是保存好播放狀態(tài),上下文,更新用戶界面等
中斷結(jié)束:我們要做的是恢復好狀態(tài)和上下文,更新用戶界面,根據(jù)需求準備好之后選擇是否激活我們session。

選擇不同的音頻播放技術,處理中斷方式也有差別,具體如下:

  • System Sound Services:使用 System Sound Services 播發(fā)音頻,系統(tǒng)會自動處理,不受APP控制,當中斷發(fā)生時,音頻播放會靜音,當中斷結(jié)束后,音頻播放會恢復。

  • AV Foundation framework:AVAudioPlayer 類和 AVAudioRecorder 類提供了中斷開始和結(jié)束的 Delegate 回調(diào)方法來處理中斷。中斷發(fā)生,系統(tǒng)會自動停止播放,需要做的是記錄播放時間等狀態(tài),更新用戶界面,等中斷結(jié)束后,再次調(diào)用播放方法,系統(tǒng)會自動激活session。

  • Audio Queue Services, I/O audio unit:使用aduio unit這些技術需要處理中斷,需要做的是記錄播放或者錄制的位置,中斷結(jié)束后自己恢復audio session。

  • OpenAL:使用 OpenAL 播放時,同樣需要自己監(jiān)聽中斷。管理 OpenAL上下文,用戶中斷結(jié)束后恢復audio session。

需要注意的是:1. 有中斷開始事件,不一定對應有中斷結(jié)束事件,所以需要在用戶進入前臺,點擊UI操作的時候,需要保存好播放狀態(tài)和對Audio Session管理,以便不影響APP的音頻功能。2.音頻資源競爭上,一定是電話優(yōu)先。3. AVAudioSession同樣可以監(jiān)聽外設音頻狀態(tài),比如耳機拔入拔出。這里不做累述

5. AVAudioSession總結(jié)

AVAudioSession的作用就是管理音頻這一唯一硬件資源的分配,通過調(diào)優(yōu)合適的AVAudioSession來適配我們的APP對于音頻的功能需求。切換音頻場景時候,需要相應的切換AVAudioSession。

參考文獻:Audio Session Programming Guide

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,882評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,208評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,746評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,666評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,477評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,960評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,047評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,200評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,726評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,617評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,807評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,327評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,049評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,425評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,674評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,432評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,769評論 2 372

推薦閱讀更多精彩內(nèi)容