一、MTK音频系统概述

大家好,我是这次课程的主讲。做音频驱动开发这么多年,我最大的感受就是——MTK的音频系统,说复杂也复杂,说清晰也清晰。关键在于你从哪个角度切入。

今天我们先从整体上把MTK音频系统的骨架搭起来。说白了,就是搞清楚三件事:硬件长什么样,谁负责干什么,软件怎么一层层叠上去的。

1.1 MTK平台音频硬件架构

先看硬件。MTK的音频硬件,我习惯把它分成三大块:

  • 音频编解码器(Audio Codec):负责模拟信号和数字信号的转换。比如你插耳机听歌,数字信号得转成模拟信号才能驱动耳机振膜。
  • 数字信号处理器(DSP):专门处理音频算法的。降噪、回声消除、音效处理,这些活儿都扔给它。
  • 音频接口(Audio Interface):I2S、TDM、PCM这些总线,负责把音频数据在不同模块之间搬来搬去。

嗯,这里要注意一点。MTK的硬件架构里,音频Codec和DSP往往是集成在一起的,不像某些平台是分开的芯片。这样做的好处是延迟低,坏处是——你调试的时候得同时看两边的寄存器。

核心要点:MTK音频硬件架构中,Codec和DSP的紧耦合设计,是理解整个系统的关键。你调试时遇到的很多诡异问题,根源往往在这里。

1.2 ADSP与主CPU的分工

这个问题,我当年刚接触MTK平台时也困惑过。主CPU和ADSP(音频DSP),到底谁干谁的活?

简单来说:

  • 主CPU(AP):负责音频策略控制。比如你点开音乐App,AP决定要不要播放、用什么采样率、走哪个输出设备。它不碰音频数据流。
  • ADSP:负责音频数据处理。编解码、混音、音效、低功耗播放,全在ADSP里跑。AP把命令发过来,ADSP把结果送出去。

为什么会这样分工?你想想看,如果所有音频处理都让主CPU干,那手机一放歌,CPU就得一直醒着,功耗直接崩了。ADSP是个低功耗处理器,专门干这活的。

个人经验:我曾经调试过一个低功耗播放的bug,音乐播着播着就卡一下。查了两天才发现,是AP和ADSP之间的IPC(核间通信)消息队列满了。AP发命令太快,ADSP处理不过来。后来加了流控,问题解决。所以,IPC通信的稳定性,是ADSP调试的重中之重

我建议你记住这张分工表:

功能模块 主CPU(AP) ADSP
音频策略管理
音频数据处理
低功耗音频播放
音频路由控制
音效算法处理
唤醒词检测

1.3 音频子系统软件栈概览

软件栈,说白了就是一层层叠上去的代码。MTK音频软件栈,从下往上分四层:

  1. 硬件驱动层:直接操作寄存器的。Codec驱动、DSP驱动、I2S驱动,都在这一层。
  2. 音频框架层:Linux ALSA框架。MTK在ALSA基础上做了不少扩展,比如ADSP的虚拟声卡。
  3. 音频服务层:Android AudioFlinger、AudioPolicyService。负责音频策略和路由。
  4. 应用层:音乐App、通话App、游戏。它们只管调用API,不关心底层怎么跑。

嗯,这里有个坑。很多初学者喜欢直接从应用层往下追,追到驱动层就懵了。我建议反过来——从驱动层往上理解。先把硬件怎么工作的搞清楚,再看框架怎么封装,最后看应用怎么调用。这样思路清晰得多。

避坑指南:我曾经带过一个新人,他调试一个录音无声的问题,从App层一路追到驱动层,花了三天。最后发现是Codec的时钟配置错了,驱动层根本没初始化成功。如果他从驱动层开始查,半小时就能定位。所以,调试音频问题,永远从底层开始排查

最后,我放一段简单的代码,看看MTK音频驱动的入口长什么样:

// mtk-afe-platform-driver.c
// MTK音频前端引擎驱动入口
static const struct of_device_id mtk_afe_pcm_dt_match[] = {
    { .compatible = "mediatek,mt6789-afe-pcm", },
    { .compatible = "mediatek,mt6895-afe-pcm", },
    {},
};

static struct platform_driver mtk_afe_pcm_driver = {
    .driver = {
        .name = "mtk-afe-pcm",
        .of_match_table = mtk_afe_pcm_dt_match,
        .pm = &mtk_afe_pcm_pm_ops,
    },
    .probe = mtk_afe_pcm_probe,
    .remove = mtk_afe_pcm_remove,
};

module_platform_driver(mtk_afe_pcm_driver);

你看,驱动入口其实很简单。通过设备树匹配到对应平台,然后probe函数里做初始化。但真正的复杂度,全藏在mtk_afe_pcm_probe这个函数里——它要初始化ADSP通信、注册DMA缓冲区、配置Codec、创建虚拟声卡...

好了,这一章我们先把MTK音频系统的整体轮廓画出来了。硬件架构、ADSP分工、软件栈分层,这三块是后面所有章节的基础。下一章,我们会深入ADSP的驱动细节,看看它到底是怎么跟主CPU通信的。

记住我这句话:搞懂MTK音频,先搞懂ADSP。ADSP搞懂了,后面全是水到渠成的事。