高通平台的音频问题,尤其是“录音文件播放有杂音”这类反馈,最大的坑在于“杂音”两个字太模糊。不同人说的杂音,可能是指全程伴随的嘶嘶底噪,也可能是音乐重低音段落里的破音,还可能是每隔几秒蹦出来的咔哒爆音。这三类现象的定位方向完全不同,甚至跨着软件算法、音频通路、硬件供电三个领域。这篇文章就围绕这个核心问题,分享一套我在高通平台上反复用过的定位路径:从现象分类、链路排除、PCM数据对比,到QXDM日志、DSP后处理参数核验,最后才是硬件测量。适合正在做智能音箱、手机、车载或者物联网音频方案的驱动工程师、音效调试工程师,也适合刚接触高通音频栈、被各种杂音bug折磨的朋友。
1. 先把“杂音”说清楚:现象分类与复现手法
接到bug单,第一件事不是打开Audacity看波形,更不是急着把EQ高频增益往下拉。先逼自己回答一个问题:这个杂音到底是什么形态。音频调试和软件调试最大的区别在于,音频问题是叠加了主观听感的,你说“有杂音”,对方听的可能是完全不同的东西。所以我会先让反馈方用一段固定话术描述杂音,然后自己戴上耳机把文件听一遍,再做分类。
1.1 杂音不是一种病:先做听感分类
我习惯把杂音分成五类,每一类对应不同的关注方向:
| 杂音类型 | 听感特征 | 最可能的来源方向 |
|---|---|---|
| 连续嘶嘶声 | 全程伴随的白噪声/粉噪声,类似收音机无台时的底噪 | 麦克风增益过高、AGC算法、模拟前端底噪 |
| 嗡嗡声 | 低频哼声,通常在50Hz/100Hz附近,坐车或充电时更明显 | 电源纹波、地环路、参考时钟串扰 |
| 周期性咔哒/爆音 | 每隔几秒或随机出现的“啪”“哒”声,像老唱片跳帧 | 采样率不匹配、缓冲区切换、DSP状态切换 |
| 破音/声音发毛 | 大动态段落声音撕裂、闷堵,响度越大越严重 | 数字削波、EQ增益过冲、DRC参数异常 |
| 间歇性滋啦声 | 像信号被干扰,时有时无,伴随通话或录音启动时出现 | 算法残留(AEC/NS)、音频焦点切换、非实时线程调度 |
这一步不要省。我自己就吃过亏,曾经花了一天调EQ,最后发现客户说的“杂音”其实是录音文件本身在采集端就有削波,跟播放链路半点关系都没有。分类之后,方向基本就锁定了。
1.2 建立可复现的最小实验环境
定位杂音最忌讳的就是拿着客户的音乐文件来回试。音频问题要快速定位,必须有“标准试剂”。我自己在办公桌上常备三个测试文件:
- 1kHz正弦波、-6dBFS,用于查削波、查底噪、查总谐波失真
- 20Hz到20kHz对数扫频信号,用于听谐振点和频响突变
- 一段标准粉红噪声,用于粗略评估频段有没有被算法染色
同时把播放音量、测试耳机/喇叭、音效开关状态全部固定下来。高通平台的调音参数都在ACDB里,不同project加载的校准参数可能完全不同,所以测试时一定要确认当前加载的是哪套ACDB、是不是客户反馈版本对应的那套。这个细节非常容易被忽略,但你用错校准文件查半天,最后发现测试环境本身就不对,真的很浪费时间。
1.3 用听感+波形先把问题缩小到三级链路
在动工具之前,先做三个听音实验:
第一,把客户反馈的那个录音文件拷到PC上,用普通播放器播放。如果PC上也有类似杂音,说明问题大概率存在于文件本身或录音采集源头,而不是播放端。
第二,在设备上不经过任何第三方APP,用AudioReplay或tinyplay直接播放该文件。如果命令直接播放时杂音消失,说明问题在应用层音频链路,比如音效后处理、音频焦点抢注、SCO蓝牙通路切换等。
第三,用同一套麦克风输入录制一段新音频,立即回放。如果新录的音频也有杂音,那就要重点查本地录音通路,包括mic增益、降噪算法、编解码器的采样率配置。
这三个实验做完,通常能砍掉一半的排查分支。剩下的问题要么集中在录音采集链路,要么集中在播放后处理链路,要么在文件本身,后面再逐个突破。
2. 源头排查:录音文件本身与录音链路到底干不干净
标题里写的是“录音文件播放有杂音”,很多人的第一反应是查播放。但我在实际项目中遇到的情况是,一半以上的“播放杂音”问题,根因在录音端。因为客户录这个文件的时候,杂音已经被嵌进去了。回放只是把问题暴露出来而已。
2.1 先在通用平台上验证文件底噪
拿到任何可疑的音频文件,我第一步就是放到Audacity里看波形和频谱。音频文件不会说谎。用Audacity打开后做三件事:
- 观察静音段的波形振幅。如果静音段不是一条“毛茸茸”的细线,而是有明显的随机波动,说明文件本身底噪偏高。
- 用频谱图(Spectrogram)看杂音频率分布。50Hz/100Hz的横线通常是电源工频干扰,10kHz以上从头到尾的连续嘶声通常是麦克风底噪或前端增益过高,短促的竖线通常是数字脉冲干扰。
- 找一段明显削波的波形。如果波形顶部被“切平”,说明采集端增益设置太高,已经产生数字削波。这种情况在回放时听到的就是破音,怎么调播放链路都救不回来。
这一步的成本很低,但信息量极大。它能直接回答“杂音是先天的还是后天的”这个关键问题。如果频谱显示问题集中在采集端,就不要继续在播放链路里白费功夫了。
2.2 用tinycap抓原始录音PCM做客观对比
如果怀疑录音采集链路本身,我会用tinycap抓取原始的PCM数据,绕过所有音效后处理。这样得到的录音是完全“素颜”的,可以客观地看到硬件和底层驱动出来的信号长什么样。
高通平台上的操作一般是这样:
# 查看当前声卡设备和PCM节点 cat /proc/asound/cards cat /proc/asound/pcm # 抓取原始录音,例如48kHz双通道16bit tinycap /data/cap_raw.wav -D 0 -d 0 -c 2 -r 48000 -b 16抓完文件后再次放进Audacity分析。如果原始PCM很干净,说明硬件采集通路没问题,问题出在后处理算法上,比如AGC、降噪、风噪抑制这类DSP算法把信号“修坏”了。如果原始PCM本身就有杂音,那就要往codec配置、硬件增益、麦克风供电、PCB布局方向查。
这一步的价值在于:你终于拿到了“未经处理的地基数据”,后面不管是跟算法团队还是硬件团队沟通,都可以用同一份数据说话,而不是站在各自的设备前用耳朵争辩。
2.3 录音增益、AGC和降噪算法是最常见的“隐形元凶”
以我的经验,录音链路里最容易被“冤枉”的三个模块就是增益、AGC和降噪算法。
先看增益。高通平台的录音通路上,增益是级联的:模拟域的麦克风偏置电压(MIC Bias)、codec内部的PGA放大、数字域的DSP数字增益,每一级都可能被配置得过高。某个项目的典型翻车场景是:为了把远场拾音做大,直接把PGA拉到最大,结果信噪比没有变好,反而是把codec自身的底噪和电源噪声一起放大了,最终表现就是全程嘶嘶声。我在调音工程里看gain结构时,会特别注意每一级增益加起来的“总放大倍数”,以及最后一级数字增益是否在削波边缘。
再看AGC。自动增益控制的设计初衷是好的——环境安静时自动把音量提上来,环境吵闹时压下去。但在实际录音场景中,AGC方向经常弄反:环境安静时,AGC把麦克风底噪当成有效信号放大;等到真的有人说话时,反而先被压了一头。最典型的表现就是,录音里听感上“噪声有呼吸感”,也就是底噪一会大一会小。针对这类问题,优先检查音频校准配置里AGC的enable状态和target level参数,必要时直接关掉AGC,改用固定增益。
最后看降噪算法。高通DSP里有NS(Noise Suppression)、AEC(Acoustic Echo Cancellation)、ANR(Ambient Noise Reduction)等模块,这些算法在参数没调好时,会引入“音乐噪声”或者“水管声”,听感上比原来的底噪更难受。判断算法是否介入,可以在安静环境下录一段空白音,观察频谱里的噪声是否随时间周期性变化。如果是,大概率是算法在处理过程中产生了残留。
3. 播放链路的检查清单:从AudioReplay到DSP后处理
排除了文件本身和录音采集链路之后,问题才真正进入播放链路的排查。高通平台的播放链路比很多人想象的要长:应用进程 -> AudioFlinger -> Audio HAL -> ADSP -> AFE端口 -> Codec -> 喇叭/耳机。任何一个环节配置异常,都可能被听成“杂音”。
3.1 分清PCM路径与offload路径再动手
高通平台的音频播放有两条常见路径:本地PCM播放和硬件offload播放。区别在于——普通PCM播放路径会经过AudioFlinger的混音和重采样,消耗CPU;而offload路径是把压缩格式(如MP3/AAC)直接丢给ADSP解码,再将解码后的PCM送往DAC,链路更短,功耗更低。
杂音问题可能只出现在其中一条路径上。区分方法很简单:
- 用tinyplay播放WAV文件,走的是PCM路径
- 用播放器播放MP3/AAC时,如果系统开了offload,走的是硬件解码路径
如果一个文件在PCM路径下正常,在offload路径下有杂音,那就要重点查ADSP里的解码器配置、输出采样率协商和AFE端口参数。如果两条路径都有杂音,问题更可能在共用部分,比如后端codec配置、时钟或者硬件。
顺便说一句,很多工程师忽略了一个基础检查:通过/proc/asound/pcm或者tinypcminfo确认当前播放节点的采样率、位深和通道数是不是和文件一致。因为音频播放链路里的每个环节,只要有一个地方配置成了不匹配的参数,就会触发隐性的重采样或者截位,表现出来就是“有杂音”。
3.2 播放链路上的音效后处理参数怎么快速排查
音效后处理是“播放杂音”问题里最大的变量。高通平台上常见的后处理模块包括EQ均衡器、DRC动态范围压缩、低音增强、虚拟环绕、扬声器保护(Speaker Protection)等。这些参数一般固化在ACDB或者Audio Calibration中,播放时由ADSP动态加载。
如果我怀疑后处理算法有问题,通常按下面的顺序排查:
第一,找“铝板测试”。在AudioReplay中直接播放文件,然后关闭所有音效,也就是走“原始PCM直通”模式。如果杂音消失,说明问题出在后处理模块;如果杂音还在,说明问题出在后处理之前或者后端。
第二,逐级打开音效模块。先从EQ开始,再到DRC,再到低音增强,每次只打开一个模块,同时播放同一个测试文件。这样就可以锁定是哪一个模块引入的杂音。
第三,打开QACT(Qualcomm Audio Calibration Tool),查看当前调音工程中后端处理的参数值。重点看两个:一是EQ各频段的增益,有没有在某几个频段拉得太高导致削波;二是DRC的阈值和压缩比,压缩比太大会出现明显的音量起伏和“呼吸效应”。
这里补充一个容易被忽视的点:很多人以为音效后处理只影响播放,不影响录音。但实际上高通平台的Voice和VoIP通话链路里,后处理同样会被加载。如果客户反馈的是“微信语音播放有杂音”,那既要查播放链路的音效,也要查通话语音链路的AEC/NS,两者可能在同一个DSP图上同时生效。
3.3 采样率、位深、通道数不匹配引发的“机械性杂音”
还有一种杂音,特征非常明显——像节拍器一样周期性咔哒声,或者放快节奏音乐时伴随“嗒嗒”声。这种通常是采样率不匹配导致的。
高通ADSP的AFE端口会维护一个固定的输出采样率。举个例子,某个平台的AFE端口配置成48kHz,但应用层播放的是一个44.1kHz的WAV文件,这时候系统必须做SRC(Sample Rate Conversion)把44.1kHz转成48kHz。如果SRC的质量等级设置成Low,或者重采样过程中有裁剪和溢出,就会产生混叠噪声,听感就是发闷的、带杂音的。
排查这类问题的常规操作:
- 先用
tinypcminfo -D <card> -d <device>确认当前设备节点支持的采样率和位深 - 再通过
dumpsys media.audio_flinger | grep -A 20 "Output thread"查看AudioFlinger实际协商出来的采样率 - 如果条件允许,用
tinyplay分别播放16kHz、44.1kHz、48kHz的测试文件,看杂音是否只在某个采样率下出现
只要是“特定采样率下出现杂音”,就别往硬件上猜了,先查SRC和AFE端口配置。
4. QXDM音频日志抓取与DSP内部状态核对
高通平台调试,离不开QXDM。很多人觉得QXDM是给modem工程师用的,其实音频调试同样依赖它。当算法参数、链路配置都检查过之后,如果问题还悬而未决,那就需要看DSP内部到底发生了什么。这类信息应用层日志是给不出来的。
4.1 日志开关与抓取方法
抓取QXDM音频日志前,先把手机或设备通过USB连到电脑,确保DIAG口可用,然后在QXDM里按下面步骤操作:
- 打开Options -> Communication,选择正确的端口(通常是USB DIAG或DM端口)
- 在View -> Message Viewer里打开消息窗口
- 通过View -> Message Packets -> Item Count或者直接加载dm_audio相关的配置文件,开启音频消息过滤
- 把DFAULT和AUDIO相关的Message Mask全部打开,尤其是AFE、ADSP、Audio HAL相关的类别
- 开始抓log,然后复现播放杂音的过程,尽量持续几十秒到一分钟,确保关键日志被完整记录
抓到的log可以用QCAT解析,过滤关键字“AFE”“AUDIO”“ADSP”“ACDB”“PCM”等。很多杂音问题的根源,在log里表现得非常直白,比如AFE端口配置的采样率莫名跳变、ACDB加载失败、后处理模块切到低功耗模式等。
4.2 关键节点:从Audio HAL到AFE端口再到Codec
QXDM日志量很大,如果对整段log无从下手,可以按下面这个顺序逐步核对。
先看Audio HAL的打开设备请求。高通平台的audio HAL在播放时会向内核ALSA申请打开某个PCM节点,同时把采样率、位宽、通道数等参数下发给ADSP。日志里能看到类似open pcm devices的记录。如果这里申请的采样率和实际文件不一致,后面就会触发重采样。
再看AFE端口的配置。AFE是ADSP里负责与外部音频总线交互的模块,日志里通常会有AFE_PORT_START、AFE_PORT_CONFIG等事件,记录端口号、采样率、位宽、通道映射等。我遇到过的问题是,AFE端口同时被多个音频流占用,导致采样率被一个低质量会话强行改变,最终播放端听到的就是周期性爆音。
最后看Codec端的配置。高通codec驱动(wcd9340/wcd9385等)在ALSA里有一堆mixer控件,日志可以确认codec的PGA增益、DAC模式、耳放是否正常启用。有些项目的杂音是codec在低功耗模式和省电模式之间切换时产生的pop音,这类在log里能看到模式切换事件。
4.3 用AudioReplay对比DSP处理前后的差异
QXDM抓log的同时,我通常会配合QACT的AudioReplay工具一起用。AudioReplay可以直接选择一个PCM设备,指定采样率、位深、通道数,播放一段WAV文件。它绕过了上层应用,可以在最短路径上验证底层播放是否正常。
实际操作时,用AudioReplay播放同一个杂音文件,如果杂音不存在,说明问题出在上层应用或AudioFlinger之后的某个环节;如果杂音依然存在,那目标就很明确了——就是在AudioReplay所走的链路上,包括ALSA配置、ADSP后处理、codec参数。
结合QXDM日志,我们可以对比“输入端下发的是什么”和“输出端实际执行的是什么”。很多时候,杂音不是某个模块自己坏掉了,而是模块之间传递的参数错位了。比如上层说播44.1kHz,ADSP却默认按48kHz处理;上层说开DRC,ADSP却加载了一套曝光过度的参数。这类问题,单看代码不一定找得到,看log反而一目了然。
5. 硬件与时钟问题:软件排查全绿时转向模拟域
如果软件链路已经查到山穷水尽,日志也看不出毛病,这时候就该冷静下来,把注意力放到模拟域。音频问题最“阴”的地方在于:软件配置全对,但硬件供电、时钟、PCB布局中的任何一个不起眼的细节,都能让输出带上杂音。
5.1 电源纹波与Codec供电
Codec对电源纹波非常敏感。特别是内部集成了DAC和耳机放大器的codec,如果AVDD、DBVDD、CPVDD这些电源脚上的纹波超标,输出音频里就会带上电源噪声。这种噪声在听感上通常表现为固定频率的嗡嗡声,用频谱仪看往往在100Hz、1kHz或者某个开关频率及其谐波上。
排查时用示波器直接量codec电源引脚,重点关注两点:
- 纹波幅度是否在datasheet要求的范围内,通常要求几十毫伏以内
- 纹波的频率和杂音的频率是否对应,比如杂音是10kHz的嘶声,而某个DC-DC的开关频率恰好是10kHz,那就八九不离十了
我遇到过最典型的案例,是智能音箱上LED驱动和音频codec共用了同一个电源轨,LED调光时PWM信号直接把杂音“刻”进了模拟音频。这种问题软件调一辈子都调不好,只能从硬件布局和电源隔离上解决。
5.2 MCLK/BCLK异常与爆音特征
数字音频时钟异常的表现和电源噪声完全不同。MCLK频率偏了,会导致音频整体音调不准;MCLK抖动大,会让DAC的时钟恢复电路工作不稳定,轻则声音发毛,重则周期性爆音。
测量时重点看MCLK的波形边沿是否干净、频率是否准确、抖动(Jitter)是否偏大。音频常用的MCLK频率是12.288MHz或者24.576MHz,它们是48kHz采样率的整数倍,和44.1kHz体系(11.2896MHz/22.5792MHz)有严格的对应关系。如果板上MCLK是用某个通用晶振凑的,频率不是标准音频时钟,DAC内部的分频逻辑就会出错,声音一定好不了。
另外,如果是I2S或TDM总线传输音频,用示波器抓BCLK、LRCLK、DATA三个信号,看电平标准和时序关系是否符合codec的要求。特别是高速总线上面,信号反射会造成码间干扰,这种问题在高低温测试中更容易暴露。
5.3 接地、走线与干扰的典型特征
硬件杂音里,最“玄学”的是接地和走线问题。典型特征有几种:
- 设备插上充电器时杂音明显加重,拔掉就消失。这是地环路和充电器噪声耦合的典型表现
- 喇叭音量和屏幕亮度同时变化时杂音大小跟着变,这是显示模组和音频走线之间的耦合
- 只有在打电话或者4G/5G数据传输时出现“滋滋”声,这是RF干扰耦合进音频链路,俗称TDD噪声
这类问题的排查方向通常是:检查codec的地和主地之间是否单点连接,检查音频走线是否远离开关电源和射频走线,检查喇叭线是否和LED线平行走线。我见过一个案子,喇叭负极端子离天线馈点太近,连上喇叭后整机灵敏度都受影响,播放音频时还伴随周期性嘶声。
硬件的排查不像软件那么“迅速”,往往要来回改版才能验证。所以在软件排查阶段,我建议大家在提硬件问题前,先准备好三样东西:示波器测的电源纹波波形、MCLK/BCLK的时钟波形、杂音输出端的频谱截图。带着数据去跟硬件工程师沟通,效率会高很多。
6. 实战案例复盘:四种高频杂音从现象到根因
理论说再多,不如复盘几个真实案例。下面这四种场景,我在不同项目里都遇到过,而且每种都有一定代表性。
6.1 案例一:AGC过度放大背景噪声
现象:设备放在桌面上不播放任何声音,用自带录音APP录制10秒“空气”,回放时能听到明显的持续嘶嘶声,并且底噪音量不稳定,有“起伏感”。
排查过程:先在PC上回放相同录音文件,确认文件本身就是这样;再用tinycap抓原始PCM。关键发现是,原始PCM在无语音输入时,波形幅度呈现周期性上升和下降,静音段振幅并不恒定。这说明问题出在录音的自动增益环节。检查音频效果器配置,发现AGC的target level设置过高,导致静音时增益被一步步推到最大,把codec底噪和房间环境噪声一起抬了上来。
处理方式:将AGC改为固定增益模式,把数字增益调到能覆盖正常讲话距离的范围,同时调低codec PGA约6dB,给动态余量留出空间。改完后重新录制空气噪声,频谱底噪明显下降,回放时不再有那种“呼—呼—”的呼吸感。
6.2 案例二:DRC参数异常导致音量起伏与失真
现象:播放节奏感强的音乐时,整体声音忽大忽小,而且在鼓点密集处出现明显的毛刺感、发闷。
排查过程:播放1kHz正弦波测试时,输出波形正常;播放音乐信号时,输出波形出现周期性的振幅包络变化。进一步检查后处理链路,发现DRC(动态范围控制)模块的压缩比被调到一个非常大且不合理的值,导致当音乐电平在某个阈值附近波动时,增益被频繁“拉扯”,产生了类似抽吸效应的听感。
处理方式:重新校准DRC参数,把压缩比调回合理范围(通常是1.5到3之间),同时调整启动时间和释放时间,让增益变化听感上更平滑。最终播放同曲目,音量起伏消失,鼓点也不再“发闷”。
6.3 案例三:采样率不匹配产生的连续爆音
现象:播放特定的44.1kHz采样率WAV文件时,每隔几十毫秒到几百毫秒出现一次“咔哒”爆音,但播放48kHz文件时现象消失。
排查过程:先用tinypcminfo确认声卡设备节点,再用dumpsys media.audio_flinger查看AudioFlinger实际输出参数,发现系统播放线程跑在48kHz,而文件是44.1kHz,两者之间依赖SRC进行转换。QXDM日志里也看到AFE端口连续报告SRC相关的warning。进一步分析发现该平台上SRC模块的配置被改成了低质量档位,且缓冲区边界存在计算误差,导致每次跨块转换时产生相位跳变。
处理方式:将SRC质量等级调整到High,并修正缓冲区长度的取整逻辑。改完后同一文件播放30分钟,未再出现任何一次爆音。
6.4 案例四:EQ低频增益过高导致的削波破音
现象:播放低频丰富的电子音乐或电影原声时,音量调到60%以上就会出现破音;播放人声播客则正常。
排查过程:在QACT调音工程里查看EQ曲线,发现低频段(80Hz到120Hz)被拉高了接近10dB,中高频段也有一个明显的增益峰。这个配置在播放响度较高的音乐时,会让数字信号在EQ模块之后触顶削波,输出方波化的低频成分。用1kHz和100Hz正弦波分别测试,1kHz输出正常,100Hz输出在幅度超过某个阈值后顶部逐渐变平。
处理方式:把低频增益降到合理范围,同时在后处理链路的最后一级之前增加峰值限制器,防止任何频段出现数字溢出。改完后再用原曲测试,音量开到80%也无破音,低频听感依然饱满。
7. 排查杂音问题的通用心法
最后分享一点我自己的长期经验。音频杂音类问题,90%以上都可以通过“先固定素材、再分段隔离、再数据化对比”的方式定位,区别只在于慢和快。很多人卡壳,是因为跳过了前两步,直接从“觉得是某个模块有问题”开始调,结果就是越调越乱。
我在做高通平台音频调试时,习惯把“原始文件、原始录音PCM、底层播放输出录音”这三份素材固化下来,放在同一个工程目录里。遇到问题先做听感分类,再快速走一遍排除实验,把杂音限制到“录音采集”“播放链路”“音效算法”“模拟硬件”这四个大筐里的某一个。这个流程看起来很基础,但真的能帮你节约大量时间。
另外建议音频调试的工位常备一副监听耳机,并且养成用频谱分析软件观察的习惯。耳朵会疲劳,但数据不会。杂音问题最大的特点就是现象会骗人,只要把数据链路抓干净,答案往往就藏在某一个节点前后。