空间音频是一种沉浸式音频体验,可让用户全身心地沉浸其中,让内容听起来更加逼真。这种音频具有“空间化”的特点,可以通过头戴式耳机营造多扬声器效果(类似于环绕声设置)。
例如,在电影中,汽车的声音可能会从用户背后开始,向前移动,然后逐渐远去。在视频聊天中,可以使用语音 放在用户周围,方便识别说话者。
如果您的内容使用受支持的音频格式,则可以将空间音频添加到 从 Android 13(API 级别 33)开始的应用。
查询功能
使用 Spatializer
类执行以下操作:
查询设备的空间化功能和行为。首先,从 AudioManager
检索 Spatializer
的实例:
val spatializer = audioManager.spatializer
Spatializer spatializer = AudioManager.getSpatializer();
获取 Spatializer
后,检查必须满足的四个条件
true,以便设备输出空间音频:
条件 | 检查 |
---|---|
设备是否支持空间化? |
getImmersiveAudioLevel() 不是 SPATIALIZER_IMMERSIVE_LEVEL_NONE
|
空间化是否可用? 是否可用取决于与当前音频输出路由的兼容性。 |
isAvailable() 为“true ” |
是否启用空间化? | isEnabled() 为“true ” |
可以对具有指定参数的音轨进行空间化吗? | canBeSpatialized() 为 true |
例如,如果没有空间化,可能无法满足这些条件 或在音频输出设备上完全停用该功能。
头部跟踪
使用受支持的耳机时,平台可以调整音频的
基于用户头部位置进行空间化处理。检查头部跟踪器是否
可用于当前音频输出路由,调用
isHeadTrackerAvailable()
。
兼容的内容
Spatializer.canBeSpatialized()
指示是否可以使用
当前输出设备路由。此方法接受 AudioAttributes
和 AudioFormat
,下面将对这两者进行详细介绍。
AudioAttributes
一个 AudioAttributes
对象
用于描述特定 API 的用法
音频流(例如游戏音频
或标准媒体),
及其播放行为和内容类型。
调用 canBeSpatialized()
时,请使用与 Player
设置相同的 AudioAttributes
实例。例如,如果您使用的是 Jetpack Media3 库,并且尚未自定义 AudioAttributes
,请使用 AudioAttributes.DEFAULT
。
停用空间音频
如需指明内容已进行空间化处理,请调用 setIsContentSpatialized(true)
,以免音频重复处理。或者,您也可以调用 setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER)
来调整空间化行为,以完全停用空间化。
AudioFormat
AudioFormat
对象用于详细说明音轨的格式和声道配置。
实例化要传入 canBeSpatialized()
的 AudioFormat
时,请将编码设置为与解码器预期的输出格式相同。您还应设置
通道掩码
与内容的频道配置相匹配的频道。请参阅
默认空间化行为部分,获取相关指导
使用特定值
监听 Spatializer
的更改
如需监听 Spatializer
状态的变化,您可以使用 Spatializer.addOnSpatializerStateChangedListener()
添加监听器。同样,如需监听头部跟踪器可用性方面的变化,请调用 Spatializer.addOnHeadTrackerAvailableListener()
。
如果您想在播放过程中调整曲目选择,这会非常有用
使用监听器的回调例如,当用户将耳机连接或断开连接到设备时,onSpatializerAvailableChanged
回调会指示空间化效果是否可用于新的音频输出路由。此时,您可以考虑更新播放器的
跟踪选择逻辑以匹配设备的新功能。如需详细了解 ExoPlayer 的曲目选择行为,请参阅 ExoPlayer 和空间音频部分。
ExoPlayer 和空间音频
ExoPlayer 的最新版本让用户可以更轻松地采用空间音频。如果您使用独立的 ExoPlayer 库(软件包名称为 com.google.android.exoplayer2
),版本 2.17 会将平台配置为输出空间化音频,版本 2.18 会引入音频声道数限制。如果您使用 Media3 库中的 ExoPlayer 模块(软件包名称
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()
。同样,您也可以使用 Player.getTrackSelectionParameters()
获取 ExoPlayer 的当前参数。例如,如需在播放过程中选择立体声音轨,请使用以下代码:
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);
如需查看实际操作示例,请参阅 ExoPlayer 的
MediaCodecAudioRenderer.java
。如需自行关闭空间化(无论 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)