空間オーディオ

空間オーディオは、コンテンツをよりリアルに聞こえるようにすることで、ユーザーをアクションの中心に据えた臨場感あふれるオーディオ エクスペリエンスです。サウンドは「空間化」され、サラウンド音声の設定に似たマルチスピーカー効果を生み出しますが、代わりにヘッドフォンを使用します。

たとえば、映画では、車の音がユーザーの後ろから始まり、前に進み、遠くに消えていく場合があります。ビデオチャットでは、声を分離してユーザーの周囲に配置できるため、話者を簡単に識別できます。

Android 13(API レベル 33)以降では、サポートされているオーディオ形式をコンテンツで使用している場合は、アプリに空間オーディオを追加できます。

機能のクエリ

Spatializer クラスを使用して、デバイスの空間化機能と動作をクエリします。まず、AudioManager から Spatializer のインスタンスを取得します。

Kotlin

val spatializer = audioManager.spatializer

Java

Spatializer spatializer = AudioManager.getSpatializer();

Spatializer を取得したら、デバイスが空間オーディオを出力するために true を維持する必要がある次の 4 つの条件を確認します。

条件 確認
デバイスは空間化をサポートしていますか? getImmersiveAudioLevel()SPATIALIZER_IMMERSIVE_LEVEL_NONE ではない
空間化は利用できますか?
使用できるかどうかは、現在のオーディオ出力ルーティングとの互換性によって異なります。
現在の isAvailable(): true
空間化が有効になっているか。 現在の isEnabled(): true
指定されたパラメータを持つ音声トラックを空間化できますか? 現在の canBeSpatialized(): true

これらの条件は、たとえば、現在のオーディオ トラックで空間化を使用できない場合や、オーディオ出力デバイス全体で無効になっている場合などです。

ヘッド トラッキング

サポートされているヘッドセットを使用すると、プラットフォームはユーザーの頭の位置に基づいてオーディオの空間化を調整できます。現在のオーディオ出力ルーティングでヘッド トラッカーを使用できるかどうかを確認するには、isHeadTrackerAvailable() を呼び出します。

互換性のあるコンテンツ

Spatializer.canBeSpatialized() は、指定されたプロパティのオーディオを現在の出力デバイス ルーティングで空間化できるかどうかを示します。このメソッドは、AudioAttributesAudioFormat を受け取ります。どちらも以下で詳しく説明します。

AudioAttributes

AudioAttributes オブジェクトは、音声ストリーム(ゲーム音声標準メディアなど)の用途と、その再生動作およびコンテンツ タイプを記述します。

canBeSpatialized() を呼び出す場合は、Player に設定したものと同じ AudioAttributes インスタンスを使用します。たとえば、Jetpack Media3 ライブラリを使用していて、AudioAttributes をカスタマイズしていない場合は、AudioAttributes.DEFAULT を使用します。

空間オーディオを無効にする

コンテンツがすでに空間化されていることを示すには、setIsContentSpatialized(true) を呼び出して、音声が二重処理されないようにします。または、setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER) を呼び出して、空間化の動作を調整し、空間化を完全に無効にすることもできます。

AudioFormat

AudioFormat オブジェクトは、音声トラックの形式とチャンネル構成の詳細を記述します。

canBeSpatialized() に渡す AudioFormat をインスタンス化するときは、エンコードをデコーダから想定される出力形式と同じに設定します。また、コンテンツのチャンネル構成と一致するチャンネル マスクを設定する必要があります。使用する特定の値については、デフォルトの空間化動作のセクションをご覧ください。

Spatializer の変更をリッスンする

Spatializer の状態の変化をリッスンするには、Spatializer.addOnSpatializerStateChangedListener() を使用してリスナーを追加します。同様に、ヘッド トラッカーの空き状況の変化をリッスンするには、Spatializer.addOnHeadTrackerAvailableListener() を呼び出します。

これは、再生中にリスナーのコールバックを使用してトラックの選択を調整する場合に便利です。たとえば、ユーザーがヘッドセットをデバイスに接続または接続解除すると、onSpatializerAvailableChanged コールバックが、新しいオーディオ出力ルーティングでスペイシャライザー エフェクトを使用できるかどうかを示します。この時点で、デバイスの新しい機能に合わせてプレーヤーのトラック選択ロジックを更新することを検討してください。ExoPlayer のトラック選択動作の詳細については、ExoPlayer と空間オーディオのセクションをご覧ください。

ExoPlayer と空間オーディオ

ExoPlayer の最近のリリースにより、空間オーディオをより簡単に導入できるようになりました。スタンドアロンの ExoPlayer ライブラリ(パッケージ名 com.google.android.exoplayer2)を使用する場合、バージョン 2.17 では空間オーディオを出力するようにプラットフォームが構成され、バージョン 2.18 ではオーディオ チャンネル数の制約が導入されます。Media3 ライブラリ(パッケージ名 androidx.media3)の ExoPlayer モジュールを使用している場合、バージョン 1.0.0-beta01 以降にも同じアップデートが含まれています。

ExoPlayer の依存関係を最新リリースに更新したら、あとは空間化可能なコンテンツをアプリに含めるだけです。

オーディオ チャンネル数の制約

空間オーディオの 4 つの条件がすべて満たされている場合、ExoPlayer はマルチチャンネル オーディオ トラックを選択します。そうでない場合、ExoPlayer は代わりにステレオ トラックを選択します。Spatializer プロパティが変更されると、ExoPlayer は新しいトラック選択をトリガーし、現在のプロパティに一致する音声トラックを選択します。この新しいトラック選択では、再バッファリング期間が短くなる場合があります。

