Пространственное аудио

Spatial Audio — это захватывающий аудиоопыт, который помещает ваших пользователей в центр действия, делая ваш контент более реалистичным. Звук «пространственен» для создания эффекта нескольких динамиков, похожего на настройку объемного звука, но через наушники.

Например, в фильме звук от автомобиля может начинаться позади пользователя, двигаться вперед и затихать вдали. В видеочате голоса могут быть разделены и размещены вокруг пользователя, что упрощает идентификацию говорящих.

Если ваш контент использует поддерживаемый аудиоформат, вы можете добавить пространственное аудио в свое приложение, начиная с Android 13 (API уровня 33).

Запрос на возможности

Используйте класс Spatializer для запроса возможностей и поведения пространственного устройства. Начните с получения экземпляра Spatializer из AudioManager :

Котлин

val spatializer = audioManager.spatializer

Ява

Spatializer spatializer = AudioManager.getSpatializer();

Получив Spatializer , проверьте четыре условия, которые должны соблюдаться для того, чтобы устройство выводило пространственный звук:

Критерии Проверять
Поддерживает ли устройство пространственную ориентацию? getImmersiveAudioLevel() не является SPATIALIZER_IMMERSIVE_LEVEL_NONE
Доступна ли пространственная ориентация?
Доступность зависит от совместимости с текущей маршрутизацией аудиовыхода.
isAvailable() имеет true
Включена ли пространственная ориентация? isEnabled() — это true
Можно ли сделать звуковую дорожку с заданными параметрами пространственной? canBeSpatialized() — это true

Эти условия могут не соблюдаться, например, если пространственная интерпретация недоступна для текущей звуковой дорожки или вообще отключена на устройстве вывода звука.

Отслеживание положения головы

С поддерживаемыми гарнитурами платформа может регулировать пространственное расположение звука на основе положения головы пользователя. Чтобы проверить, доступен ли трекер головы для текущего маршрута аудиовыхода, вызовите isHeadTrackerAvailable() .

Совместимый контент

Spatializer.canBeSpatialized() указывает, может ли аудио с заданными свойствами быть пространственно преобразовано с текущей маршрутизацией выходного устройства. Этот метод принимает AudioAttributes и AudioFormat , оба из которых более подробно описаны ниже.

AudioAttributes

Объект AudioAttributes описывает использование аудиопотока (например, игрового звука или стандартного мультимедиа ), а также поведение его воспроизведения и тип содержимого .

При вызове canBeSpatialized() используйте тот же экземпляр AudioAttributes , который установлен для вашего Player . Например, если вы используете библиотеку Jetpack Media3 и не настроили AudioAttributes , используйте AudioAttributes.DEFAULT .

Отключение пространственного звука

Чтобы указать, что ваш контент уже был пространственно преобразован, вызовите setIsContentSpatialized(true) чтобы аудио не обрабатывалось дважды. В качестве альтернативы, настройте поведение пространственного преобразования, чтобы полностью отключить пространственное преобразование, вызвав setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER) .

AudioFormat

Объект AudioFormat описывает сведения о формате и конфигурации каналов звуковой дорожки.

При создании экземпляра AudioFormat для передачи в canBeSpatialized() установите кодировку , совпадающую с выходным форматом, ожидаемым от декодера. Вам также следует установить маску канала , соответствующую конфигурации канала вашего контента. Обратитесь к разделу Поведение пространственной обработки по умолчанию для получения рекомендаций по конкретным используемым значениям.

Прослушивание изменений Spatializer

Чтобы прослушивать изменения в состоянии Spatializer , вы можете добавить прослушиватель с помощью Spatializer.addOnSpatializerStateChangedListener() . Аналогично, чтобы прослушивать изменения в доступности трекера головы, вызовите Spatializer.addOnHeadTrackerAvailableListener() .

Это может быть полезно, если вы хотите настроить выбор треков во время воспроизведения с помощью обратных вызовов слушателя. Например, когда пользователь подключает или отключает гарнитуру от устройства, обратный вызов onSpatializerAvailableChanged указывает, доступен ли эффект spaceizer для новой маршрутизации аудиовыхода. На этом этапе вы можете рассмотреть возможность обновления логики выбора треков вашего проигрывателя для соответствия новым возможностям устройства. Подробную информацию о поведении выбора треков ExoPlayer см. в разделе ExoPlayer и пространственное аудио .

