オーディオ コントロール HAL

オーディオ コントロール HAL は、自動車関連のオーディオ ユースケースをサポートするために Android 9 で導入されました。Android 14 の時点で、オーディオ コントロール HAL は以下をサポートしています。

  • フェードとバランス
  • HAL 音声フォーカス リクエスト
  • デバイスのミュートとダッキング
  • オーディオ デバイスのゲイン変更
  • オーディオ ポート構成の変更

図 1 は、カーオーディオ サービスがオーディオ コントロール HAL と通信する、カーオーディオ サービス アーキテクチャの概要を示しています。

マルチゾーン オーディオの構成

図 1. マルチゾーン オーディオの構成

オーディオのフェードとバランス

HIDL オーディオ コントロール HAL バージョン 1 は、自動車ユースケースでのオーディオのフェードとバランスをサポートするために Android 9 で導入されました。Android ですでに提供されている一般的なオーディオ エフェクトとは別に、このメカニズムによりシステムアプリは CarAudioManager API を通じてオーディオのバランスとフェードを設定できるようになります。

class CarAudioManager {
       /**
       *   Adjust the relative volume in the front vs back of the vehicle cabin.
       *
       *   @param value in the range -1.0 to 1.0 for fully toward the back through
       *   fully toward the front. 0.0 means evenly balanced.
       */
       @SystemApi
       @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME)
       public void setFadeTowardFront(float value);

       /**
       *   Adjust the relative volume on the left vs right side of the vehicle cabin.
       *
       *   @param value in the range -1.0 to 1.0 for fully toward the left through
       *   fully toward the right. 0.0 means evenly balanced.
       */
       @SystemApi
       @RequiresPermission(Car.PERMISSION_CAR_CONTROL_AUDIO_VOLUME)
       public void setBalanceTowardRight(float value);
}

これらの API が呼び出されると、カーオーディオ サービスからそれぞれのオーディオ コントロール HAL API が呼び出されます。

interface IAudioControl {
       /**
       *   Control the right/left balance setting of the car speakers.
       */
       oneway setBalanceTowardRight(float value);

       /**
       *   Control the fore/aft fade setting of the car speakers.
       */
       oneway setFadeTowardFront(float value);
}

API は、新しい AIDL HAL インターフェースを含むオーディオ コントロール HAL のすべてのバージョンで利用可能です。

HAL からの音声フォーカス リクエスト

AAOS は、Android 同様、車内でのオーディオ再生を管理するために、音声フォーカスに関するアプリの積極的な参加に依存しています。フォーカス情報は、音量やダッキングを制御するストリームを管理するために使用されます。そのため、音声フォーカスをさらに拡張し、車固有のサウンドを Android エクスペリエンスによりよく統合するために、Android 11 では以下のオーディオ属性が導入されました。

  • EMERGENCY
  • SAFETY
  • VEHICLE_STATUS
  • ANNOUNCEMENT

この変更に加え、Android の外部からのサウンドが音声フォーカス リクエストに参加できるメカニズムが追加されました。そのため、Android の外部からのフォーカス リクエストを可能にするために、HIDL オーディオ コントロール HAL バージョン 2 が導入されました。

interface IAudioControl {
       /**
       *   Registers focus listener to be used by HAL for requesting and
       *   abandoning audio focus.
       *   @param listener the listener interface
       *   @return closeHandle A handle to unregister observer.
       */
       registerFocusListener(IFocusListener listener)
       generates (ICloseHandle closeHandle);

       /**
       *   Notifies HAL of changes in audio focus status for focuses requested
       *   or abandoned by the HAL.
       *
       *   @param usage The audio usage associated with the focus change
       *   @param zoneId The identifier for the audio zone that the HAL is
       *   playing the stream in
       *   @param focusChange the AudioFocusChange that has occurred
       */
       oneway onAudioFocusChange(bitfield<AudioUsage> usage, int32_t zoneId,
       bitfield<AudioFocusChange> focusChange);
}

