概述
概覽
- 音頻會話管理音頻行為
- categories 代表音頻規(guī)則
- 中斷處理通知
- 通知支持音頻路由的更改
- 音頻會話控制設(shè)置配置
- 音頻會話保護用戶隱私
配置音頻會話
- 音頻默認行為
- 配置音頻會話
- 使用多路徑category 擴展選項
- 啟用后臺音頻
激活音頻會話
- 系統(tǒng)如何解決競爭性音頻需求
- 激活或者取消激活音頻會話
- 檢查其他音頻是否正在播放
應(yīng)對中斷
- 中斷聲明周期
- 音頻中斷處理技術(shù)
- 觀察音頻中斷
- 響應(yīng)流媒體重置
應(yīng)對路由的改變
- 各種音頻硬件路由變化
- 觀察音頻路由改變
配置設(shè)備硬件
- 選擇首選音頻硬件值
- 設(shè)置首選音頻硬件值
- 選擇和配置麥克風
包含用戶隱私
- 請求錄音的權(quán)限
昨天翻譯了官方文檔寫了博客多媒體音頻播放簡單介紹∝倚В回頭再去看LFLiveKit的音頻錄制部分滨嘱,發(fā)現(xiàn)能看懂點那伐,但是又不完全懂畜侦。因此這里就需要把Audio session 詳細學一下。
概述
音頻是ios 封孙,tvos和watchos的托管服務(wù)欢伏。系統(tǒng)通過使用音頻會話管理應(yīng)用程序,應(yīng)用程序之間和設(shè)備基本的音頻行為嚣州。
從圖中我們能看出鲫售,音頻會話既可以管理錄音,也可以管理播放该肴。
我們可以使用音頻會話向系統(tǒng)傳遞我們打算如何在應(yīng)用中使用音頻情竹。此音頻會話充當應(yīng)用和操作系統(tǒng)之間的中介-進而是底層音頻硬件。我們可以使用它來向操作系統(tǒng)傳達應(yīng)用程序音頻的性質(zhì)匀哄,而無需詳細的說明特定行為或與音頻硬件的所需交互秦效。將這些細節(jié)的管理委派給音頻會話可確保最佳的管理用戶的音頻體驗雏蛮。
概覽
我們可以使用AVAudioSession實例與應(yīng)用程序的音頻會話進行交互:
- 配置音頻會話類別和模式,以便與系統(tǒng)通信我們打算如何在應(yīng)用中使用音頻阱州。
- 激活應(yīng)用程序的音頻會話以使我們設(shè)置的類別和模式配置生效
- 訂閱并響應(yīng)重要的音頻會話通知挑秉,例如音頻中斷和路由更改
- 執(zhí)行高級別音頻設(shè)備配置,例如設(shè)置采樣率苔货,I/O緩沖持續(xù)時間和通道數(shù)犀概。
音頻會話管理音頻行為
音頻會話是應(yīng)用和操作系統(tǒng)之間的中介,用于配置應(yīng)用的音頻行為蒲赂。啟動后阱冶,應(yīng)用程序?qū)⒆詣拥奶峁﹩我灰纛l會話(單例)。我們可以配置它滥嘴,讓其提供所需的行為并且激活它讓該行為生效木蹬。
categories 代表音頻規(guī)則
表達音頻行為的主要機制就是音頻會話的category。通過設(shè)置category若皱,我們可以指示應(yīng)用程序是輸入路徑還是輸出路徑(錄音還是播放)镊叁,是否希望音樂繼續(xù)與音頻一起播放,等等走触。
AVFoundation定義了許多音頻會話category晦譬,以及一組覆蓋和修改器開關(guān),可以讓我們根據(jù)應(yīng)用的個性或者角色定義音頻行為互广。不同的類別支持不同的行為敛腌,例如可支持播放,錄制或者錄制回放惫皱。當系統(tǒng)知道我們的app所需要的音頻規(guī)則時像樊,他會為我們提供對硬件資源的適當訪問權(quán)限。系統(tǒng)還可以確保設(shè)備上的其他音頻以適合我們應(yīng)用的方式運行旅敷,并符合用戶期望生棍。
通過指定模式我們還可以進一步定制某些category,該模式用于專門給一些category指定行為媳谁。例如涂滴,當app使用視頻錄制模式時候,系統(tǒng)可能會選擇與使用默認模式時選擇的內(nèi)置麥克風不同的內(nèi)置麥克風晴音。該系統(tǒng)還可以進行針對視頻錄制來調(diào)整麥克風信號處理柔纵。
中斷處理通知
音頻中斷會立即停止音頻。當來自app的競爭音頻會話被激活并且該會話未被系統(tǒng)category以與我們的會話混合時锤躁,就發(fā)生中斷了首量。因此我們的應(yīng)該應(yīng)該保存狀態(tài),更新用戶界面等來響應(yīng)中斷。要在音頻中斷開始和結(jié)束時接受通知加缘,我們應(yīng)該注冊通知。類型看AVAudioSessionInterruptionNotification
通知支持音頻路由的更改
當用戶通過對接或取消對接設(shè)備觉啊,或者通過插入或者拔出耳機來啟動音頻路徑更改時候拣宏,用戶會有特別的期望。iOS Human Interface Guidelines 描述這些期望杠人,并提供了如何滿足這些期望的指南勋乾。我們可以通過注冊通知AVAudioSessionRouteChangeNotification 來觀察路徑的更改。
音頻會話控制設(shè)置配置
app是無法直接控制設(shè)備硬件的嗡善,但是音頻會話為我們提供了請求首先硬件設(shè)備的設(shè)置的接口辑莫。這些接口使我們可以執(zhí)行高級別音頻設(shè)備配置,例如設(shè)置采樣率罩引,I/O緩沖持續(xù)時間和音頻通道數(shù)各吨。
音頻會話保護用戶隱私
單獨或者與視頻一起錄制音頻的app在錄制之前需要用戶授權(quán)。在用戶授權(quán)之前袁铐,app只能靜音錄制揭蜒。
AVAudioSession 提供了請求此權(quán)限的接口并確定用戶的隱私設(shè)置。
配置音頻會話
音頻會話的category是標識app的一組音頻行為的key剔桨。通過設(shè)置category屉更,我們可以向系統(tǒng)指出我們的音頻意圖。例如洒缀,當翻轉(zhuǎn)Ringer/Silent開關(guān)時候我們的音頻是否應(yīng)該繼續(xù)瑰谜,我們可以通過設(shè)置音頻會話category 覆蓋和修改器開關(guān)來定義音頻行為。
Category | 通過鈴聲/靜音開關(guān)或者鎖屏是否需要靜音 | 是否中斷不可以混合的音頻 | 支持錄音和播放 |
---|---|---|---|
AVAudioSessionCategoryAmbient | Yes | No | Output only |
AVAudioSessionCategorySoloAmbient (Default) | Yes | Yes | Output only |
AVAudioSessionCategoryPlayback | No | Yes by default; no by using override switch | Output only |
AVAudioSessionCategoryRecord | No (recording continues with screen locked) | Yes | Input only |
AVAudioSessionCategoryPlayAndRecord | No | Yes by default; no by using override switch | Input and output |
AVAudioSessionCategoryMultiRoute | No | Yes | Input and output |
注意树绩,為了通過鈴聲/靜音開關(guān)設(shè)置或者屏幕鎖屏的時候能繼續(xù)播放音樂萨脑,我們在info.plist 中添加UIBackgroundModes鍵。
上表中每一個音頻會話category都指定對應(yīng)一下每個行為的特定響應(yīng)集:
- 中斷不可以混合的app的音頻:如果是yes葱峡,那么當您的應(yīng)用激活其音頻會話時砚哗,不可混合的應(yīng)用會被中斷。
- 靜音開關(guān)靜音:如果yes砰奕,當用戶激活靜音開關(guān)時蛛芥,音頻靜音。
- 支持音頻輸入:如果yes军援,那么則允許應(yīng)用音頻輸入(錄制)
- 支持音頻暑促:如果yes仅淑,那么則允許音頻輸出(播放)
大多數(shù)app應(yīng)用只需要啟動的時候設(shè)置一次category,但是我們可以根據(jù)需要更改category胸哥。我們可以在音頻會話在激活狀態(tài)下更改涯竟;但是最好在更改category或者其他會話屬性之前停用音頻會話。在會話停用時進行這些更改可防止對音頻系統(tǒng)進行不必要的重新配置。
下面列舉下mode
Mode identifiers | Compatible categories |
---|---|
AVAudioSessionModeDefault | All |
AVAudioSessionModeMoviePlayback | AVAudioSessionCategoryPlayback |
AVAudioSessionModeVideoRecording | AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryRecord |
AVAudioSessionModeVoiceChat | AVAudioSessionCategoryPlayAndRecord |
AVAudioSessionModeGameChat | AVAudioSessionCategoryPlayAndRecord |
AVAudioSessionModeVideoChat | AVAudioSessionCategoryPlayAndRecord |
AVAudioSessionModeSpokenAudio | AVAudioSessionCategoryPlayback |
AVAudioSessionModeMeasurement | AVAudioSessionCategoryPlayAndRecord AVAudioSessionCategoryRecord AVAudioSessionCategoryPlayback |
音頻默認行為
所有的ios庐船,tvos和watchos應(yīng)用程序都有一個默認的音頻會話银酬,預(yù)先配置如下:
- 支持音頻播放,不允許錄音
- 在ios中筐钟,將響鈴/靜音開關(guān)設(shè)置為靜音模式會使app正在播放的任何音頻靜音揩瞪。
- 在ios中,當設(shè)備被鎖定時篓冲,引用程序的音頻會被靜音
- 當app在播放音頻時李破,任何其他的背景音頻(例如音樂應(yīng)用播放的音頻)都會被靜音。
默認音頻會話具有有用的行為壹将,但在大多數(shù)情況下嗤攻,我們應(yīng)該對其進行自定義已更好的滿足應(yīng)用需求。要更改行為诽俯,需要配置app的音頻會話妇菱。
配置音頻會話
配置音頻會話的主要方法是設(shè)置category,音頻會話category定義一組音頻行為惊畏。每個catergory 相關(guān)的行為不是由app設(shè)置恶耽,而是由操作系統(tǒng)設(shè)置。Apple可能會在未來版本的操作系統(tǒng)中改進category行為颜启,因此我們最好的策略是選擇最準確描述我們想要的音頻行為意圖的category偷俭。
category設(shè)置app的基本音頻行為,我們可以通過設(shè)置category的mode來進一步專門話這些行為缰盏。例如:IP語音(VoIP)app 將使用AVAudioSessionCategoryPlayAndRecord涌萤。通過將音頻會話的模式設(shè)置為AVAudioSessionModeVoiceChat,這樣就可以專門的針對VoIP app使用此類別的行為口猜。該模式可以確保通過系統(tǒng)提供的信號處理為語音優(yōu)化信號负溪。
某些category通過在會話上設(shè)置一個或者多個category選項來支持覆蓋器默認行為,可參看AVAudioSessionCategoryOptions济炎。例如川抡,與AVAudioSessionCategoryPlayback category 關(guān)聯(lián)的默認行為是會在會話激活時中斷其他系統(tǒng)音頻。在大多數(shù)情況下须尚,播放app需要次行為崖堤。但是,如果我們希望音頻與其他系統(tǒng)音頻混合耐床,那么可以通過在會話上設(shè)置AVAudioSessionCategoryOptionMixWithOthers選項來覆蓋此行為密幔。
下列是設(shè)置會話category的小例子
-(void)setAudioSessionCategory{
AVAudioSession * session = [AVAudioSession sharedInstance];
@try {
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setCategory:AVAudioSessionCategoryPlayback mode:AVAudioSessionModeMoviePlayback options:0 error:nil];
} @catch (NSException *exception) {
NSLog(@"%@",exception);
} @finally {
}
}
使用多路徑category 擴展選項
多路徑category與氣體category工作方式略有不同。所有其他category遵循最后設(shè)置生效規(guī)則撩轰。但是胯甩,多路由category使app能夠使用所有的連接的輸出端口昧廷,而不是僅僅使用最后的使用的端口。例如:如果我們通過HDMI輸出路徑收聽音頻并插入一組耳機偎箫,我們的app講繼續(xù)通過hdmi輸出路徑播放音樂木柬,同事還可以通過耳機播放音頻。
通過多路徑category镜廉,我們的app還可以將不同的音頻流發(fā)送到不同的輸出路徑上弄诲。例如:我們的app可以將一個音頻流發(fā)送到左耳機,另一個音頻流發(fā)送到右耳機娇唯,第三個發(fā)送到HDMI路由。下圖展示將多個音頻流發(fā)送到不同音頻路由的示例
根據(jù)設(shè)備和任何連接的附件寂玲,以下是有效的輸出路徑組合:
- USB和耳機
+HDMI 和耳機 - lineout 和耳機
多路由category僅支持使用單個輸入的端口塔插。
重要事項:僅當沒有連接其他符合條件的輸出端口(USB,HDMI,LineOut)時拓哟,才可以使用內(nèi)置揚聲器想许。
啟用后臺音頻
ios和tvos app要求在后臺啟用某些功能。播放app所需的常見功能是播放后臺音頻断序。啟用此功能流纹,當用戶切換到其他app或者鎖定其iOS設(shè)備時,app的音頻可以繼續(xù)违诗。在ios中啟用高級包房功能(例如airlpay流媒體和畫中畫播放)也需要此功能漱凝。
配置這些功能最簡單的方式是用xcode。選擇target 選擇capabiliityies 選項卡诸迟。在capabilities選項卡下茸炒,將后臺模式開關(guān)設(shè)置為開即可。
啟用此后臺模式并使用適當?shù)念悇e配置音頻會話后阵苇,我們的應(yīng)該就可以播放后臺音頻了壁公。
注意:要允許視頻演示的音頻部分可以在后臺播放,可以參考 中的Media Playback Programming Guide中的Playing Background Audio
激活音頻會話
我們通過category mode options 配置好了音頻會話绅项。要使配置生效紊册,我們需要激活音頻會話。
系統(tǒng)如何解決競爭性音頻需求
隨著app啟動快耿,內(nèi)置的app(消息囊陡,音樂,safiri润努,手機)可能正在后臺運行关斜。這些中的每一個都可以產(chǎn)生音頻:一個文本通知到達,10分鐘錢開始的播客正在播放等等铺浇。
這里比方痢畜,我們將設(shè)備視為機場,將app表示為滑行飛機,那么系統(tǒng)可以作為控制塔丁稀。我們的app可以發(fā)出音頻請求并少女革命其所需要的優(yōu)先級吼拥,但是對“停機坪上”發(fā)生的事情的最終權(quán)限來自系統(tǒng),我們只能使用音頻會話與控制塔進行通信线衫。下圖說明了一個典型的場景-我們的app請求播放時候使用音頻凿可。在這種情況下,我們的app會中斷音樂應(yīng)用授账。
- 第一步枯跑,我們的應(yīng)用請求激活其音頻會話。例如白热,我們可以在應(yīng)用啟動時候提出此類請求敛助,也可以響應(yīng)用戶點擊音頻錄制和播放應(yīng)用中的“播放按鈕”。
- 第二步屋确,系統(tǒng)考慮激活請求纳击。具體來說,他會考慮為我們的音頻會話分配category攻臀。如圖2焕数,我們的app使用了一個要求其他音頻靜音的category。
- 第三步和第四步刨啸,系統(tǒng)停用其他app的音頻會話堡赔,停止其音頻播放。
- 第五步呜投,系統(tǒng)激活app的音頻會話開始播放加匈。
激活或者取消激活音頻會話
最熱AVFoundation播放和錄制類會自動激活音頻會話,但是手動激活它會讓我們有機會測試激活是否成功仑荐。但是雕拼,如果我們的app具有播放和暫停功能,我們需要編寫代碼粘招,以便用戶必須在激活會話之前按播放啥寇。同樣,在更改音頻會話的激活非激活狀態(tài)時洒扎,需要檢查以確保是否成功辑甜。我們應(yīng)該編寫代碼優(yōu)雅的處理系統(tǒng)拒絕激活會話的情況。
當時鐘或者日歷鬧鐘或者來電激活時會取消音頻會話袍冷。當用戶解除警報或者選擇電話呼叫時磷醋,系統(tǒng)會允許我們再次激活音頻會話。是否在中斷結(jié)束后重新激活會話取決于app的類型胡诗,該類型是在Audio Guidelines By App Type描述的邓线。
-(void)setAudioSessionCategory{
AVAudioSession * session = [AVAudioSession sharedInstance];
@try {
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setCategory:AVAudioSessionCategoryPlayback mode:AVAudioSessionModeMoviePlayback options:0 error:nil];
[session setActive:YES error:nil];
} @catch (NSException *exception) {
NSLog(@"%@",exception);
} @finally {
}
}
取消激活音頻會話傳入false即可淌友。
使用AVFoundation對象(AVPlayer,AVAudioRecoder等)播放或者錄制音頻時,系統(tǒng)會在中斷結(jié)束時處理音頻會話重新激活骇陈。但是震庭,如果我們注冊通知消息并明確重新激活音頻會話,那么可以驗證重新激活是否成功你雌,并且可以更新應(yīng)用誠信度狀態(tài)和用戶界面器联。
- 對于VoIP app的音頻會話確保僅在app處理呼叫時才處于激活狀態(tài)。在后臺婿崭,準備好接聽電話拨拓,VoIPapp的音頻會話不應(yīng)該是活動的。
- 使用錄制category的app的音頻會話確保在錄制時是處于激活狀態(tài)氓栈。在錄制開始之前和結(jié)束的時候千元,需要確保音頻會話處于非活動狀態(tài),以允許播放其他聲音颤绕,例如,傳入消息警報祟身。
- 如果app支持后臺播放和錄制奥务,那么app在未主動使用音頻(或者使用音頻)時,在進入后臺時停用其音頻會話袜硫。這樣做讓系統(tǒng)釋放音頻資源氯葬,以便其他進程可以使用它們。當操作系統(tǒng)暫停app的進程時婉陷,它還會阻止app的音頻會話被停用(app都干掉了帚称,音頻會話肯定要干掉啦)』喟模可以看這里 AVAudioSessionInterruptionWasSuspendedKey闯睹。
檢查其他音頻是否正在播放
當我們的app處于活動狀態(tài)時,設(shè)備上可能已經(jīng)在播放聲音了担神。例如楼吃,當用戶啟動app時候,音樂app可能正在播放歌曲妄讯。如果我們的app是游戲孩锡,了解其他音頻是否正在播放很重要。許多游戲都有音樂聲道和音效亥贸。在iOS Human Interface Guidelines中音頻建議假設(shè)用戶在玩游戲的時候期望其他音頻以及游戲的聲音效果繼續(xù)播放躬窜。
在app的applicationDidBecomeActive:方法中,檢查音頻會話的secondaryAudioShouldBeSilencedHint屬性以確定音頻是否在播放炕置。當具有不可混合音頻會話的另一個app正在播放音頻時荣挨,該值是true男韧。應(yīng)用程序使用此屬性作為提示,以消除應(yīng)用程序運行的次要的音頻垦沉。例如煌抒,AVAudioSessionCategoryAmbient類的游戲可以使用此屬性來確定是否應(yīng)將其音軌靜音,同時保持其靜音效果厕倍。
我們還可以訂閱AVAudioSessionSilenceSecondaryAudioHintNotification類型通知寡壮,以確保在可選的輔助音頻經(jīng)驗開始或者結(jié)束時通知app。該通知僅發(fā)送給當前位于前臺并且具有活動音頻會話的已注冊監(jiān)聽器讹弯。
具體代碼
-(void)setNotifation{
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notification:) name:AVAudioSessionSilenceSecondaryAudioHintNotification object:[AVAudioSession sharedInstance]];
}
-(void) notification:(NSNotification *) notification{
// Determine hint type
id userInfo = notification.userInfo;
NSNumber * typeValue = userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey];
if (typeValue.intValue == AVAudioSessionSilenceSecondaryAudioHintTypeBegin) {
}
}
應(yīng)對中斷
增加音頻會話中斷代碼可以讓app在接收到電話呼叫况既,日歷鬧鐘時鐘響起或者其他應(yīng)用程序激活音頻會話時可以正常運行。
音頻中斷會讓音頻停止组民。當來自app的競爭音頻會話被激活并且該會話未被系統(tǒng)category以與我們的app混合時棒仍,就會發(fā)生中斷(通俗的說,就是人家想獨自搞臭胜,不要我們就把我們暫停了)莫其。會話變成非激活狀態(tài)后,系統(tǒng)會發(fā)送中斷通知耸三,我們這個時候可以保存狀態(tài)乱陡,更新用戶界面等來響應(yīng)該通知。
app 可能在中斷后就暫停了仪壮。當用戶接聽電話就能發(fā)生這種情況憨颠。如果用戶忽略了呼叫或者取消了警報,系統(tǒng)會發(fā)出中斷結(jié)束消息积锅,并且我們的app將繼續(xù)運行爽彤。要恢復音頻,我們必須重新激活音頻會話缚陷。
中斷聲明周期
下圖說明播放app的音頻會話中斷之前适篙,期間和之后的事件序列。
- 1.激活app蹬跃,播放音頻
- 2.一個FaceTime 請求到達匙瘪。系統(tǒng)激活FaceTime的音頻會話
- 3.系統(tǒng)取消我們app的音頻會話,這時候蝶缀,app播放已經(jīng)停止了丹喻。
- 4.系統(tǒng)發(fā)送通知,告知我們的app音頻會話被取消掉了
- 5.app處理這個終端翁都,例如碍论,包括更新用戶界面等操作
- 6.如果用戶從facetime取消了音頻會話,那么柄慰,系統(tǒng)發(fā)送一個通知告訴我們app音頻中斷結(jié)束了
- 7.我們的app處理這個音頻中斷結(jié)束事件鳍悠。例如恢復播放税娜,更新用戶界面。
- 8.點擊暫停播放藏研。
音頻中斷處理技術(shù)
通過通知來處理中斷敬矩。我們在中斷代碼中執(zhí)行的操作取決于我們使用的音頻技術(shù)以及用于播放,錄制蠢挡,音頻格式轉(zhuǎn)換弧岳,讀取六十音頻數(shù)據(jù)包等的內(nèi)容。一般來說业踏,從用戶角度來看禽炬,我們需要確保盡可能的少的中斷,以及最優(yōu)雅的可能恢復勤家。
下表總結(jié)了中斷期間石洞的音頻會話行為腹尖。如果使用AVFoundation播放或者錄制對象,系統(tǒng)會自動處理其中的一些步驟
After interruption starts | Save state and context Update user interface |
---|---|
After interruption ends | Restore state and context Update user interface Reactivate audio session, if appropriate for the app |
下表總結(jié)了如何根據(jù)技術(shù)處理音頻中斷伐脖。
Audio technology | How interruptions work |
---|---|
AVFoundation framework | 系統(tǒng)會在中斷時自動暫停播放和錄制热幔,并在恢復播放和錄制時重新激活音頻會話 如果要在app啟動之間保存和恢復播放位置,需要在中斷和app退出時保存播放位置 |
Audio Queue Services, I/O audio unit | 這些技術(shù)使沃恩的app可以控制處理中斷讼庇。我們需要保存播放或者錄制的位置断凶,并在中斷結(jié)束后重新激活音頻會話 |
System Sound Services | 使用系統(tǒng)聲音服務(wù)播放的聲音在中斷開始時保存靜音。如果中斷結(jié)束巫俺,那么聲音會再次播放。應(yīng)用無法影響使用次播放技術(shù)的聲音的中斷行為 |
觀察音頻中斷
這里只是貼下代碼肿男,重復內(nèi)容
-(void)setNotifation{
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(notification:) name:AVAudioSessionSilenceSecondaryAudioHintNotification object:[AVAudioSession sharedInstance]];
}
-(void) notification:(NSNotification *) notification{
// Determine hint type
id userInfo = notification.userInfo;
NSNumber * typeValue = userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey];
if (typeValue.intValue == AVAudioSessionSilenceSecondaryAudioHintTypeBegin) {
}
}
響應(yīng)流媒體重置
媒體服務(wù)器通過共享服務(wù)器進程提供音頻和其他多媒體功能介汹。雖然很少見,但是當您的應(yīng)用處于活動狀態(tài)的時候舶沛,媒體服務(wù)器可能會重置嘹承。注冊AVAudioSessionMediaServicesWereResetNotification通知來監(jiān)視介質(zhì)服務(wù)器重置。收到通知后如庭,我們的app需要執(zhí)行以下操作:
- 處理孤立的音頻對象(如播放器叹卷,錄音機,轉(zhuǎn)換器或者音頻隊列)并創(chuàng)建新的音頻對象坪它。
- 重置正在跟蹤的所有內(nèi)部音頻狀態(tài)骤竹,包括AVAudioSession的所有屬性。
- 在適當?shù)臅r候往毡,使用setActive:error: 方法重新激活A(yù)VAudioSession實例蒙揣。
重要提示:app無需要重新注冊任何AVAudioSession的通知或者AVAudioSession屬性上的鍵值觀察器。
如果您想知道媒體服務(wù)器何時首次變的不可以用开瞭,那么我們需要注冊AVAudioSessionMediaServicesWereLostNotification通知懒震。但是大多數(shù)應(yīng)用只需要響應(yīng)重置通知罩息。僅當應(yīng)用程序必須響應(yīng)介質(zhì)服務(wù)器丟失后但在重置介質(zhì)服務(wù)器之前發(fā)生的用戶事件,才使用該通知个扰。
我們可以通過從設(shè)置中開發(fā)人員菜單中選擇“重置媒體服務(wù)觸發(fā)”來觸發(fā)媒體服務(wù)瓷炮。 使用這個可以讓app輕松的重置媒體服務(wù)觸發(fā)通知。
應(yīng)對路由的改變
當app在運行時递宅,用戶可能會插入耳機或者拔出耳機娘香,或者使用帶有音頻連接的擴展臺。iOS Human Interface Guidelines 中描述了app如何響應(yīng)此類事件恐锣。想要實現(xiàn)這些建議茅主,請編寫音頻會話代碼來處理路由的改變。有些app(如游戲)并不總是必須響應(yīng)路徑的改變土榴。但是剩下的app(媒體播放器)必須響應(yīng)所有路徑的改變诀姚。
各種音頻硬件路由變化
音頻硬件路由是用于音頻信號的有線電子路徑。當設(shè)備的用戶插入或者拔出耳機的時候玷禽,系統(tǒng)會自動更改音頻硬件路由赫段。如果我們注冊通知AVAudioSessionRouteChangeNotification,則可以通知app此類更改矢赁。
下圖描述了錄制和播放過程中各種路由路徑變化的事件順序糯笙。圖中底部顯示的四種可能結(jié)果來自我們編寫的屬性偵聽器回到函數(shù)所采取的操作
如圖所示,系統(tǒng)最初確定應(yīng)用后的音頻路徑撩银。當app運行期間给涕,他會繼續(xù)監(jiān)控活動路線。首先考慮用戶點擊應(yīng)用中的“錄制”按鈕的情況额获,由圖左側(cè)的“錄制開始”框開始够庙。
在錄制期間,用戶可以插入或者拔出耳機-看到圖中左下方的菱形決策元素抄邀。作為相應(yīng)耘眨,系統(tǒng)發(fā)送包含改變原因和先前路由的路徑改變通知。我們的應(yīng)該應(yīng)該停止錄制境肾。
播放的情況類似剔难,但結(jié)果不同,如圖右側(cè)所示奥喻。如果用戶在播放期間拔下耳機偶宫,那么應(yīng)該暫停音頻。如果用戶在播放期間插入耳機环鲤,我們的app應(yīng)該繼續(xù)播放读宙。
觀察音頻路由改變
音頻路由改變的原因有很多,包括用戶插入耳機楔绞,連接藍牙LE耳機或者拔掉USB音頻接口结闸。了解這些改變何時發(fā)生對app很重要唇兑,我們可以根據(jù)這些改變來更新用戶界面活更改其內(nèi)部狀態(tài)。通過注冊通知AVAudioSessionRouteChangeNotification來獲取路由的更改桦锄。
-(void)setRouteNotifation{
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(routeNotification:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];
}
-(void)routeNotification:(NSNotification * )notification{
// Determine hint type
id userInfo = notification.userInfo;
NSNumber * typeValue = userInfo[AVAudioSessionRouteChangeReasonKey];
if (typeValue.intValue == AVAudioSessionRouteChangeReasonNewDeviceAvailable) {
AVAudioSession * session = [AVAudioSession sharedInstance];
for (AVAudioSessionPortDescription * output in session.currentRoute.outputs) {
if (output.portType == AVAudioSessionPortHeadphones) {
}
}
}
}
路由改變發(fā)送的通知信息都在userinfo字典中扎附,提供路過更改的詳細信息。我們可以通過userinfo字典中檢索AVAudioSessionRouteChangeReason來確定此更改的原因结耀。連接新設(shè)備時留夜,原因是AVAudioSessionRouteChangeReasonNewDeviceAvailable,刪除一個設(shè)備图甜,它是AVAudioSessionRouteChangeReasonOldDeviceUnavailable碍粥。
當新設(shè)備可用時候,我們可以查詢音頻會話的currentRoute屬性來確定當前路由音頻輸出的位置黑毅。這將返回一個AVAudioSessionRouteDescription對象嚼摩,該對象列出了所有的音頻會話的輸入和輸出。刪除設(shè)備后矿瘦,我們將從userInfo字典中檢索上一個路由的AVAudioSessionRouteDescription對象枕面。這兩種情況下,我們都可以的查詢AVAudioSessionRouteDescription 的outputs屬性缚去,該屬性返回AVAudioSessionPortDescription對象的數(shù)組潮秘,提供音頻輸出路徑的詳細信息。
重要提示:如果路徑更改原因是AVAudioSessionRouteChangeReasonOldDeviceUnavailable易结,那么媒體播放應(yīng)用應(yīng)該暫停播放枕荞,但是如果是AVAudioSessionRouteChangeReasonOverride,則不應(yīng)該暫停播放搞动。
音頻路由更改還可能導致音頻會話的采樣率买猖,I/O緩沖區(qū)持續(xù)時間,通道計數(shù)活其他與硬件有關(guān)的值發(fā)生變化滋尉。如果這些值對我們很重要,那么請在路由更改后查詢他們已查看其值是否已更改飞主。
配置設(shè)備硬件
使用音頻會話屬性狮惜,我們可以在運行時優(yōu)化應(yīng)用程序的設(shè)備硬件音頻行為。這樣做可以讓我們的代碼適應(yīng)其運行設(shè)備的特性碌识,以及用戶在app運行時所作的改變碾篡。
使用AVAudioSession
- 指定采樣率和I/O 緩存區(qū)持續(xù)時間首選硬件設(shè)置
- 查詢硬件特性,例如輸入和輸出延遲筏餐,輸入和輸出通道數(shù)开泽,硬件采樣率,硬件音量設(shè)置和音頻輸入的可用性
選擇首選音頻硬件值
用音頻會話指定首選設(shè)備設(shè)置魁瞪,例如采樣率和硬件I/O緩存持續(xù)時間穆律。下表描述這些首選項的好處和成本
Setting | Preferred sample rate | Preferred I/O buffer duration |
---|---|---|
High value | Example: 48 kHz + High audio quality – Large file or buffer size |
Example: 500 mS + Less-frequent file access – Longer latency |
Low value | Example: 8 kHz + Small file or buffer size – Low audio quality |
Example: 5 mS + Low latency – Frequent file access |
例如惠呼,如果音頻質(zhì)量很重要固以,并且大文件和緩沖區(qū)大小不是很重要易迹,則可以指定高采樣率的首選項。
注意:默認音頻I/O 緩沖持續(xù)時間(44.1KHz)音頻約0.02秒可以為大多數(shù)應(yīng)用提供足夠的響應(yīng)速度旷赖。我們可以為延遲關(guān)鍵型應(yīng)用設(shè)置較低的I/O持續(xù)時間辅髓,例如現(xiàn)場樂器監(jiān)控泣崩,一般情況下不需要修改此設(shè)置。
設(shè)置首選音頻硬件值
在激活音頻會話之前設(shè)置首選硬件值洛口。如果我們已經(jīng)在運行音頻會話矫付,需要將其停用。激活音頻會話后第焰,首先值的更改會生效买优,我們可以在此時驗證更改。下列代碼顯示了如何設(shè)置首選硬件值以及如何驗他們樟遣。
-(void)setSession{
AVAudioSession * session = [AVAudioSession sharedInstance];
@try {
[session setCategory:AVAudioSessionCategoryRecord mode:AVAudioSessionModeDefault options:0 error:nil];
} @catch (NSException *exception) {
NSLog(@"%@",exception);
} @finally {
}
@try {
[session setPreferredSampleRate:44100 error:nil];
} @catch (NSException *exception) {
NSLog(@"%@",exception);
} @finally {
}
@try {
[session setPreferredIOBufferDuration:0.005 error:nil];
} @catch (NSException *exception) {
NSLog(@"%@",exception);
} @finally {
}
@try {
[session setActive:YES error:nil];
} @catch (NSException *exception) {
NSLog(@"%@",exception);
} @finally {
}
}
注意:當競爭音頻會話設(shè)置首選硬件值時而叼,系統(tǒng)會優(yōu)先考慮不可混合的會話。 使用AVAudioSessionCategoryAmbient類別或AVAudioSessionCategoryOptionMixWithOthers選項的音頻會話不太可能具有其首選的硬件設(shè)置豹悬。
選擇和配置麥克風
在具有兩個或更多內(nèi)置麥克風的設(shè)備上葵陵,ios會通過使用音頻會話模式自動旋轉(zhuǎn)麥克風。模式指定用于輸入的數(shù)字信號(DSP)和可能的路由瞻佛。輸入和路由針對每種模式的用例進行了優(yōu)化脱篙。設(shè)置模式也可能影響正在使用的路由的其他方面。
重要:在使用任何輸入選擇功能之前伤柄,請為app設(shè)置會話類別和模式并激活音頻會話
設(shè)置首選輸入
要發(fā)現(xiàn)內(nèi)置或者鏈接的輸入端口绊困,使用音頻會話的availableInputs屬性,該屬性返回AVAudioSessionPortDescription對象數(shù)組适刀,用于描述設(shè)備的可用輸入的端口秤朗。端口可以通過其portType屬性進行標識。要設(shè)置首選輸入端口(內(nèi)置麥克風笔喉,有線麥克風取视,USBB輸入等),請使用音頻會話的setPreferredInput:error: 方法。
設(shè)置首選數(shù)據(jù)源
一些端口例如內(nèi)置麥克風和一些USB配件常挚,支持數(shù)據(jù)源作谭。app可以通過查詢端口描述的dataSources屬性來發(fā)現(xiàn)可用的數(shù)據(jù)源。在內(nèi)置麥克風的情況下奄毡,返回的數(shù)據(jù)源描述對象代表每個單獨的麥克風折欠。不同的設(shè)備為內(nèi)置麥克風返回不同的值。例如,iPhone 4和iPhone 4S有兩個麥克風:底部和頂部锐秦。 iPhone 5有三個麥克風:底部咪奖,正面和背面。
可以通過數(shù)據(jù)源描述的位置屬性(上农猬,下)和方向?qū)傩裕ㄇ昂蟮龋┑慕M合來識別各個內(nèi)置麥克風赡艰。app使用setPreferredDataSource:error:方法設(shè)置首選數(shù)據(jù)源。
設(shè)置首選極坐標圖案
一些ios設(shè)備支持配置為某些內(nèi)置麥克風配置麥克風的極性模式斤葱。麥克風的極性模式定義了其對聲音相對于聲源方向的靈敏度慷垮。當前的iphone支持為前置和后置麥克風設(shè)置首選極性模式。使用數(shù)據(jù)源對象的supportedPolarPatterns屬性返回可用模式揍堕。此屬性返回數(shù)據(jù)源支持的極性模式數(shù)組(如心形或者全向)料身,或者在沒有可選模式返回nil。如果數(shù)據(jù)源具有許多支持的極坐標模式衩茸,則可以使用數(shù)據(jù)源描述的setPreferredPolarPattern:error方法設(shè)置首選極坐標模式
以上知識總結(jié)代碼實例
代碼如下
-(void)mic{
AVAudioSession * session = [AVAudioSession sharedInstance];
NSArray * inputs = session.availableInputs;
if (inputs.count<=0) {
return;
}
AVAudioSessionPortDescription * builtInmic;
for (AVAudioSessionPortDescription * item in inputs) {
if (item.portType==AVAudioSessionPortBuiltInMic) {
builtInmic = item;
break;
}
}
AVAudioSessionDataSourceDescription * dataSource ;
for (AVAudioSessionDataSourceDescription * item in builtInmic.dataSources) {
if (item.orientation == AVAudioSessionOrientationFront) {
dataSource = item;
break;
}
}
@try {
[dataSource setPreferredPolarPattern:AVAudioSessionPolarPatternCardioid error:nil];
} @catch (NSException *exception) {
} @finally {
}
@try {
[builtInmic setPreferredDataSource:dataSource error:nil];
} @catch (NSException *exception) {
} @finally {
}
@try {
[session setPreferredInput:builtInmic error:nil];
} @catch (NSException *exception) {
} @finally {
}
NSArray * array= session.currentRoute.inputs;
for (AVAudioSessionPortDescription * portDesc in array) {
NSLog(@"port: %@",portDesc.portType);
AVAudioSessionDataSourceDescription* ds = portDesc.selectedDataSource;
if (ds) {
NSLog(@"name: %@",ds.dataSourceName);
NSLog(@"polar pattern: %@",ds.selectedPolarPattern?:@"none");
}
}
}
包含用戶隱私
為了保護用戶隱私芹血,app必須在錄制音頻之前詢問并獲得用戶許可才行。如果用戶未授權(quán)楞慈,則只能記錄靜音幔烛。當我們使用支持錄制的catergory并且app嘗試使用輸入路徑時,系統(tǒng)會自動提示用戶授權(quán)囊蓝。
請求錄音的權(quán)限
代碼如下
-(void)requtst{
AVAudioSession * session = [AVAudioSession sharedInstance];
[session requestRecordPermission:^(BOOL granted) {
if (granted==YES) {
//用戶授權(quán)
}
}];
}
在ios 10.0 以后饿悬,必須在info.plist 中添加NSMicrophoneUsageDescription字段