iOS-音訊-AVAudioSession

AceDong發表於2018-07-04

1. AVAudioSession 概述

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

Audio Session

可以看到AVAudioSession就是用來管理多個APP對音訊硬體裝置(麥克風,揚聲器)的資源使用。

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

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

2. AVAudioSession Category

AVAudioSession的介面比較簡單。APP啟動的時候會自動幫啟用AVAudioSession,當然我們可以手動啟用程式碼如下。

    //匯入標頭檔案
    #import <AVFoundation/AVFoundation.h>

    //AVAudioSession是一個單例類
    AVAudioSession *session = [AVAudioSession sharedInstance];
    //AVAudioSessionCategorySoloAmbient是系統預設的category
    [session setCategory:AVAudioSessionCategorySoloAmbient error:nil];
    //啟用AVAudioSession
    [session setActive:YES error:nil];
複製程式碼

可以看到設定session這裡有兩個引數,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,這個是系統預設使用的 Category,只支援音訊播放。音訊會被靜音鍵和鎖屏鍵靜音。和AVAudioSessionCategoryAmbient不同的是,這個會打斷其他應用的音訊播放

  • AVAudioSessionCategoryPlayback,只支援音訊播放。你的音訊不會被靜音鍵和鎖屏鍵靜音。適用於音訊是主要功能的APP,像網易雲這些音樂app,鎖屏後依然可以播放。

需要注意一下,選擇支援在靜音鍵切到靜音狀態以及鎖屏鍵切到鎖屏狀態下仍然可以播放音訊 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定義了七種主場景,實際開發需求中有時候需要對Category進行微調整,我們發現這個介面還有兩個引數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 最小系統
AVAudioSessionModeVideoChat AVAudioSessionCategoryPlayAndRecord 視訊通話

下面逐一介紹下每個Mode

  • AVAudioSessionModeDefault,預設模式,與所有的 Category 相容

  • AVAudioSessionModeVoiceChat,適用於VoIP 型別的應用。只能是 AVAudioSessionCategoryPlayAndRecord Category下。在這個模式系統會自動配置AVAudioSessionCategoryOptionAllowBluetooth 這個選項。系統會自動選擇最佳的內建麥克風組合支援語音聊天。

  • AVAudioSessionModeVideoChat,用於視訊聊天型別應用,只能是 AVAudioSessionCategoryPlayAndRecord Category下。適在這個模式系統會自動配置 AVAudioSessionCategoryOptionAllowBluetooth 和 AVAudioSessionCategoryOptionDefaultToSpeaker 選項。系統會自動選擇最佳的內建麥克風組合支援視訊聊天。

  • AVAudioSessionModeGameChat,適用於遊戲類應用。使用 GKVoiceChat 物件的應用會自動設定這個模式和 AVAudioSessionCategoryPlayAndRecord Category。實際引數和AVAudioSessionModeVideoChat一致

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

  • AVAudioSessionModeMeasurement,最小化系統。只用於 AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryRecord、AVAudioSessionCategoryPlayback 這幾種 Category。

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

AVAudioSession Options

我們還可以使用options去微調Category行為,如下表

Option Option功能說明 相容的 Category
AVAudioSessionCategoryOptionMixWithOthers 支援和其他APP音訊 mix AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryPlayback AVAudioSessionCategoryMultiRoute
AVAudioSessionCategoryOptionDuckOthers 系統智慧調低其他APP音訊音量 AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryPlayback AVAudioSessionCategoryMultiRoute
AVAudioSessionCategoryOptionAllowBluetooth 支援藍芽音訊輸入 AVAudioSessionCategoryRecord AVAudioSessionCategoryPlayAndRecord
AVAudioSessionCategoryOptionDefaultToSpeaker 設定預設輸出音訊到揚聲器 AVAudioSessionCategoryPlayAndRecord

調優我們的Category

通過Category和合適的Mode和Options的搭配我們可以調優出我們的效果,下面舉兩個應用場景:

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

程式碼示例如下

 BOOL isSuccess = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionDuckOthers error:&setCategoryError];
複製程式碼

又或者我希望AVAudioSessionCategoryPlayAndRecord這個Category預設的音訊由揚聲器播放,那麼可以呼叫這個介面去調整Category

- (BOOL)setCategory:(NSString *)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError
複製程式碼

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

4. 音訊中斷處理

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

回撥回來Userinfo有鍵值

  • AVAudioSessionInterruptionTypeKey: 取值AVAudioSessionInterruptionTypeBegan表示中斷開始 取值AVAudioSessionInterruptionTypeEnded表示中斷結束

中斷開始:我們需要做的是儲存好播放狀態,上下文,更新使用者介面等 中斷結束:我們要做的是恢復好狀態和上下文,更新使用者介面,根據需求準備好之後選擇是否啟用我們session。

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

  • System Sound Services:使用 System Sound Services 播發音訊,系統會自動處理,不受APP控制,當中斷髮生時,音訊播放會靜音,當中斷結束後,音訊播放會恢復。

  • AV Foundation framework:AVAudioPlayer 類和 AVAudioRecorder 類提供了中斷開始和結束的 Delegate 回撥方法來處理中斷。中斷髮生,系統會自動停止播放,需要做的是記錄播放時間等狀態,更新使用者介面,等中斷結束後,再次呼叫播放方法,系統會自動啟用session。

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

  • OpenAL:使用 OpenAL 播放時,同樣需要自己監聽中斷。管理 OpenAL上下文,使用者中斷結束後恢復audio session。

需要注意的是:1. 有中斷開始事件,不一定對應有中斷結束事件,所以需要在使用者進入前臺,點選UI操作的時候,需要儲存好播放狀態和對Audio Session管理,以便不影響APP的音訊功能。2.音訊資源競爭上,一定是電話優先。3. AVAudioSession同樣可以監聽外設音訊狀態,比如耳機拔入拔出。這裡不做累述

5. AVAudioSession總結

AVAudioSession的作用就是管理音訊這一唯一硬體資源的分配,通過調優合適的AVAudioSession來適配我們的APP對於音訊的功能需求。切換音訊場景時候,需要相應的切換AVAudioSession。

參考文獻:Audio Session Programming Guide

相關文章