1. AVAudioSession 概述
最近一年一直在做IPC Camera的iOS客戶端開發(fā)。和音頻打交道,必須要弄清楚
AVAudioSession。
先看下蘋果的官方圖:
可以看到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。