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

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

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

Если ваш контент использует поддерживаемый аудиоформат, вы можете добавить пространственный звук в свое приложение, начиная с 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 указывает, доступен ли эффект пространственного преобразования для новой маршрутизации вывода звука. На этом этапе вы можете рассмотреть возможность обновления логики выбора треков вашего плеера в соответствии с новыми возможностями устройства. Подробную информацию о поведении выбора трека в 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)