IFocusListener は次のように定義されます。

interface IFocusListener {
       /**
       *   Called whenever HAL is requesting focus as it is starting to play
       *   audio of a given usage in a specified zone.
       *
       *   @param usage The audio usage associated with the focus request
       *    {@code AttributeUsage}
       *   @param zoneId The identifier for the audio zone where the HAL is
       *    requesting focus
       *   @param focusGain The AudioFocusChange associated with this request.
       */
       oneway requestAudioFocus(bitfield<AudioUsage> usage,
       int32_t zoneId, bitfield<AudioFocusChange> focusGain);
       /**
       *   Called whenever HAL is abandoning focus as it is finished playing audio
       *   of a given usage in a specific zone.
       *
       *   @param usage The audio usage for which the HAL is abandoning focus
       *    {@code AttributeUsage}
       *   @param zoneId The identifier for the audio zone that the HAL
       *    abandoning focus
       */
       oneway abandonAudioFocus(bitfield<AudioUsage> usage, int32_t zoneId);
}

上記の API を使用して、HAL からの音声フォーカスをそれぞれリクエストしたり、放棄したりできます。これに対して、カーオーディオ サービスは音声フォーカス リクエストを検討し、結果を IAudioControl#onAudioFocusChange メソッドに非同期で転送します。

この API は、オーディオ コントロール HAL からの音声フォーカス リクエストの変化をモニタリングするために使用することもできます。一般に、HAL からの音声フォーカス リクエストはすべてアクティブとみなされます。これは、対応するアクティブなオーディオ トラックの再生のみがアクティブとみなされる Android からの音声フォーカス リクエストとは異なります。

HIDL から AIDL オーディオ コントロール HAL への移行

AIDL の登場と Android 12 で必要な移行(詳しくは HAL 用の AIDL を参照)に伴い、オーディオ コントロール HAL は AIDL に移行されました。既存の HIDL オーディオ コントロール バージョン 2 の API については、移行に伴い既存のメソッドのマイナー アップデートが必要になりました。

interface IAudioControl {
       /**
       *   Notifies HAL of changes in audio focus status for focuses requested
       *   or abandoned by the HAL.
       *
       *   @param usage The audio usage associated with the focus change
       *        {@code AttributeUsage}. See {@code audioUsage} in
       *        audio_policy_configuration.xsd for the list of allowed values.
       *   @param zoneId The identifier for the audio zone that the HAL is
       *        playing the stream in
       *   @param focusChange the AudioFocusChange that has occurred.
       */
       oneway void onAudioFocusChange(in String usage, in int zoneId,
              in AudioFocusChange focusChange);
       /**
       *   Registers focus listener to be used by HAL for requesting and
       *   abandoning audio focus.
       *   @param listener the listener interface.
       */
       oneway void registerFocusListener(in IFocusListener listener);
       /**
       *   Control the right/left balance setting of the car speakers.
       */
       oneway void setBalanceTowardRight(in float value);
       /**
       *   Control the fore/aft fade setting of the car speakers.
       */
       oneway void setFadeTowardFront(in float value);
}

対応する IFocusListener:

       interface IFocusListener {
       /**
       *   Called whenever HAL is abandoning focus as it is finished playing audio
       *   of a given usage in a specific zone.
       *
       *   @param usage The audio usage for which the HAL is abandoning focus
       *        {@code AttributeUsage}. See {@code audioUsage} in
       *        audio_policy_configuration.xsd for the list of allowed values.
       *   @param zoneId The identifier for the audio zone that the HAL
       *        abandoning focus
       */
       oneway void abandonAudioFocus(in String usage, in int zoneId);
       /**
       *   Called whenever HAL is requesting focus as it is starting to play audio
       *        of a given usage in a specified zone.
       *
       *   @param usage The audio usage associated with the focus request
       *        {@code AttributeUsage}. See {@code audioUsage} in
       *        audio_policy_configuration.xsd for the list of allowed values.
       *   @param zoneId The identifier for the audio zone where the HAL is
       *        requesting focus
       *   @param focusGain The AudioFocusChange associated with this request.
       */
       oneway void requestAudioFocus(in String usage, in int zoneId,
              in AudioFocusChange focusGain);
}

