音量管理

AAOS には、CarAudioService 内の独自の音量管理があります。音量はソフトウェアではなくハードウェア アンプによって HAL の下に適用されることを想定して、固定音量が使用されます。また、出力デバイスを音量グループに整理し、音量グループに関連付けられたすべてのデバイスに同じゲインを適用します。

固定音量の使用

AAOS の実装では、ソフトウェア ミキサーの代わりにハードウェア アンプを使用して音量を調節する必要があります。想定外の事態を回避するには、config_useFixedVolume フラグを true に設定します(必要に応じてオーバーレイします)。

<resources>
    <!-- Car uses hardware amplifier for volume. -->
    <bool name="config_useFixedVolume">true</bool>
</resources>

config_useFixedVolume フラグが設定されていない(または false に設定されている)場合、アプリで AudioManager.setStreamVolume() を呼び出して、ソフトウェア ミキサーのストリーム タイプ別に音量を変更できます。これは他のアプリに影響を及ぼす可能性があり、ソフトウェア ミキサーで音量を下げると、ハードウェア アンプで受信した信号で利用できる有効ビットが少なくなるため、望ましくない場合があります。

音量グループ

音量グループは、オーディオ ゾーン内にあるデバイスの集合について、音量を管理します。音量グループごとに音量を個別に調節できます。結果的にゲインは関連するデバイスで設定され、車両のアンプによって適用されます。音量設定はユーザーに対して保持され、ユーザーがログインすると読み込まれます。

音量グループの定義

CarAudioService は、car_audio_configuration.xml で定義された音量グループを使用します。

<audioZoneConfiguration version="2.0">
    <zones>
        <zone name="primary zone" isPrimary="true">
            <volumeGroups>
                <group>
                    <device address="bus0_media_out">
                        <context context="music"/>
                    </device>
                </group>
                <group>
                    <device address="bus1_navigation_out">
                        <context context="navigation"/>
                    </device>
                    <device address="bus2_voice_command_out">
                        <context context="voice_command"/>
                    </device>
                </group>
                ...
            </volumeGroups>
        </zone>
     </zones>
</audioZoneConfiguration>

car_audio_configruation.xml 実装例。

各音量グループには、アドレスが関連付けられた出力デバイスを 1 つ以上含める必要があります。これらのアドレスは、audio_policy_configuration.xml で定義された出力デバイスに対応している必要があります。

音量グループのゲインの構成

各音量グループには、最小、最大、デフォルトのゲイン値とステップサイズがあります。これらは、音量グループに関連付けられたデバイスの audio_policy_configuration.xml で構成されている値に基づいて決定されます。

<devicePort tagName="bus0_media_out" role="sink" type="AUDIO_DEVICE_OUT_BUS" address="bus0_media_out">
  <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
  <gains>
    <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
      minValueMB="-3200" maxValueMB="600" defaultValueMB="0" stepValueMB="100"/>
  </gains>
</devicePort>

初期化の際、音量グループは関連するデバイスのゲイン値を確認し、グループを次のように構成します。

  • ステップサイズ: 音量グループによって調節されるすべてのデバイスで同じである必要があります
  • 最小ゲイン: グループ内のデバイスの最小ゲインのうち最小のもの
  • 最大ゲイン: グループ内のデバイスの最大ゲインのうち最大のもの
  • デフォルト ゲイン: グループ内のデバイスのデフォルト ゲインのうち最大のもの

これらの値の構成方法により、音量グループに関連付けられたデバイスでサポートされている範囲外の音量グループのゲインを設定できます。この場合、そのデバイスのゲインは、音量グループの値が範囲より上か下かに基づいて、デバイスの最小または最大ゲイン値に設定されます。

音量グループ ID

音量グループは、XML ファイル内での定義の順序によって実行時に識別されます。オーディオ ゾーン内の ID の範囲は 0 から N-1 です。ここで N は、そのゾーン内の音量グループの数です。このように、音量グループ ID はゾーン間で一意ではありません。これらの ID は、音量グループに関連付けられた CarAudioManager API に使用されます。zoneId なしで groupId を使用する API は、デフォルトでプライマリ オーディオ ゾーンになります。

マルチゾーン音量管理

各オーディオ ゾーンには音量グループが 1 つ以上必要であり、各音量グループは 1 つのオーディオ ゾーンにしか関連付けられません。この関係は、car_audio_configuration.xml の一部として定義されます。前述の音量グループの定義の例をご覧ください。

