AVAudioSession
簡要說說AVAudioSession凤粗,AVAudioSession是蘋果用來管理App對音頻硬件(I / O)的資源使用惯悠;比如說:
- 設(shè)置APP與其他APP是否混音浆兰,或者中斷、降低其他App聲音
- 手機(jī)靜音下沦偎,APP是否可以播放聲音
- 指定音頻輸入或者輸出設(shè)備
- 是否支持APP錄制木张,是否可以邊錄制邊播放
- 聲音中斷的優(yōu)先級(電話接入中斷APP音頻處理)
在APP的運(yùn)行過程中,AudioSession的配置影響所有的音頻活動煤蚌。你可以查詢Audio Session來發(fā)現(xiàn)設(shè)備的硬件特性耕挨。如聲道數(shù)(channel count)、采樣率(sample rate)铺然、和音頻輸入的可用性(availability of audio unit)
AVAudioSession 激活
/* 設(shè)置為激活或者失活俗孝。激活音頻會話是一個同步(阻塞)操作 */
- (BOOL)setActive:(BOOL)active
error:(NSError * _Nullable *)outError;
/* 調(diào)用該方法 通知中斷的應(yīng)用程序中斷已經(jīng)結(jié)束,它可以恢復(fù)播放魄健,僅在會話停用時(shí)有效
active:NO
options:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation */
- (BOOL)setActive:(BOOL)active withOptions:(AVAudioSessionSetActiveOptions)options error:(NSError **)outError;
AVAudioSession 硬件設(shè)置
/* 首選硬件采樣率 */
- (BOOL)setPreferredSampleRate:(double)sampleRate error:(NSError **)outError
/* 首選的硬件IO緩沖區(qū)持續(xù)時(shí)間(以秒為單位) */
- (BOOL)setPreferredIOBufferDuration:(NSTimeInterval)duration error:(NSError **)outError
// 輸入通道數(shù)
- (BOOL)setPreferredInputNumberOfChannels:(NSInteger)count error:(NSError **)outError
// 輸出通道數(shù)
- (BOOL)setPreferredOutputNumberOfChannels:(NSInteger)count error:(NSError **)outError
// 設(shè)置立體聲方向
- (BOOL)setPreferredInputOrientation:(AVAudioStereoOrientation)orientation error:(NSError **)outError
// 使用此方法可臨時(shí)覆蓋內(nèi)置揚(yáng)聲器的輸出
- (BOOL)overrideOutputAudioPort:(AVAudioSessionPortOverride)portOverride error:(NSError **)outError
設(shè)置音頻輸出方式
當(dāng)iPhone接入多個外部設(shè)備時(shí)赋铝,AudioSeesion將遵循last-in wins原則(后入為主),即聲音將被導(dǎo)向到最后接入的設(shè)備沽瘦。在沒有接入任何設(shè)備時(shí)革骨,一般情況下聲音會默認(rèn)從揚(yáng)聲器發(fā)出,但有一個例外:在使用AVAudioSessionCategoryPlayAndRecord
這種category下析恋,聽筒成為默認(rèn)的輸出設(shè)備良哲。
如果需要改變揚(yáng)聲器的輸出,有以下幾種方式:
- 方式一:調(diào)用音頻輸出方法
overrideOutputAudioPort:
(這種方式調(diào)用更短暫)
如果選擇揚(yáng)聲器輸出助隧,設(shè)置為AVAudioSessionPortOverrideSpeaker
;
如果默認(rèn)狀態(tài)輸出筑凫,設(shè)置為AVAudioSessionPortOverrideNone
; - 方式二:設(shè)置
AVAudioSessionCategoryOption
值
如果選擇揚(yáng)聲器輸出,設(shè)置為AVAudioSessionCategoryOptionDefaultToSpeaker
;
如果默認(rèn)狀態(tài)輸出,不設(shè)置;
AVAudioSessionCategory
在AVAudioSession中可以設(shè)置Category和Option巍实,每一種Category都對應(yīng)是否支持以下幾種能力:
- Interrupts non-mixable apps audio :是否打斷不支持混音播放的APP
- Silenced by the Silent switch:是否會被手機(jī)靜音鍵開關(guān)影響
- Supports audio input / output:是否支持音頻錄制滓技、播放
Category | Play | Record | MixWithOther | Silenced |
---|---|---|---|---|
AVAudioSessionCategoryAmbient | ? | ? | ? | ? |
AVAudioSessionCategorySoloAmbient | ? | ? | ? | ? |
AVAudioSessionCategoryPlayback | ? | ? | 可選,默認(rèn)? | ? |
AVAudioSessionCategoryRecord | ? | ? | ? | ? |
AVAudioSessionCategoryPlayAndRecord | ? | ? | 可選棚潦,默認(rèn)? | ? |
AVAudioSessionCategoryAudioProcessing | ? | ? | ? | ? |
AVAudioSessionCategoryMultiRoute | ? | ? | ? | ? |
-
AVAudioSessionCategoryAmbient
:只支持音頻播放令漂,音頻播放時(shí)會被靜音鍵和鎖屏鍵靜音,可以與其他APP混音丸边。 -
AVAudioSessionCategorySoloAmbient
: 系統(tǒng)默認(rèn)叠必,只支持音頻播放,音頻會被靜音鍵和鎖屏鍵靜音妹窖,會打斷其他APP音頻播放纬朝。 -
AVAudioSessionCategoryPlayback
:支持音頻播放,音頻不會被靜音鍵和鎖屏鍵靜音嘱吗,適用于音頻是主要功能的APP玄组,鎖屏后依然可以播放。(后臺播放需要開啟音頻相關(guān)的后臺支持UIBackgroundModes) -
AVAudioSessionCategoryRecord
: 只支持音頻錄制谒麦,不支持播放俄讹。 -
AVAudioSessionCategoryPlayAndRecord
: 支持音頻錄制和播放,聲音在沒有外設(shè)的情況下绕德,默認(rèn)為聽筒播放患膛。 -
AVAudioSessionCategoryAudioProcessing
: 使用硬件編解碼器或信號處理器而不播放或錄制音頻時(shí)使用此類別。 -
AVAudioSessionCategoryMultiRoute
: 使用硬件編解碼器或信號處理器而不播放或錄制音頻時(shí)使用此類別耻蛇。
/* set session category */
- (BOOL)setCategory:(AVAudioSessionCategory)category error:(NSError **)outError API_AVAILABLE(ios(3.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
/* set session category with options */
- (BOOL)setCategory:(AVAudioSessionCategory)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);
/* set session category and mode with options */
- (BOOL)setCategory:(AVAudioSessionCategory)category mode:(AVAudioSessionMode)mode options:(AVAudioSessionCategoryOptions)options error:(NSError **)outError API_AVAILABLE(ios(10.0), watchos(3.0), tvos(10.0)) API_UNAVAILABLE(macos);
/* set session category, mode, routing sharing policy, and options */
- (BOOL)setCategory:(AVAudioSessionCategory)category mode:(AVAudioSessionMode)mode routeSharingPolicy:(AVAudioSessionRouteSharingPolicy)policy options:(AVAudioSessionCategoryOptions)options error:(NSError **)outError API_AVAILABLE(ios(11.0), tvos(11.0), watchos(5.0)) API_UNAVAILABLE(macos);
注意:設(shè)置category要考慮設(shè)置失敗的情況
AVAudioSessionMode
AVAudioSessionMode | Category | Scene |
---|---|---|
AVAudioSessionModeDefault | All | 默認(rèn) |
AVAudioSessionModeVoiceChat | AVAudioSessionCategoryPlayAndRecord | VoIP (語音通話) |
AVAudioSessionModeGameChat | AVAudioSessionCategoryPlayAndRecord | 游戲模式 |
AVAudioSessionModeVideoRecording | AVAudioSessionCategoryRecord踪蹬、AVAudioSessionCategoryPlayAndRecord | 適用于使用攝像頭采集視頻的應(yīng)用 |
AVAudioSessionModeMeasurement | AVAudioSessionCategoryRecord、AVAudioSessionCategoryPlayAndRecord | 最小化系統(tǒng) |
AVAudioSessionModeMoviePlayback | AVAudioSessionCategoryPlayback | 視頻播放 |
AVAudioSessionModeVideoChat | AVAudioSessionCategoryPlayback臣咖、AVAudioSessionCategoryPlayAndRecord | 視頻通話 |
AVAudioSessionModeSpokenAudio | AVAudioSessionCategorySoloAmbient跃捣、AVAudioSessionCategoryPlayback、AVAudioSessionCategoryPlayAndRecord夺蛇、AVAudioSessionCategoryMultiRoute | 有聲讀物 |
AVAudioSessionModeVoicePrompt | - | 語音提示 |
-
AVAudioSessionModeDefault
:默認(rèn)模式 兼容所有category -
AVAudioSessionModeVoiceChat
:適用于語音聊天VoIP -
AVAudioSessionModeGameChat
:適用于游戲模式愿伴,不需要主動設(shè)置(若不想用GKVoiceChat但希望達(dá)到類似功能粘室,可以使用AVAudioSessionModeVoiceChat) -
AVAudioSessionModeVideoRecording
:適用于使用攝像頭采集視頻的應(yīng)用 -
AVAudioSessionModeMeasurement
:適用于希望將系統(tǒng)提供的用于輸入和/或輸出音頻信號的信號處理的影響最小化的應(yīng)用 -
AVAudioSessionModeMoviePlayback
:適用于AVAudioSessionCategoryPlayback
下的視頻播放 -
AVAudioSessionModeVideoChat
:適用于視頻聊天 系統(tǒng)會自動配置AVAudioSessionCategoryOptionAllowBluetooth
和AVAudioSessionCategoryOptionDefaultToSpeaker
-
AVAudioSessionModeSpokenAudio
:當(dāng)其他應(yīng)用程序播放短暫的語音提示時(shí),希望自己的音頻暫停而不是回避(聲音變小)時(shí)使用 -
AVAudioSessionModeVoicePrompt
:當(dāng)程序內(nèi)音頻為簡單的語音提示時(shí)使用蹦误。適用于導(dǎo)航中的播報(bào)
AVAudioSessionCategoryOptions
AVAudioSessionCategoryOption | Function Describe | Supports Category |
---|---|---|
AVAudioSessionCategoryOptionMixWithOthers | 支持混音 |
AVAudioSessionCategoryPlayback AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryMultiRoute
|
AVAudioSessionCategoryOptionDuckOthers | 降低其他應(yīng)用的音量 |
AVAudioSessionCategoryPlayback AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryMultiRoute
|
AVAudioSessionCategoryOptionAllowBluetooth | 支持藍(lán)牙音頻輸入 |
AVAudioSessionCategoryRecord AVAudioSessionCategoryPlayAndRecord
|
AVAudioSessionCategoryOptionDefaultToSpeaker | 設(shè)置默認(rèn)輸出到揚(yáng)聲器 | AVAudioSessionCategoryPlayAndRecord |
AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers | 音頻播放過程中薪伏,支持中斷其他應(yīng)用 |
AVAudioSessionCategoryPlayback AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryMultiRoute
|
AVAudioSessionCategoryOptionAllowBluetoothA2DP | 支持立體聲藍(lán)牙 |
AVAudioSessionCategoryAmbient AVAudioSessionCategorySoloAmbient AVAudioSessionCategoryPlayback AVAudioSessionCategoryPlayAndRecord
|
AVAudioSessionCategoryOptionAllowAirPlay | 支持遠(yuǎn)程AirPlay | AVAudioSessionCategoryPlayAndRecord |
-
AVAudioSessionCategoryOptionMixWithOthers
:AVAudioSessionCategoryPlayAndRecord 猾瘸、AVAudioSessionCategoryMultiRoute默認(rèn)不設(shè)置勉盅,若設(shè)置后,當(dāng)程序同時(shí)啟動音頻輸入輸出時(shí)牺氨,允許程序后臺運(yùn)行狡耻;AVAudioSessionCategoryPlayback默認(rèn)不設(shè)置墩剖,若設(shè)置后,無論是鈴聲還是在靜音模式下夷狰,仍然能夠播放 -
AVAudioSessionCategoryOptionDuckOthers
:當(dāng)前session處于active時(shí)涛碑,其他音頻就是回避狀態(tài)(壓低聲音) AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryPlayback孵淘、AVAudioSessionCategoryMultiRoute 默認(rèn)不混音,不回避 -
AVAudioSessionCategoryOptionAllowBluetooth
:允許將藍(lán)牙作為可用途徑歹篓。支持AVAudioSessionCategoryPlayAndRecord瘫证、AVAudioSessionCategoryRecord -
AVAudioSessionCategoryOptionDefaultToSpeaker
:允許改變音頻session默認(rèn)選擇內(nèi)置揚(yáng)聲器(免提);僅支持AVAudioSessionCategoryPlayAndRecord -
AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers
:如果設(shè)置了這個選項(xiàng)庄撮,系統(tǒng)就會將你的音頻與其他音頻會話混合背捌,但是會中斷(并停止)使用AVAudioSessionModeSpokenAudio模式的音頻會話;只要會話處于活動狀態(tài)洞斯,它就會暫停來自其他應(yīng)用程序的音頻毡庆。音頻會話失活后,系統(tǒng)恢復(fù)被中斷的應(yīng)用程序的音頻烙如。 -
AVAudioSessionCategoryOptionAllowBluetoothA2DP
:A2DP是一種立體聲么抗、僅輸出的配置文件用于更高帶寬的音頻。如果使用AVAudioSessionCategoryAmbient亚铁、AVAudioSessionCategorySoloAmbient或AVAudioSessionCategoryPlayback類別蝇刀,系統(tǒng)會自動路由到A2DP端口;從iOS 10.0開始徘溢,使用AVAudioSessionCategoryPlayAndRecord類別的應(yīng)用程序也可以將輸出路由到配對的藍(lán)牙A2DP設(shè)備吞琐。要啟用此行為,請?jiān)谠O(shè)置音頻會話的類別時(shí)傳遞此類別選項(xiàng)然爆。 -
AVAudioSessionCategoryOptionAllowAirPlay
:設(shè)置此選項(xiàng)可使音頻會話將音頻輸出路由到AirPlay設(shè)備站粟。設(shè)置為AVAudioSessionCategoryPlayAndRecord,則只能顯式地設(shè)置此選項(xiàng)曾雕。對于大多數(shù)其他音頻會話類別奴烙,系統(tǒng)隱式地設(shè)置此選項(xiàng)。
注意: 如果應(yīng)用中使用到MPNowPlayingInfoCenter翻默,最好避免設(shè)置AVAudioSessionCategoryOptionMixWithOthers缸沃;因?yàn)橐坏┰O(shè)置了這個值之后,那么MPNowPlayingInfoCenter就不能正常顯示信息
AVAudioSessionRouteSharingPolicy
路由策略:
- AVAudioSessionRouteSharingPolicyDefault 遵循正常的規(guī)則路由音頻輸出
- AVAudioSessionRouteSharingPolicyLongFormAudio 將輸出路由到共享的長格式音頻輸出
-
AVAudioSessionRouteSharingPolicyLongForm已廢棄 - AVAudioSessionRouteSharingPolicyIndependent 應(yīng)用程序不應(yīng)試圖直接設(shè)置此值修械。在iOS上趾牧,當(dāng)路由選擇器UI用于將視頻定向到無線路由時(shí),系統(tǒng)將設(shè)置此值肯污。
- AVAudioSessionRouteSharingPolicyLongFormVideo 將輸出路由到共享的長格式視頻輸出(使用此策略的應(yīng)用程序在其Info.plist中設(shè)置AVInitialRouteSharingPolicy鍵)
AVAudioSessionNotification
AVAudioSession有以下多個通知來提示用戶事件翘单;
- AVAudioSessionInterruptionNotification:系統(tǒng)中斷響應(yīng)通知
- AVAudioSessionInterruptionNotification:音頻線路變更通知
- AVAudioSessionSilenceSecondaryAudioHintNotification:其他應(yīng)用音頻狀態(tài)提示通知
AVAudioSessionInterruptionNotification
當(dāng)App內(nèi)音頻被中斷吨枉,系統(tǒng)會將AudioSession置為失活狀態(tài),音頻也會因此立即停止哄芜。當(dāng)一個別的App的AudioSession被激活并且它的類別未設(shè)置與系統(tǒng)類別或你應(yīng)用程序類別混合時(shí)貌亭,中斷就會發(fā)生。你的應(yīng)用程序在收到中斷通知后應(yīng)該保存當(dāng)時(shí)的狀態(tài)认臊,以及更新用戶界面等相關(guān)操作圃庭。通過注冊AVAudioSessionInterruptionNotification
通知,可以處理中斷的開始和結(jié)束失晴。
/* keys for AVAudioSessionInterruptionNotification */
/* Value is an NSNumber representing an AVAudioSessionInterruptionType */
AVAudioSessionInterruptionTypeKey
typedef NS_ENUM(NSUInteger, AVAudioSessionInterruptionType)
{
AVAudioSessionInterruptionTypeBegan = 1, /* the system has interrupted your audio session */
AVAudioSessionInterruptionTypeEnded = 0, /* the interruption has ended */
};
/* Only present for end interruption events. Value is of type AVAudioSessionInterruptionOptions.*/
AVAudioSessionInterruptionOptionKey
typedef NS_OPTIONS(NSUInteger, AVAudioSessionInterruptionOptions)
{
AVAudioSessionInterruptionOptionShouldResume = 1
};
提示:這里的通知的中斷開始和中斷結(jié)束不一定都會出現(xiàn)(蘋果文檔中有提到)
AVAudioSessionRouteChangeNotification
當(dāng)用戶連接或者斷開音頻輸入剧腻,輸出設(shè)備時(shí)(插拔耳機(jī)、或者藍(lán)牙耳機(jī)的斷開涂屁、連接)书在,音頻線路發(fā)生變更,通過注冊AVAudioSessionRouteChangeNotification
通知拆又,可以在音頻線路發(fā)生變更時(shí)做出相應(yīng)處理儒旬。
/* keys for AVAudioSessionRouteChangeNotification */
/* value is an NSNumber representing an AVAudioSessionRouteChangeReason */
AVAudioSessionRouteChangeReasonKey
typedef NS_ENUM(NSUInteger, AVAudioSessionRouteChangeReason)
{
AVAudioSessionRouteChangeReasonUnknown = 0,
AVAudioSessionRouteChangeReasonNewDeviceAvailable = 1, //設(shè)備可用(耳機(jī)插好)
AVAudioSessionRouteChangeReasonOldDeviceUnavailable = 2, //設(shè)備不可用(耳機(jī)被拔下)
AVAudioSessionRouteChangeReasonCategoryChange = 3, // 設(shè)置的分類被改變
AVAudioSessionRouteChangeReasonOverride = 4, // 路由被覆蓋
AVAudioSessionRouteChangeReasonWakeFromSleep = 6, // 設(shè)備被激活
AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory = 7, //當(dāng)前類別沒有路由時(shí)返回
AVAudioSessionRouteChangeReasonRouteConfigurationChange = 8 // added in iOS 7
};
AVAudioSessionSilenceSecondaryAudioHintNotification
當(dāng)來自其他應(yīng)用的主音頻啟動,或者停止時(shí)帖族,通過注冊AVAudioSessionSilenceSecondaryAudioHintNotification
通知栈源,前臺應(yīng)用可以作為啟動或者禁用次要音頻的提示;
/* keys for AVAudioSessionSilenceSecondaryAudioHintNotification */
/* value is an NSNumber representing an AVAudioSessionSilenceSecondaryAudioHintType */
AVAudioSessionSilenceSecondaryAudioHintTypeKey
typedef NS_ENUM(NSUInteger, AVAudioSessionSilenceSecondaryAudioHintType)
{
AVAudioSessionSilenceSecondaryAudioHintTypeBegin = 1, /* the system is indicating that another application's primary audio has started */
AVAudioSessionSilenceSecondaryAudioHintTypeEnd = 0, /* the system is indicating that another application's primary audio has stopped */
};
AVAudioSession 常用音頻建議
使用AVAudioSessionCategoryRecord
盟萨,AVAudioSessionCategoryPlayAndRecord
凉翻,AVAudioSessionCategoryPlayback
類別的APP,蘋果建議的準(zhǔn)則如下:
- 當(dāng)應(yīng)用程序進(jìn)入前臺時(shí)捻激,請等待用戶按下“播放”或“錄制”按鈕制轰,然后再激活音頻會話。
- 當(dāng)應(yīng)用程序處于前臺時(shí)胞谭,除非中斷垃杖,否則請保持音頻會話處于活動狀態(tài)。
- 如果應(yīng)用程序在過渡到后臺時(shí)沒有活躍的播放或錄制音頻丈屹,請停用其音頻會話调俘。這樣可以防止其音頻會話被另一個不可混合的應(yīng)用程序中斷,或者在應(yīng)用程序被系統(tǒng)掛起時(shí)響應(yīng)中斷其音頻會話旺垒。
- 在被中斷后更新用戶界面的播放或錄制到暫停彩库。請勿停用音頻會話。
- 觀察
AVAudioSessionInterruptionNotification
有關(guān)音頻會話中斷的通知類型先蒋。中斷結(jié)束后骇钦,請勿再次開始播放或錄制音頻,除非該應(yīng)用在中斷之前就已經(jīng)開始了竞漾。 - 如果路由更改是由拔出事件引起的眯搭,則暫停播放或錄制窥翩,但請保持音頻會話處于活動狀態(tài)。
- 假設(shè)應(yīng)用程序的音頻會話從掛起狀態(tài)轉(zhuǎn)換為前臺狀態(tài)時(shí)處于失活狀態(tài)鳞仙。當(dāng)用戶按下“播放”或“錄制”按鈕時(shí)寇蚊,重新激活音頻會話。
- 確保
UIBackgroundModes
已設(shè)置音頻標(biāo)志棍好。 - 注冊遠(yuǎn)程控制事件(請參閱參考資料
MPRemoteCommandCenter
)仗岸,并為您的媒體提供適當(dāng)?shù)摹罢诓シ拧毙畔ⅲㄕ垍㈤唴⒖假Y料MPNowPlayingInfoCenter
)。 - 使用一個
MPVolumeView
對象顯示系統(tǒng)音量滑塊和路線選擇器借笙。 - 使用后臺任務(wù)而不是靜默播放流爹梁,以防止應(yīng)用程序被暫停。
- 要求用戶許可使用該
requestRecordPermission:
方法記錄輸入提澎。不要依靠操作系統(tǒng)來提示用戶。 - 對于錄制應(yīng)用程序念链,請使用
AVAudioSessionCategoryPlayAndRecord
類別而不是AVAudioSessionCategoryRecord
類別盼忌。“僅記錄”類別幾乎使所有系統(tǒng)輸出靜音掂墓,并且通常對于大多數(shù)應(yīng)用程序而言過于嚴(yán)格谦纱。
詳情可以參照蘋果指南
AVAudioSession 聲音常用處理
- 播放應(yīng)用內(nèi)的音頻時(shí)暫停外部音樂
[[AudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:0 error:&error];
[[AudioSession sharedInstance] setActive:YES error:&error];
[[AudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];
- 混音播放外部音頻,同時(shí)插播一條應(yīng)用內(nèi)的語音(播放語音時(shí)君编,外部音頻降低音量跨嘉,播放語音完畢后,外部音頻恢復(fù)音量)
/* start */
[[AudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionDuckOthers error:&error];
/* end */
[[AudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];
- 喚起其他App播放
[[AudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
參考文檔