音量グループ ミュート

Android 12 では、ユーザーのオーディオ操作中により包括的なミュート コントロールを可能にするため、音量グループ ミュートが導入されました。これにより、オーディオ・コントロール HAL は、カーオーディオ サービスによってインターセプトされたミュート イベントを受け取れるようになります。

この機能を有効にするには、OEM はカーサービス config.xml 内で audioUseCarVolumeGroupMuting 構成を true に設定する必要があります。

<!-- Configuration to enable muting of individual volume groups.
If this is set to false, muting of individual volume groups is disabled,
instead muting will toggle master mute. If this is set to true, car volume
group muting is enabled and each individual volume group can be muted separately. -->
<bool name="audioUseCarVolumeGroupMuting">true</bool>

Android 13 より前では、packages/services/Car/service/res/values/config.xml のランタイム リソース オーバーレイで構成を上書きする必要がありました(詳しくは、リソース オーバーレイを使用してビルドをカスタマイズするをご覧ください)。Android 13 からは、ランタイム リソース オーバーレイを使用して構成値を変更できます。詳しくは、実行時にアプリのリソースの値を変更するをご覧ください。

システムアプリは、CarAudioManager#isAudioFeatureEnabled API を使用することで、この機能が有効かどうかを判断できます。渡されるパラメータは、CarAudioManager.AUDIO_FEATURE_VOLUME_GROUP_MUTING 定数でなければなりません。このメソッドは、その機能がデバイスで有効になっていれば true を返し、有効でなければ false を返します。

audioUseCarVolumeGroupMuting 機能を有効にすることに加えて、AIDL オーディオ コントロール HAL は、音量グループ ミュート メカニズムを実装する必要があります

interface IAudioControl {
       /**
       *   Notifies HAL of changes in output devices that the HAL should apply
       *   muting to.
       *
       *   This will be called in response to changes in audio mute state for each
       *   volume group and will include a {@link MutingInfo} object per audio
       *   zone that experienced a mute state event.
       *
       *   @param mutingInfos an array of {@link MutingInfo} objects for the audio
       *   zones where audio mute state has changed.
       */
       oneway void onDevicesToMuteChange(in MutingInfo[] mutingInfos);
}

ミュート情報は、関連するオーディオ システムのミュート情報を含みます。

parcelable MutingInfo {
       /**
       *   ID of the associated audio zone
       */
       int zoneId;
       /**
       *   List of addresses for audio output devices that should be muted.
       */
       String[] deviceAddressesToMute;
       /**
       *   List of addresses for audio output devices that were previously be
       *   muted and should now be unmuted.
       */
       String[] deviceAddressesToUnmute;
}

AAOS には以下に基づく 2 つの異なるミュートのメカニズムがあります。

  • オーディオ KEYCODE_VOLUME_MUTE {:.external} を使用するキーイベント。

  • カーオーディオ マネージャー ミュート API CarAudioManager#setVolumeGroupMute を使用した、カーオーディオ サービスの直接呼び出し。

有効になっている場合、両メカニズムはオーディオ コントロール HAL への通話ミュートをトリガーします。

カーオーディオ ダッキング

Android 12 では、オーディオ ストリームの同時再生制御を最適化するために、カーオーディオ ダッキングが導入されました。これにより、OEM はカーオーディオ サービスによって決定される、車の物理的なオーディオ構成と現在の再生状態に基づいて、独自のダッキング動作を実装できます。

ダッキング メカニズムは音声フォーカス スタックの変更に基づきます。フォーカスの変更が発生するたびに(フォーカス リクエストかフォーカス放棄かを問わず)、オーディオ コントロール HAL に通知されます。カー音量グループのミュート サポートと同様に、カーオーディオのダッキングは audioUseHalDuckingSignals 構成フラグで有効にできます。

