9、音频输入设备选择:输入设备选择逻辑、麦克风路由策略、多麦克风场景处理

好,我们进入第九章。这一章聊的是音频输入设备的选择逻辑。说白了,就是系统怎么决定用哪个麦克风来录音。

你可能觉得这很简单——不就一个麦克风吗?但现在的手机、平板、智能音箱,哪个不是两三个麦克风起步?甚至有些设备有四个、六个。系统怎么选?选错了会怎样?我踩过的坑,今天就全倒给你。

9.1 输入设备选择的核心逻辑

Android 的音频输入选择,不是拍脑袋决定的。它有一套完整的优先级策略。我把它总结成三个层级:

  • 应用层指定:开发者通过 AudioRecordMediaRecorder 的 API 指定输入源
  • 策略层匹配:AudioPolicy 根据当前场景匹配最佳设备
  • 硬件层兜底:如果策略层找不到合适设备,由 HAL 层做最后选择

嗯,这里要注意:应用层指定的只是「输入源类型」,比如 MediaRecorder.AudioSource.MICCAMCORDER。真正决定用哪个物理麦克风的,是策略层。

关键点:应用层说「我要用主麦克风」,但系统可能给你切换到副麦克风。为什么?因为策略层认为副麦克风更适合当前场景。

9.2 麦克风路由策略

路由策略,说白了就是一套规则集。我参与过几个项目的策略定制,发现核心就三个维度:

维度 说明 我遇到的坑
音频源类型 MIC、CAMCORDER、VOICE_RECOGNITION 等 VOICE_RECOGNITION 在某些设备上被路由到了副麦,导致语音识别率暴跌
设备形态 手机、平板、折叠屏、车载等 折叠屏展开和折叠状态,麦克风路由策略完全不同
外部设备连接 有线耳机、蓝牙耳机、USB 麦克风等 蓝牙耳机连上后,系统可能强制切换输入源,用户一脸懵

我曾经遇到过一个 case:某款手机在录像时,用户插上蓝牙耳机,系统自动把录音输入切到了蓝牙耳机的麦克风。结果录出来的视频声音质量极差。为什么?因为蓝牙耳机的麦克风采样率被限制在了 8kHz,而录像需要 48kHz。

我的建议:在定制路由策略时,一定要考虑采样率匹配。如果外部设备的采样率不满足当前场景需求,应该保持使用内置麦克风。

9.3 多麦克风场景处理

多麦克风场景,是音频输入选择中最复杂的部分。我把它分成三种典型场景:

9.3.1 降噪场景

最常见的多麦克风应用。通常是一个主麦克风(采集语音)+ 一个或多个副麦克风(采集环境噪声)。系统通过算法把噪声减掉。

这里有个坑:如果副麦克风被遮挡(比如手机壳挡住了),降噪算法会失效,反而引入更多噪声。我调试过一个项目,用户反馈通话有「呼呼」的风声,查了半天发现是副麦克风位置设计不合理,容易被手指挡住。

9.3.2 波束成形场景

智能音箱、会议设备常用。通过多个麦克风阵列,定向采集某个方向的声音。

路由策略在这里就变得很关键。系统需要知道:

  • 当前哪个方向的声源是目标
  • 哪些麦克风参与波束成形
  • 哪些麦克风作为参考

我记得有一次,某款智能音箱在播放音乐时,用户喊「小X小X」,系统死活听不到。后来发现是播放音乐时,系统把麦克风阵列切换到了「音乐播放模式」,降低了麦克风增益。这就是路由策略没处理好场景切换。

9.3.3 多通道录音场景

专业录音场景,比如会议记录、采访。系统需要同时从多个麦克风采集音频,每个通道独立输出。

Android 从 10 开始支持 AudioRecord 的多通道采集。但要注意:不是所有设备都支持。我建议你在开发时先查询设备支持的通道数:

AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
String devices = am.getDevices(AudioManager.GET_DEVICES_INPUTS);
// 遍历 devices,检查每个设备的通道数
for (AudioDeviceInfo device : devices) {
    int channelCount = device.getChannelCounts().length;
    Log.d("AudioInput", "设备: " + device.getProductName() + " 通道数: " + channelCount);
}

警告:多通道录音对性能要求很高。如果同时采集 4 个通道的 48kHz/24bit 音频,数据量大约是 4 * 48000 * 3 = 576KB/s。处理不当会导致音频卡顿或丢帧。

9.4 输入设备选择的完整流程

我把整个流程画了一张图,方便你理解:

音频输入设备选择流程 应用层指定输入源 (MIC / CAMCORDER / VOICE_RECOGNITION) AudioPolicy 策略匹配 (音频源类型 + 设备形态 + 外部设备连接) 匹配成功? (策略层决策) 使用匹配设备 (如:主麦克风) HAL 层兜底选择 (硬件默认设备) 确定输入设备

这个流程看起来简单,但实际项目中,每个环节都可能出问题。我举个例子:

某款手机在微信语音时,用户插上 3.5mm 耳机。策略层判断:外部设备连接了有线耳机,应该使用耳机麦克风。但耳机麦克风的质量很差,对方听到的声音像「在水里说话」。这就是策略层匹配成功了,但匹配的结果不是用户期望的。

我的经验:在定制策略时,不仅要考虑「能不能用」,还要考虑「好不好用」。如果外部设备的麦克风质量明显低于内置麦克风,应该优先使用内置麦克风。

9.5 避坑指南

最后,我总结几个实战中容易踩的坑:

  1. 麦克风权限问题:Android 11 开始,麦克风权限属于敏感权限。如果应用没有动态申请权限,AudioRecord 会静默失败。我曾经调试过一个 bug,用户说「录音没声音」,查了半天发现是权限被拒绝了。
  2. 采样率不匹配:不同麦克风支持的采样率可能不同。如果应用设置 48kHz,但某个麦克风只支持 44.1kHz,系统会进行重采样,导致音质下降。
  3. 设备热插拔:用户在使用过程中插拔耳机或蓝牙设备,系统需要动态切换输入源。如果切换不及时,会导致几秒钟的音频丢失。
  4. 多应用冲突:两个应用同时请求音频输入,系统怎么处理?Android 的策略是后一个应用抢占前一个。但有些场景下(比如通话中),系统会保护通话应用的输入通道。

特别提醒:在调试多麦克风问题时,建议使用 dumpsys audio 命令查看当前的输入设备状态。这个命令会列出所有可用的输入设备、当前使用的设备、以及路由策略的决策过程。

好了,这一章的内容就到这里。输入设备选择看似简单,但涉及到的细节非常多。希望我的经验能帮你少走一些弯路。


公众号:蓝海资料掘金营,微信deep3321