kevin知识库
首页 / GMS 认证 / /gms/multichannel-mixdown-test-fail/
整理中 创建 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);