AV Foundation ⑨ 音頻會(huì)話

前言

????回憶一個(gè)場(chǎng)景宣增,我們使用iPhone 打開(kāi)一首歌曲货抄,音頻從內(nèi)置揚(yáng)聲器中播放出來(lái),此時(shí)有電話撥入烹吵,音樂(lè)會(huì)立即停止并處于暫停狀態(tài)碉熄。此時(shí)聽(tīng)到的是手機(jī)呼叫的鈴聲,當(dāng)我們掛掉電話后肋拔,剛才的音樂(lè)再次響起锈津。在這一過(guò)程中 iOS 提供了一個(gè)可管理的音頻環(huán)境,通過(guò) 音頻會(huì)話(Audio Session)來(lái)管理應(yīng)用程序凉蜂、應(yīng)用程序間和設(shè)備級(jí)別的音頻行為琼梆。

音頻會(huì)話介紹

????音頻會(huì)話在應(yīng)用程序和操作系統(tǒng)之間扮演者中間人的角色性誉,它提供了一種簡(jiǎn)單實(shí)用的方法使得系統(tǒng)得知應(yīng)用程序應(yīng)該如何與 iOS 音頻環(huán)境進(jìn)行交互。開(kāi)發(fā)者不需要了解與音頻硬件交互的具體細(xì)節(jié)茎杂,只需要對(duì)應(yīng)用程序的行為進(jìn)行抽象的配置错览,并把對(duì)該行為的管理委托給音頻會(huì)話,可確保對(duì)用戶的音頻體驗(yàn)進(jìn)行最佳管理煌往。

音頻會(huì)話介紹.png

????所有 iOS 應(yīng)用程序啟動(dòng)后倾哺,都具有一個(gè)默認(rèn)音頻會(huì)話,無(wú)論是否使用刽脖。默認(rèn)音頻會(huì)話來(lái)自于以下一些預(yù)配置:

  • 支持音頻播放羞海,但不允許錄音。
  • 在 iOS 中曲管,將響鈴/靜音開(kāi)關(guān)設(shè)置為靜音模式會(huì)使應(yīng)用程序正在播放的任何音頻靜音却邓。
  • 在 iOS 中,當(dāng)設(shè)備被鎖定時(shí)院水,應(yīng)用程序的音頻會(huì)靜音腊徙。
  • 當(dāng)應(yīng)用程序播放音頻時(shí),任何其他后臺(tái)音頻(例如音樂(lè)應(yīng)用程序正在播放的音頻)都會(huì)被靜音檬某。

音頻會(huì)話類別

????默認(rèn)音頻會(huì)話提供了很多實(shí)用的功能撬腾,但在大多數(shù)情況下,開(kāi)發(fā)者應(yīng)該對(duì)其進(jìn)行自定義以更好地滿足應(yīng)用程序的需求橙喘。要更改行為时鸵,需要配置應(yīng)用的音頻會(huì)話。幸運(yùn)的是厅瞎,通過(guò)設(shè)置”類別“功能饰潜,可以很容易地定制我們的特殊需求。

????表達(dá)音頻行為的主要機(jī)制是音頻會(huì)話類別和簸。通過(guò)設(shè)置類別彭雾,可以指定應(yīng)用程序是使用輸入還是輸出,是否希望音樂(lè)與音頻一起繼續(xù)播放等等锁保。AV Foundation 定義了許多音頻會(huì)話類別薯酝,可讓開(kāi)發(fā)者自定義音頻行為。下面表格總結(jié)了 AV Foundation 定義的 6 種類別行為細(xì)節(jié)爽柒。

類別 作用 是否允許混音 音頻的輸入與輸出 由響鈴/靜音開(kāi)關(guān)和屏幕鎖定靜音
AVAudioSessionCategoryAmbient 游戲吴菠、效率應(yīng)用程序 Yes 僅輸出 Yes
AVAudioSessionCategorySoloAmbient (默認(rèn)) 游戲、效率應(yīng)用程序 No 僅輸出 Yes
AVAudioSessionCategoryPlayback 音頻和視頻播放器 可選 僅輸出 No
AVAudioSessionCategoryRecord 錄音機(jī)浩村、音頻捕捉 No 僅輸入 No
AVAudioSessionCategoryPlayAndRecord Voip做葵、語(yǔ)言聊天 可選 輸入和輸出 No
AVAudioSessionCategoryMultiRoute 使用外部硬件的高級(jí) A/V應(yīng)用程序 No 輸入和輸出 No