各ゾーンの現在の音量レベルは、そのゾーンに関連付けられているユーザーに対して保持されます。こうした設定はゾーン固有です。つまり、ユーザーがプライマリ ゾーンに関連付けられたゾーンにログインした後、セカンダリ オーディオ ゾーンに関連付けられたゾーンにログインする場合、最初のゾーン用に読み込まれ保持される音量レベルは、セカンダリ ゾーン用とは異なります。

音量キーイベントの処理

Android では、KEYCODE_VOLUME_UPKEYCODE_VOLUME_DOWNKEYCODE_VOLUME_MUTE など、音量調節用のいくつかのキーコードを定義しています。デフォルトでは、Android は音量キーイベントをアプリにルーティングします。Automotive の実装では、こうしたキーイベントを CarAudioService に対して強制実行する必要があります。その後、必要に応じて setGroupVolume または setMasterMute を呼び出すことができます。

この動作を強制するには、config_handleVolumeKeysInWindowManager フラグを true に設定します。

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

音量キーイベントには現在のところ、どのゾーンを対象としているかを区別する方法はなく、すべてがプライマリ オーディオ ゾーンに関連付けられていると仮定されます。音量キーイベントを受け取ると、CarAudioService はアクティブなプレーヤーのオーディオ コンテキストを取得してから、優先度が最も高いオーディオ コンテキストに関連付けられた出力デバイスを含む音量グループを調整することで、調整する音量グループを決定します。優先度は、CarVolume.AUDIO_CONTEXT_VOLUME_PRIORITY で定義された固定の順序に基づいて決定されます。

フェードとバランス

両バージョンの AudioControl HAL には、車両にフェードとバランスを設定するための API が含まれています。CarAudioManager 用の対応するシステム API があり、AudioControl HAL に値を渡します。これらの API には android.car.permission.CAR_CONTROL_AUDIO_VOLUME が必要です。

AudioControl API は次のとおりです。

  • setBalanceTowardRight(float value): スピーカーの音量を車両の右側(+)または左側(-)に切り替えます。0.0 は中央、+1.0 は完全右方、-1.0 は完全左方、-1~1 の範囲外の値はエラーです。
  • setFadeTowardFront(float value): スピーカーの音量を車両の前方(+)または後方(-)に切り替えます。0.0 は中央、+1.0 は完全前方、-1.0 は完全後方、-1~1 の範囲外の値はエラーです。

これらの値をどのように適用し、ユーザーに対しどのように表示するかについては、OEM が決定します。メディアに限定して適用することも、Android のすべてのサウンドに一律に適用することもできます。

また Android 11 では、出力デバイスに対するオーディオ エフェクトの適用がサポートされました。これにより、これらの API ではなく、該当する出力デバイスのオーディオ エフェクトを介して、フェードとバランスを管理できます。

オーディオ ダッキング

オーディオ ダッキングは、車両で 1 つのストリームのゲインを下げることで、同時に再生されている別のストリームを明瞭に聞こえるようにする際に発生します。OS で調節できない Android 以外のサウンドが多数存在する可能性があることから、AAOS では、他の音量を下げる機能の実装は HAL に任せられています。2 つの出力デバイスの両方にアクティブなストリームがあるかどうかということが、Android 11 で HAL がダッキングの判断を行うために利用できる主な情報です。

ダッキングするタイミング

HAL によるダッキングの処理方法は個々の OEM が決定しますが、おすすめの一般的なガイドラインがいくつかあります。Android 内で複数のストリームが再生されるのは、2 つのアプリやサービスが音声フォーカスを同時に保持している場合がほとんどです。これを踏まえて、Android が同時フォーカスを許可するタイミング、つまり異なる 2 つのストリームを同時に再生できるタイミングについては、インタラクション マトリックスをご覧ください。

Android で混合されるストリームは、ゲインが適用されるより前に混合されることに留意してください。そのため、別のストリームと同時に再生されたときにダッキングするストリームは、それらを混合する前に HAL がダッキングを適用できるように、別々の出力デバイスにルーティングする必要があります。

おすすめのダッキング動作

ダッキングを適用することをおすすめする同時インタラクションとしては、次のものが挙げられます。

  • EMERGENCY: ドライバーにサウンドが聞こえるように、SAFETY を除くすべてをダッキングまたはミュートする
  • SAFETY: ドライバーにサウンドが聞こえるように、EMERGENCY を除くすべてをダッキングする
  • NAVIGATION: SAFETYEMERGENCY を除くすべてをダッキングする
  • CALL: SAFETYEMERGENCYNAVIGATION を除くすべてをダッキングする
  • VOICE: CALL_RING をダッキングする
  • アクティブな VEHICLE_SOUNDS の重要性を判断し、ドライバーに聞こえるように他のサウンドをダッキングするかどうかは、OEM が決定します。
  • MUSICANNOUNCEMENT は、何に対してもダッキングされる必要があります。主な例外は、SYSTEM_SOUND として現在再生されているタッチ操作音です。

