ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Android音频驱动核心:mixer_paths.xml配置与调试实战

Android音频驱动核心:mixer_paths.xml配置与调试实战 搞音频驱动的人迟早都要跟mixer_paths.xml这个文件打交道。我第一次接触它的时候是因为客户报了一个诡异的Bug手机插上耳机后音乐声断断续续有时候还一边有声一边没声。当时我翻遍上层音频策略查了AudioPolicy最后才发现问题出在这个配置文件里一条通路参数的设置上。从那天开始我就明白Android音频 HAL 层真正控制音频流向的核心就是这份不起眼的 XML。这篇内容我打算把mixer_paths.xml从头到尾拆开讲清楚包括它的定位、语法结构、常用配置节点、通路的选路原则、实际调试时怎么改怎么验以及在底层驱动调试中踩过的一些坑。无论你是刚入行做音频驱动的新人还是从上层应用转到底层的老手只要想搞懂 Android 音频通路是怎么串起来的这份内容都可以给你一个比较完整的参考。1. mixer_paths.xml 到底是什么它在音频系统中扮演什么角色1.1 先搞清楚它在整个音频架构里的位置Android 的音频系统从上层到硬件大致可以拆成几层应用层通过 AudioTrack/AudioRecord 跟 AudioFlinger 交互AudioFlinger 根据 AudioPolicy 的策略决定把音频流送往哪个输出设备最终通过 Audio HAL 调用内核 ALSA 驱动由 Codec音频编解码芯片或 SoC 内置的音频模块驱动耳机、扬声器、麦克风等物理器件。mixer_paths.xml就在 Audio HAL 层负责描述“某个逻辑音频设备比如耳机、扬声器、听筒对应的混音器控件组合以及控制顺序”。也就是说上层说“现在要播到耳机”HAL 层就会根据这份 XML 去查“耳机”这个 path 要操作哪些 Kcontrol打开哪些开关切换哪些 MUX最后把音频信号从 SoC 的数字接口一路送到耳机的模拟输出端口。有人可能会把它跟audio_policy_configuration.xml弄混。前者是策略层描述的是系统有哪些音频设备、每种设备支持什么采样率、声道数以及路由选择的策略规则后者是通路配置层描述的是具体到 Codec 寄存器级别的通路设置。简单来说策略文件告诉系统“可以选哪条路”通路配置文件告诉驱动“走这条路要经过哪些开关”。1.2 为什么非要用这样一个配置文件而不是直接改 C 代码你可能会有疑问既然 Audio HAL 层本身就是 C/C 写的为什么不直接在代码里写死通路配置而是要搞一个 XML 在运行时解析原因有两个第一个是解耦第二是可配置性。音频 Codec 的种类非常多即使同一颗 SoC搭配不同的 Codec 芯片、不同的板卡设计通路就会有很大差异。如果把通路配置写在 C 代码里每换一种硬件组合就要重新编译 HAL 库这对方案商来说是不能接受的。通过mixer_paths.xml同一个 HAL 二进制可以加载不同的 XML适配不同硬件平台大大简化了移植工作。另外这个文件在运行时可以修改也方便了调试。底层驱动开发时经常要试听不同增益设置、切换不同通路直接改 XML 后重启audioserver进程就能生效比每次改完 C 代码重新编译烧录要快得多。2. 文件结构与配置语法基础2.1 根节点与命名空间标准的mixer_paths.xml以mixer为根节点通常在根节点上会带上 XML 命名空间声明mixer xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:noNamespaceSchemaLocationhttp://source.android.com/schema/audio/mixer_paths.xsd整个文件的内容都嵌套在mixer节点中。文件里主要包含两种子节点一种是直接挂在mixer下的ctl节点用于配置全局生效的混音器控件另一种是path节点用于定义具体的音频通路。2.2 全局配置节点一组始终生效的默认值没有嵌套在任何path内部的ctl就是全局配置。这类节点描述的是一条路径创建或切换时必须保证的“前提条件”通常用于配置音频编译码器内部对多个通路都必须有效的部分例如核心时钟的 MUX、共享的音频总线通道模式、默认的采样率配置等。举个例子高通平台上经常能看到这样一段mixer ctl nameSLIM RX0 MUX valueAIF1_PB / ctl nameSLIM_0_RX Channels valueOne / ctl nameRX0 MIX1 INP0 valueRX0 / ctl nameRX1 MIX1 INP0 valueRX1 / /mixer这里SLIM RX0 MUX指定了 SlimBus 接收通道 0 的信号源SLIM_0_RX Channels设置了通道数RX0 MIX1 INP0和RX1 MIX1 INP0则定义了后端数字混音器的输入源。全局配置意味着这些设置在 HAL 初始化时会写入一次在后续的通路切换过程中只要没有别的ctl去覆盖它它们就一直有效。所以全局配置更准确的描述是“默认配置”用于确保系统处于一个已知的、合理的初始状态。2.3 path 节点一条音频通路的完整描述path节点是mixer_paths.xml的核心。它通过name属性定义了一个逻辑音频设备的名称节点内部则是一组要写入的ctl控件。path nameheadphones ctl nameSLIM RX0 MUX valueAIF1_PB / ctl nameSLIM RX1 MUX valueAIF1_PB / ctl nameSLIM_0_RX Channels valueTwo / ctl nameRX0 MIX1 INP0 valueRX0 / ctl nameRX1 MIX1 INP1 valueRX1 / ctl nameHPHL value1 / ctl nameHPHR value1 / /path高通平台的mixer_paths.xml中通常能看到这样一段headphonespath 配置。它完成的事可以拆成三步第一把两条 SlimBus RX 通道的信号源选到 AIF1让数字音频数据从 AP 侧进入 Codec第二把两条 RX 通道分别送入后端混音器 RX0 和 RX1完成从数字总线到 DAC 的数据路由第三打开左右耳机通道的驱动开关HPHL、HPHR让 DAC 输出的模拟信号真正送到耳机引脚上。2.4 为什么需要 path 内部的 path 标签多级控制与设备细分除了直接在path节点里放ctl很多平台的mixer_paths.xml里还可以看到path节点内部再嵌套path的情况。这种嵌套一般用于描述同一逻辑设备在不同场景下的细分通路。举例来说扬声器可能有“正常播放”和“免提通话”两个场景虽然最终输出的物理设备都是扬声器但前级数字通路可能不同path namespeaker ctl nameSPK DAC value1 / path namespeaker-multimedia ctl nameRX3 MIX1 INP0 valueRX3 / ctl nameINTERNAL SPK PA value1 / /path path namespeaker-voice ctl nameRX5 MIX1 INP1 valueRX5 / ctl nameINTERNAL SPK PA value1 / /path /path嵌套path的具体工作机制是HAL 层在查找某个设备通路时如果发现目标 path 内部还有子 path就会把父 path 节点和匹配的子 path 节点的ctl合并执行父 path 的配置先写子 path 的配置后写形成一条完整的通路。这种设计灵活很多比如不同使用场景切换时只需在上层切换 subdevice子设备HAL 层就会自动把匹配的子 path 拿出来执行避免把不同场景的通路配置全部堆在一起互相干扰。3. 核心概念拆解Kcontrol、MUX、DAPM 与配置顺序3.1 Kcontrol用户空间与内核 ALSA 之间的小开关要真正理解mixer_paths.xml必须先理解 Kcontrol。Kcontrol 是内核 ALSA 驱动对外暴露的一个逻辑控制点。你可以把它想象成一块混音控制台上的旋钮和开关只不过这些开关不是物理存在的而是驱动代码里用snd_kcontrol_new结构体注册的。每个 Kcontrol 有一个唯一的名字一个可读可写的值用户空间通过tinymix或者 HAL 层封装的接口去读写它。驱动工程师在编写机器驱动machine driver和 Codec 驱动时会根据 Codec 的规格书把音频通路中所有需要外部控制的点注册成 Kcontrol。有些点是开关类型只有 0 和 1 两种状态例如功放使能、DAC 使能有些点是 MUX 类型值代表不同输入信号源的枚举有些点是音量类型值直接对应硬件寄存器中的增益档位。mixer_paths.xml中的ctl name...对应的name就是内核 ALSA 驱动中注册的ctl.name。如果名字对不上HAL 层写入时找不到对应控制点日志里会报Failed to apply ctl之类的错误所以配置文件里写的控制名必须跟驱动tinymix输出的名字完全一致。3.2 从 tinymix 中认识真实的 Kcontrol在实际调试过程中第一步几乎都是先跑一下tinymix命令看看系统里到底有哪些 Kcontrol 可用。例如在高通平台上输出会非常长几百行到上千行都有可能其中比较典型的几类长这样Number of controls: 461 ctl type num name value 0 ENUM 1 SLIM RX0 MUX AIF1_PB 1 ENUM 1 SLIM_0_RX Channels One ... 45 BOOL 1 HPHL false 46 BOOL 1 HPHR false ...值得说明的是tinymix输出的name必须跟 XML 中ctl name完全一致包括大小写和空格。否则驱动会调用ctl_name去查找时匹配不到通路配置写入失败表现出来就是设备没声音。我曾经在联调时遇到过因为大小写不一致导致耳机通路一直打不开的情况这类问题从 log 里很难发现但直接对比tinymix输出与 XML 内容很快就能定位到。3.3 信号流向视角下的通路配置拿到 Codec 的 datasheet 之后配置通路的思路其实很简单把信号从源头到目的地路径上的每一个开关都打开把每一条 MUX 都选对方向路径上的节点也就是需要配置的 Kcontrol。以播放通路为例。一个典型的 I2S 播放通路会经过这样几个环节首先SoC 的 I2S 或 SlimBus 控制器把数字音频流发送给 Codec 的数字接口接着数字信号进入 Codec 内部的前端Front-end通道通过* MUX选择进入特定的 DACDAC 把数字信号转成模拟信号后模拟信号会经过通道 MixerMIX*、音量控制器、功放PA最终送到耳机的左右声道引脚。所以在配置 headphones 通路时你会看到类似这样的背靠背逻辑前端通道开启SLIM RX0 MUX选择到AIF1_PB将 SlimBus RX0 数据接入 Playback 通路通道数配置SLIM_0_RX Channels设为Two确保左右两个声道都被启用DAC 通路选择RX0 MIX1 INP0、RX1 MIX1 INP1选后级信号源让 DAC 正常接收前端数据输出使能HPHL、HPHR置 1打开耳机放大器的左右通道模拟信号送达耳机。这就是一次完整的通路配置过程。录音通路则完全反过来从模拟麦克风输入到 ADC再到数字接口传输给 SoC。3.4 配置顺序的讲究为什么先开 DAC再开 PAmixer_paths.xml中的配置顺序不是一个随意的事。Kcontrol 的写入顺序对音频质量有直接影响最典型的就是爆音问题。比如播放通路中如果先打开功放PA再去打开 DAC 和 MUX在 DAC 尚未稳定输出时功放就可能把 DAC 初始化的瞬间电压变化直接放大送到耳机或扬声器产生一声很响的“啪”。正确做法是先把数据通路打通让 DAC 的直流偏置稳定下来最后才打开 PA这样听到的就是干净的音乐声。高通平台上的PA开关注入点会放在 path 节点里很靠后的位置而 MUX 和 DAC 相关配置放在前面正是为了避免爆音。反过来关闭通路时则要先把 PA 关掉再关 DAC顺序同样重要。所以当你看到一份mixer_paths.xml里ctl的排列次序时不要觉得只是随手一写那基本上都是经过反复验证的最优时序。3.5 DAPM那些文件里没写的动态电源管理除了显式的ctl写入Codec 驱动中还有一套自动管理机制叫 DAPMDynamic Audio Power Management动态音频电源管理。DAPM 会根据音频流是否处于开启状态自动上下电某些音频组件例如 ADC、DAC、放大器等。在mixer_paths.xml里有些 Kcontrol 是带DAPM前缀的控件它们由 DAPM 机制管理驱动会实时探测音频通路的使用状态自动决定是否打开或关闭某些内部电源域。比如ctl nameSPK DAC value1 /这样的设置表面上看是写了一个控件实际底层是由 DAPM 根据通路完整性自动推导的。不过DAPM 自动管理的是内部电源域外部功放的使能引脚GPIO 控制的 PA通常还是要靠 path 节点里显式的ctl去操作因为外部功放不在 Codec 芯片内部DAPM 无法感知它的状态。4. 实操从零开始配置一条耳机通路4.1 动手前的准备工作摸清平台现状在动手改mixer_paths.xml之前先把基础环境准备好。首先是拿到对应平台的源码通常mixer_paths.xml放在hardware/qcom/audio/configs/platform/目录下或者device/vendor/product/audio/目录下不同方案商路径会有差异。其次确认你有一个可以获取 root 权限的调试机因为我们需要用到tinymix、tinyplay等工具来查看和验证效果。如果系统里没有这些工具可以在源码的external/tinyalsa目录下编译出来然后 push 到/data/local/tmp/并加执行权限。adb root adb remount adb push tinymix /data/local/tmp/ adb push tinyplay /data/local/tmp/ adb shell chmod 755 /data/local/tmp/tinymix adb shell chmod 755 /data/local/tmp/tinyplay这些工具是非常轻量级的 ALSA 用户空间工具可以直接访问/dev/snd/controlC0等设备节点绕过 Android 上层框架直接操作底层控件调试效率非常高。4.2 查看现有通路与 Kcontrol 列表接下来把当前所有 Kcontrol 的值导出一份作为参考基准adb shell /data/local/tmp/tinymix /tmp/current_mixer.txt然后在文件里搜索跟耳机相关的控件名字常见的关键词有HPHL、HPHR、HEADPHONE、HP、RX、MUX、DAC、PA等。举个例子在某颗 Codec 上跟耳机输出相关的 Kcontrol 可能是这样的ctl type num name value ... 77 ENUM 1 HP MUX DAC 78 BOOL 1 HP Driver false 79 ENUM 1 Class G Always 80 INT 1 HP Volume 100 ...还要看看当前处于什么状态。如果是刚开机大部分输出开关应该都是关闭的DAC 和 PA 处于 standby 状态。如果之前已经播过音乐有些开关可能还停留在上次打开的状态。4.3 设计通路配置方案假设我们要配置一个常规的耳机播放通路设计目标很清楚把 Playback 前端的数据送到 DAC再从 DAC 送到耳机驱动器HP Driver输出。那我们需要的配置项大致如下path nameheadphones ctl nameSLIM RX0 MUX valueAIF1_PB / ctl nameSLIM RX1 MUX valueAIF1_PB / ctl nameSLIM_0_RX Channels valueTwo / ctl nameRX0 MIX1 INP0 valueRX0 / ctl nameRX1 MIX1 INP1 valueRX1 / ctl nameHP MUX valueDAC / ctl nameHP Driver value1 / ctl nameHP Volume value100 / /path这里有几个设计要点需要说明第一SLIM RX0 MUX和SLIM RX1 MUX是 MUX 类型的控件用于选择信号源。在不同平台上MUX 可选的枚举值可能不同例如AIF1_PB、AIF2_PB、AIF3_PB等所以必须参照目标 Codec 的驱动源码和tinymix输出来确认枚举值是否有效。第二HP Volume的意义很关键。有些 Codec 的HP Volume控件其实控制的是模拟域的音量直接影响到耳机输出的响度和信噪比。很多工程师在调试时习惯用上层 AudioManager 的音量来调但底层也有自己的一套增益两层之间需要配合。如果底层增益偏低上层即使音量拉满也会觉得声音小如果底层增益过高又容易破音。第三关于 HPHL 和 HPHR 的开关时间点。如果耳机通路使用的是“耳机驱动”Headphone Driver这类控制点把HP Driver放在最后一个写就是为了确保在信号链路上所有前置环节都稳定之后才让信号到达耳机引脚从而把开机爆音风险降到最低。4.4 修改配置并验证将 headphones path 添加到mixer_paths.xml后需要重启音频服务让配置生效adb shell stop adb shell start也可以只重启 audioserveradb shell killall audioserver需要说明的是stop/start重启了 Android 框架会比较慢但能确保 AudioPolicy 和 AudioFlinger 全部重新初始化。而只重启 audioserver 通常也够了但如果 HAL 层库有缓存逻辑不一定能保证重新加载 XML 配置。验证时准备一首比较高质量的 WAV 音乐文件push 到手机上然后用tinyplay直接播放测试adb push test_stereo.wav /data/local/tmp/ adb shell /data/local/tmp/tinyplay /data/local/tmp/test_stereo.wav如果耳机端没有声音先检查tinymix输出确认刚才配置的控件是否都已正确写入adb shell /data/local/tmp/tinymix HP Driver adb shell /data/local/tmp/tinymix SLIM RX0 MUX如果某个值跟配置不一致重点排查几个方向Kcontrol 名字是否匹配、枚举值是否合法、驱动中是否有其他的机制比如 DAPM 时序把刚刚设定的值又覆盖掉了。如果播放正常再继续验证其他功能比如插拔耳机时自动切换通路、来电时通话音量、调节音量时是否有杂音等这些都要走完整的系统级验证。5. 常见问题排查与避坑技巧实录5.1 通路没声音从命名错误到 DAPM 状态通路配置后没声音是最常见的问题排查思路要系统化。先用tinyplay确认底层是否能出声如果底层能出声但上层没声音问题出在 AudioPolicy 或调用链上跟mixer_paths.xml无关。如果底层也没声音回到tinymix把整个通路相关的控件值都打出来逐个检查。常见原因之一ctl name跟驱动注册名不一致。这种情况在启动音频服务后logcat 里会有类似这样的错误Failed to apply ctl: nameHPHL, value1看到这种日志基本可以断定是名字或枚举值不匹配。还有一个容易被忽略的原因DAPM 把相关电源域给关掉了。如果你配置的是 DAC 输入到模拟输出的通路但驱动中 DAPM 认为这条通路并没有真正的音频流经过它可能会自动把 DAC 或放大器关掉以省电。这种情况下虽然tinymix里控件看起来是设置的但 DAPM 又给你改回去了。解决方法是检查音频流是否真正建立也不要在测试时设置过短的 AudioTrack 播放免得状态还没稳定流就停了。5.2 只有一边有声音左右声道数据通路不对称单声道或左右不对称问题通常出在声道配置上。前面提到过SLIM_0_RX Channels它决定了开启的通道数。如果这里设置成One即使混音器里 RX0、RX1 都配了实际数据可能只在一个通道上传输。排查思路是先确认 AP 侧是否有双声道数据输出再确认 HAL 通路是否配置为双声道。SLIM_0_RX Channels的枚举值也可能是Two或One必须根据具体驱动来确定。其次检查 RX 通道到 DAC 的映射关系比如耳机左声道通常由 RX0 负责右声道由 RX1 负责如果映射反了就会出现左右反过来。另外有些平台还存在“Mono Mix”这类声道的混音开关如果它被误开了左右声道会被合成到一边造成另一边没有任何声音。这个跟通路配置是两回事但同样会干扰最终输出效果。5.3 爆音Pop 音几乎都是时序问题最典型也最难缠的是爆音问题。前面已经说过HP Driver的开关顺序影响很大。在实际调试中我还遇到过一种情况DAC 本来还没稳定但前端 MUX 已经切过去了此时会有一个瞬时电压尖峰在耳机里就是“嗝”的一声。有几个在实践中有效的处理方式第一保证 PA 或 HP Driver 在最后一个打开遇到断电时第一个关闭。这个优先序是最基础的。第二某些 Codec 有专门的爆音抑制开关比如 Charge Pump、Class G 使能等需要先开启。这类控件可以让耳机输出为参考地电平减少输出瞬间的电压跳变。第三调整音量斜坡。很多驱动支持音量渐变Volume Ramp在打开通路时从低增益缓升到目标增益也能有效抑制爆音。ctl nameHP Vol Ramp value1 / ctl nameHP Driver value1 /这个HP Vol Ramp并不是所有 Codec 都有建议对照 Codec datasheet 或驱动源码确认后再使用。不过思路是通用的尽量减少模拟输出在使能瞬间的 dv/dt爆音自然就能被抑制。5.4 底噪与杂音从数字域还是模拟域入手底噪问题的排查逻辑核心在于区分噪声来自数字域还是模拟域。如果噪声是“嗡嗡”声或者随音量变化非常明显大概率是模拟域的电源纹波或信号线耦合。此时可以看看 Codec 内部有没有专门的降噪功能比如降低耳机放大器的增益档位或者把系统电源切到更干净的 LDO 供电轨上。这类问题通过改mixer_paths.xml能缓解一部分但终究要靠硬件设计优化。如果噪声是“嘶嘶”的白噪声并且在使用高质量音频文件时依然存在可能是数字接口的位宽或采样率配置不匹配导致量化噪声偏大。还有一种常见情况DAC 通路中的数据经过了 SRC采样率转换模块SRC 引入的噪声在某些采样率下会变得很突出这时可以考虑是否绕过 SRC以源采样率直接播放。另外底噪还有一个容易被忽略的来源就是录音通路跟播放通路共用同一个主时钟或者电源域如果播放时麦克风偏置没有关闭或者 Codec 内部共享的 LDO 被拉偏也会产生噪声。这种情况要在配置通路时把当前不用的模块相关控件都关闭。5.5 音量异常忽大忽小、调不动或者破音音量问题通常不只是一个点的问题而是整个 Gain Structure增益结构没有对齐。mixer_paths.xml里的Volume类控件通常控制的是 Codec 内部 DAC 模拟输出的增益。上层 Android 音量控制的是 AudioFlinger 里的数字增益。两层之间需要配合好如果底层增益太低上层数字增益拉高后会出现明显的量化噪声如果底层增益太高上层数字增益稍大就会削波破音。一个比较实用的经验做法先把上层音量设为中等偏上的固定值再去调底层模拟增益直到听感输出在平均响度下不失真、底噪也可接受为止。如果无论怎么调音量调节都无效检查一下是否配置了音量映射控制点有些平台需要单独把音量控制绑定到某个 Kcontrol 上。若没有绑定上层调节音量时根本不会触发任何底层控制。5.6 问题排查速查表为了便于日常开发时快速定位我把这些典型问题的排查思路整理成了一个速查表现象优先排查项操作建议通路完全无声Kcontrol 名称/枚举值是否匹配对照 tinymix 输出检查 XML 中 ctl name通路完全无声DAPM 是否自动断电检查音频流是否真正建立播放时间是否过短只有一边有声音channel 通道数配置确认 Channels 控件设为 Two/Multi左右声道互反RX 与 DAC 映射关系交换 HPL/HPR 的 MUX 来源确认映射上电/下电爆音功放使能时序确保 PA 最后一个开第一个关有持续性底噪模拟电源 vs 数字信号质量分别降低模拟增益和数字增益对比音量一高就破音增益结构不匹配将上层音量固定逐级调底层增益找到不失真拐点音量调节无效音量映射缺失检查是否有音量控制绑定到对应 output 设备5.7 一个和底层驱动相关的避坑经验最后分享一个很多人容易忽略的小问题mixer_paths.xml中写到的 Kcontrol 名称必须和内核驱动注册的名字完全一致但很多平台的驱动里名称带有前后缀差异。比如某个高通驱动的枚举类型注册名为SLIM_0_RX Channels而你可能在别处看到过SLIM RX Channels或SLIM_0_RX_Channels稍有不同应用就会失败。所以在拿到新平台代码时别急着看参考文档里的 XML——先跑一遍tinymix让驱动把真实存在的 Kcontrol 列出来再从这个列表中找你要用的控件把名字和枚举值都对照确认。这个习惯能省下非常多的排查时间也是为什么我一直强调“先摸清平台再动手改配置”。6. 从配置到系统的最后一步多通路切换与场景适配6.1 通路切换时的过渡处理很多时候单条通路配置好并不是终点。产品实际使用中音频设备会在不同通路之间频繁切换比如来电时从播歌切到听筒挂断后再从听筒切回音箱。切换过程中如果只是简单地把旧通路的控件都关掉再按新通路配置打开很容易出现“咔嚓”一下的切换噪声。解决这类问题一般会在 HAL 层的通路切换函数中做处理但从mixer_paths.xml的角度我们也可以做两件事第一在所有通路切换过程里保持某些公共控件的状态不变比如主时钟和 MUX 尽量少动减少全局扰动第二为不同场景设置好父 path 下的子 path让 HAL 切换子 path 时只动差异部分不动公共部分降低切换噪声的发生概率。6.2 场景适配通话、录音、FM 各有各的通路以通话场景为例语音走的一般不是普通多媒体 DAC 通路而是 Codec 内部的语音通路可能从 AP 的 modem 接口直接进入 Codec不经由多媒体播放通路。对应的mixer_paths.xml中就有专门针对 audio mode 的通路配置例如path namehandset ctl nameSLIM TX7 MUX valueDEC7 / ctl nameDEC7 MUX valueADC2 / ctl nameADC2 Volume value80 / ctl nameEAR PA value1 / /path录音通路则要特别关注两个点第一麦克风偏置MIC Bias要正确使能否则麦克风没有工作电压第二ADC 的增益档位要跟麦克风的灵敏度匹配。在一些平台上数字麦克风和模拟麦克风的通路差别非常大前者直接走 PDM 接口后者还需要经过模拟放大器和 ADC。换句话说mixer_paths.xml是一条条物理通路的映射表什么时候用哪条由上层策略决定但能不能走通、走得干不干净全靠底层 XML 配得好不好。6.3 从配置文件到驱动调试的后半程配置mixer_paths.xml只是万里长征的第一步真正的难点在于如何根据 Codec datasheet 理解每个 Kcontrol 背后对应的寄存器以及如何结合示波器和听感测试来验证通路的正确性。调试周期中我会频繁地使用tinymix记录不同配置下 Kcontrol 的值留着跟波形对比。比如把耳机输出引脚引脚接上示波器观察不同音量档位下的波形幅度把 PA 使能瞬间的波形抓下来检查有没有异常的毛刺用 AP音频分析仪测信噪比和 THD判断底噪来源。最终确认通路质量和上层策略稳定后再把最终的mixer_paths.xml固化到产品代码里。调试过程中还有一个小工具tinyplay的最终播放效果受限于测试音乐的质量如果实在手头没有好的 WAV可以用sox或者 Python 生成各种频率的标准正弦波测试文件这样至少能通过听感和波形快速定位通路中的频率响应问题。在搞定耳机通路之后我会继续去翻mixer_paths.xml里那些看起来不起眼的子 path以及录音链路相关的部分。音频系统好玩的地方在于一条条的配置开关最终串起来的就是用户实际听到的声音一个时序的先后差异可能在示波器上只是一个微小的毛刺但到了人耳里就是一次糟糕的体验。所以每当面对一个通路问题我总会先去翻一遍mixer_paths.xml把思路理顺再动代码。
返回列表