写在开始

这篇文章整理项目中比较有代表性的音量问题单。只保留已经写明原因和处理方向的内容,并按音量控制链路归为三类。

排查音量问题时,可以先确认四个结果:

1. 收到的目标音量是否正确
       ↓
2. 左右耳保存的音量是否一致
       ↓
3. 两耳应用音量的时间是否一致
       ↓
4. 实际写入硬件的音量是否正确

本文围绕下面三类问题,整理对应的现象和排查思路:

  1. 回连后的初始音量不对 ;
  2. 快速调节时双耳音量不同步 ;
  3. 出盒恢复时单耳突然变大 。

一、回连后的初始音量不对

问题现象 1

耳机重新组队并连接手机后,预期使用耳机的默认音量,实际却变成手机之前保存的最大音量。

排查思路 1

按时间确认三个值:重新组队后恢复的默认音量、手机首次下发的历史音量,以及最终实际生效的音量。若默认值恢复正确,但最终值变成手机历史值,说明问题出在手机下发后的覆盖。

耳机重新组队后已恢复到默认音量,但手机连接时下发的历史音量又覆盖了本地值。如果要求重新组队后采用耳机默认音量,可以在首次连接的短暂保护窗口内忽略手机下发的音量,使用耳机的默认音量,同时将默认音量写回给 App。

问题现象 2

一拖二场景下,设备 A 已连接耳机且音量调到最大;设备 B 的音量较小,在播放音乐时抢连耳机。抢连成功后,音乐开始时仍按设备 A 的最大音量播放,随后才突然降到设备 B 的低音量。

排查思路 2

检查抢连后耳机采用的是哪台设备的音量,以及 A2DP 开始播放前硬件音量是否已经更新。

已有问题中,设备 B 抢连成功后,硬件音量设置晚于音乐开始,导致开始播放时仍保留设备 A 的最大音量。处理时要在 A2DP 出声前,按设备 B 的音量设置好硬件音量。

二、快速调节时双耳音量不同步

问题现象 1

长按手机音量键或快速滑动音量条时,声音会短暂偏向一边;从最大音量降到静音时,一只耳机比另一只更晚无声。反复在最大和最小音量之间切换时,还可能出现音量跳变。

排查思路 1

先看手机下发音量后,主从耳是不是在 alarm 到点前就各自更新了本地媒体音量;再对比 alarm 回调里两边实际采用的目标值。

已有问题中,主从耳在 alarm 到点前更新本地媒体音量的路径不同。快速滑动时,虽然两边在同一时刻进入 alarm 回调,但取到的音量基准已经不一致,所以会出现一边先变大、先变小或更晚静音。

处理时,不在收到手机音量后立即更新本地媒体音量,而是把换算后的耳机音量等级编码进 alarm 音量包。alarm 到点后,左右耳从同一个包中取出目标值,再统一更新本地状态和实际输出。

目标值同步后,再由应用层的平滑函数处理听感。它不直接把目标值写到实际输出,而是让当前实际值按定时步进逐步逼近目标值,直到到达目标值。

这部分平滑方案由我主导设计,已经在实际产品中使用。以目前的测试体验来看,手机快速滑动音量时,双耳变化更连贯,听感也更自然。验证时要同时确认两边目标值、最终音量和变化过程是否一致。

下图记录了当前实际值逐步逼近目标值的过程:

音量平滑处理

三、出盒恢复时单耳突然变大

问题现象 1

音乐播放中,一只耳机入盒后再次取出,刚恢复声音时会突然偏大,随后才与另一只耳机一致。

排查思路 1

先看出盒后的第一段声音,此时音量寄存器是否已经写入安全值,再看后续同步值是否正常。若只在启动瞬间偏大,问题通常出在硬件初始化,而不是两耳保存的音量不同。

已有问题中,DAC 初始化时音量寄存器默认写成最大值,而且没有经过淡入。处理方向是在 DAC 初始化阶段先把音量设为 0,再由后续音量流程恢复到目标值,避免硬件通路刚打开时直接输出最大音量。

四、最后总结

音量异常可以先按下面三类判断:

恢复错误:查本地记忆、手机下发和最终采用值
快速调节异常:查两耳目标值、定时点和硬件设置时间
启动偏大:查 DAC 初始值和淡入过程

先把手机显示、耳机内部值和实际听感分开,再对照左右耳的执行时间,通常就能判断问题是在恢复策略、同步时序,还是最后的硬件音量设置。

如果你也遇到类似的音量问题,欢迎一起交流排查思路。