<!-- Configuration to enable IAudioControl#onDevicesToDuckChange API to
inform HAL when to duck. If this is set to true, the API will receive signals
indicating which output devices to duck as well as what usages are currently
holding focus. If set to false, the API will not be called. -->
<bool name="audioUseHalDuckingSignals">true</bool>

機能を有効にするために、AIDL オーディオ コントロール HAL は、カーオーディオ サービスから受け取るシグナルで関連するロジックを実装する必要があります。

interface IAudioControl {
       /**
       *   Notifies HAL of changes in output devices that the HAL should apply
       *   ducking to.
       *
       *   This will be called in response to changes in audio focus, and will
       *   include a {@link DuckingInfo} object per audio zone that experienced
       *   a change in audo focus.
       *
       *   @param duckingInfos an array of {@link DuckingInfo} objects for the
       *   audio zones where audio focus has changed.
       */
       oneway void onDevicesToDuckChange(in DuckingInfo[] duckingInfos);
}

関連するオーディオ システム情報はオーディオ ダッキング情報に含まれています。

parcelable DuckingInfo {
       /**
       *   ID of the associated audio zone
       */
       int zoneId;
       /**
       *   List of addresses for audio output devices that should be ducked.
       */
       String[] deviceAddressesToDuck;
       /**
       *   List of addresses for audio output devices that were previously be
       *   ducked and should now be unducked.
       */
       String[] deviceAddressesToUnduck;
       /**
       *   List of usages currently holding focus for this audio zone.
       */
       String[] usagesHoldingFocus;
}

ダッキング情報には、ダッキング(解除)するデバイス アドレスに含まれるカーオーディオ構成情報のほかに、どのオーディオ属性の用途がフォーカスされているかという情報も含まれます。このデータの目的は、どのオーディオ属性の用途がアクティブであるかをオーディオ システムに知らせることです。

カーオーディオ構成では、1 つのデバイスに複数のオーディオ属性を割り当てられるため、追加情報がないとどの用途がアクティブなのかが明確にならないからです。

AIDL オーディオ コントロール HAL 2.0

API を更新し、新機能を促進するために、Android 13 で AIDL オーディオ コントロール HAL はバージョン 2.0 に更新されました。

  • PlaybackTrackMetadata での音声フォーカス
  • オーディオ ゲイン コールバック

再生メタデータは android.hardware.audio.common で次のように定義されます。

parcelable PlaybackTrackMetadata {
       AudioUsage usage = INVALID;
       AudioContentType contentType = UNKNOWN;
       float gain;
       AudioChannelLayout channelMask;
       AudioDevice sourceDevice;
       String[] tags;
}

AIDL オーディオ コントロール バージョン 1.0 の他のすべての機能は残っており、使用できます。例外は、音声フォーカスの変更方法についてで説明されている音声フォーカス変更メソッドに関するものです。

再生トラック メタデータでのオーディオ コントロール フォーカス

HAL の下のオーディオ システムにより多くの情報を公開するため、アップデートにより PlaybackTrackMetadata が公開されるようになりました。具体的には、オーディオ コントロール HAL が新しいメソッドで拡張されました。

interface IAudioControl {
       /**
       *   Notifies HAL of changes in audio focus status for focuses requested
       *   or abandoned by the HAL.
       *
       *   The HAL is not required to wait for a callback of AUDIOFOCUS_GAIN
       *   before playing audio, nor is it required to stop playing audio in the
       *   event of a AUDIOFOCUS_LOSS callback is received.
       *
       *   @param playbackMetaData The output stream metadata associated with
       *    the focus request
       *   @param zoneId The identifier for the audio zone that the HAL is
       *    playing the stream in
       *   @param focusChange the AudioFocusChange that has occurred.
       */
       oneway void onAudioFocusChangeWithMetaData(
       in PlaybackTrackMetadata playbackMetaData, in int zoneId,
       in AudioFocusChange focusChange);
}

