目录
[1. 简述](#1. 简述)
[2 类结构说明](#2 类结构说明)
[3. 初始化流程](#3. 初始化流程)
[4. 设备连接管理](#4. 设备连接管理)
[5. 输出路由策略](#5. 输出路由策略)
[1) 获取输出 (getOutputForAttr)](#1) 获取输出 (getOutputForAttr))
[2) Engine 选设备逻辑 (getDevicesForStrategyInt)](#2) Engine 选设备逻辑 (getDevicesForStrategyInt))
[6. 输入路由策略](#6. 输入路由策略)
[1) getInputForAttr](#1) getInputForAttr)
[2) getDeviceForInputSource](#2) getDeviceForInputSource)
[7. 动态策略与 Mix](#7. 动态策略与 Mix)
[8. 总结](#8. 总结)
深入剖析 Android AudioPolicyManager (后面简称APM) 及其策略引擎 (Engine) 的内部运作机制、核心数据结构与关键流程。
本文基于 Android 源码,重点关注设备管理、路由策略选择及其与 Engine 的交互。
1. 简述
AudioPolicyManager (APM) 是 Android 音频系统的策略中心:
- 设备管理:维护系统所有可用输入输出设备的状态。
- 策略路由:决定特定音频流(Stream)或属性(Attributes)应路由到哪个设备。
- 资源控制:管理音频输入输出并发、音量计算。
Engine 是 APM 的策略决策模块(Strategy Decision Module):
- 定义产品策略 (Product Strategy):将 Audio Attributes 映射到 Strategy。
- 设备选择算法:根据当前 Use Case(如通话、媒体、铃声)和强制配置(Force Use),为每个 Strategy 计算最佳输出设备。
这种分离设计使得 APM 框架可以保持通用,而具体的路由策略(如插入蓝牙耳机等等)可以通过替换 Engine 实现或配置。
2 类结构说明
APM 管理着由于音频策略配置文件audio_policy_configuration.xml解析出的对象模型。

图1 APM与Engine简单图
如图1,APM与Engine是一种策略模式,更详细的关系如图2所示。

图2 APM与Engine
HwModule: 对应 HAL 模块(如 primary、 a2dp、usb)。包含其支持的 IOProfile。
IOProfile: 描述了 HAL 能提供的输入输出能力(采样率、格式、通道、支持的设备)。它是静态配置的。
SwAudioOutputDescriptor: 描述了一个实际打开的输出流(Stream)。它关联到一个具体的 IOProfile 和当前路由的 DeviceDescriptor。
DeviceDescriptor: 运行时设备对象,包含地址、类型、能力等。
3. 初始化流程
初始化阶段,APM 会加载 XML 配置文件,构建 HwModule 和 IOProfile 及其支持的 DeviceDescriptor 集合。
1)Factory 创建: AudioPolicyService 调用 createAudioPolicyManager。
2) Config 解析: APM 构造函数中解析 audio_policy_configuration.xml,填充 mHwModules。
3)Engine 初始化: Engine 加载自己的策略配置(如有),建立 Attributes 到 Strategy 的映射表。
4)打开 Output: APM 遍历 HwModule,预先打开那些 Attached(非动态)的 Output Profile(如 Speaker/Earpiece 对应的 Output)。
4. 设备连接管理
当设备插入(如有线耳机、蓝牙耳机)时,流程如图3所示:

图3
checkOutputsForDevice 逻辑如下:
当新设备连接时,APM 会检查所有活动输出,询问 Engine:"这个 Output 现在应该去哪个设备?"
如果 Engine 返回的新设备就是刚连接的设备(或者包含它),APM 就会执行路由切换(Tear down patch > Create new patch)。
5. 输出路由策略
这是 APM 最核心的部分:App 请求播放 -> 决定使用哪个 Output -> 路由到哪个 Device。
1) 获取输出 (getOutputForAttr)
当 App 创建 AudioTrack 时, AudioTrack调用AudioFlinger::createTrack, 然后会调用getOutputForAttr函数:
cpp
status_t AudioFlinger::createTrack(const media::CreateTrackRequest& _input,
media::CreateTrackResponse& _output)
{
......
// Aptiv Audio
lStatus = AudioSystem::getOutputForAttr(&localAttr, &output.outputId, sessionId,
&streamType,adjAttributionSource, &input.config, input.flags,
&output.selectedDeviceId, &portId, &secondaryOutputs);
......
}
后续流程如图4所示:

图4 getOutputForAttr流程
2) Engine 选设备逻辑 (getDevicesForStrategyInt)
在 Engine.cpp 中,getDevicesForStrategyInt 是决策核心。以下是 STRATEGY_MEDIA 为例简单说明下:
- 强制配置检查: getForceUse(FOR_MEDIA)。如果是 FORCE_SPEAKER,直接选 Speaker。
- 外部设备优先: 检查 A2DP, Wired Headset, USB Device。getLastRemovableMediaDevices() 会返回最后连接的外部设备。
- 默认设备: 如果没有外部设备,退回默认(Speaker 或 Earpiece)。
- 特殊规则:
STRATEGY_PHONE (通话):优先蓝牙 SCO,然后 Earpiece。
STRATEGY_SONIFICATION (铃声):同时从 Speaker 和 Headset 出声(Dual Routing)。
6. 输入路由策略
输入路由即决定录音来源选择哪个麦克风或输入设备。
1) getInputForAttr

图5 getInputForAttr流程
2) getDeviceForInputSource
Engine::getDeviceForInputSource 处理输入源映射:
VOICE_COMMUNICATION: 如果在通话中,可能强制使用与输出设备匹配的输入(如蓝牙耳机麦克风)。
DEFAULT/MIC: 优先蓝牙 A2DP/SCO(如果支持),其次有线耳机麦克风,最后是内置 Mic。
7. 动态策略与 Mix
除了传统的基于 Stream Type 的策略,Android 还支持 Dynamic Policy (Audio Mix),常用于:
车机系统(Car Audio):将特定 uid 的导航声音路由到特定 BUS 设备。
投屏/录屏:捕获特定内容的音频。
相关类:AudioPolicyMix。Engine 在计算设备时,会优先检查是否有 AudioPolicyMix 匹配当前 Attributes,如果有,则强制路由到对应的 Mix 输出,绕过默认策略。
8. 总结
Android 音频策略框架是一个分层清晰的系统:
1) 静态配置层 (HwModule/IOProfile):定义硬件能力底座。
2) 动态状态层 (DeviceDescriptor/SwAudioOutputDescriptor):维护运行时状态。
3) 策略决策层 (Engine):getDevicesForStrategyInt 是"大脑",根据优先级规则输出目标设备。
4) 执行层 (APM):根据 Engine 的决策,操作 AudioPolicyClient 完成物理连接。
理解 Engine 的 getDevicesForStrategyInt 和 APM 的 setDeviceConnectionState 是掌握 Android 音频路由切换的关键。
更多的内容,敬请关注,待分解。