1、音频子系统概述:AOSP音频架构全景图

各位同学,咱们今天正式开始聊AOSP音频子系统。说实话,这个系统我前前后后折腾了快十年,从Android 4.4一直跟到现在的Android 14,每次大版本升级都有新坑要踩。但不管怎么变,核心架构那几块东西,始终没动过。

你想想看,一部手机要能打电话、放音乐、录视频、玩游戏有音效,背后得有多少代码在跑?我刚开始接触时也觉得头大,但后来发现,只要把几个关键模块搞明白,整个音频系统就像一张地图一样清晰。

1.1 AOSP音频架构全景图

先看整体架构。AOSP音频系统从上到下分四层:

  • 应用层:你写的App,调用MediaPlayer、AudioTrack这些API
  • 框架层:AudioFlinger、AudioPolicyService这些核心服务
  • HAL层:硬件抽象层,连接系统和驱动
  • 内核层:ALSA驱动、tinyalsa这些底层东西

我个人习惯把中间两层叫「音频中枢」。为什么?因为所有音频数据的路由、策略、混音,全在这两层完成。应用层只管发请求,内核层只管读写硬件,中间这两层才是真正干活的地方。

核心要点:音频架构的本质,就是「应用发请求 → 策略做决策 → Flinger执行混音 → HAL操作硬件」这条链。搞懂这条链,你就掌握了80%。

1.2 音频HAL接口定义

HAL接口,说白了就是Google定的一套标准。你写驱动的人,必须按这个接口来实现。我见过不少新手上来就问:「为什么我的音频没声音?」——八成是HAL接口没实现全。

主要的HAL接口有这些:

接口作用我踩过的坑
open_output_stream打开输出流参数传错直接crash
open_input_stream打开输入流采样率不匹配会静音
set_parameters设置参数字符串key拼错没报错
get_parameters获取参数返回空指针不检查

嗯,这里要注意。HAL接口定义在hardware/libhardware/include/hardware/audio.h里。你打开这个文件,会发现一堆结构体和函数指针。我当年第一次看时,心想:「这玩意儿也太原始了吧?」但后来发现,正是这种简单粗暴的设计,让移植变得异常灵活。

我的经验:移植时别急着改代码。先把audio_hw_device结构体里的每个函数指针都列出来,对照芯片手册确认哪些必须实现,哪些可以返回空。我曾经因为漏了set_master_volume,调试了整整两天。

1.3 音频Flinger核心职责

AudioFlinger,这个名字起得好——它就是个「音频搅拌机」。所有音频流进来,它负责混音、重采样、格式转换,然后丢给HAL输出。

它的核心职责就三件事:

  1. 混音:多个App同时播放,它把音频数据叠加在一起
  2. 路由:决定音频走扬声器还是耳机
  3. 策略执行:听AudioPolicyService的指挥

为什么会需要混音?你想想看,微信语音通话时,突然来个电话,两个音频流要同时存在。Flinger就得把它们混成一路,再送出去。我遇到过最头疼的情况是,某款芯片的硬件混音器只支持8路,但系统同时开了10路——Flinger就得自己用软件混。

// AudioFlinger核心混音逻辑(简化版)
status_t AudioFlinger::MixerThread::prepareTracks_l() {
    for (size_t i = 0; i < mTracks.size(); i++) {
        // 检查每个track的状态
        // 做音量调整、重采样
        // 最后混入主缓冲区
    }
    return NO_ERROR;
}

这段代码我看了不下五十遍。每次移植新平台,都要回来确认混音逻辑有没有被改坏。

警告:千万别在Flinger里加自己的业务逻辑!我见过有人把音效处理直接塞进Flinger,结果每次OTA升级都要重新适配。正确的做法是走HAL层的音效接口。

1.4 音频策略服务作用

AudioPolicyService,简称APS。它是个「决策者」,不干活,只下命令。

它的核心职责:

  • 设备选择:插耳机时自动切换,拔掉时回到扬声器
  • 音量策略:媒体音量和通话音量分开管理
  • 焦点管理:电话进来时,音乐要暂停

我记得有一次,客户反馈说「插上耳机后,音乐还在扬声器播放」。查了半天,发现是APS的配置文件里,耳机对应的设备ID写错了。你想想看,策略层配错了,Flinger再努力也没用。

APS的配置通常在/vendor/etc/audio_policy_configuration.xml里。这个文件定义了所有音频设备、路由规则、音量曲线。我建议你移植时,先把这份XML吃透。

避坑指南:我曾经在某个项目里,把扬声器和听筒的设备ID搞反了。结果打电话时,声音从扬声器出来,整个办公室都听得见...从那以后,我每次改配置都会用dumpsys audio_policy验证一遍。

好了,这一章就聊这么多。音频架构全景图、HAL接口、Flinger职责、策略服务作用——这四个概念是后续所有章节的基础。你如果现在觉得有点模糊,没关系,后面每章都会反复提到它们。

下一章,咱们开始动手搭建开发环境。到时候我会分享一些「血泪史」,比如怎么在三天内搞定一个没人维护的老平台。