????可以通過(guò) setCategory:mode:options:error:設(shè)置上述音頻會(huì)話類別,其中一些分類可以通過(guò)使用 optionsmodes進(jìn)一步自定義附加行為心墅。示例如下:

AVAudioSession *session = [AVAudioSession sharedInstance];

NSError *error;
if (![session setCategory:AVAudioSessionCategoryPlayback error:&error]) {
    NSLog(@"Category Error: %@", [error localizedDescription]);
}

if (![session setActive:YES error:&error]) {
    NSLog(@"Activation Error: %@", [error localizedDescription]);
}

音頻中斷及處理

????音頻中斷是應(yīng)用程序音頻會(huì)話的停用——它會(huì)立即停止音頻酿矢。當(dāng)來(lái)自其它應(yīng)用程序的音頻會(huì)話被激活并且該會(huì)話未被系統(tǒng)分類以與我們的應(yīng)用程序的音頻混合時(shí)榨乎,就會(huì)發(fā)生中斷。在會(huì)話處于非活動(dòng)狀態(tài)后瘫筐,系統(tǒng)會(huì)發(fā)送一條“被中斷”消息蜜暑,可以通過(guò)保存狀態(tài)、更新用戶界面等來(lái)響應(yīng)該消息策肝。
????應(yīng)用程序可能會(huì)在中斷后暫停肛捍。當(dāng)用戶接聽(tīng)電話時(shí)會(huì)發(fā)生這種情況。如果用戶轉(zhuǎn)而忽略呼叫或解除警報(bào)之众,系統(tǒng)會(huì)發(fā)出“中斷結(jié)束”消息篇梭,并且應(yīng)用程序會(huì)繼續(xù)運(yùn)行。要恢復(fù)音頻酝枢,必須重新激活音頻會(huì)話。下圖說(shuō)明了回放應(yīng)用程序的音頻會(huì)話中斷之前悍手、期間和之后的事件順序帘睦。

應(yīng)用程序的音頻會(huì)話被電話中斷的時(shí)間線表示。

中斷事件(在此示例中為 FaceTime 請(qǐng)求的到達(dá))按如下方式進(jìn)行坦康。編號(hào)的步驟對(duì)應(yīng)于圖中的數(shù)字竣付。

  1. 應(yīng)用程序處于活動(dòng)狀態(tài),正在播放音頻滞欠。
  2. FaceTime 請(qǐng)求到達(dá)古胆。系統(tǒng)激活 FaceTime 應(yīng)用程序的音頻會(huì)話。
  3. 系統(tǒng)會(huì)停用當(dāng)前音頻會(huì)話筛璧。此時(shí)逸绎,應(yīng)用程序中的播放已停止。
  4. 系統(tǒng)會(huì)發(fā)布通知夭谤,表明會(huì)話已被停用棺牧。
  5. 通知處理程序需要采取適當(dāng)?shù)拇胧@缋嗜澹梢愿掠脩艚缑娌⒈4嬖谕V裹c(diǎn)恢復(fù)播放所需的信息颊乘。
  6. 如果用戶解除中斷(忽略傳入的 FaceTime 請(qǐng)求),系統(tǒng)會(huì)發(fā)布通知醉锄,指示中斷已結(jié)束乏悄。
  7. 通知處理程序會(huì)采取適合中斷結(jié)束的操作。例如恳不,它可能會(huì)更新用戶界面檩小、重新激活音頻會(huì)話并恢復(fù)播放。
  8. (圖中未顯示妆够。)如果用戶接聽(tīng)電話识啦,而不是在第 6 步消除中斷负蚊,則應(yīng)用程序?qū)和!?/li>

????在開(kāi)發(fā)音頻功能時(shí)颓哮,我們要確保應(yīng)用程序可以正確地處理中斷事件家妆,音頻會(huì)話相關(guān)代碼以處理中斷可確保應(yīng)用程序的音頻在來(lái)電、時(shí)鐘或日歷警報(bào)響起或其他應(yīng)用程序激活其音頻會(huì)話時(shí)繼續(xù)正常運(yùn)行冕茅。

