这篇写什么?
做 TV / Soundbar / HDMI 音频时,一堆问题最后都会问到同一句:
声音是从哪一层发出去的?谁决定走喇叭还是 ARC?谁真正打开设备?
本文按 分层架构 把 Android 音频框架捋一遍:入口谁注册、两大服务各干什么、mediaserver / audioserver 怎么起来,以及 AudioPatch 如何把「源 → 宿」接到 HAL。
一句话:
App(MediaPlayer / AudioTrack …)
→ Framework Java + Binder
→ audioserver:AudioFlinger(干活)+ AudioPolicyService(定策略)
→ HAL(audio.primary / policy)
→ TinyALSA / ALSA → 芯片与喇叭

相关:音量设置流程、HDMI-IN Patch。
一、先看整张分层图(从上往下)
| 层 | 典型组件 | 干什么 |
|---|---|---|
| Application | 音乐、录音、通话… | 用户场景 |
| Framework(Java) | MediaPlayer / AudioTrack / AudioRecord / AudioManager / AudioService |
App 调用的 API;AudioManager↔AudioService 走 Binder |
| Libraries Client | libmedia.so 里的 native Track/Record |
App 进程内的客户端代理 |
| Binder IPC | 虚线隔开 Client / Server | 跨进程调用系统服务 |
| Libraries Server | AudioFlinger、AudioPolicyService、Mixer/Resampler、MediaPlayerService |
混音、策略、播放器服务 |
| HAL | audio.primary.*.so、audio_policy.*.so |
统一接口对接厂商实现 |
| TinyALSA / alsa-lib | 用户态访问 PCM/CONTROL | 简化 ALSA 调用 |
| Kernel | ALSA / ASoC、DAI、Codec、DAPM | 驱动与功耗路径 |
| Hardware | Speaker / Mic / Headset… | 真实器件 |
记两个中枢:
- AudioFlinger:真正混音、开输出、碰硬件(经 HAL)
- AudioPolicyService:设备连接状态、路由策略(定主意;真正
openOutput仍多在 Flinger 侧执行)
二、AndroidRuntime:框架侧起点与 JNI 注册
系统 Framework 启动路径里,一个重要入口是:
frameworks/base/core/jni/AndroidRuntime.cpp
它更像 系统主线程 / Runtime 侧总装点 之一:注册大量模块的 JNI(native、sensor、media、audioflinger、display、camera、binder…)。
与音频相关的是:在 media 服务完全起来之前,就会把 AudioRecord / AudioSystem / AudioTrack 等 JNI 挂好,让 Java API 能落到 native。
同时源码里大量使用:
sp<IServiceManager> sm(defaultServiceManager());
通过 ServiceManager 添加 / 查找 系统服务。App 侧则通过 Context.getSystemService(...)(底层仍是 Binder + SM)拿到 audio 等服务——理解「安卓一切皆服务」时,从这条线最直观。
三、两大音频服务:Flinger 与 Policy
| 服务 | 职责(口语) | 要点 |
|---|---|---|
| AudioFlinger | 音频「工厂车间」 | 经 HAL/AudioHardwareInterface 与底层交互;PCM 混音、输入输出、音量等 |
| AudioPolicyService | 音频「调度台」 | 设备插拔状态、选哪条路由(本机 Codec / A2DP / Headset / HDMI…);策略在这,切换执行多在 Flinger |
二者都是 Framework 本地服务,由 audioserver 进程拉起(现代 Android 已把音频从早期 mediaserver 里拆出,见下一节)。
口诀:
Policy 决定「该走哪」
Flinger 负责「真的走」
四、mediaserver 与 audioserver
都由 init 拉起,但 职责与优先级不同。
4.1 mediaserver(偏「媒体播放器」)
mediaserver.rc 里多为 class main,例如启动:
MediaPlayerServiceResourceManagerService
main_mediaserver.cpp 典型流程:拿到 ProcessState / ServiceManager → MediaPlayerService::instantiate() → 线程池 join。
4.2 audioserver(偏「音频中枢」,往往更早)
audioserver.rc 常见为 class core,比一般 main 更早进入就绪;zygote 重启时也会 onrestart restart audioserver。
main_audioserver.cpp 核心两句:
AudioFlinger::instantiate();
AudioPolicyService::instantiate();
rc 里还能看到:audioserver 挂掉时会 重启 vendor audio HAL(vendor.audio-hal 等),保证音频服务与 HAL 生命周期绑在一起。
| 对比 | mediaserver | audioserver |
|---|---|---|
| 典型 class | main | core(更早) |
| 核心实例 | MediaPlayerService… | AudioFlinger + AudioPolicyService |
| 和 HAL | 间接 | 直接依赖,挂了会拉 HAL |
排查「开机无声 / 音频服务反复起」时:先看 audioserver 与 vendor.audio-hal 是否成对崩溃。
五、AudioFlinger:如何挂进 ServiceManager
AudioFlinger 继承大致是:
AudioFlinger
: BinderService<AudioFlinger>
, BnAudioFlinger
BinderService<T>::instantiate() → publish() →:
sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), ...);
于是系统里出现可被 Binder 查到的 audio flinger 服务。
智能指针首次引用会走到 onFirstRef():读 standby 时间属性、设 AUDIO_MODE_NORMAL、挂 HAL factory 回调等——对象真正「可用」。
构造阶段还会创建:
DevicesFactoryHalInterface/EffectsFactoryHalInterface(对接 HAL / 音效)PatchPanel(和 AudioPatch 强相关)- 主音量、mute、metrics 等状态
承上启下可以记成:
上层 Track / Record / Policy
↕ Binder
AudioFlinger
↕ HAL
primary / a2dp / usb …
↕ TinyALSA
Kernel ALSA
音量路径细节见 Android 音量设置流程。
六、AudioPatch:逻辑「线」,接源和宿
TV 上切 HDMI-IN、DTV、线路输入,几乎都会碰到 Audio Patch:不是「再开一个普通 App Track」那么简单,而是 Framework / Policy 声明:
把某些 source port 连到某些 sink port。
6.1 数据结构(框架认识)
system/media/audio/include/system/audio.h 里:
struct audio_patch {
audio_patch_handle_t id;
unsigned int num_sources;
struct audio_port_config sources[AUDIO_PATCH_PORTS_MAX];
unsigned int num_sinks;
struct audio_port_config sinks[AUDIO_PATCH_PORTS_MAX];
};
audio_port_config 描述某一端的配置:采样率、声道、格式、增益,以及 device / mix / session 扩展。
设备侧扩展里关键字段:
struct audio_port_device_ext {
audio_module_handle_t hw_module;
audio_devices_t type; // 如 SPEAKER、HDMI、…
char address[...];
};
这就是 Framework 与底层 HAL 设备 的衔接点之一:策略层选 type,HAL 打开对应通路。
6.2 谁创建、谁真正连线?
| 角色 | 常见动作 |
|---|---|
| AudioPolicy / App API | 决定要建哪条 patch(哪些源、哪些宿) |
| AudioFlinger(PatchPanel) | 协调、下发 |
| audio HAL | create_audio_patch / release_audio_patch 等,落到厂商实现 |
TV HDMI-IN 的线程与缓冲细节,见 TV 切到 HDMI-IN:Audio Patch 流程。
口诀:
port = 逻辑插头(设备或 mix)
patch = 若干插头之间的连线
HAL = 把连线落到真实硬件路径
七、再往下:HAL → TinyALSA → Kernel
图的下半部分在适配时同样关键:
| 块 | 含义 |
|---|---|
audio_hw_device / stream_out / stream_in |
HAL 设备与流 |
audio_policy_device |
策略 HAL(与 Framework Policy 配合) |
| TinyALSA / alsa-lib | 用户态读写 PCM、改 control |
| ALSA Core(PCM / CONTROL) | 内核音频核心 |
| ASoC(Machine / Platform / Codec、I2S、DAPM) | SoC 上 CPU DAI ↔ Codec DAI、动态功耗 |
厂商 audio.primary.xxx.so 往往在这里和 MS12、HDMI、eARC、功放 纠缠——上层策略对了、HAL/驱动错了,一样无声或爆音。
八、对照排查时怎么用这张图?
| 现象 | 优先看哪一层 |
|---|---|
| App 能播系统铃、某 App 不行 | App / AudioTrack 用法、usage、focus |
| 所有声音都没有 | audioserver、HAL 是否起来 |
| 设备插了但路由不对 | AudioPolicy(策略) |
| 路由对了仍无声 / 爆音 | AudioFlinger 输出、HAL、ALSA |
| TV 切 HDMI / 直播 | AudioPatch + 厂商 patch 线程 |
| 单核打满、卡顿 | Flinger/MS12 线程与 CPU(见性能相关文) |
九、小结
- 分层:App → Java Framework → Binder → Flinger/Policy → HAL → ALSA → 硬件。
- 两大服务:Policy 定路由,Flinger 做混音与开流。
- 进程:现代系统音频核心在
audioserver(常 class core);mediaserver更偏播放器服务。 - Patch:用
audio_port/audio_patch描述逻辑连线,是 TV 外输入的关键抽象。 - Runtime:JNI 与 ServiceManager 是「服务能被 App 找到」的前提。
先把这张图装进脑子,再看音量、HDMI-IN、ARC、MS12 单点文章,就不容易在层与层之间迷路。
相关阅读
评论
还没有评论,来做第一个吧
读完了不评论,作者会以为你在沉思