Android音频系列(09)-AudioPolicyManager代码解析

目录

[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 音频路由切换的关键。

更多的内容,敬请关注,待分解。

相关推荐
李子红了时2 小时前
【无标题】
android
听麟2 小时前
HarmonyOS 6.0+ 个性化音乐播放器APP开发实战:音频可视化与场景化推荐落地
华为·音视频·harmonyos
博客zhu虎康3 小时前
音视频处理:视频时间轴在指定时间处添加音频并展示可视化拖拽条
音视频
大学生小郑3 小时前
亮度噪声和色度噪声
图像处理·音视频·视频
星海之恋9923 小时前
便宜又好用的移动 4G 蜂窝代理快来看看!
音视频
传说故事3 小时前
【论文自动阅读】视频生成模型的Inference-time物理对齐 with Latent World Model
人工智能·深度学习·音视频·视频生成
Android系统攻城狮3 小时前
Android tinyalsa深度解析之pcm_close调用流程与实战(一百零四)
android·pcm·tinyalsa·音频进阶·音频性能实战·android hal
Bits to Atoms3 小时前
宇树G1语音助手完整开发指南(下)——从零构建智能知识库对话系统
人工智能·机器人·音视频·语音识别
weixin_411191843 小时前
LifecycleEventObserver和DefaultLifecycleObserver使用
android