ExoPlayer и пространственный звук

Последние выпуски ExoPlayer облегчают принятие пространственного звука. Если вы используете автономную библиотеку ExoPlayer (имя пакета com.google.android.exoplayer2 ), версия 2.17 настраивает платформу для вывода пространственного звука, а версия 2.18 вводит ограничения на количество аудиоканалов . Если вы используете модуль ExoPlayer из библиотеки Media3 (имя пакета androidx.media3 ), версии 1.0.0-beta01 и более новые включают эти же обновления.

После обновления зависимости ExoPlayer до последней версии вашему приложению просто нужно включить контент, который можно пространственно расположить.

Ограничения по количеству аудиоканалов

Когда все четыре условия для пространственного звука выполнены, ExoPlayer выбирает многоканальную звуковую дорожку. Если нет, ExoPlayer выбирает стереодорожку. Если свойства Spatializer изменяются, ExoPlayer активирует новый выбор дорожки, чтобы выбрать звуковую дорожку, которая соответствует текущим свойствам. Обратите внимание, что этот новый выбор дорожки может вызвать короткий период повторной буферизации.

Чтобы отключить ограничения по количеству аудиоканалов, установите параметры выбора дорожек на проигрывателе, как показано ниже:

Котлин

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

Ява

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

Аналогичным образом вы можете обновить параметры существующего селектора дорожек, чтобы отключить ограничения по количеству аудиоканалов, выполнив следующие действия:

Котлин

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

Ява

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() . Например, чтобы выбрать стереодорожку во время воспроизведения:

Котлин

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

Ява

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

Обратите внимание, что изменение параметров выбора треков во время воспроизведения может привести к прерыванию воспроизведения. Более подробная информация о настройке параметров выбора треков плеера доступна в разделе выбора треков в документации ExoPlayer.

Поведение пространственного размещения по умолчанию

Стандартное поведение пространственного позиционирования в Android включает следующие варианты поведения, которые могут быть настроены OEM-производителями:

  • Пространственно преобразуется только многоканальный контент, а не стереоконтент. Если вы не используете ExoPlayer, в зависимости от формата вашего многоканального аудиоконтента вам может потребоваться настроить максимальное количество каналов , которые может выводить аудиодекодер, на большое число. Это гарантирует, что аудиодекодер выводит многоканальный PCM для платформы для пространственного преобразования.

    Котлин

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

    Ява

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

    Для примера в действии см. MediaCodecAudioRenderer.java от ExoPlayer. Чтобы отключить пространственное звучание самостоятельно, независимо от настроек OEM, см. Отключение пространственного звука .

  • AudioAttributes : Звук может быть подвергнут пространственному преобразованию, если для usage установлено значение USAGE_MEDIA или USAGE_GAME .

  • AudioFormat : используйте маску канала, которая содержит как минимум каналы AudioFormat.CHANNEL_OUT_QUAD (передний левый, передний правый, задний левый и задний правый), чтобы звук подлежал пространственному преобразованию. В примере ниже мы используем AudioFormat.CHANNEL_OUT_5POINT1 для аудиодорожки 5.1. Для стереодорожки используйте AudioFormat.CHANNEL_OUT_STEREO .

    Если вы используете Media3, вы можете использовать Util.getAudioTrackChannelConfig(int channelCount) для преобразования количества каналов в маску канала.

    Кроме того, установите кодировку AudioFormat.ENCODING_PCM_16BIT , если вы настроили декодер на вывод многоканального PCM.

    Котлин

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

    Ява

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

Тест пространственного звука

Убедитесь, что на вашем тестовом устройстве включен пространственный звук:

  • Для проводных гарнитур перейдите в Настройки системы > Звук и вибрация > Пространственный звук .
  • Для беспроводных гарнитур перейдите в Настройки системы > Подключенные устройства > Значок шестеренки для вашего беспроводного устройства > Пространственный звук .

Чтобы проверить доступность Spatial Audio для текущего маршрута, выполните команду adb shell dumpsys audio на вашем устройстве. Вы должны увидеть следующие параметры в выходных данных, пока воспроизведение активно:

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