Spatializer spatializer = AudioManager.getSpatializer();
获取
Spatializer
后,检查设备是否满足以下四个必须为 true 的条件,以便输出空间化音频:
设备是否支持空间化?
getImmersiveAudioLevel()
不是
SPATIALIZER_IMMERSIVE_LEVEL_NONE
是否支持空间化?
是否可用取决于与当前音频输出路由的兼容性。
isAvailable()
为
true
是否
启用了
空间化?
isEnabled()
为
true
指定参数
的音轨能否进行空间化处理?
canBeSpatialized()
为
true
这些条件可能不满足,例如,如果当前音轨不支持空间化或音频输出设备上完全停用了空间化。
在支持的头戴式耳机上,平台可以根据用户的头部位置调整音频的空间化效果。如需检查头部追踪器是否适用于当前的音频输出路由,请调用
isHeadTrackerAvailable()
。
兼容的内容
Spatializer.canBeSpatialized()
指示具有给定属性的音频是否可以使用当前输出设备路由进行空间化处理。此方法接受
AudioAttributes
和
AudioFormat
,下面将详细介绍这两者。
AudioAttributes
AudioAttributes
对象用于描述音频串流的
用途
(例如
游戏音频
或
标准媒体
),以及其播放行为和
内容类型
。
调用
canBeSpatialized()
时,请使用与
Player
设置相同的
AudioAttributes
实例。例如,如果您使用的是 Jetpack Media3 库,并且尚未自定义
AudioAttributes
,请使用
AudioAttributes.DEFAULT
。
停用空间音频
如需指明内容已进行空间化处理,请调用
setIsContentSpatialized(true)
,以免音频重复处理。或者,您也可以调用
setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER)
来调整空间化行为,以完全停用空间化。
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 将触发新的轨道选择,以选择与当前属性匹配的音轨。请注意,选择新轨道可能会导致短暂的重新缓冲期。
如需停用音频声道数限制,请在播放器上设置曲目选择参数,如下所示:
Kotlin
exoPlayer.trackSelectionParameters = DefaultTrackSelector.Parameters.Builder(context)
.setConstrainAudioChannelCountToDeviceCapabilities(false)
.build()
exoPlayer.setTrackSelectionParameters(
new DefaultTrackSelector.Parameters.Builder(context)
.setConstrainAudioChannelCountToDeviceCapabilities(false)
.build()
同样,您可以更新现有轨道选择器的参数,以停用音频声道数约束条件,如下所示:
Kotlin
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 的当前参数。例如,如需在播放过程中选择立体声音轨,请执行以下操作:
Kotlin
exoPlayer.trackSelectionParameters = exoPlayer.trackSelectionParameters
.buildUpon()
.setMaxAudioChannelCount(2)
.build()
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)
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) 将声道计数转换为声道掩码。
此外,如果您已将解码器配置为输出多声道 PCM,请将编码设置为 AudioFormat.ENCODING_PCM_16BIT。
Kotlin
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)
[[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["没有我需要的信息","missingTheInformationINeed","thumb-down"],["太复杂/步骤太多","tooComplicatedTooManySteps","thumb-down"],["内容需要更新","outOfDate","thumb-down"],["翻译问题","translationIssue","thumb-down"],["示例/代码问题","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2025-06-11。"],[],[]]