MTK8189 双 MIC 设备强制单MIC录制

1. 背景

  • 平台:MTK8189,系统已开启双 MIC 支持。
  • 目标:上层通过 AudioManager.setParameters("SET_MIC_CHOOSE=1|2") 选择单路物理 MIC 录制。
    • 1:主 MIC
    • 2:副 MIC

2. 现象与问题

  • APP使用AudioManager.getDevices验证设置 input device 后仍无法强制设置单MIC录制,实际还是双MIC录音。
    • 堵住左 MIC 仍可录音;
    • 堵住右 MIC 仍可录音;
    • 仅同时堵住两个 MIC 才明显无声。
  • 结论:实际采集链路仍处于双 MIC 生效状态,而非单物理 MIC。

3. 根因分析

3.1 路由设备与物理单麦并不等价

  • 即使路由为 AUDIO_DEVICE_IN_BUILTIN_MICAudioALSAHardwareResourceManager 在默认场景会按 mNumPhoneMicSupport 选择 SingleMic/DualMic/ThreeMic
  • 在双 MIC 机型上,默认常落到 builtin_Mic_DualMic,仍会开启左右 ADC。

3.2 BackMic 路径本身也是双路配置

  • audio_device.xmlbuiltin_Mic_BackMic 的 turnon 序列同时打开了左右 ADC(ADC_L_Mux + ADC_R_Mux),不满足“单物理 MIC”目标。

4. HAL 修改清单

4.1 修改文件

  1. vendor/vendor/mediatek/proprietary/hardware/audio/common/V3/include/AudioALSAHardware.h
  2. vendor/vendor/mediatek/proprietary/hardware/audio/common/V3/aud_drv/AudioALSAHardware.cpp

4.2 修改点

A) 新增全局状态:mSetMicChoose

  • AudioALSAHardware 中新增成员:
    • volatile int32_t mSetMicChoose;
    • 语义:0=默认1=主单麦2=副单麦
  • 构造函数初始化为 0

B) 新增参数键:SET_MIC_CHOOSE

  • AudioALSAHardware::setParameters() 中解析:
    • SET_MIC_CHOOSE=1 -> mSetMicChoose=1
    • SET_MIC_CHOOSE=2 -> mSetMicChoose=2
    • 其他值 -> mSetMicChoose=0

C) 关键增强:联动 ResourceManager 选择单麦序列

  • 同时调用 AudioALSAHardwareResourceManager::setBuiltInMicSpecificType(...)
    • 1 -> BUILTIN_MIC_MIC1_ONLY
    • 2 -> BUILTIN_MIC_MIC2_ONLY
    • 0 -> BUILTIN_MIC_DEFAULT

强制切换到底层“单麦专用 turnon sequence”。

D) 调整 createAudioPatch() 输入设备覆盖策略

  • mSetMicChoose=1/2 且当前输入为内置 MIC 家族时:
    • 统一覆盖为 AUDIO_DEVICE_IN_BUILTIN_MIC 路由;
    • 具体主/副区分由上一步 MIC1_ONLY/MIC2_ONLY 控制。
  • 原先 SET_MIC_CHOOSE=2 直接走 AUDIO_DEVICE_IN_BACK_MIC,已改为上述方式,避免命中 builtin_Mic_BackMic 的双路配置。

5. 修改后实际生效流程

  1. APP 调用:AudioManager.setParameters("SET_MIC_CHOOSE=1|2")
  2. AudioFlinger 全局参数下发到 HAL。
  3. AudioALSAHardware::setParameters()
    • 记录 mSetMicChoose
    • 设置 BuiltInMicSpecificTypeMIC1_ONLYMIC2_ONLY
  4. 录音建链 createAudioPatch()
    • 输入设备保持 AUDIO_DEVICE_IN_BUILTIN_MIC
    • StreamManager -> CaptureHandler -> HardwareResourceManager 生效。
  5. AudioALSAHardwareResourceManager::startInputDevice_l()
    • 命中 BUILTIN_MIC_MIC1_ONLY / BUILTIN_MIC_MIC2_ONLY 对应 turnon 序列;
    • audio_device.xml 应用相应 kctl,形成单路物理 MIC 采集。

6. 关联配置说明

  • 具体 kctl 序列定义文件:
    • vendor/device/mediatek/mt8189/audio_device.xml
    • 运行时对应 /vendor/etc/audio_device.xml
  • 典型路径:
    • builtin_Mic_Mic1(单路主麦)
    • builtin_Mic_Mic2(单路副麦)
    • builtin_Mic_DualMic(双路,非本次目标)
    • builtin_Mic_BackMic(该路径配置可同时启用左右 ADC)