音声チャンネル数の制約を無効にするには、次のようにプレーヤーのトラック選択パラメータを設定します。

Kotlin

exoPlayer.trackSelectionParameters = DefaultTrackSelector.Parameters.Builder(context)
  .setConstrainAudioChannelCountToDeviceCapabilities(false)
  .build()

Java

exoPlayer.setTrackSelectionParameters(
  new DefaultTrackSelector.Parameters.Builder(context)
    .setConstrainAudioChannelCountToDeviceCapabilities(false)
    .build()
);

同様に、既存のトラック セレクタのパラメータを更新して、音声チャンネル数の制約を無効にするには、次のようにします。

Kotlin

val trackSelector = DefaultTrackSelector(context)
...
trackSelector.parameters = trackSelector.buildUponParameters()
  .setConstrainAudioChannelCountToDeviceCapabilities(false)
  .build()

Java

DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
...
trackSelector.setParameters(
  trackSelector
    .buildUponParameters()
    .setConstrainAudioChannelCountToDeviceCapabilities(false)
    .build()
);

音声チャンネル数の制約を無効にして、コンテンツに複数の音声トラックがある場合、ExoPlayer は最初にチャンネル数が最も高く、デバイスから再生できるトラックを選択します。たとえば、コンテンツにマルチチャンネル音声トラックとステレオ音声トラックが含まれ、デバイスが両方の再生をサポートしている場合、ExoPlayer はマルチチャンネル トラックを選択します。この動作をカスタマイズする方法について詳しくは、音声トラックの選択をご覧ください。

音声トラックの選択

ExoPlayer のオーディオ チャンネル数の制約動作が無効になっている場合、ExoPlayer はデバイスのスペイシャライザーのプロパティに一致するオーディオ トラックを自動的に選択しません。代わりに、再生前または再生中にトラック選択パラメータを設定することで、ExoPlayer のトラック選択ロジックをカスタマイズできます。デフォルトでは、ExoPlayer は MIME タイプ(エンコード)、チャンネル数、サンプルレートに関して初期トラックと同じ音声トラックを選択します。

トラック選択パラメータの変更

ExoPlayer のトラック選択パラメータを変更するには、Player.setTrackSelectionParameters() を使用します。同様に、ExoPlayer の現在のパラメータは Player.getTrackSelectionParameters() で取得できます。たとえば、再生中にステレオ音声トラックを選択するには、次のようにします。

Kotlin

exoPlayer.trackSelectionParameters = exoPlayer.trackSelectionParameters
  .buildUpon()
  .setMaxAudioChannelCount(2)
  .build()

Java

exoPlayer.setTrackSelectionParameters(
  exoPlayer.getTrackSelectionParameters()
    .buildUpon()
    .setMaxAudioChannelCount(2)
    .build()
);

再生中にトラック選択パラメータを変更すると、再生が中断される可能性があります。プレーヤーのトラック選択パラメータの調整について詳しくは、ExoPlayer のドキュメントのトラックの選択セクションをご覧ください。

デフォルトの空間化動作

Android のデフォルトの空間化動作には、OEM がカスタマイズできる以下の動作があります。

  • ステレオ コンテンツではなく、マルチチャンネル コンテンツのみが空間化されます。ExoPlayer を使用しない場合、マルチチャンネル音声コンテンツの形式によっては、オーディオ デコーダが多数の出力に出力できるチャンネルの最大数を構成する必要があります。これにより、オーディオ デコーダはマルチチャンネル PCM を出力し、プラットフォームが空間化できるようになります。

    Kotlin

    val mediaFormat = MediaFormat()
    mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99)
    

    Java

    MediaFormat mediaFormat = new MediaFormat();
    mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99);
    

    動作例については、ExoPlayer の MediaCodecAudioRenderer.java をご覧ください。OEM のカスタマイズに関係なく、空間化を自分でオフにするには、空間オーディオを無効にするをご覧ください。

  • AudioAttributes: usageUSAGE_MEDIA または USAGE_GAME に設定されている場合、オーディオは空間化の対象となります。

  • AudioFormat: 音声を空間化の対象にするには、少なくとも AudioFormat.CHANNEL_OUT_QUAD チャンネル(前から左、前と右、後と左、後と右)を含むチャンネル マスクを使用します。次の例では、5.1 音声トラックに AudioFormat.CHANNEL_OUT_5POINT1 を使用します。ステレオ音声トラックの場合は、AudioFormat.CHANNEL_OUT_STEREO を使用します。

    Media3 を使用している場合は、Util.getAudioTrackChannelConfig(int channelCount) を使用してチャンネル数をチャンネル マスクに変換できます。

    また、マルチチャンネル PCM を出力するようにデコーダを構成している場合は、エンコードを AudioFormat.ENCODING_PCM_16BIT に設定します。

    Kotlin

    val audioFormat = AudioFormat.Builder()
      .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
      .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
      .build()
    

    Java

    AudioFormat audioFormat = new AudioFormat.Builder()
      .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
      .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
      .build();
    

空間オーディオをテストする

テストデバイスで空間オーディオが有効になっていることを確認します。

  • 有線ヘッドセットの場合は、[システム設定] > [音とバイブレーション] > [空間オーディオ] に移動します。
  • ワイヤレス ヘッドセットの場合は、[システム設定] > [接続済みのデバイス] > ワイヤレス デバイスの歯車アイコン > [空間オーディオ] に移動します。

現在のルーティングで空間オーディオが利用できるかどうかを確認するには、デバイスで adb shell dumpsys audio コマンドを実行します。再生がアクティブになっている間、出力に次のパラメータが表示されます。

Spatial audio:
mHasSpatializerEffect:true (effect present)
isSpatializerEnabled:true (routing dependent)