音声フォーカス

論理ストリームを開始する前に、アプリは論理ストリームに使用されるものと同じオーディオ属性を使用して、音声フォーカスをリクエストします。アプリはフォーカス喪失を尊重して、自動車のユースケースで求められるとおりに実行する必要があります。

フォーカス リクエストの送信は推奨されますが、システム側で実行されることはありません。このため、フォーカスはメインのオーディオ コントロール メカニズムではなく、再生を間接的に制御し、競合を解消するための方法と考えてください。車両におけるオーディオ サブシステムのオペレーションをフォーカス システムに依存してはいけません。

フォーカス インタラクション

AAOS をサポートするために、音声フォーカス リクエストは、リクエストの CarAudioContext と現在のフォーカス ホルダーの間で、事前定義されたインタラクションに基づいて処理されます。インタラクションには次の 3 つのタイプがあります。

  • 排他的
  • 拒否
  • 同時

排他的インタラクション

これは Android でよく使用されるインタラクション モデルです。

排他的インタラクションでは、一度に 1 つのアプリのみがフォーカスを保持できます。したがって、既存のフォーカス ホルダーがフォーカスを失っている間、受信フォーカス リクエストにフォーカスが付与されます。どちらのアプリでもメディアを再生するため、1 つのアプリのみフォーカスの保持が許可されます。その結果、新たに開始されたアプリのフォーカス リクエストは AUDIOFOCUS_REQUEST_GRANTED で返され、現在音楽を再生しているアプリは、そのリクエストの種類に応じた喪失ステータスのフォーカス変更イベントを受け取ります。

拒否インタラクション

拒否インタラクションでは、受信リクエストが常に拒否されます。たとえば、通話中に音楽を再生しようとした場合が挙げられます。この場合、電話が通話の音声フォーカスを保持している状態で、2 つ目のアプリが音楽を再生するためにフォーカスをリクエストすると、音楽アプリはそのリクエストに対して AUDIOFOCUS_REQUEST_FAILED を受け取ります。フォーカス リクエストは拒否されるため、現在のフォーカス ホルダーにはフォーカス喪失はディスパッチされません。

同時インタラクション

AAOS に固有のインタラクションは同時インタラクションです。これにより、車内で音声フォーカスをリクエストするアプリは、他のアプリと同時にフォーカスを保持できます。同時インタラクションを行うには、次の条件を満たしている必要があります。

これらの基準を満たすと、フォーカス リクエストは AUDIOFOCUS_REQUEST_GRANTED で返され、現在のフォーカス ホルダーのフォーカスは変更されません。ただし、現在のフォーカス ホルダーがダッキング イベントの受け取り、またはダッキング時の一時停止を選択した場合、現在のフォーカス ホルダーは、排他的インタラクションのようにフォーカスを失います。

同時ストリームの処理

同時インタラクションには数多くの用途がありますが、出力デバイス全体のハードウェア レベルでのミキシングとダッキングは慎重に行う必要があります。CarAudioContext で同時再生を許可する場合は、異なる出力デバイスにルーティングすることを強くおすすめします。

同時ストリーム用に個別の出力デバイスがあれば、ミキシングする前に HAL でいずれかのストリームをダッキングしたり、車内の異なるスピーカーに物理ストリームをルーティングしたりできます。論理ストリームが Android 内で混在している場合、ゲインは変わらず、同じ物理ストリームの一部として配信されます。

たとえば、ナビゲーションとメディアが同時に配信される場合、ナビゲーションの案内が明瞭に聞こえるように、メディア ストリームのゲインを一時的に低減(ダッキング)できます。または、ナビゲーション ストリームを運転席側スピーカーにルーティングし、車内のそれ以外の部分ではメディアの再生を継続できます。

インタラクション マトリックス

次の表は、CarAudioService で定義されるインタラクション マトリックスを示しています。各行は現在のフォーカス ホルダーの CarAudioContext、各列はその受信リクエストを示しています。

たとえば、音楽メディアアプリがフォーカスを保持しているときにナビゲーション アプリがフォーカスをリクエストした場合、マトリックスでは 2 つのインタラクションは同時に再生されることを示しています。これは同時インタラクションの他の条件を満たしていることが前提となります。

同時インタラクションにより、複数のフォーカス ホルダーが可能となります。この場合、適用するインタラクションを決定する前に、受信フォーカス リクエストが現在の各フォーカス ホルダーと比較されます。その際、最も保守的なインタラクションが優先されます。優先順位は拒否、次に排他的、最後に同時となります。

図 1. 音声フォーカスのインタラクション マトリックス

