音訊焦點

在開始邏輯串流之前,應用程式會使用與邏輯串流相同的音訊屬性要求音訊焦點。應用程式必須尊重焦點損失,才能在汽車用途中正常運作。

雖然建議您傳送焦點要求,但系統不會強制執行這項操作。因此,請將焦點視為間接控制方式,避免在播放期間發生衝突,而非主要的音訊控制機制。車輛不應依賴焦點系統來操作音訊子系統。

焦點互動

為了支援 AAOS,系統會根據要求的 CarAudioContext 與目前焦點持有者之間預先定義的互動,處理音訊焦點要求。互動有三種類型:

  • 獨家
  • 拒絕
  • 並行

獨家互動

這是 Android 最常用的互動模型。

專屬互動中,一次只能有一個應用程式保留焦點。因此,當現有焦點持有者失去焦點時,傳入的焦點要求會獲得焦點。由於兩個應用程式都會播放媒體,因此只允許一個應用程式保留焦點。因此,當目前播放音樂的應用程式收到焦點變更事件時,系統會使用 AUDIOFOCUS_REQUEST_GRANTED 傳回新啟動的應用程式焦點要求,並附上與所提出要求類型相對應的遺失狀態。

拒絕互動

在「拒絕」互動中,系統一律會拒絕傳入要求。例如,在通話期間嘗試播放音樂。在這種情況下,如果撥號應用程式保留通話的音訊焦點,而第二個應用程式要求播放音樂,音樂應用程式會收到 AUDIOFOCUS_REQUEST_FAILED 做為要求的回應。由於焦點要求遭到拒絕,因此不會將焦點遺失事件傳送至目前的焦點持有者。

並行互動

AAOS 專屬的互動類型是並行互動。這可讓在車輛中要求音訊焦點的應用程式,同時與其他應用程式保持焦點。如要進行並行互動,必須符合下列條件:以下是:

如果符合這些條件,焦點要求會傳回 AUDIOFOCUS_REQUEST_GRANTED,而目前的焦點容器則不會變更焦點。不過,如果目前的聚焦持有者選擇接收 duck 事件,或在 duck 時暫停,則目前的聚焦持有者會失去焦點,就像在專屬互動發生時一樣。

處理並行串流

雖然並行互動有許多用途,但請小心在硬體層級混合和抑制輸出裝置。強烈建議您將允許同時播放的 CarAudioContext 路由至不同的輸出裝置。

透過為並行串流提供個別輸出裝置,可讓 HAL 在混合串流前將其中一個串流靜音,或將實體串流路由至車輛中的不同喇叭。如果邏輯串流在 Android 中混合,增益會保持不變,並且會以相同的實體串流的一部分提供。

舉例來說,如果導航和媒體同時傳送,媒體串流的增益值可能會暫時降低 (或降低),以便更清楚地聽到導航指示。或者,您也可以將導航串流傳送至駕駛座喇叭,同時在車內其他地方繼續播放媒體。

互動矩陣

下表顯示 CarAudioService 定義的互動矩陣。每列代表目前焦點持有者的 CarAudioContext,每欄則代表傳入要求的 CarAudioContext

舉例來說,當音樂媒體應用程式在導航應用程式要求焦點時保留焦點,矩陣會指出這兩項互動可同時進行,前提是同時互動的其他條件已滿足。

由於同時進行的互動,可能會有多個焦點持有者。在這種情況下,系統會先比較傳入的焦點要求與目前的焦點持有者,再決定要套用的互動。在這種情況下,最保守的互動會勝出。拒絕、排他,最後是並行。

圖 1. 音訊焦點互動矩陣。

在 Android 11 中,我們推出了新的使用者設定,讓使用者變更導覽和電話通話之間的互動行為。設定後,android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL 會將傳入的 NAVIGATION 焦點要求與目前 CALL 焦點持有者之間的互動,從「同時」變更為「拒絕」。如果使用者不希望導航指示干擾通話,可以啟用這項設定。這項設定會保留給使用者,且可動態設定,以便後續的焦點要求遵循新設定。

可延遲的音訊焦點

在 Android 11 中,AAOS 新增了支援功能,可要求可延遲的音訊焦點。這樣一來,當非暫時性焦點要求與目前焦點持有者的互動通常會導致拒絕時,系統就會延遲這些要求。一旦焦點變更導致延遲要求可獲得焦點,系統就會授予要求。

延遲音訊焦點要求的規則

  • 僅限非暫時性要求。延遲要求只能針對非暫時性來源提出,以免暫時性音效在相關時間過後仍持續播放。

  • 一次只能延遲一項要求。如果在已有延遲要求的情況下提出可延遲要求,原始延遲要求會收到 AUDIOFOCUS_LOSS 變更事件,而新要求會收到 AUDIOFOCUS_REQUEST_DELAYED 的同步回應。

  • 可延遲的要求必須具備 OnAudioFocusChangeListener 一旦要求延遲,事件監聽器就會在要求最終核准 (AUDIOFOCUS_GAIN) 或稍後遭到拒絕 (AUDIOFOCUS_LOSS) 時通知要求者。

要求可延遲的焦點

