KunSpace
返回博客

Soundbar 多路语音唤醒:Google 远场与自研助手如何同时用麦

2026年7月20日
3 次阅读

读完了?别空手走啊 😏

若有所获,赐一赞 — 作者会假装很忙实则刷新页面

写评论

赞同、吐槽、提问都行,评论区开放

这篇写什么?

Soundbar / 带屏音箱上经常同时存在:

  1. 系统远场唤醒(例如 Google 远场)——后台长期占用麦克风
  2. 自研语音助手 / 数字人——也要实时听麦、做本地唤醒

若两路都走同一个逻辑输入(常见是 Built-In Mic),策略层往往只允许一路打开:远场占着麦,自研应用一 AudioRecord 就失败,表现为「只有系统能唤醒,自己的助手醒不了」。

本文总结一种工程做法:再挂一路逻辑输入设备(复用 AUDIO_DEVICE_IN_FM_TUNER),让两路都能从物理麦取数,并允许 mic mixPort 双开。

一句话:

问题:远场占 Built-In Mic → 自研助手录不到
做法:新增 FM Tuner 设备端口 → 路由到 built-in mic mixPort
      → maxOpenCount/maxActiveCount = 2
      → 自研走 FM Tuner,系统远场仍走 Built-In Mic
结果:两路可同时录音、各自唤醒

多路语音唤醒:Built-In Mic 与 FM Tuner 共用物理麦

底层 Mic/Ref 怎么采,见 Mic + Ref 做唤醒 / 降噪;硬件麦阵是否干净,见 麦克风阵列音频检查


一、问题本质:抢的不是「物理麦」,是「策略上的唯一输入」

Android AudioPolicy 眼里,应用录音要选 device / mixPort / source
Google 远场常年以 Built-In Mic 打开输入;自研助手若也申请同一路径,会遇到:

现象 原因(常见)
自研 AudioRecord 失败 / 无数据 Built-In Mic 已被远场占用,默认不允许再开一路
只有杀远场才能录 策略上 mic 是「单开」
HAL 其实能出多路数据 卡在 policy XML + 路由,不是麦坏了

所以要做的是:策略层承认「同一物理麦 → 两个逻辑设备」,并允许 mic 相关 mixPort 同时打开 2 路


二、方案概览

角色 逻辑设备 典型用途
系统远场 Built-In Mic Google 等远场唤醒
自研助手 / 数字人 FM TunerAUDIO_DEVICE_IN_FM_TUNER 本地唤醒 / 数字人录音

物理上仍是同一套麦阵(或同一采集后端);HAL 侧把 FM Tuner 接到与 Built-In Mic 相同的数据源即可。
选用 FM_TUNER 是因为它是系统已有的 输入 device 类型,便于在 policy 里扩端口,而不必新造一套私有枚举(具体 HAL 映射按平台适配)。

同时建议:

  • built-in micmixPort 设置 maxOpenCount="2"maxActiveCount="2"
  • 路由:built-in micBuilt-In Mic, FM Tuner
  • 按需把 Echo Reference 等唤醒相关 profile 统一到 16 kHz / 16-bit,与唤醒链路一致

三、必须改的 AudioPolicy 配置(概念级)

不同产品会拆成 audio_policy_devices.xml*_sbr.xml 与公共 audio_policy_common_*.xml。改动点如下。

1)设备列表挂上 FM Tuner

attachedDevicesdevicePorts 引用列表中增加:

<item>FM Tuner</item>

Soundbar 专用 policy、公版 policy 若分文件,两边都要加,避免某一机型漏配。

2)声明 devicePort

在公共 devicePorts 中增加源端口,例如:

<devicePort tagName="FM Tuner" type="AUDIO_DEVICE_IN_FM_TUNER" role="source">
    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
             samplingRates="16000"
             channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
</devicePort>

采样率 / 声道与自研唤醒约定对齐(常用 16 kHz 立体声 16-bit)。

3)允许 mic mixPort 双开

在公共 base 里,给 built-in mic mixPort 加上:

