音訊輸入通常來自內建麥克風、外接麥克風或連接至裝置的音訊介面。音訊輸入也可以來自電話對話。
有時兩個以上的應用程式可能會想「擷取」相同的音訊輸入內容。 他們可能正在執行不同的工作。 舉例來說,有些應用程式可能會「錄音」,例如簡單的錄音工具;其他應用程式則可能「聆聽」,例如 Google 助理或回應語音指令的無障礙服務。
無論哪種情況,這些應用程式都想接收音訊輸入內容。 無論應用程式是錄音還是只是聆聽,本頁面一律使用「擷取」一詞。
如果兩個以上的應用程式想同時擷取音訊,將同一來源的音訊訊號傳送給所有應用程式時,可能會發生問題。本頁說明 Android 系統如何在擷取音訊的多個應用程式之間共用音訊輸入。
Android 10 之前的行為
在 Android 10 之前,一次只能有一個應用程式擷取輸入音訊串流。如果其他應用程式正在錄製或聆聽音訊,您的應用程式可以建立 AudioRecord
物件,但呼叫 AudioRecord.startRecording()
時會傳回錯誤,且不會開始錄製。
但如果具備權限的應用程式 (例如 Google 助理或無障礙服務) 使用 HOTWORD
類型的音訊來源,則不在此限。android.permission.CAPTURE_AUDIO_HOTWORD
在這種情況下,其他應用程式可能會開始錄製。發生這種情況時,具備特殊權限的應用程式會終止,而新應用程式會擷取輸入內容。
Android 9 又新增一項異動:只有在前景執行的應用程式 (或前景服務) 才能擷取音訊輸入內容。如果應用程式沒有前景服務或前景 UI 元件,但開始擷取音訊,應用程式會繼續執行,但會收到無聲音訊,即使當時只有該應用程式擷取音訊也一樣。
Android 10 行為
在 Android 10 之前的行為是「先到先得」。應用程式開始擷取音訊後,其他應用程式就無法存取音訊輸入,直到擷取音訊的應用程式停止擷取為止。
Android 10 採用優先順序配置,可在應用程式執行期間切換應用程式之間的輸入音訊串流。在大多數情況下,如果新應用程式取得音訊輸入,先前擷取音訊的應用程式會繼續執行,但會收到無聲音訊。在某些情況下,系統可以繼續將音訊傳送至這兩個應用程式。以下說明各種共用情境。
這個機制與音訊焦點處理多個應用程式爭用音訊輸出功能的方式類似。不過,音訊焦點是透過程式輔助要求來管理,以取得及釋放焦點,而本文所述的輸入切換機制則是以優先順序政策為依據,每當有新的應用程式開始擷取音訊時,系統就會自動套用這項政策。
為擷取音訊,Android 會區分兩種應用程式:
- 「一般」應用程式是由使用者安裝。
- 「具備特殊權限」的應用程式會預先安裝在裝置上。包括 Google 助理和所有無障礙服務。
此外,如果應用程式使用「隱私權敏感」音訊來源:CAMCORDER
或 VOICE_COMMUNICATION
,處理方式也會有所不同。
使用及分享音訊輸入內容的優先順序規則如下:
- 具備特殊權限的應用程式優先順序高於一般應用程式。
- 與背景應用程式相比,具有可見前景 UI 的應用程式優先順序較高。
- 如果應用程式從隱私權敏感來源擷取音訊,優先順序會高於未擷取音訊的應用程式。
- 兩個一般應用程式絕不會同時擷取音訊。
- 在某些情況下,具備特殊權限的應用程式可以與其他應用程式共用音訊輸入內容。
- 如果兩個優先順序相同的背景應用程式都在擷取音訊,最後啟動的應用程式優先順序較高。
共用情境
如果兩個應用程式都嘗試擷取音訊,兩者可能都能接收輸入訊號,也可能只有一個應用程式收到訊號,另一個則收到無聲訊號。
主要有四種情況:
- Google 助理 + 一般應用程式
- 無障礙服務 + 一般應用程式
- 兩個一般應用程式
- 語音通話 + 一般應用程式
Google 助理 + 一般應用程式
Google 助理是預先安裝的應用程式,且具有 RoleManager.ROLE_ASSISTANT
角色,因此屬於具備特殊權限的應用程式。其他具有這項角色的預先安裝應用程式也會以類似方式處理。
Android 會根據下列規則分享輸入音訊:
除非其他應用程式已在擷取隱私權敏感的音訊來源,否則無論 Google 助理是在前景或背景運作,都能接收音訊。
除非 Google 助理在畫面上方顯示 UI 元件,否則應用程式會接收音訊。
請注意,只有在 Google 助理處於背景狀態,且其他應用程式未從隱私權敏感的音訊來源擷取音訊時,這兩個應用程式才會收到音訊。
無障礙服務 + 一般應用程式
AccessibilityService
需要嚴格的宣告。
Android 會根據下列規則分享輸入音訊:
如果服務的 UI 位於最上層,服務和應用程式都會收到音訊輸入。這項行為提供多種功能,例如透過語音指令控制語音通話或影片擷取。
如果服務並非位於最上層,系統會將此情況視為下方的一般雙應用程式案例。
兩個一般應用程式
如果兩個應用程式同時擷取音訊,只有一個應用程式會收到音訊,另一個則會收到靜音。
Android 會根據下列規則分享輸入音訊:
- 如果這兩款應用程式都不會存取隱私權敏感資訊,則音訊會傳送至 UI 位於頂端的應用程式。如果兩者都沒有使用者介面,則最近開始擷取的應用程式會收到音訊。
- 如果其中一個應用程式會存取隱私權資訊,即使該應用程式的 UI 位於頂端,或最近才開始擷取音訊,系統也會將音訊傳送給該應用程式,另一個應用程式則會收到無聲音訊。
- 如果兩個應用程式都需要存取隱私權,則最近開始擷取音訊的應用程式會收到音訊,另一個應用程式則會收到無聲訊號。
語音通話 + 一般應用程式
如果 AudioManager.getMode()
傳回的音訊模式為 MODE_IN_CALL
或 MODE_IN_COMMUNICATION
,表示語音通話處於啟用狀態。
Android 會根據下列規則分享輸入音訊:
- 通話時一律會收到音訊。
- 如果應用程式是無障礙服務,就能擷取音訊。
如果應用程式是具備
CAPTURE_AUDIO_OUTPUT
權限的預先安裝應用程式,就能擷取語音通話內容。如要擷取語音通話的上行 (TX)、下行 (RX) 或兩者,應用程式必須指定音訊來源
MediaRecorder.AudioSource.VOICE_UPLINK
或MediaRecorder.AudioSource.VOICE_DOWNLINK
,和/或裝置AudioDeviceInfo.TYPE_TELEPHONY
。
Android 11 行為
Android 11 (API 級別 30) 會採用上述 Android 10 優先順序配置。此外,AudioRecord
、MediaRecorder
和 AAudioStream
也提供新方法,可啟用及停用同時擷取音訊的功能,無論選取的用途為何皆適用。
新方法如下:
AudioRecord.Builder.setPrivacySensitive()
AudioRecord.isPrivacySensitive()
MediaRecorder.setPrivacySensitive()
MediaRecorder.isPrivacySensitive()
AAudioStreamBuilder_setPrivacySensitive()
AAudioStream_isPrivacySensitive()
當 setPrivacySensitive()
為 true
時,擷取用途為私密,即使是具有權限的 Google 助理也無法同時擷取。這項設定會覆寫取決於音訊來源的預設行為。舉例來說,VOICE_COMMUNICATION
預設為私有,但 UNPROCESSED
則否。
設定變更
如果多個應用程式同時擷取音訊,只有一或兩個應用程式會「啟用」(接收音訊),其他應用程式則會靜音 (接收無聲)。當使用中的應用程式變更時,音訊架構可能會根據下列規則重新設定音訊路徑:
- 每個有效應用程式的音訊輸入裝置可能會變更 (例如從內建麥克風變更為連接的藍牙耳機)。
- 系統會啟用與優先順序最高的有效應用程式相關聯的前置處理。系統會忽略所有其他預先處理作業。
由於優先順序較高的應用程式啟動時,作用中的應用程式可能會遭到靜音,因此您可以在 AudioRecord
或 MediaRecorder
物件上登錄 AudioManager.AudioRecordingCallback,以便在設定變更時收到通知。可能的變更包括:
- 擷取靜音或非靜音的影片
- 裝置已變更
- 預先處理已變更
- 串流屬性已變更 (取樣率、聲道遮罩、取樣格式)
您必須在開始擷取前呼叫 AudioRecord.registerAudioRecordingCallback()
。只有在應用程式接收音訊且發生變更時,系統才會執行回呼。
onRecordingConfigChanged()
方法會傳回 AudioRecordingConfiguration
,其中包含目前的音訊擷取狀態。如要瞭解這項異動,請使用下列方法:
isClientSilenced()
- 如果因擷取政策而導致傳回給用戶端的音訊目前遭到靜音,則傳回 true。
getAudioDevice()
- 傳回作用中的音訊裝置。
getEffects()
- 傳回有效的預先處理效果。請注意,如果用戶端不是優先順序最高的活動應用程式,則有效效果可能與
getClientEffects()
傳回的效果不同。 getFormat()
- 傳回串流屬性。請注意,用戶端收到的實際音訊資料一律會遵守
getClientFormat()
傳回的必要格式。架構會自動執行必要的重新取樣、管道和格式轉換,從硬體介面使用的格式轉換為用戶端指定的格式。 AudioRecord.getActiveRecordingConfiguration()
。- 傳回有效的錄製設定。
您可以呼叫 AudioManager.getActiveRecordingConfigurations()
,概略查看裝置上所有進行中的錄音。