音訊路由

在 Android 10 中,car_audio_configuration.xml 取代 car_volumes_groups.xmlIAudioControl.getBusForContext。在新設定檔中,定義了區域清單。每個區域都會有一或多個含有相關聯裝置的音量群組,而每個裝置都會有應在該區域內路由的內容。所有情境都必須在各個區域中顯示。

設定音訊路由

音訊政策檔案通常位於供應商分區,代表主機板的音訊硬體設定。car_audio_configuration.xml 中參照的所有裝置都必須在 audio_policy_configuration.xml 中定義。

啟用 AAOS 路由

如要使用 AAOS 導向,您必須將 audioUseDynamicRouting 標記設為 true

<resources>
    <bool name="audioUseDynamicRouting">true</bool>
</resources>

false 時,路由和大部分 CarAudioService 都會停用,作業系統會回復至 AudioService 的預設行為。

主要可用區

根據預設,所有音訊都會轉送至主要區域。只有一個主要區域,在設定中以屬性 isPrimary="true" 表示。

設定範例

舉例來說,車輛可能有兩個區域:主要區域和後座娛樂系統。因此,可能的 car_audio_configuration.xml 定義如下:

<audioZoneConfiguration version="2.0">
       <zone name="primary zone" isPrimary="true">
           <volumeGroups>
               <group>
                   <device address="bus0_media_out">
                       <context context="music"/>
                       <context context="announcement"/>
                   </device>
                   <device address="bus3_call_ring_out">
                       <context context="call_ring"/>
                   </device>
                   <device address="bus6_notification_out">
                       <context context="notification"/>
                   </device>
                   <device address="bus7_system_sound_out">
                       <context context="system_sound"/>
                       <context context="emergency"/>
                       <context context="safety"/>
                       <context context="vehicle_status"/>
                   </device>
               </group>
               <group>
                   <device address="bus1_navigation_out">
                       <context context="navigation"/>
                   </device>
                   <device address="bus2_voice_command_out">
                       <context context="voice_command"/>
                   </device>
               </group>
               <group>
                   <device address="bus4_call_out">
                       <context context="call"/>
                   </device>
               </group>
               <group>
                   <device address="bus5_alarm_out">
                       <context context="alarm"/>
                   </device>
               </group>
           </volumeGroups>
       </zone>
        <zone name="rear seat zone" audioZoneId="1">
           <volumeGroups>
               <group>
                   <device address="bus100_rear_seat">
                       <context context="music"/>
                       <context context="navigation"/>
                       <context context="voice_command"/>
                       <context context="call_ring"/>
                       <context context="call"/>
                       <context context="alarm"/>
                       <context context="notification"/>
                       <context context="system_sound"/>
                       <context context="emergency"/>
                       <context context="safety"/>
                       <context context="vehicle_status"/>
                       <context context="announcement"/>
                   </device>
               </group>
           </volumeGroups>
    </zones>
</audioZoneConfiguration>

在此情況下,主要區域已將不同裝置的內容區隔開來。這樣一來,HAL 就能使用車輛的硬體,在每個裝置輸出內容上套用不同的後製效果和混合效果。裝置已分為四個音量群組:媒體、導航、通話和鬧鐘。如果系統已設為 useFixedVolume,則每個群組的音量會傳遞至 HAL,以便套用至這些裝置的輸出內容。

對於次要區域,預期的輸出內容是透過單一輸出裝置。在這個範例中,所有用途都會路由至單一裝置和音量群組,以簡化操作。

乘客區音訊設定

在 Android 11 中,car_audio_configuration.xml 進一步擴充,推出兩個新欄位:audioZoneIdoccupantZoneId。第一個 audioZoneId 可用於進一步控管區域管理。另一方面,occupantZoneId 可用於設定以 User-ID 為依據的路由。

如要使用這些新欄位,您必須使用 car_audio_configuration.xml 的 V2 版本。回到上述的音訊設定,但使用新欄位來對應住戶區 ID 和音訊區 ID,您可以將沒有音量群組定義的新設定設為:

<audioZoneConfiguration version="2.0">
       <zone name="primary zone" isPrimary="true" occupantZoneId="0">
         ...
       </zone>
       <zone name="rear seat zone" audioZoneId="1" occupantZoneId="1">
         ...
       </zone>
    </zones>
