借助 Jetpack SceneCore 中的空间音频功能,您可以在 Android XR 应用中打造沉浸式音频体验。
空间音频可模拟用户在 3D 环境中感知声音的方式。它能营造出声音来自四面八方(包括用户上方和下方)的感觉。为此,系统会在 3D 空间中的特定位置模拟一个或多个“虚拟扬声器”。
对于并非专为 Android XR 设计或未针对 Android XR 进行修改的现有应用,其音频会在 Android XR 中自动空间化。当用户在空间中移动时,所有应用音频都将从呈现应用界面的面板发出。例如,如果时钟应用中的定时器响了,声音听起来就像是从应用面板所在的位置发出的。Android XR 会自动调整声音,以实现逼真的位置效果。例如,应用面板与用户之间的感知距离会细微地影响音量,从而营造更逼真的体验。
如需详细了解现有应用如何呈现空间音频,请参阅本页面上的为应用添加立体声和环绕声。
如果您要针对 XR 优化应用,Jetpack SceneCore 可提供用于高级空间音频自定义的工具。您可以在 3D 环境中精确放置声音,使用立体环绕声音频营造逼真的声场,并利用内置的环绕声集成功能。
Android XR 中提供的空间音频类型
Android XR 支持定位音频、立体声音频、环绕声音频和全景声音频。
定位音频
您可以将位置音频定位到 3D 空间中的特定点进行播放。 例如,您可以在虚拟环境的角落放置一个吠叫的狗的 3D 模型。您可以让多个实体从各自的位置发出声音。如需呈现定位音频,文件必须是单声道或立体声。
空间化立体声和环绕声
所有 Android 媒体格式都支持位置、立体声和环绕声。除了这些格式之外,Android XR 设备可能还支持杜比全景声、杜比数字和杜比数字+ 音频格式。
立体声音频是指具有两个声道的音频格式,而环绕声是指具有两个以上声道的音频格式,例如 5.1 环绕声或 7.1 环绕声配置。每个声道的音频数据都与一位说话者相关联。例如,在播放立体声音乐时,左扬声器声道发出的乐器音轨可能与右扬声器声道不同。
环绕声通常用于电影和电视节目中,通过使用多个扬声器声道来增强真实感和沉浸感。例如,对话通常通过中央扬声器声道播放,而直升机飞行的声音可能会依次使用不同的声道,让您感觉直升机正在 3D 空间中飞行。
立体环绕声音频
立体环绕声音频(或立体环绕声)就像音频的天空盒,可为用户提供沉浸式音景。在背景环境音效或其他需要复制环绕聆听者的全球面声场的场景中,请使用立体环绕声。Android XR 支持一阶、二阶和三阶 AmbiX 环绕声格式。我们建议使用 Opus (.ogg) 和 PCM/Wave (.wav) 文件类型。
将空间音频与 Jetpack SceneCore 搭配使用
使用 Jetpack SceneCore 实现空间音频涉及检查空间功能,并选择用于加载空间音频的 API。
检查空间功能
在使用空间音频功能之前,请检查 Session 是否支持空间音频。在以下各部分的所有代码段中,都会在尝试播放空间音频之前检查功能。
加载空间音频
您可以使用以下任一 API 加载空间音频,以便在 Jetpack SceneCore 中使用。
SoundPool:非常适合大小小于 1 MB 的短音效,它们会提前加载,并且可以重复使用。这是加载位置音频的绝佳方式。ExoPlayer:非常适合加载立体声和环绕声内容,例如音乐和视频。还允许在后台播放媒体。MediaPlayer:提供加载立体环绕声音频的最简单方法。AudioTrack:提供对音频数据加载方式的最大控制。允许直接写入音频缓冲区,或者允许您合成或解码自己的音频文件。
检查媒体格式支持情况
Android 平台支持某些媒体格式。不过,特定 Android XR 设备可能支持其他格式,例如 Dolby Atmos。如需查询媒体格式支持情况,请使用 ExoPlayer 的 AudioCapabilities:
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 在 3D 空间中的渲染位置。对 SpatialMediaPlayer 调用 setPointSourceParams,以在 MediaPlayer 实例上设置 PointSourceParams 及其关联的 entity。
位置音频示例
以下示例将音效音频文件加载到音效池中,并在 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,以便在后台继续播放立体声或环绕声,则当应用在后台运行时,虚拟扬声器定位将会发生变化。由于没有面板或其他空间点可供锚定声音,空间音频会随用户移动(换句话说,它是“头部锁定”的)。
环绕声示例
以下示例使用 MediaPlayer 加载 5.1 音频文件,并将该文件的中置声道设置为 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 }
代码要点
- 与位置音频示例中一样,第一步是使用
spatialCapabilities检查空间音频功能是否可用。 - 将
contentType设置为AudioAttributes.CONTENT_TYPE_MUSIC,并将用法设置为AudioAttributes.USAGE_MEDIA,可让系统将此音频文件视为环绕声。
向应用添加立体环绕声场
播放立体环绕声场的最简单方法是使用 MediaPlayer 加载文件。由于立体环绕声适用于整个声景,因此您无需指定 Entity 来提供位置。而是创建具有适当立体环绕声阶数(指定声道数)的 SoundFieldAttributes 实例。
Ambionics 示例
以下示例使用 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 }
代码要点
- 与前面的代码段一样,第一步是使用
spatialCapabilities检查空间音频功能是否可用。 contentType和用量仅供参考。SpatializerConstants.AmbisonicsOrder.FIRST_ORDER向 SceneCore 发出信号,表明声场文件定义了四个声道。