IFocusListener に同様の対応する変更が加えられます。

       /**
       *   Called to indicate that the audio output stream associated with
       *   {@link android.hardware.audio.common.PlaybackTrackMetadata} is
       *   abandoning focus as playback has stopped.
       *
       *   @param playbackMetaData The output stream metadata associated with
       *    the focus request
       *   @param zoneId The identifier for the audio zone that the HAL
       *    abandoning focus
       */
       oneway void abandonAudioFocusWithMetaData(
       in PlaybackTrackMetadata playbackMetaData, in int zoneId);
       /**
       *   Called to indicate that the audio output stream associated with
       *   {@link android.hardware.audio.common.PlaybackTrackMetadata} has taken
       *   the focus as playback is starting for the corresponding stream.
       *
       *   @param playbackMetaData The output stream metadata associated with
       *    the focus request
       *   @param zoneId The identifier for the audio zone that the HAL
       *    abandoning focus
       *   @param focusGain The focus type requested.
       */
       oneway void requestAudioFocusWithMetaData(
       in PlaybackTrackMetadata playbackMetaData, in int zoneId,
       in AudioFocusChange focusGain);
}

音声フォーカスの変更方法について

上記のフォーカス操作は、HAL からの音声フォーカス リクエストに記載の操作と同じです。再生トラック メタデータのみが、オーディオ属性の用途とともにより多くの情報を持っています。一般的に、再生トラック メタデータによって提供される追加情報が必要とされない限り、アップデートされた Android コントロール HAL で以前のメソッドを使い続けられます。

HAL のデベロッパーが IAudioControl#onAudioFocusChangeWithMetaData をサポートしないと決定した場合、このメソッドは、バージョン管理されたインターフェースの使用に記載されているように、UNKNOWN_TRANSACTION エラーで結果を返す必要があります。

オーディオ サービスはまず onAudioFocusChangeWithMetaData を呼び出し、結果が UNKNOWN_TRANSACTION で失敗となった場合は onAudioFocusChange メソッドで再度試行します。

再生トラック メタデータでのカーオーディオ ダッキング

AIDL オーディオ コントロール HAL のバージョン 2.0 では、オーディオ ダッキング情報に再生トラックのメタデータが追加されました。

parcelable DuckingInfo {
       /**
       *   ID of the associated audio zone
       */
       int zoneId;
       /**
       *   List of addresses for audio output devices that should be ducked.
       */
       String[] deviceAddressesToDuck;
       /**
       *   List of addresses for audio output devices that were previously be
       *   ducked and should now be unducked.
       */
       String[] deviceAddressesToUnduck;
       /**
       *   List of usages currently holding focus for this audio zone.
       */
       String[] usagesHoldingFocus;
       /**
       *   List of output stream metadata associated with the current focus
       *   holder for this audio zone
       */
       @nullable PlaybackTrackMetadata[] playbackMetaDataHoldingFocus;
}

usagesHoldingFocus が非推奨となりました。デベロッパーは、playbackMetaDataHoldingFocus を使用してオーディオ属性の用途やその他のオーディオ情報を判断する必要があります。ただし、このオプションが正式に削除されるまでは、usagesHoldingFocus パラメータに必要な情報が引き続き含まれます。

オーディオ ゲイン コールバック

Android 13 では、HAL の下のオーディオの変更が AAOS でよりわかりやすくなるように、車のオーディオ システムからカーオーディオ サービスにオーディオ ゲインの変更を伝えるために使用できるメカニズムを追加しました。このメカニズムは、オーディオ ゲイン音量インデックスの変更を、ゲインが変更されたその理由とともに公開します。

  • ブロックまたはミュートされた制限
  • 制約、制限
  • 減衰の制限

これらの変更は、これらの制限を HAL の下からカーオーディオ サービスに公開し、最終的にシステム UI アプリに公開してユーザーに通知します。後半のシステム UI への公開は Android 14 でさらに拡張され、音量グループ情報のコールバック メカニズムを通じて、システム UI アプリがより簡単にこの情報を取得できるようになりました。

