マルチゾーンの概要

自動車については、プラットフォームを操作する複数のユーザーが個別のメディアを同時に利用するという、新しい一連のユースケースが考えられます。たとえば、運転手はキャビンで音楽を再生し、バックシートの同乗者は後部座席のディスプレイで YouTube 動画を視聴できます。マルチゾーン オーディオでは、異なる音声ソースを車両の異なるエリアで同時に再生できるようにすることで、これを可能にしています。

Android 10 のマルチゾーン オーディオにより、OEM はオーディオを個別のゾーンに構成できます。各ゾーンは、車両内のデバイスの集合であり、独自の音量グループ、コンテキストのルーティング構成、フォーカス管理を備えています。このようにして、メインのキャビンを 1 つのオーディオ ゾーンとして、後部座席のディスプレイのヘッドフォン端子を 2 つ目のゾーンとして構成できます。

ゾーンは car_audio_configuration.xml の一部として定義されます。次に、CarAudioService が構成を読み取り、関連付けられているゾーンに基づいて AudioService が音声ストリームをルーティングするのをサポートします。各ゾーンは引き続き、コンテキストとアプリ uid に基づいてルーティングのルールを定義します。プレーヤーが作成されると、CarAudioService はプレーヤーが関連付けられているゾーンを判別し、その使用状況に基づいて、AudioFlinger による音声ルーティングの対象デバイスを決定します。

また、フォーカスはオーディオ ゾーンごとに独立して管理されます。これにより、異なるゾーンのアプリは、相互に干渉することなく、オーディオを独立して生成しながら、各ゾーン内のフォーカスの変化に対応できます。CarAudioService 内の CarZonesAudioFocus は、各ゾーンのフォーカスを管理します。

マルチゾーン オーディオを構成する

図 1. マルチゾーン オーディオを構成する

複数ゾーンの構成

Android 10 では、car_volumes_groups.xmlIAudioControl.getBusForContextcar_audio_configuration.xml に置き換えられています。新しい構成ファイルでは、ゾーンのリストが定義されています。各ゾーンには 1 つ以上の音量グループが存在し、それぞれのグループにデバイスが関連付けられています。各デバイスには、そのゾーン内にルーティングする必要があるコンテキストがあります。すべてのコンテキストが各ゾーン内で表現される必要があります。

audio_policy(通常はベンダー パーティションに存在します)は、ボードのオーディオ ハードウェア構成を表します。car_audio_configuration.xml で参照されているすべてのデバイスは、audio_policy_configuration.xml 内で定義されます。

マルチゾーン サポートの有効化

マルチゾーン オーディオが存在する場合は、audioUseDynamicRouting フラグを true に設定する必要があります。

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

false の場合、CarAudioService は代わりに car_volumes_groups.xmlIAudioControl.getBusForContext を使用します。HAL レイヤでは変更は必要ありませんが、car_audio_configuration.xml ファイルによってデバイスとコンテキストの関係が定義されるため、IAudioControl.getBusForContext は Android 10 ではサポートが終了しています。

プライマリ ゾーン

プライマリ ゾーンは、デフォルトですべての音声がルーティングされる場所です。属性 isPrimary="true" により構成で指定できるプライマリ ゾーンは 1 つのみです。プライマリ ゾーンが指定されていない場合、デフォルトではリスト内の最初のゾーンがシステムによって指定されます。

構成の例

前述したサンプルのユースケースでは、車両にプライマリ ゾーンとリアシート エンターテイメント システムの 2 つのゾーンが必要です。この場合、car_audio_configuration.xml は次のように定義されることが考えられます。

<audioZoneConfiguration version="1.0">
       <zone name="primary zone" isPrimary="true">
           <volumeGroups>
               <group>
                   <device address="bus0_media_out">
                       <context context="music"/>
                   </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"/>
                   </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>
           <displays>
                <display port="0"/>
           </displays>
       </zone>
        <zone name="rear seat zone">
           <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"/>
                   </device>
               </group>
           </volumeGroups>
           <displays>
               <display port="1"/>
           </displays>
    </zones>
</audioZoneConfiguration>

このプライマリ ゾーンには、個々のデバイスと、それぞれが持つコンテキストがあります。これにより、HAL は車両のハードウェアを使用して、さまざまな後処理効果を適用し、各デバイス出力にミキシングできます。デバイスは、メディア、ナビゲーション、通話、アラームの 4 つの音量グループに分類されています。システムが useFixedVolume に構成されている場合は、各グループの音量レベルが HAL に渡され、これらのデバイスの出力に適用されます。

セカンダリ ゾーンについては、1 つのヘッドフォン ジャックによる出力が想定されます。この例では、わかりやすくするために、すべての使用が 1 つのデバイスと音量グループにルーティングされます。

ゾーンごとにオプションのディスプレイ リストを含めることができます。各ディスプレイには物理ディスプレイ ポートが関連付けられています。これにより、アプリによっては、ターゲットとする特定のディスプレイに関連付けられたゾーンを照会できるようになります(以下を参照)。

新しい非表示 API(OEM とシステムアプリのみ)

Android 10 では、一連の非表示 API が CarAudioManager に導入され、アプリでオーディオ ゾーンとフォーカスを照会して設定できるようになりました。

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

アプリのゾーンの変更

デフォルトでは、すべての音声がプライマリ ゾーンにルーティングされます。別のゾーンにルーティングされるようにアプリを更新するには、setZoneIdForUid を使用します。

int zoneIdForDisplayId =
mCarAudioManager.getZoneIdForDisplay(selectedDisplay);

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"); }

注: ストリームでは、ゾーンを動的に切り替えることができません。したがって、ゾーンを変更するには、再生を停止する必要があります。