Как добавить пространственное звучание в приложение XR

Поддерживаемые XR-устройства
Это руководство поможет вам создавать контент для таких устройств.
XR-шлемы
Проводные XR-очки

Функции пространственного аудио в Jetpack SceneCore позволяют создавать иммерсивные аудиоэффекты в приложениях Android XR.

Пространственное звучание имитирует восприятие звука в трехмерной среде. Он создает ощущение, что звук исходит со всех сторон, в том числе сверху и снизу. Система делает это, имитируя один или несколько "виртуальных динамиков" в определенных местах трехмерного пространства.

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

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

Если вы оптимизируете приложение для XR, Jetpack SceneCore предоставит вам инструменты для расширенной настройки пространственного звучания. Вы можете точно размещать звуки в 3D-среде, использовать амбисонический звук для создания реалистичных звуковых полей и пользоваться встроенной интеграцией объемного звука.

Типы пространственного звука, доступные в Android XR

Android XR поддерживает позиционный, стереофонический, объемный и амбисонический звук.

Позиционирование звука

Позиционный звук можно настроить так, чтобы он воспроизводился из определенной точки в трехмерном пространстве. Например, в углу виртуальной среды можно разместить 3D-модель лающей собаки. Несколько объектов могут издавать звук из разных точек. Для позиционирования звука файлы должны быть моно- или стереофоническими.

Пространственное стерео и объемный звук

Для позиционного, стерео- и объемного звука поддерживаются все медиаформаты Android. Кроме того, устройства Android XR могут поддерживать аудиоформаты Dolby Atmos, Dolby Digital и Dolby Digital+.

Стереозвук – это формат с двумя каналами, а объемный звук – с более чем двумя каналами, например 5.1 или 7.1. Звуковые данные каждого канала связаны с одним динамиком. Например, при воспроизведении стереомузыки левый динамик может воспроизводить одни инструменты, а правый – другие.

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

Амбисоник

Амбисоник – это звуковое сопровождение, которое создает для пользователей эффект присутствия. Используйте амбисоникс для фоновых звуков окружающей среды или в других случаях, когда нужно воспроизвести сферическое звуковое поле, окружающее слушателя. Android XR поддерживает формат многоканального звука AmbiX с амбисоникой первого, второго и третьего порядка. Мы рекомендуем использовать файлы Opus (.ogg) и PCM/Wave (.wav).

Как использовать пространственное звучание с Jetpack SceneCore

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

Как проверить пространственные возможности

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

Как загрузить пространственное звучание

Вы можете использовать любой из следующих API для загрузки пространственного звука в Jetpack SceneCore.

  • SoundPool – идеальный вариант для коротких звуковых эффектов размером менее 1 МБ. Они загружаются заранее и могут использоваться многократно. Это отличный способ загрузить аудио для позиционного звука.
  • ExoPlayer: подходит для загрузки стерео- и объемного звука, например музыки и видео. Также позволяет воспроизводить медиаконтент в фоновом режиме.
  • MediaPlayer – самый простой способ загрузить аудио в формате Ambisonics.
  • AudioTrack – позволяет наиболее точно управлять загрузкой аудиоданных. Позволяет напрямую записывать буферы аудио, если вы синтезировали или декодировали собственные аудиофайлы.

Проверьте, поддерживается ли формат медиафайла

Некоторые форматы медиаконтента поддерживаются платформой Android. Однако некоторые устройства Android XR могут поддерживать дополнительные форматы, например Dolby Atmos. Чтобы запросить поддержку формата медиаконтента, используйте AudioCapabilities ExoPlayer:

val audioCapabilities = AudioCapabilities.getCapabilities(
    context,
    androidx.media3.common.AudioAttributes.DEFAULT,
    null,
    emptyList()
)

if (audioCapabilities.supportsEncoding(C.ENCODING_AC3)) {
    // Device supports playback of the Dolby Digital media format.
}
if (audioCapabilities.supportsEncoding(C.ENCODING_E_AC3)) {
    // Device supports playback of the Dolby Digital Plus media format.
}
if (audioCapabilities.supportsEncoding(C.ENCODING_E_AC3_JOC)) {
    // Device supports playback of the Dolby Digital Plus with Dolby Atmos media format.
}

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

Как добавить в приложение позиционный звук

Источники позиционного звука определяются с помощью PointSourceParams и связанного с ним Entity. Положение и ориентация Entity определяют, где PointSourceParams будет отображаться в трехмерном пространстве. Вызовите метод setPointSourceParams для объекта SpatialMediaPlayer, чтобы задать PointSourceParams и связанный с ним объект entity для экземпляра MediaPlayer.

Пример позиционирования звука

В следующем примере аудиофайл со звуковым эффектом загружается в пул звуков и воспроизводится в позиции Entity.

