空間音訊

空間音訊提供身歷其境的聽覺饗宴,讓影音內容變得更加逼真。音訊會經過「空間化」處理,產生宛如有多個喇叭的音效體驗 (類似環場音效設定),但透過耳機播放。

以電影為例,汽車的聲音可能會在使用者後面 然後沿著這個距離前進在視訊通話中,系統可以將聲音分離並放置在使用者周圍,方便辨識講者。

如果內容使用支援的音訊格式,您可以從 Android 13 (API 級別 33) 開始,在應用程式中加入空間音訊。

功能查詢

使用 Spatializer 類別執行下列操作: 查詢裝置的空間化功能和行為。從擷取開始 呼叫窗格中的 Spatializer 例項 AudioManager:

Kotlin

val spatializer = audioManager.spatializer

Java

Spatializer spatializer = AudioManager.getSpatializer();

取得 Spatializer 後,請檢查哪四個條件 true,裝置才能輸出空間音訊:

條件 查看
裝置是否支援空間化? getImmersiveAudioLevel() 不是 SPATIALIZER_IMMERSIVE_LEVEL_NONE
是否支援空間化?
適用情況取決於與目前音訊輸出轉送的相容性。
isAvailable()true
是否已啟用空間化功能? isEnabled()true
包含特定參數的音軌是否可以進行空間化? canBeSpatialized()true

可能無法滿足這些條件,例如無法使用空間化功能 ,或在音訊輸出裝置中完全停用。

頭部追蹤

使用支援的耳機後,平台就能調整音訊 根據使用者的頭部位置自動調整空間化如何檢查頭部追蹤器是否 適用於目前的音訊輸出轉送,呼叫 isHeadTrackerAvailable()

相容內容

Spatializer.canBeSpatialized() 指出能否使用指定屬性的音訊進行空間化 目前的輸出裝置轉送方式這個方法會使用 AudioAttributesAudioFormat,兩者皆會在下方詳細說明。

AudioAttributes

AudioAttributes 物件 說明瞭 Pod 的用途 音訊串流 (例如遊戲音訊) 或標準媒體), 以及播放行為和內容類型

呼叫 canBeSpatialized() 時,請使用與 Player 相同的 AudioAttributes 例項。舉例來說 您使用的是 Jetpack Media3 程式庫,且並未自訂 AudioAttributes,請使用 AudioAttributes.DEFAULT

停用空間音訊

如要指出內容已完成空間化處理,請呼叫 setIsContentSpatialized(true),以免音訊遭到重複處理。或者,您也可以調整 透過呼叫 setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER)

AudioFormat

AudioFormat 物件會說明 音軌格式與頻道設定的詳細資料。

AudioFormat 例項化以傳入 canBeSpatialized() 時, 設定編碼 與解碼器預期的輸出格式相同您也應設定與內容管道設定相符的管道遮罩。詳情請參閱 預設空間化行為一節,瞭解 指定要使用的特定值

監聽 Spatializer 的變更

如要監聽 Spatializer 狀態的變更,您可以使用 Spatializer.addOnSpatializerStateChangedListener() 新增事件監聽器。同樣地,如要監聽頭部追蹤器可用性變化, 呼叫 Spatializer.addOnHeadTrackerAvailableListener()

如果你想在播放期間調整選擇的曲目,這項功能就能派上用場 透過事件監聽器的回呼例如,當使用者連線或中斷連線時 裝置上的耳機,onSpatializerAvailableChanged 回呼指出新式參數是否可使用空間化效果 音訊輸出轉送此時,您可以考慮更新播放器的 追蹤選取邏輯以配合裝置的新功能。如要進一步瞭解 ExoPlayer 的曲目選取行為,請參閱「ExoPlayer 和空間音訊」一節。

ExoPlayer 和空間音訊

ExoPlayer 最新版本還能輕鬆採用空間音訊功能。如果您使用獨立的 ExoPlayer 程式庫 (套件名稱 com.google.android.exoplayer2),2.17 版會將平台設為輸出空間化音訊,而 2.18 版則會引入音訊頻道數限制。如果使用 Media3 程式庫中的 ExoPlayer 模組 (套件名稱), androidx.media3),版本 1.0.0-beta01 更新後,就會加入相同的更新

將 ExoPlayer 依附元件更新為最新版本後,應用程式 都必須包含能空間化的內容

音訊頻道數量限制

符合所有四個空間音訊條件時,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()。 同樣地,您也可以使用 Player.getTrackSelectionParameters() 取得 ExoPlayer 目前的參數。舉例來說,如要在播放期間選取立體聲音軌,請按照下列步驟操作:

Kotlin

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

Java

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

請注意,如果在播放期間變更音軌選擇參數,可能會導致 中斷播放。進一步瞭解如何調整玩家音軌 選取參數 音軌選取 一節所述的所有內容。

預設空間化行為

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。自行關閉空間化功能 (無論原始設備製造商為何) 請參閱「停用空間音訊」一文。

  • AudioAttributes:音訊可用於空間化 如果usage 設為 USAGE_MEDIAUSAGE_GAME

  • AudioFormat:使用至少包含 AudioFormat.CHANNEL_OUT_QUAD 聲道 (前左、前右、後左和後右) 的頻道遮罩,讓音訊符合空間化處理的條件。在以下範例中,我們使用 AudioFormat.CHANNEL_OUT_5POINT1 來處理 5.1 音軌。如果是立體聲音軌,請使用 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)