<mixPort name="built-in mic" role="sink"
         maxOpenCount="2" maxActiveCount="2">
    ...
</mixPort>

含义(人话):

  • maxOpenCount="2":最多允许打开 2 个与该 port 相关的客户端
  • maxActiveCount="2":最多 2 路可同时处于 active

没有这两项,即使声明了 FM Tuner,策略仍可能按「单麦单开」拒掉第二路。

4)路由:两路设备都进 built-in mic

<route type="mix" sink="built-in mic"
       sources="Built-In Mic,FM Tuner"/>

这样无论应用选 Built-In Mic 还是 FM Tuner,都会进同一套 mic mix 路径(再由 HAL 决定如何从硬件取数)。

5)Echo Reference 与唤醒采样对齐(可选但常见)

若远场 / AEC 回采也走 policy,可将 echo reference 从例如 48 kHz / 32-bit 收到与唤醒一致的 16 kHz / 16-bit,减少「麦一路 16k、回采一路 48k」的错配。是否改、改到多少,以你们算法与 HAL 为准。


四、Framework:输入源权限策略

AudioPolicyInterfaceImpl 获取 input 时,会对 inputSource 做录音权限判断。
引入 FM Tuner 做「第二路麦」后,需要确认:

  • 自研应用持有正常的录音权限
  • FM Tuner 路径不会被旧逻辑误拦或误放行

实践中常会梳理 AUDIO_SOURCE_FM_TUNERrecordingAllowed 的关系,使 第二路在授权应用下可开、未授权不可偷录。具体 diff 随 Android 大版本略有差异,合入时对照当前分支的 getInputForAttr 逻辑回归一遍。

HAL 侧:为 AUDIO_DEVICE_IN_FM_TUNER 提供打开 / 读流实现,数据源与 Built-In Mic 同源(或同源后做轻量拷贝),否则 policy 配通了仍无 PCM。


五、应用怎么用?

客户端 建议
Google 远场 继续原有 Built-In Mic / 系统约定 source
自研助手 / 数字人 录音时指定 FM Tuner 设备(或平台封装好的第二路 API)
两边 都按 16 kHz(或统一约定)开流,避免各开各的速率

验证建议:

  1. 只开远场 → 系统可唤醒
  2. 只开自研 → 助手可唤醒
  3. 两路同时开 → 两边都能持续出数、都能唤醒
  4. 杀一路不影响另一路(或符合产品定义的降级策略)

六、注意点与边界

  1. 不是无限多开maxOpenCount=2 只保证两路;再加第三家助手要重新评估。
  2. 功耗与带宽 — 双开意味着采集/拷贝成本上升,注意待机远场场景。
  3. 隐私 — 第二路同样是麦克风;权限与前台提示要合规。
  4. HAL 必须真支持双读 — 仅改 XML 不够;底层要能同时服务两个输入客户端。
  5. 命名别误解 — 这里的 FM Tuner 是 借用设备类型当第二路麦,不是真的在听 FM 电台。

七、改动文件清单(按模块)

模块 文件(示例路径) 改什么
产品 policy audio_policy_devices.xml / *_sbr.xml 挂上 FM Tuner
公共 policy audio_policy_common_base.xml mic maxOpenCount/maxActiveCount=2;echo 采样按需
公共 policy audio_policy_common_devicePorts.xml 声明 FM Tuner devicePort
公共 policy audio_policy_common_routes.xml Built-In Mic + FM Tuner → built-in mic
Framework AudioPolicyInterfaceImpl.cpp FM Tuner 输入源权限/放行逻辑
Audio HAL 平台实现 FM Tuner 打开与读数接到真实麦

总结

多路语音唤醒要解决的,是 「两个产品功能都要听麦,但 AudioPolicy 默认只给一路 Built-In Mic」
做法是:第二逻辑设备(FM Tuner)+ mic 双开配额 + 路由合流 + HAL 同源出数
配通之后,Google 远场与自研助手可以同时录音、各自唤醒,而不必互相「踢麦」。


相关阅读

评论

还没有评论,来做第一个吧

赞同、吐槽、提问都行,评论区开放