简介:面向嵌入式驱动开发者的高通平台音频入门手册,基于实际bringup经验整理,帮助读者系统建立从硬件底层到软件框架的完整认知,特别适合刚接触高通平台音频调试的工程师。资源为1个DOCX文档,压缩包大小仅2.61MB,轻量易读,已有近三千人学习查看。手册首先介绍音频软硬件系统框架,包括CODEC的数模/模数转换、均衡及噪声消除等处理功能,以及SLIMbus总线、GPIO控制和PIL固件加载机制;随后按bringup环节逐步拆解,从确认PIL是否成功加载、SLIMbus是否UP、声卡注册状态,到codec上电时序与复位、软硬件版本匹配、GPIO配置、外部芯片集成和audio通路搭建,每项均给出明确检查点与排查思路。更值得一提的是,手册还覆盖kernel层的device tree配置、系统层的audio相关系统属性列表以及HAL层的device table设置,让读者能沿着内核、系统、Hal三层脉络快速定位问题。对于需要撰写或理解高通音频驱动代码、排查无声或录音异常的开发者,这份文档是一份实用的速查参考。
1. 高通平台Audio入门:从“声卡不认”到“出声”的排查路线图
某个周一下午,我拿到一块新的高通平台主板,烧完系统,放歌没声音、录音全是底噪,dmesg里连声卡注册的日志都找不到。那会儿最缺的不是熟练度,而是一份能把Audio bringup按顺序走完的手册。这份《高通平台Audio入门》就是干这个的:它先讲Audio软硬件系统框架,把CODEC、SLIMbus、GPIO、PIL这几个关键硬件的角色捋清楚;再把bringup拆成八个检查点,从固件加载一路查到通路配置;接着给出kernel、HAL、系统层的代码位置和Route配置方法;最后是ACDB校准、QXDM日志分析和一批真实平台的踩坑案例。适合还在对着dmesg发呆的BSP新手,也适合需要快速判断问题出在硬件还是dts配置的老手。
2. 软硬件框架与代码地图:CODEC、SLIMbus与每一行代码的位置
要对高通平台的音频系统下手,第一件要做的事不是翻代码,而是把“音频数据从AP到Speaker到底经过哪些环节”在脑子里画出来。手册把这条链路分成了硬件和软件两条线,两张图讲完才进入bringup,这个顺序看着基础,实际能省掉后面一大半的定位时间。
2.1 硬件链路:AP、SLIMbus与CODEC的三角关系
硬件部分的核心是三块:AP端的音频DSP(ADSP)、负责数模/模数转换的CODEC、以及把两者连起来的SLIMbus总线。手册里特别强调了SLIMbus的作用——它是一种低功耗、多通道的串行总线,用来承载音频数据和控制命令。与传统I2S传数据、I2C传配置各管各的方案相比,SLIMbus把数据和配置通道统一了,但代价是bringup时多一个“总线是否UP”的检查项,这也是第3章排查清单里它排在第二的原因。
CODEC是音频信号进出的核心器件。以手册里提到的WCD9326为例,它内部包含ADC和DAC,分别负责把麦克风的模拟信号转成数字信号、把数字信号转成模拟信号去驱动Speaker。手册在硬件部分还专门对比了单端输出和差分输出的区别:Speaker通常走差分输出,两个输出端之间的电压差作为有效信号,共模噪声会互相抵消;而麦克风一般是单端输入,信号以地为基准,抗干扰能力相对弱。这块电路知识在排查“嘶嘶声”“底噪”的时候非常管用——如果差分线被布成单端,或者地线处理得不好,后边调通路的活全是白干。
把硬件角色归纳成一张表,排查时对照着看会更清楚:
| 器件 | 角色 | Bringup时需要确认的点 |
|---|---|---|
| AP/ADSP | 音频DSP与数据处理 | PIL固件是否加载成功 |
| SLIMbus | 数据与控制总线 | 总线是否UP、从设备是否枚举 |
| CODEC(如WCD9326) | ADC/DAC转换 | 上电时序、复位、供电是否正常 |
| WSA881x智能功放 | Speaker驱动 | BusID是否匹配、是否有输出 |
| GPIO | 电源/使能/复位控制 | 电平方向与dts配置是否一致 |
2.2 软件分层:内核、HAL与用户空间工具的代码位置
软件部分的代码位置,手册列得很细,几乎每个模块都给了具体路径。我在项目里最常翻的就这几处,按调试使用频率排个序:
| 代码路径 | 干什么用的 |
|---|---|
| /kernel/sound/soc/msm 与 qdsp6v2 | machine driver、平台驱动、FE/BE DAI |
| /kernel/sound/soc/codecs/ | WCD9320/9335等codec驱动 |
| /kernel/drivers/slimbus | SLIMbus总线驱动 |
| /hardware/qcom/audio/hal/msm8974 | 音频HAL层,声卡通路切换都在这 |
| /external/tinyalsa/ | tinymix / tinyplay / tinycap 三个调试工具 |
| /vendor/qcom/proprietary/mm-audio/ | ACDB校准数据库相关驱动 |
| /frameworks/av/services/audioflinger/ | 上层音频流管理 |
这里值得多说一句HAL层。高通平台的Audio HAL不只是把ALSA接口包一层,它还要负责ACDB(Audio Calibration Database)的加载和通路切换。你在audio_policy.conf里看到的路由策略,最终都是通过HAL调用tinyalsa底层的ALSA控件来生效的。所以改通路只改xml不重启HAL,很容易出现“配置看起来改了、实际没生效”的错觉,第5章的问题五就是典型。
2.3 一条播放链路:从APP到CODEC的完整路径
把硬件和软件合起来看,一次播放的请求要经过这些环节:应用进程把音频数据交给AudioFlinger,AudioFlinger按audio_policy.conf里的策略选择输出设备,HAL层查找对应的mixer通路,通过tinyalsa把PCM数据写进kernel的ALSA框架,ALSA再经qdsp6v2平台驱动把数据送进ADSP,ADSP通过SLIMbus写到CODEC的DAC,最后由功放驱动Speaker出声。手册后面所有bringup排查动作,本质上都是在确认这条链路上每一段有没有打通。
提示:排查时从两头往中间试效率最高——先确定 /proc/asound/cards 里有没有声卡,再确定应用层 tinyplay 能不能出声音,最后才去查中间的总线和寄存器。
内容看到这里只是“看懂架构”,真正的工作量在第3章的bringup流程。接下来把八个检查点逐个过一遍,你就知道这份手册为什么会把“确认PIL加载”放在第一位。
3. Bringup全流程拆解:PIL、SLIMbus与声卡注册的八个检查点
手册的bringup章节是整份文档里含金量最高的一部分。它把Audio bringup拆成八个检查点,严格按顺序走完,大部分“无声、无麦、声卡不认”的问题都能在某个环节被定位到。
3.1 八个检查点:按顺序执行的启动清单
检查点一:PIL(Peripheral Image Loader)是否成功加载。ADSP的固件是由PIL在启动阶段加载的,固件没起来,后边所有音频寄存器的读写都是空的。排查命令如下:
# 查 PIL 加载日志,关注有没有 failed / error adb shell dmesg | grep -iE "pil|adsp|qdsp" # 确认 ADSP 相关节点是否创建 adb shell ls /sys/kernel/boot_adsp /dev/adsprpc-smd 2>&1第一行命令看加载过程中有没有报错,第二行看节点是否真实存在。如果dmesg里出现类似pil failed to load的报错,优先检查固件镜像有没有放对分区、版本是否和平台匹配。
检查点二:SLIMbus是否UP。总线不起来,CODEC在AP眼里就是隐形设备:
# 抓 SLIMbus 相关日志 adb shell dmesg | grep -i slim # 有 debugfs 时直接看总线状态 adb shell "cat /sys/kernel/debug/slimbus/* 2>/dev/null"正常状态下能枚举出slave设备,设备ID和硬件原理图对得上就说明总线OK。这里常见的问题是SLIMbus的时钟没起,或者dts里slim节点status没配成okay。
检查点三:确认声卡是否注册,这个最直观:
adb shell cat /proc/asound/cards声卡没出现在列表里,基本可以断定问题出在检查点一、二或codec驱动对硬件的探测上,而不是上层HAL的问题。到了这一步不要急着改HAL,先把底层设备找出来。
检查点四:确认codec上电时序和是否正确复位。手册的原话是“确认codec上电时序和是否正确复位”,实践里我会用示波器同时抓电源、复位、CLK三根线的上电顺序,对照参考原理图的时序要求。电源没稳就先拉复位,或者复位脚一直被低电平拉住,codec的寄存器读出来全是0xFF,读什么都是错。
检查点五:软硬件是否匹配。这个“匹配”包含两层:一是CODEC型号和dts里的compatible是否一致;二是固件版本里的ACDB数据和硬件版本是否对得上。高通平台常见做法是在HAL初始化时读codec的device ID,和预期值比对,ID对不上就直接判定音频不可用。
检查点六:GPIO配置。CODEC的供电、复位、使能信号都挂在GPIO上,配置错了轻则功能异常,重则烧器件:
# 确认某个 GPIO 当前电平状态(以 54 号为例) adb shell "cat /sys/class/gpio/gpio54/value"对照原理图检查每个控制脚的电平方向,是拉高还是拉低、是输出还是输入,全部要和硬件设计一致。很多“上电没反应”的问题,最后查下来就是GPIO默认电平把复位脚一直压住了。
检查点七:集成外部芯片模块。像WSA8815这类智能功放,本身就是挂在soundwire或i2s上的独立器件,需要单独确认芯片有没有起来、BusID是否匹配。手册的问题集里专门有一条WSA8815 BusID问题导致声卡注册失败的案例,第5章会展开讲。
检查点八:配置audio通路。前面七个都过了还是没有声音,剩下就是通路配置的问题。用tinymix把某个控件打开声音就出来,基本可以定位到mixer path配置漏了节点。
3.2 Kernel层配置:Device Tree与machine driver
kernel层的bringup主体是设备树。手册给的代码位置在 /LINUX/android/kernel/arch/arm/boot/dts/ 下,对应平台就是msm8***-.dts和msm8**-*.dtsi。machine driver在 /kernel/sound/soc/msm 下,负责把CPU DAI、CODEC和DMA通过snd_soc_dai_link组织起来。
新平台要加音频支持,第一步是确认dts里slimbus节点和codec节点都配了:
// msm8xxx.dtsi 中 codec 节点配置示意 &slim_msm { status = "okay"; // 总线必须打开 wcd9326: wcd9326@0 { compatible = "qcom,wcd9326"; reg = <0x0 0x0>; reset-gpios = <&msm_gpio 54 0>; // 复位脚:GPIO54,低有效 power-gpios = <&msm_gpio 55 0>; // 电源控制脚 vdd-supply = <&pm8994_l22>; // 供电轨 }; };compatible的值要和codec驱动里of_device_id里的字符串完全一致,否则驱动probe不进来。reset-gpios、power-gpios这两个属性名对应驱动里gpiod_get()的命名,改动后要同步驱动。常见的坑是只改了dts没看驱动里对GPIO语义的定义,还有供电轨的regulator没配导致probe反复返回-517(EPROBE_DEFER)。
3.3 系统层与HAL层:系统属性与Device table
系统层的bringup主要是audio相关的系统属性。手册列了一张audio系统属性表,像persist.vendor.audio.*这一类的键值,作用包括控制ACDB校准数据是否加载、是否启用某一类音效、以及调试log开关。到新平台先把调试相关属性打开,就能在logcat里看到HAL每个通路的切换过程,对排查“为什么走这条路”帮助很大。
HAL层有两个地方要改:一是device table,它定义了平台支持的音频设备列表,比如Speaker、Headset、Mic对应的声卡端口号,上层策略根据这个表做路由决策;二是Audio HAL自身的改动,主要是通路切换逻辑和新硬件的适配。手册里专门有一节“Audio hal changes”讲这两个文件的修改方法,内容不深但路径给得很准。
3.4 Route配置:Mixer path xml与ADB调试通路
通路配置是bringup最后一步,也是日常调音最频繁改的东西。高通平台的通路定义在mixer_paths.xml里,每一路都是一个path节点,节点内是一组ctl控件和值的组合:
<!-- mixer_paths.xml:定义一条 Speaker 播放通路 --> <path name="speaker-playback"> <ctl name="SLIM RX0 MX Volume" value="84" /> <ctl name="SLIM_0_RX Path" value="SLIM RX0" /> <ctl name="SPK Switch" value="ON" /> </path>每个ctl名字都必须能在tinymix的输出里找到,value的取值范围也要和控件定义一致。值不在合法范围内,控件写入会直接失败。改完xml要重新编译进system镜像,替换到/vendor/etc或/system/etc对应位置后重启生效。
调试通路时最快的办法是绕过xml,用tinymix手动一条条打开控件,确认声音出来后再回头改xml。手册里把这种方法叫ADB DEBUG ROUTE,实际项目里我几乎每次都这么干:先手动切通路确认硬件没问题,再固化到xml,能省掉一大半“改xml无效”的扯皮时间。
4. 调试与校准实战:寄存器读写、QXDM日志与ACDB参数
bringup跑通之后,项目进入调试期,最常用的技能就是读写寄存器、抓日志和调ACDB校准数据。这三样东西分别对应硬件层、DSP层和参数层,缺哪个都容易在现场抓瞎。
4.1 寄存器读写:SLIMbus与soundwire设备的操作方式
Audio调试绕不开寄存器。手册把寄存器读写分成了SLIMbus、soundwire和WCD codec三大类,每类都给了具体的操作方式。
SLIMbus从设备的寄存器读写,调试入口一般在debugfs下:
# dump SLIMbus 从设备全部寄存器 adb shell "cat /sys/kernel/debug/slimbus/slimbus_slave_reg" # 读单个寄存器:参数依次是设备地址和寄存器偏移 adb shell "echo 0x0d 0x00 > /sys/kernel/debug/slimbus/slimbus_slave_reg" # 写寄存器:在设备地址和偏移后追加要写入的值 adb shell "echo 0x0d 0x00 0x1f > /sys/kernel/debug/slimbus/slimbus_slave_reg"echo进debugfs这个动作,看起来像写文件,实际上是触发内核里的slimbus驱动完成一次总线读写。0x0d替换成你自己平台上CODEC的slave设备地址,0x00是目标寄存器偏移,第三个参数是写入值。读寄存器时不要带第三个参数,否则会被当成写操作。
WCD系列codec的寄存器读写更直接,ALSA框架已经把codec寄存器映射到了asoc调试节点:
# 查看 WCD 系列 codec 寄存器一览 adb shell "cat /sys/kernel/debug/asoc/codec:*regs" # 读特定偏移(以 0x40 为例) adb shell "cat /sys/kernel/debug/asoc/codec:0x40"至于soundwire的master和slave设备,操作方式和SLIMbus类似,只是debugfs节点路径换成soundwire对应的目录。读寄存器这一步是判断codec是否在工作状态的最快手段。比如读DAC的数字音量寄存器,能确认音量有没有被正确设置;读ADC状态寄存器,能知道录音通路有没有真正打开。
4.2 日志调试:QXDM、QCAT与代码层的log开关
到了framework层和DSP层,寄存器就不够用了,得上日志。手册把日志分成三个量级:kernel层、framework层、以及DSP侧的QXDM日志。
代码层的log开关分JAVA、C/C++、kernel三种:
| 代码类型 | 开启方式 | 对应代码位置 |
|---|---|---|
| Java | 把具体Java文件里的Log.i/d改为Log.v | /frameworks/base/media/java/android/media |
| C/C++ | 打开audio HAL里的ALOGE/ALOGV宏开关 | /hardware/qcom/audio/hal |
| kernel | 打开sound/soc下驱动的dev_dbg、pr_debug | /kernel/sound/soc/msm |
QXDM的用法分两步:先在QXDM里勾选audio/voice的log codes,让DSP把内部日志上报;然后把抓下来的log用QCAT打开分析。QCAT里能看到AFE、ADM、ASM这些DSP模块的处理过程,比如某个session有没有建立、端点的采样率是多少、有没有报underrun。手册给了QXDM代码对照表,里面把每段DSP日志对应到音频通路的具体环节,排查DSP侧问题时对照着查就行,不用自己猜日志含义。
4.3 ACDB校准:为新设备创建ID与校准数据
ACDB(Audio Calibration Database)是高通平台音频校准的核心,管着每个音频设备的增益、滤波器和DSP参数。新平台如果加了一个Mic或Speaker,不校准的话,表现就是录音声音小、播放破音、回声消不掉。
手动加设备的流程手册写得很清楚,分两步。第一步创建ACDB device ID,这个ID要和HAL里使用该设备的端口对应上;第二步在ACDB工具里录入校准数据,通常是增益值和滤波器系数,最后生成acdb文件放到系统的校准目录下。校准数据和应用层对接的路径在 /vendor/qcom/proprietary/mm-audio/ 下的ACDB驱动里,HAL在启动时会加载对应平台的acdb文件。
这一步是纯经验活,没有任何命令能替代听感和设备测量。我一般会先用声学测试仪量出频响曲线,再在ACDB工具里把增益和EQ调到目标曲线,最后用tinyplay播放标准音频人工验一遍。新手最容易犯的错是只调了增益没调滤波器,结果响度对了但音色还是不对。
5. 常见问题排查:声卡注册失败与无声无麦的五个踩坑现场
手册最后的问题集收录了两代平台的典型案例,我按“现象→原因→解决”的顺序整理成五条。这些案例的共性结论是:大多数音频问题不是代码逻辑写错,而是某个配置和硬件对不上。
5.1 问题一:WCD9326磁珠问题导致声卡注册失败
现象:系统起来后 /proc/asound/cards 是空的,dmesg里codec的probe报错,寄存器读出来全是0。
原因:WCD9326的供电网络上有一个磁珠,磁珠虚焊或者选型不对,导致codec供电纹波过大,芯片没能完成内部上电初始化,probe就失败了。这种问题只看log很难定位,因为代码路径上看到的是总线读写超时,很容易让人去查SLIMbus配置。
解决:用示波器测磁珠两端的波形,确认供电是否干净、上电时序是否满足要求。更换或补焊磁珠后声卡正常注册。我当时的排查顺序是先查总线再查GPIO,最后才想到电源网络,实际应该第一步就量磁珠两端电压——因为codec的probe失败在log上表现都一样,但供电问题检查成本最低、最容易先排除。
5.2 问题二:WSA8815 BusID问题导致声卡注册失败
现象:声卡注册失败,log里报WSA8815相关设备找不到,或者设备枚举到了但ID和预期不符。
原因:WSA8815挂在soundwire总线上,BusID分配错了。驱动里期望的ID和实际硬件或固件烧录的ID不一致,设备就认不出来。这属于典型的软硬件配置不一致问题,有时候连参考设计都容易看漏。
解决:对照硬件原理图和芯片手册确认实际BusID,修改dts或驱动里的BusID配置,重新编译烧录。这个问题的本质是配置一致性,排查时先把源文件里的ID值和芯片上的丝印或烧录值对齐,不要在代码里反复试。
5.3 问题三:Speaker无输出
现象:声卡正常、应用层播放不报错,但扬声器无声。
原因:通路没配全。最常见的是mixer_paths.xml里Speaker播放通路少了一个关键的控件开关,比如功放的使能控件没打开;或者GPIO配置把功放使能脚拉反了。
解决:先用tinymix逐一打开Speaker通路所有控件,确认手动能出声;再对比参考平台的xml把缺失的ctl补上。这一步用第3章说的ADB DEBUG ROUTE方法,比反复改xml重烧快得多。
5.4 问题四:Mic无输入
现象:录音文件生成正常,但内容全是噪声或无信号,tinymix里也看不到MIC对应的控件电平变化。
原因:MIC的偏置电压(bias)没打开,或输入通路没有接上codec的ADC。有些平台的MIC通路需要单独打开bias控件,漏了这个,麦克风等于没供电。
解决:检查dts和mixer_paths.xml里MIC bias相关配置,用tinymix打开MIC Bias控件,再用tinycap录音验证波形。如果bias电压量出来不对,还要回头查供电电路。
5.5 问题五:修改mixer xml无效
现象:改完mixer_paths.xml、编译烧录后,tinymix查到的控件状态还是旧值,行为没变。
原因:xml没有被编进实际使用的路径。高通平台不同产品可能把xml放在/system/etc、/vendor/etc两个位置,或者被编译成动态配置后由HAL从persist分区读取——改错了文件等于白改。
解决:用find确认设备上实际加载的xml路径,修改后确认镜像里的文件确实被刷新(看时间戳或md5),重启后再验证tinymix输出。后来我每次都先adb pull把设备上实际生效的xml拉下来对比再改,先拉下来对比再改,这个步骤帮我省了不少无用功。
提示:上述五个问题,现象和原因在不同平台会有差异,但排查顺序是通用的——先看声卡和总线,再查供电与复位,最后才是通路与配置。
6. 二次开发指南:从Mixer Path动手改一条自定义录音通路
拿到这份手册,最值得动手的二次开发不是改驱动,而是学会自己加一条音频通路。很多项目需求听起来复杂,比如“外部麦克风单独一路录音、不和主Mic混音”,其实实现就两步:在mixer_paths.xml里加一条path,再确认HAL能调用到它。
第一步先看现有通路,找一条最接近的:
# 拉取设备上实际生效的通道配置文件 adb pull /vendor/etc/mixer_paths.xml . # 搜现有录音通路,通常有 headset-mic、main-mic 等 grep -n "mic" mixer_paths.xml第二步仿写一条新通路,控件名都从现有通路里复制,不要自己编:
<path name="external-mic-record"> <ctl name="MIC Bias" value="ON" /> <ctl name="ADC1 Switch" value="ON" /> <ctl name="MultiMedia1 Mixer" value="ADC1" /> </path>第三步验证。把xml替换到设备上重启,先用tinymix看看新控件能不能查到,再用tinycap录音:
# 录制 5 秒验证新通路 # -D 指定声卡设备号,-c 声道数,-r 采样率,-b 位深,-T 录制时长 adb shell tinycap /data/local/tmp/test.wav -D 0 -c 2 -r 48000 -b 16 -T 5 # 回放确认 adb shell tinyplay /data/local/tmp/test.wav如果录出来无声或破音,回到第4章的寄存器读写方法,查ADC1对应的寄存器有没有正确切换。
这条流程走通之后,再去看HAL层如何根据场景选择通路、ACDB如何给新设备挂校准参数,就都顺理成章了。我从那以后,每次拿到新平台都强制自己先走一遍“查声卡→查总线→查供电→手动tinymix→固化xml”的完整链路,而不是上来就翻代码。这个习惯让我的Audio调试时间至少少了一半,希望也能帮到你。
本文还有配套的精品资源,点击获取