オーディオ コントロール HAL API は次のようにゲイン コールバックを登録します。

interface IAudioControl {
       /**
       *   Registers callback to be used by HAL for reporting unexpected gain(s)
       *    changed and the reason(s) why.
       *
       *   @param callback The {@link IAudioGainCallback}.
       */
       oneway void registerGainCallback(in IAudioGainCallback callback);
}

IAudioGainCallback は次のように定義されます。

interface IAudioGainCallback {
       /**
       *   Used to indicate that one or more audio device port gains have changed,
       *   i.e. initiated by HAL, not by CarAudioService.
       *   This is the counter part of the
       *   {@link onDevicesToDuckChange}, {@link onDevicesToMuteChange} and,
       *   {@link setAudioDeviceGainsChanged} APIs.
       *
       *   @param reasons List of reasons that triggered the given gains changed.
       *   @param gains List of gains affected by the change.
       */
       void onAudioDeviceGainsChanged(in Reasons[] reasons,
       in AudioGainConfigInfo[] gains);
}

API ドキュメントで強調されているように、ゲイン コールバックはカーオーディオ サービスによってオーディオ コントロール HAL に登録されます。API がオーディオ コントロール HAL から呼び出されると、カーオーディオ サービスは対応するアクション(ゲイン インデックスのブロック、制限、減衰など)で応答します。

HAL は、主にゲイン インデックスのステータスの変更を報告するために、API をいつ呼び出すかを決定します。特に規則要件では、車のオーディオ システムは必要なアクションを取り、コールバックを使用してカーオーディオ サービスに情報を報告し、ユーザーが消費できるようにする必要があります。たとえば、ユーザーに対して UI を表示します。

AIDL オーディオ コントロール HAL 3.0

より堅牢なオーディオ ゲイン インデックス機能を提供できるように API を更新するため、Android 14 AIDL オーディオ コントロール HAL バージョンはバージョン 3.0 に更新されます。オーディオ コントロール HAL API は、オーディオ サービスが IModuleChangeCallback を設定および設定解除できるようにします。

interface IAudioControl {
       /**
       *   Sets callback with HAL for notifying changes to hardware module
       *   (that is: {@link android.hardware.audio.core.IModule}) configurations.
       *
       *   @param callback The {@link IModuleChangeCallback} interface to use
       *    use when new updates are available for
       */
       void setModuleChangeCallback(in IModuleChangeCallback callback);
       /**
       *   Clears module change callback
       */
       void clearModuleChangeCallback();
}

setModuleChangeCallback は、カーオーディオ サービスの起動時やエラーからの復帰時に、カーオーディオ サービスによって登録されます。たとえば、カーオーディオ サービスが受信したオーディオ コントロール HAL バインダ終了通知などです。API が呼び出された場合、オーディオ コントロール HAL の実装は既存のモジュール変更コールバックを置き換える必要があります。

clearModuleChangeCallback API については、実装は、既存のコールバックを消去し、コールバックが存在しない場合は何もしない必要があります。オーディオ コントロールの実装では、コールバックの終了オブザーバーを登録し、バインダの終了がトリガーされたらコールバックを消去するのがおすすめです。

IModuleChangeCallback は次のように定義されます。

oneway interface IModuleChangeCallback {
       /**
       *   Used to indicate that one or more {@link AudioPort} configs have
       *   changed. Implementations MUST return at least one AudioPort.
       *
       *   @param audioPorts list of {@link AudioPort} that are updated
       */
       void onAudioPortsChanged(in AudioPort[] audioPorts);
}

モジュール変更コールバックは、カーオーディオ サービスによって登録される場合、onAudioPortChanged API を通じてオーディオ ポートの変更を受け取る準備ができています。この API は、コールバックが登録されるとすぐに、オーディオ システムの音量ゲインを初期化するために使用できます。その他の動的なゲイン変更については、API はいつでも呼び出せます。対応する変更が適用され、それに応じてカーオーディオ サービスが更新されます。