// Check spatial capabilities before using spatial audio
if (session.scene.spatialCapabilities.contains(SpatialCapability.SPATIAL_AUDIO)
) { // The session has spatial audio capabilities
    val maxVolume = 1F
    val lowPriority = 0
    val infiniteLoop = -1
    val normalSpeed = 1F

    val soundPool = SoundPool.Builder()
        .setAudioAttributes(
            AudioAttributes.Builder()
                .setContentType(CONTENT_TYPE_SONIFICATION)
                .setUsage(USAGE_ASSISTANCE_SONIFICATION)
                .build()
        )
        .build()

    val pointSource = PointSourceParams()

    val soundEffect = appContext.assets.openFd("sounds/tiger_16db.mp3")
    val pointSoundId = soundPool.load(soundEffect, lowPriority)

    soundPool.setOnLoadCompleteListener { soundPool, sampleId, status ->
        // wait for the sound file to be loaded into the soundPool
        if (status == 0) {
            SpatialSoundPool.play(
                session = session,
                entity = entity,
                soundPool = soundPool,
                soundID = pointSoundId,
                params = pointSource,
                volume = maxVolume,
                priority = lowPriority,
                loop = infiniteLoop,
                rate = normalSpeed
            )
        }
    }
} else {
    // The session does not have spatial audio capabilities
}

Важная информация о коде

  • Сначала проверьте, доступна ли функция "Пространственное звучание", с помощью spatialCapabilities.
  • Если задать для contentType значение CONTENT_TYPE_SONIFICATION, а для usage – USAGE_ASSISTANCE_SONIFICATION, система будет воспринимать этот аудиофайл как звуковой эффект.
  • В приведенном выше примере аудиофайл загружается в пул непосредственно перед использованием, чтобы код был проще. Рекомендуем загружать все звуковые эффекты асинхронно при запуске приложения, чтобы все аудиофайлы были доступны в пуле, когда они понадобятся.

Как добавить в приложение стерео- и объемный звук

Рекомендуемый способ добавить в приложение стерео- и объемный звук – использовать Exoplayer. Подробнее о том, как использовать пространственное звучание с Exoplayer, рассказывается в руководстве по пространственному звучанию.

Расположение стереоколонок и колонок с объемным звуком

При позиционировании виртуальных колонок объемного звука они располагаются и ориентируются относительно центральной колонки вокруг пользователя в соответствии со стандартной конфигурацией ITU.

По умолчанию центральный канал размещается на mainPanelEntity приложения. В частности, это касается мобильных приложений, в которых пространственное звучание создается автоматически с помощью Android XR.

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

Если у вас несколько панелей и вы хотите выбрать, какая из них будет воспроизводить звук, или если вы хотите, чтобы стерео- или многоканальный звук воспроизводился относительно другой Entity, вы можете использовать PointSourceAttributes, чтобы задать местоположение центрального канала. Остальные каналы будут размещены в соответствии с описанными выше правилами. В таких случаях также необходимо использовать параметр MediaPlayer.

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

Если вы настроили MediaPlayer или ExoPlayer так, чтобы стерео- или объемный звук продолжал воспроизводиться в фоновом режиме, когда приложение свернуто, виртуальное позиционирование динамиков будет изменено. Поскольку нет панели или другой точки в пространстве, к которой можно привязать звук, пространственное аудио перемещается вместе с пользователем (то есть "привязано к голове").

Пример объемного звука

В следующем примере аудиофайл 5.1 загружается с помощью MediaPlayer, а центральный канал файла устанавливается как Entity.

// Check spatial capabilities before using spatial audio
if (session.scene.spatialCapabilities.contains(SpatialCapability.SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val pointSourceAttributes = PointSourceParams()

    val mediaPlayer = MediaPlayer()

    val fivePointOneAudio = appContext.assets.openFd("sounds/aac_51.ogg")
    mediaPlayer.reset()
    mediaPlayer.setDataSource(fivePointOneAudio)

    val audioAttributes =
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()

    SpatialMediaPlayer.setPointSourceParams(
        session,
        mediaPlayer,
        pointSourceAttributes,
        entity = session.scene.mainPanelEntity,
    )

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()
} else {
    // The session does not have spatial audio capabilities
}

Важная информация о коде

Как добавить в приложение звуковые поля ambisonic

Самый простой способ воспроизвести звуковое поле Ambisonics – загрузить файл с помощью MediaPlayer. Поскольку амбисонический звук применяется ко всему звуковому пространству, вам не нужно указывать Entity, чтобы задать положение. Вместо этого вы создаете экземпляр SoundFieldAttributes с подходящим порядком амбисоники, указывающим количество каналов.

Пример Ambionics

В следующем примере показано, как воспроизвести звуковое поле ambisonic с помощью MediaPlayer.

// Check spatial capabilities before using spatial audio
if (session.scene.spatialCapabilities.contains(SpatialCapability.SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val soundFieldAttributes =
        SoundFieldAttributes(SpatializerConstants.AmbisonicsOrder.FIRST_ORDER)

    val mediaPlayer = MediaPlayer()

    val soundFieldAudio = appContext.assets.openFd("sounds/foa_basketball_16bit.wav")

    mediaPlayer.reset()
    mediaPlayer.setDataSource(soundFieldAudio)

    val audioAttributes =
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()

    SpatialMediaPlayer.setSoundFieldAttributes(
        session,
        mediaPlayer,
        soundFieldAttributes
    )

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()
} else {
    // The session does not have spatial audio capabilities
}

Важная информация о коде

  • Как и в предыдущих фрагментах кода, сначала нужно проверить, доступна ли функция пространственного звучания, с помощью hasCapability().
  • Значок contentType и информация об использовании носят исключительно информационный характер.
  • AMBISONICS_ORDER_FIRST_ORDER указывает SceneCore, что файл поля sound определяет четыре канала.