如要建構可延遲的要求,請按照下列步驟操作:

  1. 使用 AudioFocusRequest.Builder#setAcceptsDelayedFocusGain

    mMediaWithDelayedFocusListener = new MediaWithDelayedFocusListener();
    
    mDelayedFocusRequest = new AudioFocusRequest
         .Builder(AudioManager.AUDIOFOCUS_GAIN)
         .setAudioAttributes(mMusicAudioAttrib)
         .setOnAudioFocusChangeListener(mMediaWithDelayedFocusListener)
         .setForceDucking(false)
         .setWillPauseWhenDucked(false)
         .setAcceptsDelayedFocusGain(true)
         .build();
    
  2. 提出要求時,請處理 AUDIOFOCUS_REQUEST_DELAYED 回應:

    int delayedFocusRequestResults = mAudioManager.requestAudioFocus(mDelayedFocusRequest);
    if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
        // start audio playback
        return;
    }
    if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
         // audio playback delayed to audio focus listener
         return;
    }
    
  3. 當要求延遲時,焦點事件監聽器會處理焦點變更:

    private final class MediaWithDelayedFocusListener implements
    OnAudioFocusChangeListener {
           @Override
           public void onAudioFocusChange(int focusChange) {
               synchronized (mLock) {
                   switch (focusChange) {
                       case AudioManager.AUDIOFOCUS_GAIN:
                           … // Start focus playback
                       case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                           … // Pause media transiently
                       case AudioManager.AUDIOFOCUS_LOSS:
                           … // Stop media
    

多區焦點管理

對於有多個音訊區的車輛,系統會為每個區域個別管理音訊焦點。因此,對某個區域提出的要求不會考量其他區域的焦點持有者,也不會導致其他區域的焦點持有者失去焦點。這樣一來,您就能透過後座娛樂系統單獨管理主車廂的焦點,因此不會因為焦點變更而中斷某個區域的音訊播放。

對於所有應用程式,CarAudioService 會自動管理焦點。焦點要求的音訊區域取決於其相關聯的 UserIdUID (詳情請參閱「多區域音訊路由」)。

同時要求多個區域的音訊

如果應用程式想在多個區域中同時播放音訊,就必須在 bundle 中加入 AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID,為每個區域要求焦點:

//Create attribute with bundle and AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID
Bundle bundle = new Bundle();
bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID,
               zoneId);

AudioAttributes attributesWithZone = new AudioAttributes.Builder()
     .setUsage(AudioAttributes.USAGE_MEDIA)
     .addBundle(bundle)
     .build();

//Create focus request using built attributesWithZone

這個套件參數可讓要求者覆寫自動音訊區域對應項目,改為使用指定的區域 ID。因此,應用程式可以針對不同的音訊區域發出個別要求。

HAL 音訊焦點

從 Android 11 開始,HAL 可代表外部串流要求焦點。雖然這些 API 屬於選用,但我們強烈建議您使用這些 API,讓外部音效成為 Android 生態系統中的最佳參與者,並提供流暢的使用者體驗。

HAL 會決定哪些聲音應優先播放。因此,無論 HAL 是否已獲得音訊焦點,都應播放緊急和安全性重要音效,且即使 HAL 失去音訊焦點,也應繼續適當播放。同樣地,任何政府法規規定的聲音也適用這項規定。

播放緊急或安全性關鍵的音效時,HAL 應主動將 Android 串流靜音,確保音效能清楚播放。

AudioControl@2.0

AudioControl HAL 2.0 版推出以下新 API:

API 目的
IAudioControl#registerFocusListener IFocusListener 例項註冊至 AudioControl HAL。這個事件監聽器可讓 HAL 要求及放棄音訊焦點。HAl 會提供 ICloseHandle 例項,供 Android 使用來取消註冊監聽器。
IAudioControl#onAudioFocusChange 通知 HAL,針對透過 IFocusListener 提出的焦點要求,狀態有何變動,包括對初始焦點要求的回應。
IFocusListener#requestAudioFocus 代表 HAL 要求指定用途、區域 ID 和對焦增益類型的對焦功能。
IFocusListener#abandonAudioFocus 放棄現有的 HAL 焦點要求,適用於指定的使用情形和區域 ID。

HAL 可同時有多個聚焦要求,但每個用途和區域 ID 配對只能有一個要求。Android 會假設 HAL 在收到要求後,會立即開始播放聲音,並持續播放,直到放棄焦點為止。

除了 registerFocusListener 之外,這些要求都是 oneway,可確保 Android 在處理焦點要求時不會延遲 HAL。HAL 應在播放安全攸關的音效前等待取得焦點。HAL 可透過 IAudioControl#onAudioFocusChange 監聽並回應音訊焦點的變更,但這並非必要。

原始設備製造商 (OEM) 車輛音訊焦點服務

在 Android 14 中,AAOS 推出了汽車原始設備製造商外掛程式服務,可讓部分汽車元件具備可設定性。對於車用音訊外掛程式服務,外掛程式服務可讓原始設備製造商管理車用音訊服務攔截的焦點要求。這可讓原始設備製造商在管理焦點時,更靈活地遵循規則和法規。因此,不同製造商和地區的音訊專注互動方式可能有所不同。音訊焦點的基本前提仍適用,應用程式仍應要求焦點,以便妥善管理音訊,提升使用者體驗。一般來說,應用程式提出的音訊專注要求仍須遵守特定規則:

  • 在沒有任何持續性高優先順序音訊焦點 (包括電話、緊急警報或安全通知) 的情況下,應用程式應能暫時或永久獲得音訊焦點。

  • 媒體焦點處於啟用狀態時:

    • 要求使用通話焦點的應用程式應能同時或獨占接聽通話。

    • 要求導覽使用者專注力的應用程式應能同時或獨占地接收導覽專注力。

    • 要求使用 Google 助理的應用程式應能同時或獨占使用者焦點。

  • 當高優先順序音訊焦點 (包括電話、緊急警報或安全通知) 應用程式處於啟用狀態時,應根據需要授予或延遲任何傳入的延遲音訊焦點要求。

雖然上述建議並非詳盡無遺,但如果沒有有效的高優先順序音效,這些建議可協助要求專注模式的應用程式取得專注模式。即使高優先順序的聲響處於啟用狀態,延遲的焦點要求仍應受到尊重,且應能在高優先順序的聲響停止時獲得焦點。