
MTK平台音频出问题最折磨人的就是无声——不是那种罕见的偶发bug而是你明明改了配置、烧了版本上电后喇叭和听筒就是一声不吭。MTK的音频路径配置跟高通的路子不一样很多从高通平台转过来的工程师第一次碰MTK翻源码翻到怀疑人生最后发现就是某个mixer通路没连上或者audio_policy_configuration里的route关系写错了。这篇文章就围绕MTK平台音频无声这个问题把音频路径配置的排查思路从头到尾捋一遍从框架日志到HAL层路由再到ALSA control节点每一步怎么查、查什么、为什么这么查都会说清楚。适合正在调MTK音频驱动、做carrier定制、或者刚从其他平台切过来的系统工程师参考。1. 先搞明白你说的无声是哪种无声音频无声不是一个单一问题排查之前一定要先把现象定义清楚。我见过太多人上来就说没声音结果坐下来一聊有的是播放音乐没声但通话正常有的是扬声器没声但插耳机可以还有的是第三方应用没声音但系统铃声正常——这些完全是不同层面的问题排查路径也不一样。1.1 三种典型的无声场景第一种是全局无声。这种最好定位大概率是audio policy或HAL底层的问题比如路由表没配对、codec供电没起来、I2S时钟没跑或者音频服务直接crash了。全局无声一般问题出在底层链路不是应用层能解决的。第二种是场景性无声。比如来电铃声没声音但媒体播放正常或者录音没声音但播放正常。这类问题通常是route配置里某个特定的设备或mixPort组合没配好。MTK的audio route是矩阵式的source和sink要一一对应漏一条就废一条。第三种是软件状态导致的无声。音量被拉到0、音频焦点被其他应用抢占、用了某种音效后处理导致数据没送出去、DTS或杜比没授权导致PCM被静音。这些在log里往往能看出来但容易被忽略。1.2 排查思路的整体框架不管哪种无声排查顺序都建议从上往下走应用→AudioFlinger→AudioPolicyManager→Audio HAL→ALSA驱动→Codec。在log里就是一层一层往上翻看数据在哪一层断掉。最直接的办法是用logcat抓音频相关日志然后根据关键字逐层过滤。MTK平台比较有用的tag包括AudioPolicyManager、AudioMTKStreamManager、AudioAnalog、AudioALSAStreamManager、AudioRouteManager、audio_route以及AudioFlinger和audioserver。看到数据流在哪一层消失问题就基本锁定在哪一层了。2. MTK音频路径是这么设计的很多人在MTK上栽跟头是因为没搞懂它的音频路径架构跟高通的差异。MTK的音频通路设计思路其实不复杂但配置文件分散、命名习惯特殊没适应之前会觉得很乱。2.1 从Android框架到Codec的数据流向先看标准Android音频架构。应用通过AudioTrack写入PCM数据数据进AudioFlingerAudioFlinger根据AudioPolicyManager的路由策略把数据送到对应的Audio HAL设备。HAL再通过ALSA通常是tinyalsa把PCM数据写到codec或DSP最终驱动喇叭或听筒发出声音。MTK在这一层和高通最大的区别在于高通的音频数据路径大量依赖ADSP很多音频处理在DSP内部完成CPU侧的HAL相对简单而MTK在部分平台上是用MDPMTK DSP或AP侧直接处理HAL层参与的环节更多尤其是路由决策、采样率转换、数据格式封装很多是在HAL的AudioMTKStreamOut/AudioMTKStreamIn里做的。MTK的AudioPolicyManager路由决策完成后会通过setParameters往HAL下发路由信息比如routing2这种内部格式。HAL收到后根据设备类型、采样率、通路需求去查音频路由配置表找到对应的mixer path再通过tinymix把各个ALSA控制节点设置到正确状态。2.2 配置文件里到底有什么MTK的音频路径配置主要集中在这几个文件audio_policy_configuration.xml有时是mtk_audio_policy_configuration.xml、audio_device.xml、audio_route相关的头文件或配置表。不同Android版本、不同MTK芯片平台文件位置不太一样常见的路径在/vendor/etc/audio/或/system/etc/audio/下source code里通常在device/mediatek/board/configs/audio/或vendor/mediatek/proprietary/external/audio/相关目录。audio_policy_configuration.xml描述的是顶层设备视图有哪些音频设备speaker、earpiece、headphone、bluetooth等、哪些mixPort对应HAL的输入输出stream、设备与mixPort之间的route关系。而audio_device.xml或者类似命名的配置则更接近HAL层的设备描述它定义了设备名、设备ID、ALSA设备节点映射关系。真正控制codec和mixer通路的是audio route配置。MTK的HAL里维护了一张路由表每个route条目会定义一条从source到sink的完整通路同时附带一组需要设置的ALSA control值。这些control值一旦配置错误PCM数据就送不到codec的输出级表现出来就是无声。提示MTK不同平台比如Helio G系列和Dimensity系列的音频DSP架构差异很大稍微老一点的项目和新平台的配置文件格式、HAL实现方式都不完全一样。但排查思路是通用的——先定位断点再去比对配置文件。2.3 MTK与高通在音频上的核心差异搞过这两个平台的人应该深有体会。高通平台从APQ8064那一代开始音频架构已经彻底转向ADSP为核心的方案很多音频处理、路由、mixer逻辑都在DSP固件里侧的HAL相对薄。MTK则保留了更多传统的ALSA通路和HAL层控制codec往往是集成的比如MT635x系列PMIC内置codec通过I2S/TDM接口与AP连接。配置层面最大的差异是高通习惯用mixer_paths.xml来定义所有通路的mixer设置而MTK不同平台、不同方案用得不一样。有些平台沿用ALSA的route表有些平台一开始就自己搞了一套XML驱动式路由还有些平台保留了大量宏控和硬编码逻辑。这导致网上搜到的解决方案往往不通用。所以排查MTK音频问题时不建议直接套用高通或者别人的经验一定要先确认你当前的平台、Android版本、HAL version然后顺着源码里的路由实现去查。3. 手把手排查从log到配置逐层定位下面这套排查流程是我在实际项目里反复用过的。不保证覆盖所有MTK平台但绝大多数音频路由导致的无声问题按这个思路走都能找到根因。3.1 第一步抓log确认问题断在哪一层拿到一台无声的设备先别急着改代码。连上adb先抓一份完整log。抓log需要打开一些开关最简单的方式是直接抓全量logcatadb logcat -b all -v threadtime full_log.txt同时抓kernel log这个对排查I2S、codec供电、DSP加载问题有帮助adb shell cat /proc/kmsg kmsg.txt抓完之后用关键字逐层过滤。先看音频焦点和音量。AudioManager: requestAudioFocus、setStreamVolume、AudioPolicyManagerBase::setDeviceConnectionStateInt这些关键字。确认播放的时候音量不是0焦点没被别人抢走。再看AudioPolicy的路由决策。搜AudioPolicyManager、getDeviceForStrategy、getOutputForAttr。这里能看到系统为某个stream选了哪个输出设备比如SPEAKER、EARPIECE、BLUETOOTH_A2DP_OUTPUT。如果策略选错了设备比如媒体播放选了EARPIECE但声音根本没从听筒出来那就是路由策略问题要去查audio_policy_configuration.xml的产品配置。然后看HAL层有没有正确处理route。MTK的关键字一般是AudioMTKStreamOut::setParameters、AudioRouteManager::setRoute或者selectRoute。在这个位置能看到上层下发下来的routing值HAL有没有尝试去设置对应的mixer path。如果这里什么都没打说明HAL就没进入路由设置的逻辑。最后看ALSA和codec层。搜索tinymix、ALSA、codec、I2S。如果HAL设了route但ALSA层没有对应用的control写入大概率是route表和ALSA的control名字对不上。实操心得MTK的HAL日志非常啰嗦过滤的时候建议用一个组合表达式比如grep -iE Audio|ALSA|route|mixer|codec|I2S|DSP。日志如果被刷掉先logcat -G 32M把buffer调大再复现一遍。3.2 第二步用量化和dump命令验证系统状态log只能说明软件流程具体硬件状态还得靠命令去验证。先用dumpsys确认系统的音频设备状态adb shell dumpsys audio重点看Audio Policy相关的段落里面列出了当前系统知道的所有设备、每个stream当前的音量、当前active的播放客户端和输出设备。然后adb shell dumpsys media.audio_policy这个能看到更详细的路由策略和输出profile。确认系统认为音频应该从哪个设备出去。如果系统侧状态正常接下来查HAL和ALSA状态。MTK平台一般用tinyalsa工具adb shell tinypcminfo -D 0 adb shell tinymixtinypcminfo能看PCM节点是否打开、采样率、格式是否正常。tinymix输出的是当前所有ALSA control的值这里面能直观看到I2S、DAC、speaker amplifier、耳机HP driver的enable/disable状态。比如播放音乐时喇叭没声音用tinymix查一下发现MTK_SPEAKER_EN这个control是0说明route设置没把这个节点打开或者设置之后被其他逻辑覆盖了。顺着tinymix输出的kctl名字再去HAL源码里搜对应的设置逻辑往往就能找到原因。3.3 第三步检查audio_policy_configuration.xml的路由关系如果dumpsys和HAL log都正常route也set了但tinymix里的某个关键节点没起来那问题多半出在route关系配置。以一个真实碰到的场景为例。一台设备音乐播放到扬声器无声插耳机就正常。dumpsys显示路由策略选的是SPEAKERHAL也打出了setSpeakerOn(true)之类的日志但tinymix里speaker amplifier的控制节点值始终没变。后来检查audio_device.xml发现设备定义里speaker对应ALSA声卡和PCM节点而audio_policy_configuration.xml里speaker的mixPort没有正确关联到HAL的output stream上。系统确实认为speaker可用但HAL去设置route时发现speaker不在可用的device list里导致route设置被静默跳过。这类问题看XML最直接。devicePort tagNameSpeaker typeAUDIO_DEVICE_OUT_SPEAKER rolesink profile name formatAUDIO_FORMAT_PCM_16_BIT samplingRates48000 channelMasksAUDIO_CHANNEL_OUT_STEREO/ /devicePort mixPort nameprimary output rolesource profile name formatAUDIO_FORMAT_PCM_16_BIT samplingRates48000 channelMasksAUDIO_CHANNEL_OUT_STEREO/ /mixPort route typemix sinkSpeaker sourcesprimary output/这里的关键逻辑是每一个devicePort需要被顶层attachedDevices标记为连接状态mixPort的name要和HAL实现里返回的output name一致route的sink和sources要和devicePort、mixPort的name完全匹配一个字都不能差。如果XML里name有大小写不同、或多了个空格route就不会生效。这种错误编译期完全查不出来只有运行期静默失败。注意MTK的XML里samplingRates不要乱改在写48000的地方写了个44100HAL会认为该设备不支持48k采样然后强制做SRC万一SRC路径有问题也一样无声。3.4 第四步确认HAL层route下发和ALSA control节点如果XML和dumpsys都正常那就是HAL的route实现问题。MTK的HAL里通常有个AudioRouteManager之类的组件负责把audio_policy_configuration.xml里定义的route转换成具体的ALSA control设置。常见问题是控制节点名字不对。MTK的ALSA控制节点命名不像高通那么统一某些平台叫DAC_L_volume某些平台叫DIGITAL_L_Volume还有的藏在PMIC内部叫MT6357_DACL_Enable。如果HAL的route表里写的kctl名字在ALSA节点上根本不存在设置自然无效。这个可以用一个小技巧验证手动用tinymix把关键节点打开看有没有声音。adb shell tinymix MTK_SPEAKER_EN 1 adb shell tinymix DAC_L_volume 200如果手动开节点有声音说明硬件和驱动没问题纯粹是HAL route表没配对。这时候就去HAL实现里把kctl name改成和/proc/asound/card0/codec#0里一致的名字。反过来如果手动开节点依然无声那就是硬件链路问题要去查speaker的供电、PA的GPIO、I2S时钟、codec的时钟有没有起来。这一步就不是配置问题了需要拿示波器去量硬件信号或者查驱动初始化流程。4. 典型无声问题的实例复盘理论说再多不如看实际案例。这里整理几个我在MTK项目里遇到的典型无声问题包括现象、排查过程和最终修复方式供参考。4.1 案例一听音乐扬声器无声插耳机正常一台MT6765设备Android 10版本。客户反馈播放本地音乐时外放无声插耳机播放正常。系统音量、媒体音量都已经调到最大。排查过程抓log确认AudioPolicyManager的路由选择。日志显示媒体播放时路由选的是AUDIO_DEVICE_OUT_SPEAKER策略正确。继续看HAL发现AudioMTKStreamOut::setParameters收到的参数里routing0x2对应speaker没问题。用tinymix查看speaker PA的控制节点值处于关闭状态。手动执行tinymix Speaker_En 1后声音恢复。查HAL的route表发现speaker对应的mixer path里Speaker_En这个control被写在了一个只在耳机通路才执行的代码分支里。也就是说route表把耳机和扬声器的通路搞混了。修复方式修改HAL的route配置将Speaker_En从耳机分支挪到speaker分支重新编译烧录后正常。4.2 案例二通话全无声音播放正常MT6877平台Android 12。通话时听筒、麦克风全部无声但媒体播放、录音都正常。这个问题的特征很明显通话走的是telephony audio path和媒体播放的route是独立的。播放正常说明AP侧的音频链路没问题问题出在通话专用的音频路由。排查发现通话时MODEM侧的PCM数据和AP侧codec之间的通路没建立。查看HAL log发现setCallBack相关的数据参数没有正确下发到modem驱动导致通话的音频数据根本没进入codec。最终定位到是modem音频参数配置文件通常是AudioParam或AudioTuning相关的配置里通话通路的采样率配置和AP侧codec支持的采样率不一致导致modem上报了错误的能力HAL侧没能把通话通路建立起来。重新生成正确参数后通话恢复正常。4.3 案例三录音无声但播放正常还有一个常见的案例设备录音没声音无论用自带录音机还是第三方应用都一样。播放音乐正常说明输出通路完好问题缩小到输入采集链路。查了dumpsys audio录音时路由选的是AUDIO_DEVICE_IN_BUILTIN_MICHAL也确实执行了startInput但tinymix显示codec的mic bias没有打开。最后翻到audio_device.xml里mic对应的设备定义发现AUDIO_DEVICE_IN_BUILTIN_MIC的mask值写法不对用的是0x80000004但HAL实际枚举的输入设备mask是0x80000004u代码里做了强转导致的匹配失败。修正后HAL的route匹配就对上了。这类问题属于配置和实现之间契约不一致导致的平台HAL版本更新后尤其容易踩坑。5. 常见问题与排查技巧速查最后把排查MTK音频无声时容易踩的坑和高效技巧整理成一份速查表方便下次直接照着操作。常见问题特征表现快速定位方法XML里devicePort名称和HAL不匹配HAL日志没有任何route设置dumpsys正常对比XML中name和HAL源码中的字符串注意大小写和空格attachedDevices漏配置系统不认为该设备存在dumpsys里看不到dumpsys audio里查device connection信息kctl名字与ALSA节点不一致HAL执行了route但节点无变化tinymix对比HAL源码里的control名采样率不匹配某个采样率下无声换个采样率正常tinypcminfo查PCM节点实际配置音量被安全策略限制某些应用无声系统声音正常dumpsys audio看stream volume查volumemanager配置音频焦点被抢占播放时其他应用在抢focuslogcat搜requestAudioFocus音频服务crash全局无声重启后恢复logcat搜audioserver、AudioFlinger crash backtrace排查技巧方面有几个我一直在用的习惯修改audio_policy_configuration.xml后不要只靠重新编译系统验证。先推送到设备上adb root adb remount adb push audio_policy_configuration.xml /vendor/etc/audio/ adb reboot然后直接复现用dumpsys audio policy比对修改前后的策略变化。这样能快速确认是不是XML导致的route问题不用每次都要整包编译烧录。另外MTK平台建议在抓log的时候顺便抓一份bugreportadb bugreportbugreport里包含了系统的完整配置、所有服务的状态、更详细的ALSA信息。很多时候比单独抓logcat更有效率尤其是需要看/proc/asound、/sys/class/sound下面的信息时不用自己一条条去cat了。最后还有一个容易被忽略的地方MTK平台在Android 9之后很多音频dumpsys和配置信息被隐藏了需要自己开debug。比如HAL的verbose日志往往是通过setprop vendor.audio.dump.route 1或者setprop debug.audio.mtk.log 1来开启的。不同平台属性名不完全一样可以在HAL源码里搜property_get看看当前版本支持哪些调试开关。注意如果改了XML后仍然无声建议先排查是不是audio policy缓存导致的问题。Android有运行时的audio policy缓存刚才提到adb reboot而不是仅仅重启audioserver就是为了让缓存彻底失效。有时候只重启audioserveradb shell stop audioserver adb shell start audioserver但在缓存没清干净的情况下配置可能不会重新加载。直接reboot最省心。我个人的体会是MTK平台的音频无声问题十有八九最后都落在配置和实现不一致上。AudioPolicyManager选择了正确设备但HAL的route表对不上HAL认为路由没问题但ALSA节点状态没变。每一层都觉得自己是对的结果就是最底层不放声。所以排查的时候不要带着肯定是某个特定文件写错的预设去翻代码而是用log和dumpsys一层一层锚定断点然后在断点周围用源码和配置double confirm。这套方法论在MTK、高通、展锐平台上都是通用的。