整理中 创建 2026/06/06 更新 2026/06/06
记录 [GMS] 解决 Multichannel Mixdown Test fail 的问题现象、排查过程、修改方案和验证方法。
#gms
[GMS] 解决 Multichannel Mixdown Test fail
问题现象:跑 GMS / CTS(ExoPlayer 相关用例)时出现以下错误:
Multichannel Mixdown Test fail / ExoPlaybackException: Source error
一、问题分析
问题本质:HAL 层错误地将不支持的 audio_format 强制转换为 PCM format,导致误判 format 合法。
原始代码逻辑
enum pcm_format fmt = pcm_format_from_audio_format(config->format);
if (profile_is_format_valid(&device_info->profile, fmt)) {
proxy_config.format = fmt;
}
❌ 问题点
pcm_format_from_audio_format()先转换,再校验- 某些
audio_format(如压缩格式、特殊 PCM)转换后得到的pcm_format并不真实支持 - 导致 HAL 误认为 format 合法 → 实际打开 stream 失败 → ExoPlayer 报
Source error
二、解决方案
核心思路:先判断 audio_format 是否支持,再进行转换。
三、修改内容
1️⃣ 新增函数:is_audio_format_supported()
static bool is_audio_format_supported(const alsa_device_profile* profile,
audio_format_t format)
{
for (int i = 0; profile->formats[i] != PCM_FORMAT_INVALID; i++) {
if (audio_format_from(profile->formats[i]) == format) {
return true;
}
}
return false;
}
关键点:遍历 profile->formats,使用 audio_format_from(pcm_format) 做反向匹配,避免”错误映射”导致的假支持。
2️⃣ Patch 内容(libhardware/modules/usbaudio/audio_hal.c)
--- a/libhardware/modules/usbaudio/audio_hal.c
+++ b/libhardware/modules/usbaudio/audio_hal.c
@@ -478,6 +478,17 @@ static unsigned int populate_sample_rates_from_profile(const alsa_device_profile
return num_sample_rates;
}
+static bool is_audio_format_supported(const alsa_device_profile* profile,
+ audio_format_t format)
+{
+ for (int i = 0; profile->formats[i] != PCM_FORMAT_INVALID; i++) {
+ if (audio_format_from(profile->formats[i]) == format) {
+ return true;
+ }
+ }
+ return false;
+}
+
static bool are_all_devices_found(unsigned int num_devices_to_find,
const int cards_to_find[],
const int devices_to_find[],
@@ -1013,8 +1024,8 @@ static int adev_open_output_stream(struct audio_hw_device *hw_dev,
proxy_config.format = profile_get_default_format(&device_info->profile);
config->format = audio_format_from_pcm_format(proxy_config.format);
} else {
- enum pcm_format fmt = pcm_format_from_audio_format(config->format);
- if (profile_is_format_valid(&device_info->profile, fmt)) {
+ if (is_audio_format_supported(&device_info->profile, config->format)) {
+ enum pcm_format fmt = pcm_format_from_audio_format(config->format);
proxy_config.format = fmt;
} else {
ret = -EINVAL;
@@ -1526,8 +1537,8 @@ static int adev_open_input_stream(struct audio_hw_device *hw_dev,
in->config.format = profile_get_default_format(&device_info->profile);
config->format = audio_format_from_pcm_format(in->config.format);
} else {
- enum pcm_format fmt = pcm_format_from_audio_format(config->format);
- if (profile_is_format_valid(&device_info->profile, fmt)) {
+ if (is_audio_format_supported(&device_info->profile, config->format)) {
+ enum pcm_format fmt = pcm_format_from_audio_format(config->format);
in->config.format = fmt;
} else {
in->config.format = profile_get_default_format(&device_info->profile);