Пространственное звучание

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

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

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

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

Используйте класс Spatializer, чтобы запрашивать информацию о возможностях и поведении пространственного звучания на устройстве. Сначала получите экземпляр Spatializer из AudioManager:

Kotlin

val spatializer = audioManager.spatializer

Java

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

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

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

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);

    Пример реализации можно найти в 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).

    Кроме того, если декодер настроен на вывод многоканального 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)