WebRTC 系列之音訊會話管理

網易雲信發表於2021-02-19

WebRTC(Web Real-Time Communication)是一個支援網頁瀏覽器進行實時語音對話或視訊對話的 API。W3C 和 IETF 在2021年1月26日共同宣佈 WebRTC 1.0 定稿,促使 WebRTC 從事實上的網際網路通訊標準成為了官方標準,其在不同場景的應用將得到更為廣泛的普及。

WebRTC 提供了視訊會議的核心技術,包括音視訊的採集、編解碼、網路傳輸、顯示等功能,並且還支援跨平臺:Windows,Mac,iOS,Android。本文主要介紹 WebRTC 其 iOS 平臺的音訊會話 AVAudioSession。關於 WebRTC 往期相關技術分享,在文末有集合,也歡迎持續關注~

概念介紹

iOS 音訊會話 AVAudioSession 是每一個進行 iOS 音訊開發的開發者必須瞭解的基本概念。音訊會話在作業系統 iOS、tvOS、watchOS 中是一項託管服務,系統通過音訊會話在應用程式內、應用程式間和裝置間管理音訊行為。

我們可以使用音訊會話來與系統交流,計劃如何在應用程式中使用音訊。此時,音訊會話充當應用程式與作業系統之間的中介,進而充當基礎音訊硬體之間的中介。我們可以使用它向作業系統傳達應用程式音訊的性質,而無需詳細說明特定行為或與音訊硬體的必要互動。將這些細節的管理委派給音訊會話,可以確保對使用者的音訊體驗進行最佳管理。

下圖出自《Audio Session Programming Guide》,從圖中可以看到 AVAudioSession 就是用來管理多個 APP 對音訊硬體裝置的資源使用。

AVAudioSession

音訊會話的能力

iOS 的音訊會話能力主要分為以下幾種情況:

  • 配置音訊會話
  • 啟用音訊會話
  • 響應中斷
  • 響應路由更改
  • 配置裝置硬體
  • 保護使用者隱私

具體的詳細說明可以參考官網:《Audio Session Programming Guide》,這裡就不再全盤細說,本文將主要分析配置音訊會話、配置裝置硬體兩方面的技術細節以及分享實際開發過程中踩過的坑。

配置音訊會話

AVAudioSession 的 Category、CategoryOption、Mode 配合使用,不同的應用型別或者使用場景需要搭配不同的組合。

Category 主要有以下7種型別,其主要描述以及特點在表中詳細介紹:

Category 的7種型別

CategoryOption 主要有以下7種型別:

CategoryOption 的7種型別

下圖詳細列出了 Category、CategoryOption、Mode 配合使用情況:

Category、CategoryOption、Mode 配合使用情況

分類表達音訊角色

表達音訊行為的主要機制是使用音訊會話類別。通過設定類別,我們可以指示應用程式是使用音訊輸入還是音訊輸出,例如是否需要麥克風的採集、是否需要揚聲器的播放等等。下文主要介紹音訊會話類別 Category 在不同場景的應用,針對不同的 Category 的區別,可以對應上文表一詳細檢視。

遊戲應用的場景

大多數遊戲都需要使用者互動發生在遊戲中。使用者調出另一個應用程式或鎖定螢幕時,他們不希望該應用程式繼續播放。設計遊戲時,可以使用 AVAudioSessionCategoryAmbient 或 AVAudioSessionCategorySoloAmbient 類別。

使用者控制的播放和錄製應用程式的場景

錄製應用程式和播放應用程式具有相似的準則。這些型別的應用程式的使用 AVAudioSessionCategoryRecord,AVAudioSessionCategoryPlayAndRecord 或 AVAudioSessionCategoryPlayback 類別。

VoIP 和聊天應用程式的場景

VoIP 和聊天應用程式要求輸入和輸出路由均可用。這些型別的應用程式使用 AVAudioSessionCategoryPlayAndRecord 類別,並且不會與其他應用程式混合使用。