Android 11 では、新しいユーザー設定が導入され、ナビゲーションと通話のインタラクション動作をユーザーが変更できるようになりました。これを設定すると、android.car.KEY_AUDIO_FOCUS_NAVIGATION_REJECTED_DURING_CALL は受信した NAVIGATION フォーカス リクエストと現在の CALL フォーカス ホルダーの間のインタラクションを同時から拒否に変更します。ユーザーがナビゲーション通知により通話が邪魔されないようにしたい場合は、設定を有効にできます。この設定はそのユーザーに対して保持され、その後のフォーカス リクエストが新しい設定を尊重するように、動的に設定できます。

遅延可能な音声フォーカス

Android 11 では、遅延可能な音声フォーカスのリクエストのサポートが AAOS に追加されました。これにより、通常であれば現在のフォーカス ホルダーとのインタラクションが拒否される場合に、一時的でないフォーカス リクエストを遅延できます。フォーカスの変更により、遅延リクエストがフォーカスを保持できる状態になると、リクエストが許可されます。

遅延音声フォーカス リクエストのルール

  • 一時的でないリクエストのみ。遅延リクエストは一時的でないソースに対してのみ実行できます。これは一時的なサウンドが関係するタイミングから時間が経った後で再生されることを防ぐためです。

  • 遅延できるリクエストは一度に 1 つのみ。遅延リクエストがすでにある状態で遅延可能リクエストが実行されると、元の遅延リクエストは、AUDIOFOCUS_LOSS 変更イベントを受信し、新しいリクエストは AUDIOFOCUS_REQUEST_DELAYED の同期レスポンスを受信します。

  • 遅延可能なリクエストには OnAudioFocusChangeListener がある必要がある。リクエストが遅延すると、最終的にリクエストが許可されたとき(AUDIOFOCUS_GAIN)、または後で拒否されたとき(AUDIOFOCUS_LOSS)に、リスナーを使用してリクエスト元に通知されます。

遅延可能なフォーカスをリクエストする

