音頻會話(Audio Session)編碼向?qū)?/h1>

概述

概覽

  • 音頻會話管理音頻行為
  • 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字段


Core Audio Overview
audio session programming guide

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者

  • 序言:七十年代末,一起剝皮案震驚了整個濱河市聚霜,隨后出現(xiàn)的幾起案子狡恬,更是在濱河造成了極大的恐慌,老刑警劉巖蝎宇,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件弟劲,死亡現(xiàn)場離奇詭異,居然都是意外死亡姥芥,警方通過查閱死者的電腦和手機兔乞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凉唐,“玉大人庸追,你說我怎么就攤上這事⌒荛唬” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵腕巡,是天一觀的道長玄坦。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么煎楣? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任豺总,我火速辦了婚禮,結(jié)果婚禮上择懂,老公的妹妹穿的比我還像新娘喻喳。我一直安慰自己,他們只是感情好困曙,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布表伦。 她就那樣靜靜地躺著,像睡著了一般慷丽。 火紅的嫁衣襯著肌膚如雪蹦哼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天要糊,我揣著相機與錄音纲熏,去河邊找鬼。 笑死锄俄,一個胖子當著我的面吹牛局劲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奶赠,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼鱼填,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了车柠?” 一聲冷哼從身側(cè)響起剔氏,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎竹祷,沒想到半個月后谈跛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡塑陵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年感憾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片令花。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡阻桅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出兼都,到底是詐尸還是另有隱情嫂沉,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布扮碧,位于F島的核電站趟章,受9級特大地震影響杏糙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蚓土,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一宏侍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜀漆,春花似錦谅河、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蠕嫁,卻和暖如春锨天,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剃毒。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工病袄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赘阀。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓益缠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親基公。 傳聞我的和親對象是個殘疾皇子幅慌,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

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