計量應用的場景

計量應用程式需要應用到輸入和輸出路徑的系統提供的訊號處理量最少。設定 AVAudioSessionCategoryPlayAndRecord 類別和測量模式以最小化訊號處理。此外,此型別的應用程式不能與其他應用程式混合使用。

播放音訊類似瀏覽器的應用程式場景

社交媒體或其他類似瀏覽器的應用程式經常播放短視訊。他們使用 AVAudioSessionCategoryPlayback 類別,並且不服從鈴聲開關。這些應用程式也不會與其他應用程式混合使用。

導航和健身應用程式的場景

導航和鍛鍊應用程式使用 AVAudioSessionCategoryPlayback 或 AVAudioSessionCategoryPlayAndRecord 類別。這些應用的音訊通常包含簡短的語音提示。播放時,這些提示會中斷口語音訊(例如播客或有聲書),並與其他音訊(例如從“音樂”應用中播放)混音。

合作音樂應用的場景

合作音樂應用程式旨在播放其他應用程式時播放。這些型別的應用程式使用 AVAudioSessionCategoryPlayback 或 AVAudioSessionCategoryPlayAndRecord 類別,並與其他應用程式混合使用。

網易雲信使用情況

表中為網易雲信在不同的使用場景下,Category、Options、Mode 的配置情況:

網易雲信在不同的使用場景下 Category、Options、Mode 配置情況

針對上表的內容,我們也整理了一些常見的問題:

  • 問題一:相信瞭解這塊的小夥伴們肯定會有疑問,為什麼 NERTC 實時音視訊 SDK 預設不帶 DefaultToSpeaker 選項嗎?

  • 答:其實原來我們使用聽筒和揚聲器切換都是使用 AVAudioSessionCategoryOptions 帶AVAudioSessionCategoryOptionDefaultToSpeaker 和 不帶AVAudioSessionCategoryOptionDefaultToSpeaker 操作的;當 APP 為揚聲器時,AVAudioSessionCategoryOptions 帶 AVAudioSessionCategoryOptionDefaultToSpeaker;而 callkit 本身切換聽筒和揚聲器應該使用的輸出路由的變更 overrideOutputAudioPort: 操作的,因此切到聽筒 AVAudioSessionPortOverrideNone 時,由於 category 和 categoryOptions 都沒有變化,因此無法切換。最後 SDK 內部 AVAudioSessionCategoryOptions 將不再攜帶 AVAudioSessionCategoryOptionDefaultToSpeaker;同時揚聲器和聽筒切換都改為 overrideOutputAudioPort: 操作。

  • 問題二:AVAudioSessionPortOverrideSpeaker 和AVAudioSessionCategoryOptionDefaultToSpeaker 之間的區別是什麼呢?

  • 答:區別在於,AVAudioSessionPortOverride 通過呼叫 overrideOutputAudioPort:,設定的時間要比使用 category 選項 AVAudioSessionCategoryOptionDefaultToSpeaker 更短暫。呼叫overrideOutputAudioPort:和設定 AVAudioSessionPortOverride 到 AVAudioSessionPortOverrideSpeaker 是暫時壓倒一切的輸出將其路由到揚聲器的方式。遵循後進位制勝規則,任何路線更改或中斷都將導致音訊被路由回到其正常路線。考慮使用overrideOutputAudioPort: 可能用於實現擴音電話按鈕的方式,在該按鈕上您希望能夠在揚聲器(AVAudioSessionPortOverrideSpeaker)和正常輸出路線(AVAudioSessionPortOverrideNone)之間切換。AVAudioSessionCategoryOptionDefaultToSpeaker 修改 AVAudioSessionCategoryPlayAndRecord 類別的路由行為,以便在不使用其他附件(例如耳機)的情況下,音訊將始終路由到揚聲器,而不是接收器。使用時AVAudioSessionCategoryOptionDefaultToSpeaker,將尊重使用者的手勢。例如,插入耳機將導致路由更改為耳機麥克風/耳機,拔出耳機將導致路由更改為內建麥克風/揚聲器(與內建麥克風/接收器相反)被設定。

  • 問題三:為什麼 NERTC 實時音視訊 SDK 會有2種模式?

  • 答:因為 VoIP 情況下會使用AVAudioSessionModeVoiceChat模式,在 RemoteIO 情況下,會使用AVAudioSessionModeDerfault模式。

  • 問題四:在AVAudioSessionCategoryPlayAndRecord類別下,Mode 有哪些隱藏含義?

  • 答:設定AVAudioSessionModeVoiceChat模式將啟用AVAudioSession類別選項AVAudioSessionCategoryOptionAllowBluetooth,從而進一步修改類別的行為,AVAudioSessionCategoryPlayAndRecord以允許將配對的藍芽擴音配置檔案(HFP)裝置用於輸入和輸出。設定AVAudioSessionModeVideoChat模式將AVAudioSessionCategoryPlayAndRecord通過設定AVAudioSessionCategoryOptionAllowBluetooth選項和AVAudioSessionCategoryOptionDefaultToSpeaker選項,進一步修改類別的行為。