</audioZoneConfiguration>

上述設定會將主要區域對應至居住區域 0,並將 audioZoneId 1 對應至 occupantZoneId 1。一般來說,您可以設定任何乘客區和音訊區之間的對應關係,但對應關係必須是一對一。以下是定義這兩個新欄位的規則:

  • 主要區域的 audioZoneId 一律為零
  • audioZoneIdoccupantZoneId 號碼不得重複
  • audioZoneIdoccupantZoneId 只能一對一對應

透過應用程式 UID 進行轉送

在 10 版中,我們在 CarAudioManager 中引進了一系列隱藏的 API,讓應用程式可以查詢及設定音訊區域和焦點。

int[] getAudioZoneIds();
int getZoneIdForUid(int uid);
boolean setZoneIdForUid(int zoneId, int uid);
boolean clearZoneIdForUid(int uid);

上述 API 可讓第一方應用程式根據應用程式的 UID 管理音訊路由。因此,您也需要音訊區 ID 和應用程式的 UID。有了這些資訊,您就可以使用 CarAudioManager#setZoneIdForUid API 設定音訊路由。

變更應用程式的區域

根據預設,所有音訊都會傳送至主要區域。如要更新應用程式,將其路由至其他區域,請使用 CarAudioManager#setZoneIdForUid

// Find zone to play
int zoneId = ...

// Find application's uid
Int uid = mContext.getPackageManager()
        .getApplicationInfo(mContext.getPackageName(), 0)
        .uid;

if (mCarAudioManager.setZoneIdForUid(zoneId, info.uid)) {
    Log.d(TAG, "Zone successfully updated");
} else {
    Log.d(TAG, "Failed to change zone");
}

N 注意:串流和焦點無法動態切換區域。因此,必須停止播放並重新要求焦點,才能變更區域。

使用 User ID 進行轉送

雖然應用程式的 UID 導向路由可精細控管每個應用程式的音訊路由,但也要求在應用程式實際要求音訊焦點及播放音訊之前,先定義每個應用程式的音訊路由。為緩解這個問題,並進一步協助第三方應用程式在不修改的情況下播放音訊,CarAudioService 會使用車輛乘客區域和音訊區域對應功能,定義以使用者 ID 為基礎的路由。這樣一來,當使用者登入乘客區時,車輛音訊服務就會收到通知。有了這項信號,系統就會自動為所有音訊區域設定音訊焦點管理和路由。

您仍可使用應用程式 UID 型路由,但必須與使用者 ID 路由分開執行。也就是說,如果已定義乘客區到車輛音訊區的對應項目,系統就會停用 UID 導向,且嘗試呼叫 CarAudioManager#setZoneidForUid 時會擲回錯誤。

雖然使用者區域管理功能已簡化音訊路由和焦點管理作業,但使用者仍必須指派至使用者區域。您可以使用 CarOccupantZoneManager#assignProfileUserToOccupantZone 執行這項操作。這個 API 需要管理使用者的權限。目前預期原始設備製造商 (OEM) 會透過某種系統 UI 管理使用者與乘客區的指派作業。完成後,系統會自動為使用者設定應用程式啟動、音訊路由和焦點管理。

使用 setPreferredDevice 進行轉送

除了上述變更之外,Android 11 也提供新的 API,可查詢與每個區域相關聯的輸出裝置,即 CarAudioManager#getOutputDeviceForUsage(int zoneId, int usage)。

這個 API 可用於查詢特定區域的輸出裝置和音訊屬性用途。如此一來,第一方應用程式就能利用播放器的 setPreferredDevice API,將音訊路由至不同的區域。getOutputDeviceForUsage API 需要 PERMISSION_CAR_CONTROL_AUDIO_SETTINGS,且為系統 API。以下是使用 setPreferredDevice API 找出特定區域的媒體裝置,並將路由導向該裝置的範例。

audioZoneId = ... ;
mediaDeviceInfo = mCarAudioManager
            .getOutputDeviceForUsage(audioZoneId, AudioAttributes.USAGE_MEDIA);
…
mPlayer.setPreferredDevice(mediaDeviceInfo);