音頻路由

在 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可用於配置基於使用者 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 進行路由

CarAudioManager在 10 中引入了一系列隱藏的 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注意:串流和焦點無法動態切換區域。因此,必須停止播放並重新請求焦點以更改區域。

使用用戶 ID 進行路由

雖然應用程式基於 UID 的路由允許對每個應用程式的音訊路由進行精細控制,但它還要求在應用程式實際請求音訊焦點和播放音訊之前定義每個應用程式的音訊路由。為了緩解此問題並進一步方便第三方應用程式無需修改即可播放音頻, CarAudioService使用汽車乘員區域和音頻區域映射來定義基於用戶 ID 的路由。這樣,當使用者登入佔用區域時,汽車音訊服務就會收到通知。透過此訊號,可以自動為所有音訊區域配置音訊焦點管理和路由。

基於 UID 的應用程式路由仍然可以使用,但必須獨立於使用者 ID 路由來完成。這意味著,如果定義了乘員區域到汽車音訊區域的映射,則基於 UID 的路由將被停用,並且嘗試呼叫CarAudioManager#setZoneidForUid將引發錯誤。

雖然透過佔用區域管理簡化了音訊路由和焦點管理,但使用者仍然必須被分配到佔用區域。這可以透過使用CarOccupantZoneManager#assignProfileUserToOccupantZone來完成。此 API 需要管理使用者的權限。目前的期望是 OEM 透過某種系統 UI 來管理使用者到佔用區域的分配。一旦完成,應用程式啟動、音訊路由、焦點管理都將為使用者自動設定。

使用 setPreferredDevice 進行路由

除了上述變更之外,Android 11 還提供了一個新的 API 來查詢與每個區域關聯的輸出裝置:CarAudioManager#getOutputDeviceForUsage(int zoneId, int use)。

此 API 可用於查詢輸出裝置的特定區域和音訊屬性使用情況。透過這種方式,第一方應用程式可以利用播放器的setPreferredDevice API 將音訊路由到不同的區域。 getOutputDeviceForUsage API 需要PERMISSION_CAR_CONTROL_AUDIO_SETTINGS且是系統 API。以下是尋找特定區域的媒體裝置並使用setPreferredDevice API 路由到該裝置的範例。

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