遅延可能なリクエストは次のように作成します。

  1. AudioFocusRequest.Builder#setAcceptsDelayedFocusGain を実行します。

    mMediaWithDelayedFocusListener = new MediaWithDelayedFocusListener();
    
    mDelayedFocusRequest = new AudioFocusRequest
         .Builder(AudioManager.AUDIOFOCUS_GAIN)
         .setAudioAttributes(mMusicAudioAttrib)
         .setOnAudioFocusChangeListener(mMediaWithDelayedFocusListener)
         .setForceDucking(false)
         .setWillPauseWhenDucked(false)
         .setAcceptsDelayedFocusGain(true)
         .build();
    
  2. リクエストを行う際に AUDIOFOCUS_REQUEST_DELAYED レスポンスを処理します。

    int delayedFocusRequestResults = mAudioManager.requestAudioFocus(mDelayedFocusRequest);
    if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
        // start audio playback
        return;
    }
    if (delayedFocusRequestResults == AudioManager.AUDIOFOCUS_REQUEST_DELAYED) {
         // audio playback delayed to audio focus listener
         return;
    }
    
  3. リクエストが遅延すると、フォーカス リスナーがフォーカスの変化を処理します。

    private final class MediaWithDelayedFocusListener implements
    OnAudioFocusChangeListener {
           @Override
           public void onAudioFocusChange(int focusChange) {
               synchronized (mLock) {
                   switch (focusChange) {
                       case AudioManager.AUDIOFOCUS_GAIN:
                           … // Start focus playback
                       case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                           … // Pause media transiently
                       case AudioManager.AUDIOFOCUS_LOSS:
                           … // Stop media
    

マルチゾーン フォーカス管理

オーディオ ゾーンが複数ある車両の場合、音声フォーカスはゾーンごとに個別に管理されます。そのため、あるゾーンへのリクエストでは、他のゾーンでフォーカスを保持しているものは考慮されず、他のゾーンのフォーカス ホルダーがフォーカスを失うこともありません。これにより、メインのキャビンのフォーカスを後部座席のエンターテイメント システムとは別に管理できるため、あるゾーンでのフォーカスの変更によって別のゾーンでのオーディオ再生が中断されることはありません。

すべてのアプリで、CarAudioService が自動的にフォーカスを管理します。フォーカス リクエストのオーディオ ゾーンは関連する UserId または UID に基づき決定されます(詳細はマルチゾーン オーディオ ルーティングをご覧ください)。

複数のゾーンから同時にオーディオをリクエストする

アプリが複数のゾーンで同時にオーディオを再生する場合は、次のようにバンドルに AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID を含めて、ゾーンごとにフォーカスをリクエストする必要があります。

//Create attribute with bundle and AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID
Bundle bundle = new Bundle();
bundle.putInt(CarAudioManager.AUDIOFOCUS_EXTRA_REQUEST_ZONE_ID,
               zoneId);

AudioAttributes attributesWithZone = new AudioAttributes.Builder()
     .setUsage(AudioAttributes.USAGE_MEDIA)
     .addBundle(bundle)
     .build();

//Create focus request using built attributesWithZone

このバンドル パラメータにより、リクエスト元はオーディオ ゾーンの自動マッピングをオーバーライドして、代わりに指定したゾーン ID を使用できます。したがって、アプリはオーディオ ゾーンごとに個別のリクエストを発行できます。

HAL 音声フォーカス

Android 11 以降、外部ストリームに代わって HAL がフォーカスをリクエストできます。この API の使用は任意ですが、外部サウンドを Android エコシステムに参加しやすくし、シームレスなユーザー エクスペリエンスを実現するために、使用することを強くおすすめします。

HAL は優先するサウンドに関して最終的な決定を行います。この点で、緊急のサウンドと安全上重要なサウンドは、HAL が音声フォーカスを付与されたかどうかにかかわらず再生する必要があり、HAL が音声フォーカスを失っても、必要に応じて再生され続ける必要があります。法規制で定められているサウンドについても同じことが言えます。

HAL は緊急のサウンドと安全上重要なサウンドを再生する際、Android ストリームを必要に応じて自発的にミュートし、明瞭に聞こえるようにする必要があります。

AudioControl@2.0

AudioControl HAL のバージョン 2.0 では、次の新しい API が導入されています。

API 目的
IAudioControl#registerFocusListener AudioControl HAL に IFocusListener のインスタンスを登録します。このリスナーにより、HAL は音声フォーカスのリクエストと破棄ができます。HAL はリスナーの登録解除のために Android で使用される ICloseHandle インスタンスを提供します。
IAudioControl#onAudioFocusChange HAL によって IFocusListener を介して行われたフォーカス リクエストに対するステータスの変更について、最初のフォーカス リクエストに対するレスポンスも含め、HAL に通知します。
IFocusListener#requestAudioFocus 指定された用途、ゾーン ID、フォーカス ゲイン タイプについて、HAL に代わってフォーカスをリクエストします。
IFocusListener#abandonAudioFocus 指定された用途とゾーン ID に対する既存の HAL フォーカス リクエストを破棄します。

HAL は同時に複数のフォーカス リクエストを実行できますが、用途とゾーン ID のペアごとに 1 つのリクエストに限られます。Android では、リクエストが行われるとすぐに HAL がその用途のサウンドの再生を開始し、フォーカスが破棄されるまで再生を継続すると想定しています。

registerFocusListener を除き、こうしたリクエストは oneway であり、フォーカス リクエストの処理中に Android が HAL を遅延させないようにします。HAL は安全上重要なサウンドを再生する前にフォーカスの取得を待つべきではありません。オプションで HAL は IAudioControl#onAudioFocusChange を通じて音声フォーカスの変化をリッスンし、応答できます。

OEM 車両音声フォーカス サービス

Android 14 では、AAOS は車の OEM プラグイン サービスを導入し、一部の車両コンポーネントの設定ができるようにしています。カーオーディオのプラグイン サービスでは、OEM はカーオーディオ サービスによりインターセプトされたフォーカス リクエストを管理できます。これにより OEM はルールおよび規則の要件に従って、より柔軟にフォーカスを管理できます。音声フォーカスのインタラクションはメーカー間、地域間で異なる場合があります。音声フォーカスの基本的な前提は引き続き変更ありません。アプリは音声を適切に管理するためにフォーカスをリクエストして、ユーザー エクスペリエンスを強化する必要があります。通常、特定のルールが引き続きアプリによる音声フォーカス リクエストに適用されます。

  • 優先順位の高い音声フォーカス(電話、緊急速報メール、安全性通知など)がない場合、アプリが一時的または永続的に音声フォーカスを得られるようにする必要があります。

  • メディア フォーカスがアクティブになっているとき:

    • 通話用途のフォーカスをリクエストしたアプリは、同時または排他的に電話を取れる必要があります。

    • ナビゲーション用途のフォーカスをリクエストしたアプリは、同時または排他的にナビゲーション フォーカスを受け取れる必要があります。

    • アシスタント用途のフォーカスをリクエストしたアプリは、同時または排他的に用途フォーカスを受け取れる必要があります。

  • 優先順位の高い音声フォーカス(電話、緊急速報メール、安全性通知など)がアクティブの場合、受信した遅延音声フォーカス リクエストを必要に応じて許可または遅延する必要があります。

上記の提案はすべてを網羅しているわけではありませんが、優先度の高いサウンドがアクティブでないとき、フォーカスをリクエストしているアプリがフォーカスを得られるようになります。優先順位の高いサウンドがアクティブであっても、遅延フォーカス リクエストは尊重され、優先順位の高いサウンドが停止した時点でフォーカスを得られる必要があります。