網易雲音樂使用情況

正常音樂軟體使用 AVAudioSessionCategoryPlayback 類別,在雲音樂新上線的“一起聽”功能模組會使用實時音視訊,因此使用 AVAudioSessionCategoryPlayAndRecord 類別。因為音樂軟體對音質要求比較高,所以在藍芽情況下,會使用 A2DP 模式,使用 AVAudioSessionCategoryOptionAllowBluetoothA2DP。

配置裝置硬體

使用音訊會話屬性,可以在執行時針對裝置硬體優化應用程式的音訊行為。這樣做可以使我們的程式碼適應正在執行裝置的特性,以及使用者在應用程式執行時所做的更改(例如插入耳機或將裝置對接)。

我們在配置裝置硬體 ,可以通過 AVAudioSession 實現相應的屬性配置:

  • 為取樣率和 I / O 緩衝區持續時間指定首選的硬體設定。
  • 查詢許多硬體特性,例如輸入和輸出延遲,輸入和輸出通道數,硬體取樣率,硬體音量設定以及音訊輸入的可用性。

想要配置裝置硬體,首先需要了解清楚硬體的詳細情況,具體可以看下面的2張圖,自行測試和查閱文件得出。

iPhone 硬體詳情:

iPhone 硬體詳情

iPad 硬體詳情:

iPad 硬體詳情

問題排查

音訊可用性問題

音訊可用性問題通常指音訊的採集和播放是否正常工作,那麼會有哪些因素會影響音訊的可用性呢?

  • 裝置許可權:無麥克風許可權、沒有配置音訊後臺許可權。
  • 被其他聲音搶佔,如微信通話、打電話中斷、siri 中斷等。
  • 使用者行為:介面呼叫 mute,修改 AVAudioSession 的 Category 等。
  • 機器故障:硬體啟動失敗。

為了應對音訊問題的排查,我們新增了音訊事件上報和音訊迴路檢測功能。

iOS 音訊事件上報型別