ダッキングする際のその他の考慮事項

一部のアプリやサービス(ナビゲーションやアシスタントなど)では、アクションを完了するために複数のプレーヤーを使用することがあります。OEM は、こうした出力デバイスからのストリーム データがいつ停止するかに基づいてダッキング解除しすぎないようにする必要があります。そうすることで、ナビゲーションまたはアシスタント アプリから次の再生が開始されてダッキングされる前に、ユーザーがメディアの音量を一時的に最大に戻さないようになります。

十分に隔離された複数のサウンド ステージを備えた車両の場合、ダッキングではなく、異なる車両エリアにオーディオをルーティングする方法もあります。たとえば、車内全体に音楽を通常の音量で再生し続けながら、ナビゲーションの案内をドライバーのヘッドレスト スピーカーにルーティングできます。

安全上重要なサウンド

Android 11 では HAL 音声フォーカス API が導入されましたが、安全上重要なサウンドを他より優先するかどうかは、依然として HAL 次第です。HAL が USAGE_EMERGENCY に音声フォーカスを保持していても、Android 内のアプリやサービスがサウンドを再生しないとは限りません。安全上重要なサウンドが再生されているときに Android からどのストリームを混合またはミュートするかは、HAL が決定します。

音量設定 UI の構成

AAOS では、音量設定 UI が音量グループの構成と切り離されています(「音量グループの構成」の説明に従ってオーバーレイできます)。そのため、将来的に音量グループの構成が変わっても変更は不要です。

車両設定 UI では、packages/apps/Car/Settings/res/xml/car_volume_items.xml ファイルには、定義された各 AudioAttributes.USAGE に関連付けられた UI 要素(タイトルとアイコン リソース)が含まれます。このファイルは、各 VolumeGroup に含まれる最初に認識された用途に関連付けられたリソースを使用して、定義された VolumeGroups の適切なレンダリングを可能にします。

たとえば次の例では、voice_communicationvoice_communication_signalling の両方を含む VolumeGroup を定義しています。車両設定 UI のデフォルトの実装では、voice_communication に関連付けられたリソースを使用して VolumeGroup をレンダリングします。これがファイル内で最初に一致するためです。

<carVolumeItems xmlns:car="http://schemas.android.com/apk/res-auto">
    <item car:usage="voice_communication"
          car:title="@*android:string/volume_call"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="voice_communication_signalling"
          car:title="@*android:string/volume_call"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="media"
          car:title="@*android:string/volume_music"
          car:icon="@*android:drawable/ic_audio_media"/>
    <item car:usage="game"
          car:title="@*android:string/volume_music"
          car:icon="@*android:drawable/ic_audio_media"/>
    <item car:usage="alarm"
          car:title="@*android:string/volume_alarm"
          car:icon="@*android:drawable/ic_audio_alarm"/>
    <item car:usage="assistance_navigation_guidance"
          car:title="@string/navi_volume_title"
          car:icon="@drawable/ic_audio_navi"/>
    <item car:usage="notification_ringtone"
          car:title="@*android:string/volume_ringtone"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="assistant"
          car:title="@*android:string/volume_unknown"
          car:icon="@*android:drawable/ic_audio_vol"/>
    <item car:usage="notification"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_communication_request"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_communication_instant"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_communication_delayed"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="notification_event"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="assistance_accessibility"
          car:title="@*android:string/volume_notification"
          car:icon="@*android:drawable/ic_audio_ring_notif"/>
    <item car:usage="assistance_sonification"
          car:title="@*android:string/volume_unknown"
          car:icon="@*android:drawable/ic_audio_vol"/>
    <item car:usage="unknown"
          car:title="@*android:string/volume_unknown"
          car:icon="@*android:drawable/ic_audio_vol"/>
</carVolumeItems>

上の構成で使用される属性と値は packages/apps/Car/Settings/res/values/attrs.xml で宣言されています。音量設定 UI は、次の VolumeGroup ベースの CarAudioManager API を使用します。

  • getVolumeGroupCount(): 描画するコントロールの数を確認します。
  • getGroupMinVolume()getGroupMaxVolume(): 下限値と上限値を取得します。
  • getGroupVolume(): 現在の音量を取得します。
  • registerVolumeChangeObserver(): 音量の変更に関する通知を受け取ります。