首先需要得到中斷出現(xiàn)的通知伤极,可以選擇注冊(cè)應(yīng)用程序的 AVAudioSession 發(fā)送的通知 AVAudioSessionInterruptionNotification

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];

????在系統(tǒng)發(fā)送通知調(diào)用 handlerInterruption: 時(shí)傳遞的NSNotification 實(shí)例包含一個(gè) userInfo 提供中斷詳細(xì)信息的填充字典姨伤∩谄海可以通過(guò)從字典中檢索 AVAudioSessionInterruptionType 值來(lái)確定中斷的類型,中斷類型指示中斷是已經(jīng)開(kāi)始還是已經(jīng)結(jié)束乍楚。

typedef NS_ENUM(NSUInteger, AVAudioSessionInterruptionType) {
    AVAudioSessionInterruptionTypeBegan = 1, ///< the system has interrupted your audio session
    AVAudioSessionInterruptionTypeEnded = 0, ///< the interruption has ended
};
  • 當(dāng)中斷出現(xiàn)時(shí)当编,類型為 AVAudioSessionInterruptionTypeBegan,需要采取的動(dòng)作就是暫停音頻播放以及 UI 界面的處理徒溪。

  • 當(dāng)中斷結(jié)束時(shí)忿偷,類型為 AVAudioSessionInterruptionTypeEndeduserInfo 中可能包含一個(gè)AVAudioSessionInterruptionOptions 值臊泌,指示音頻會(huì)話是否以及重新激活以及它是否可以再次播放鲤桥。如果選項(xiàng)值為 AVAudioSessionInterruptionOptionShouldResume,則可以繼續(xù)播放渠概。

響應(yīng)路由的變化

????當(dāng)應(yīng)用程序運(yùn)行時(shí)茶凳,用戶可能會(huì)插入或拔出耳機(jī),或使用帶有音頻連接的擴(kuò)展塢播揪。iOS 人機(jī)界面指南描述了應(yīng)用程序應(yīng)如何響應(yīng)此類事件贮喧。要實(shí)施這些建議,可以通過(guò)音頻會(huì)話處理音頻硬件路由的更改猪狈。

????音頻硬件路由是音頻信號(hào)的有線電子通路塞淹。當(dāng)設(shè)備的用戶插入或拔出耳機(jī)時(shí),系統(tǒng)會(huì)發(fā)生線路改變罪裹, AVAudioSession 會(huì)廣播一個(gè)描述該變化的通知AVAudioSessionRouteChangeNotification 給所有相關(guān)的監(jiān)聽(tīng)者饱普。下圖描述了錄入和播放期間各種路線變化的事件:

Core Audio 和屬性監(jiān)聽(tīng)器回調(diào)函數(shù)如何交互以在音頻硬件路由更改時(shí)提供良好的用戶體驗(yàn)的流程圖表示.png

????如上圖所示,在應(yīng)用啟動(dòng)后状共,系統(tǒng)會(huì)初步確定音頻路由套耕。當(dāng)應(yīng)用程序運(yùn)行時(shí),它會(huì)繼續(xù)監(jiān)控活動(dòng)路線峡继。首先考慮用戶在應(yīng)用程序中點(diǎn)擊“錄制”按鈕的情況冯袍,由圖左側(cè)的“錄制開(kāi)始”框表示。
????在錄制過(guò)程中,用戶可以插入或拔出耳機(jī)康愤,請(qǐng)參見(jiàn)圖中左下角的菱形決策元素儡循。作為響應(yīng),系統(tǒng)發(fā)送包含更改原因和先前路由的路由更改通知征冷,應(yīng)用應(yīng)停止錄制择膝。
????播放的情況類似,但結(jié)果不同检激,如圖右側(cè)所示肴捉。如果用戶在播放過(guò)程中拔下耳機(jī),應(yīng)用應(yīng)暫停音頻叔收。如果用戶在播放過(guò)程中插入耳機(jī)齿穗,應(yīng)用應(yīng)該只允許繼續(xù)播放。那么應(yīng)該怎么做呢饺律?
????首先需要注冊(cè) AVAudioSession 發(fā)送的通知AVAudioSessionRouteChangeNotification窃页,該通知包含一個(gè) userInfo 字典,攜帶了通知發(fā)送的原因及前一個(gè)路由的描述复濒。

