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_MIC,AudioALSAHardwareResourceManager在默认场景会按mNumPhoneMicSupport选择SingleMic/DualMic/ThreeMic。 - 在双 MIC 机型上,默认常落到
builtin_Mic_DualMic,仍会开启左右 ADC。
3.2 BackMic 路径本身也是双路配置
-
audio_device.xml中builtin_Mic_BackMic的 turnon 序列同时打开了左右 ADC(ADC_L_Mux+ADC_R_Mux),不满足“单物理 MIC”目标。
4. HAL 修改清单
4.1 修改文件
vendor/vendor/mediatek/proprietary/hardware/audio/common/V3/include/AudioALSAHardware.hvendor/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. 修改后实际生效流程
- APP 调用:
AudioManager.setParameters("SET_MIC_CHOOSE=1|2")。 - AudioFlinger 全局参数下发到 HAL。
-
AudioALSAHardware::setParameters():- 记录
mSetMicChoose; - 设置
BuiltInMicSpecificType为MIC1_ONLY或MIC2_ONLY。
- 记录
- 录音建链
createAudioPatch():- 输入设备保持
AUDIO_DEVICE_IN_BUILTIN_MIC; -
StreamManager -> CaptureHandler -> HardwareResourceManager生效。
- 输入设备保持
-
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.xml的builtin_Mic_Mic1/builtin_Mic_Mic2生效单麦控件。