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输出。
它的核心职责就三件事:
- 混音:多个App同时播放,它把音频数据叠加在一起
- 路由:决定音频走扬声器还是耳机
- 策略执行:听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职责、策略服务作用——这四个概念是后续所有章节的基础。你如果现在觉得有点模糊,没关系,后面每章都会反复提到它们。
下一章,咱们开始动手搭建开发环境。到时候我会分享一些「血泪史」,比如怎么在三天内搞定一个没人维护的老平台。