7. 结果

  • SET_MIC_CHOOSE=1/2 不再仅停留在“设备路由偏好”层面,
  • 而是下沉到 HAL 侧单麦序列控制,解决“堵单孔仍有声”的双 MIC 同时生效问题。

8. 新增/修改代码(可直接对照)

8.1 AudioALSAHardware.h

// App sets this through "SET_MIC_CHOOSE=1/2" to force single-mic path.
// 0: default by policy, 1: primary single mic, 2: secondary single mic.
volatile int32_t    mSetMicChoose;

8.2 AudioALSAHardware.cpp - 新增 key 定义

// App manual mic selection: 1 = primary single mic, 2 = secondary single mic.
static String8 keySetMicChoose = String8("SET_MIC_CHOOSE");

8.3 AudioALSAHardware.cpp - 构造初始化

AudioALSAHardware::AudioALSAHardware() :
    ...
    mSetMicChoose(0),
    mFmTxEnable(false),
    ...

8.4 AudioALSAHardware.cpp - setParameters() 中新增解析

if (param.getInt(keySetMicChoose, value) == NO_ERROR) {
    param.remove(keySetMicChoose);
    // 0: default routing, 1: primary single mic, 2: secondary single mic
    if (value == 1 || value == 2) {
        mSetMicChoose = value;
    } else {
        mSetMicChoose = 0;
    }
    // Force single physical mic sequence in resource manager.
    // 1 -> Mic1 only, 2 -> Mic2 only, 0 -> default policy sequence.
    if (mSetMicChoose == 1) {
        AudioALSAHardwareResourceManager::getInstance()->setBuiltInMicSpecificType(BUILTIN_MIC_MIC1_ONLY);
    } else if (mSetMicChoose == 2) {
        AudioALSAHardwareResourceManager::getInstance()->setBuiltInMicSpecificType(BUILTIN_MIC_MIC2_ONLY);
    } else {
        AudioALSAHardwareResourceManager::getInstance()->setBuiltInMicSpecificType(BUILTIN_MIC_DEFAULT);
    }
    ALOGD("%s(), %s=%d (effective=%d)", __FUNCTION__,
          keySetMicChoose.c_str(), value, (int)mSetMicChoose);
}

8.5 AudioALSAHardware.cpp - createAudioPatch() 中输入设备覆盖

eInputDeviceList = initDeviceVector(sources[0].ext.device.type);
eInputSource = sinks[0].ext.mix.usecase.source;
if (!isEqualDevice(eInputDeviceList, AUDIO_DEVICE_IN_FM_TUNER) &&
    !isEqualDevice(eInputDeviceList, AUDIO_DEVICE_IN_TELEPHONY_RX)) {
    if (mSetMicChoose == 1 &&
        (hasTargetDevice(eInputDeviceList, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
         hasTargetDevice(eInputDeviceList, AUDIO_DEVICE_IN_BACK_MIC))) {
        eInputDeviceList = initDeviceVector(AUDIO_DEVICE_IN_BUILTIN_MIC);
        ALOGD("%s(), force input to primary single mic by %s=1",
              __FUNCTION__, keySetMicChoose.c_str());
    } else if (mSetMicChoose == 2 &&
               (hasTargetDevice(eInputDeviceList, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
                hasTargetDevice(eInputDeviceList, AUDIO_DEVICE_IN_BACK_MIC))) {
        // Use built-in-mic path with MIC2_ONLY to avoid dual-mic back path.
        eInputDeviceList = initDeviceVector(AUDIO_DEVICE_IN_BUILTIN_MIC);
        ALOGD("%s(), force input to secondary single mic by %s=2",
              __FUNCTION__, keySetMicChoose.c_str());
    }
}

8.6 改造目的与这段代码的对应关系

  • mSetMicChoose:保存 App 选择态;
  • setBuiltInMicSpecificType(MIC1_ONLY/MIC2_ONLY):把选择下沉到“单麦 turnon 序列”;
  • createAudioPatch 统一走 BUILTIN_MIC:避免命中 BackMic 双路 path;
  • 最终由 audio_device.xmlbuiltin_Mic_Mic1 / builtin_Mic_Mic2 生效单麦控件。
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容