這裡我們羅列幾種常見的 iOS 音訊事件上報的具體型別:

  • 音訊輸入裝置變更事件:上報裝置名,如【 麥克風 (BuiltInMic)、普通耳機 (HeadsetMic)、藍芽耳機 (BluetoothHFP)(一般指HFP)】
    • 示例: {"InputDeviceChange":"BuiltInMic"}
  • 音訊輸出裝置變更事件:上報裝置名,如【 揚聲器 (BuiltInSpeaker)、聽筒 (BuiltInReceiver)、普通耳機 (Headphones)、藍芽耳機 (BluetoothHFP)、藍芽耳機 (BluetoothLE)、藍芽耳機 (BluetoothA2DP)】
    • 示例:{"OutputDeviceChange":"BuiltInSpeaker"}
  • 音訊採集取樣率變更事件:上報當前採集取樣率
    • 示例:{"RecordSampleRateChange":"48000"}
  • 音訊播放取樣率變更事件:上報當前播放取樣率
    • 示例:{"PlayoutSampleRateChange":"48000"}
  • 音訊裝置異常狀態變更事件:上報當前異常狀態
    • 示例:{"InitRecordingErr\StartRecordingErr\StopRecordingErr...":"-108"}
  • 音訊系統音量變更事件:上報當前系統音量
    • 示例:{"SystemVolumeChange":"70"}
  • 音訊播放故障檢測變更事件:上報當前播放故障次數
    • 示例:{"PlayoutGlitch":"3"}
  • 音訊會話相關變更事件有以下8種情況:
    • 音訊打斷開始事件 audioInterruptionBegin 0
    • 音訊打斷結束事件 audioInterruptionEnd 1
    • 音訊媒體服務丟失事件 audioMediaServicesWereLost 2
    • 音訊媒體服務重置事件 audioMediaServicesWereReset 3
    • 沉默輔助音訊提示通知開始事件 audioSilenceSecondaryAudioHintBegin 4
    • 沉默輔助音訊提示通知結束事件 audioSilenceSecondaryAudioHintEnd 5
      • 示例:{"audioInterruptionBegin\audioInterruptionEnd...":"0"}
    • AVAudioSession 相關的 Category 6
      • 示例: {"CategoryChange":"AVAudioSessionCategoryPlayAndRecord"}
    • AVAudioSession 相關的 CategoryOption 7
      • 示例:{"CategoryOptionChange":"37"}
    • AVAudioSession 相關的 Mode 8
      • 示例:{"ModeChange":"AVAudioSessionModeVoiceChat"}

音訊迴路檢測

我們在使用過程中需要實時觀察音訊的迴路工作狀態,我們重點分析以下兩種情況:

  • 當我們需要準確瞭解音訊迴路的實際工作狀態,那麼我們可以通過採集音訊和播放音訊對應的取樣率以及單位時間內的音訊取樣 Samples 偏差,同時也能瞭解到它向NetEQ(即:音訊 Buffer) 索要音訊播放資料的節奏。
  • 當播放執行緒出現卡頓的時候,我們需要實時獲取音訊播放執行緒狀態以及分析解碼、混音等各個階段的耗時,排查其他環節對於播放執行緒的影響。

未來展望

產品以及系統也在不斷迭代升級,例如:

  1. 麥克風的位置選擇(Built-in 不可控,因為要完美處理回聲問題)和麥克風的極性模式設定(極性模式定義了其對聲音相對於聲源方向的靈敏度)。
  2. 從 iOS 14 和 iPadOS 14 開始,我們現在可以使用支援的裝置上的內建麥克風來捕獲立體聲音訊,從而獲得非常有沉浸式的錄音體驗。

我們期望未來可以結合這些優勢能力,在音訊會話技術上深度挖掘,以提供更好的音訊服務。

總結

本文介紹了基於 WebRTC 實現 iOS 音訊會話的實現以及管理。一個完整的系統,需要有預警各種異常、處理各種異常情況的能力。由於移動端裝置的複雜性,移動端音訊預警,自行恢復機制是一個比較核心的技術。

熟練掌握 AVAudioSession 的 Category、CategoryOption、Mode 的各個含義和了解 iPhone、iPad的硬體構造,對於理解 iOS 音訊至關重要,上文如有不正確之處,歡迎指出,也歡迎交流。

系列文章

作者介紹

陶金亮,網易雲信資深客戶端音視訊工程師,一直從事客戶端音視訊相關開發工作,期間負責網易雲信的 G1 和 G2 的相關研發工作。

相關文章