20、音频策略与多用户:多用户场景下的音频路由、用户切换时的策略重置、用户隔离策略
多用户场景,说白了就是一台设备上,不同用户登录后,音频该怎么管。
我最早接触这个问题,是在做平板的企业定制项目。设备要支持学生和老师两个账号,学生切到老师账号时,蓝牙耳机突然没声了。嗯,这就是典型的策略没处理好。
今天咱们就聊聊,Android 在多用户场景下,音频策略是怎么玩的。
20.1 多用户场景下的音频路由
先想一个问题:用户 A 连了蓝牙耳机,用户 B 切换过来,蓝牙耳机该归谁?
Android 的策略是:音频设备是全局共享的,但路由策略是按用户隔离的。
什么意思?蓝牙耳机这个硬件,谁都能用。但每个用户有自己的「音频偏好」和「路由规则」。用户 A 可能习惯用蓝牙,用户 B 可能只喜欢扬声器。系统不会因为用户 A 连过蓝牙,就强制用户 B 也用蓝牙。
我遇到过的一个坑:用户 A 在后台播放音乐,切到用户 B 后,音乐还在响。为什么?因为音频焦点和路由策略没有跟着用户切换而重置。后来我查了 AudioService 的源码,发现关键在 setCurrentUserId() 这个方法。
核心逻辑:每个用户有自己的 AudioPolicy 实例。切换用户时,系统会重新加载目标用户的策略配置。
具体来说,路由决策依赖以下几个因素:
- 当前用户 ID:决定加载哪套策略
- 设备偏好:用户是否主动选择了某个输出设备
- 应用归属:音频流来自哪个用户空间的应用
你想想看,如果这些不隔离,那用户 B 一登录,听到的全是用户 A 的微信消息提示音,这体验得多糟糕。
20.2 用户切换时的策略重置
用户切换,不是简单的「换个人脸识别一下」。对音频系统来说,这是一次完整的策略重置。
我习惯把切换过程拆成三步:
- 暂停当前用户的音频:所有属于旧用户的音频流会被静音或暂停
- 重置路由策略:清除旧用户的设备选择,加载新用户的默认路由
- 恢复新用户的音频:如果新用户之前有后台播放,恢复其音频流
这里有个细节:策略重置不是全盘清空。比如系统铃声、闹钟这类全局音频,不会因为用户切换而丢失。它们走的是「系统用户」的路由,不受普通用户切换影响。
小技巧:调试多用户音频问题时,可以用 adb shell dumpsys audio 查看当前用户的音频策略状态。重点关注 mCurrentUserId 和 mDeviceConnections 字段。
我曾经遇到一个 bug:用户切换后,蓝牙耳机虽然显示已连接,但音频还是从扬声器出来。查了半天,发现是 AudioPolicyManager 在切换时没有重新评估蓝牙设备的优先级。修复方法很简单,在 switchUser() 里加一个 reevaluateDeviceConnections() 调用。
20.3 用户隔离策略
隔离,是多用户音频的底线。
说白了,用户 A 的音频数据,绝对不能跑到用户 B 的耳朵里。这不仅是隐私问题,也是合规要求。
Android 的隔离策略分三个层面:
| 层面 | 隔离方式 | 我的经验 |
|---|---|---|
| 应用层 | 每个用户有独立的 AudioManager 实例 | 应用拿不到其他用户的音频焦点 |
| 服务层 | AudioService 按 userId 分发事件 | 切换用户时,旧用户的回调会被注销 |
| HAL 层 | 音频流通过 userId 标签区分 | 底层驱动可以按用户做策略路由 |
嗯,这里要注意:HAL 层的隔离不是强制的。很多硬件厂商的驱动并不支持按用户 ID 路由。这时候,隔离全靠上层软件保证。
警告:如果你的设备要过 CTS 认证,多用户音频隔离是必测项。测试方法很简单:创建两个用户,同时在两个用户下录音,检查音频数据是否混叠。
我见过一个翻车案例:某厂商的平板,两个用户同时开微信语音,结果对方听到的是两个人的声音混在一起。原因就是 HAL 层没有做用户隔离,两个音频流混到了同一个输入通道。
20.4 知识体系图
下面这张图,是我自己总结的多用户音频策略核心逻辑。你看一眼,基本就能理清脉络。
这张图的核心就一句话:用户切换 → 策略重置 → 隔离输出。每一步都有对应的代码实现,不是玄学。
20.5 避坑指南
最后,分享几个我踩过的坑,希望能帮你少走弯路。
- 蓝牙设备不释放:用户 A 切走后,蓝牙 A2DP 连接没有断开,导致用户 B 连不上同一副耳机。解决方案:在
switchUser()中主动断开非系统用户的蓝牙音频连接。 - 音频焦点泄漏:用户 A 的应用在后台持有音频焦点,切到用户 B 后,焦点没有释放,导致用户 B 的应用无法获取焦点。修复:切换用户时,强制释放所有旧用户的音频焦点。
- 路由策略缓存:用户 B 之前选择过「扬声器输出」,但系统缓存了用户 A 的「蓝牙输出」,导致用户 B 的偏好没生效。修复:切换用户时,清空路由策略缓存,重新加载。
我的习惯:每次做多用户音频测试,我都会用 logcat -b audio 抓完整的音频日志。重点关注 AudioPolicyManager 和 AudioService 的日志输出。切换用户时,如果看不到 switchUser() 的调用,那肯定有问题。
多用户音频策略,说难不难,说简单也不简单。核心就是记住三个词:隔离、重置、路由。把这三点理清楚,大部分问题都能迎刃而解。
公众号:蓝海资料掘金营,微信deep3321