[[NSNotificationCenter defaultCenter] addObserver:self
             selector:@selector(handleRouteChange:)
                 name:AVAudioSessionRouteChangeNotification
               object:[AVAudioSession sharedInstance]];

????收到通知后查看保存在userInfo 字典中 AVAudioSessionRouteChangeReasonKey 判斷路由變更的原因:

  • AVAudioSessionRouteChangeReasonNewDeviceAvailable腮出,連接新設(shè)備
  • AVAudioSessionRouteChangeReasonOldDeviceUnavailable,移除設(shè)備

????當(dāng)有設(shè)備斷開(kāi)時(shí)芝薇,獲取 userInfo 中描述前一個(gè)路由信息 的AVAudioSessionRouteChangePreviousRouteKey,其整合在一個(gè)輸入 NSArray 和一個(gè)輸出 NSArray 中作儿,判斷其中第一個(gè)是否為 AVAudioSessionPortHeadphones (耳機(jī)接口)洛二。

- (void)handleRouteChange:(NSNotification *)notification {

    NSDictionary *info = notification.userInfo;

    AVAudioSessionRouteChangeReason reason =
        [info[AVAudioSessionRouteChangeReasonKey] unsignedIntValue];

    if (reason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {

        AVAudioSessionRouteDescription *previousRoute =
            info[AVAudioSessionRouteChangePreviousRouteKey];

        AVAudioSessionPortDescription *previousOutput = previousRoute.outputs[0];
        NSString *portType = previousOutput.portType;

        if ([portType isEqualToString:AVAudioSessionPortHeadphones]) {
            //暫停
        }
    }
}

開(kāi)啟后臺(tái)播放

????音頻應(yīng)用程序所需的一項(xiàng)常見(jiàn)功能是后臺(tái)播放音頻。啟用此功能后攻锰,當(dāng)用戶切換到另一個(gè)應(yīng)用程序或鎖定他們的 iOS 設(shè)備時(shí)晾嘶,應(yīng)用程序的音頻可以繼續(xù)播放。在 iOS 中啟用 AirPlay 流式傳輸和畫(huà)中畫(huà)播放等高級(jí)播放功能也需要此功能娶吞。

????配置這些功能的最簡(jiǎn)單方法是使用 Xcode垒迂。在 Xcode 中選擇應(yīng)用程序的目標(biāo),然后選擇 Capabilities 選項(xiàng)卡妒蛇。在“功能”選項(xiàng)卡下机断,將“后臺(tái)模式”開(kāi)關(guān)設(shè)置為“開(kāi)”,然后從可用模式列表中選擇“音頻绣夺、AirPlay 和畫(huà)中畫(huà)”選項(xiàng)吏奸。

background_modes
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市陶耍,隨后出現(xiàn)的幾起案子奋蔚,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泊碑,死亡現(xiàn)場(chǎng)離奇詭異坤按,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)馒过,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)臭脓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人沉桌,你說(shuō)我怎么就攤上這事谢鹊。” “怎么了留凭?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵佃扼,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蔼夜,道長(zhǎng)兼耀,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任求冷,我火速辦了婚禮瘤运,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匠题。我一直安慰自己拯坟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布韭山。 她就那樣靜靜地躺著郁季,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钱磅。 梳的紋絲不亂的頭發(fā)上梦裂,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音盖淡,去河邊找鬼年柠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛褪迟,可吹牛的內(nèi)容都是我干的冗恨。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼味赃,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼派近!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起洁桌,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤渴丸,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谱轨,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡戒幔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了土童。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诗茎。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖献汗,靈堂內(nèi)的尸體忽然破棺而出敢订,到底是詐尸還是另有隱情,我是刑警寧澤罢吃,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布楚午,位于F島的核電站,受9級(jí)特大地震影響尿招,放射性物質(zhì)發(fā)生泄漏矾柜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一就谜、第九天 我趴在偏房一處隱蔽的房頂上張望怪蔑。 院中可真熱鬧,春花似錦丧荐、人聲如沸缆瓣。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)弓坞。三九已至,卻和暖如春窟却,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呻逆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工夸赫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咖城。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓茬腿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親宜雀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子切平,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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