Пространственный звук — это иммерсивный аудиоопыт, который помещает ваших пользователей в центр событий, делая ваш контент более реалистичным. Звук «пространственен», создавая эффект многоканального звука, похожий на систему объёмного звучания, но с использованием наушников.
Например, в фильме звук автомобиля может начинаться позади пользователя, продвигаться вперёд и затихать вдали. В видеочате голоса можно разделить и расположить вокруг пользователя, что упрощает идентификацию говорящих.
Если ваш контент использует поддерживаемый аудиоформат, вы можете добавить пространственное аудио в свое приложение, начиная с 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();
Тест пространственного звука
Убедитесь, что на вашем тестовом устройстве включено пространственное аудио:
- Для проводных гарнитур перейдите в Настройки системы > Звук и вибрация > Пространственный звук .
- Для беспроводных гарнитур перейдите в Системные настройки > Подключенные устройства > Значок шестеренки вашего беспроводного устройства > Пространственный звук .
Чтобы проверить доступность пространственного звука для текущего маршрута, выполните команду adb shell dumpsys audio
на вашем устройстве. Во время воспроизведения в выходных данных должны отображаться следующие параметры:
Spatial audio:
mHasSpatializerEffect:true (effect present)
isSpatializerEnabled:true (routing dependent)