Android音频学习(十)——audio_policy_configuration.xml解析(1)
Android 的音频策略配置文件j即APS的配置文件()是系统音频策略的基石,决定者音频数据的流向。其解析过程直接影响设备行为采用模块化 XML 设计,解析过程涉及多个关键步骤。
Android 的音频策略配置文件j即APS的配置文件(audio_policy_configuration.xml)是系统音频策略的基石,决定者音频数据的流向。其解析过程直接影响设备行为采用模块化 XML 设计,解析过程涉及多个关键步骤。以下是完整解析流程与技术要点:
1. 配置文件层级结构
文件通常位于/vendor/etc或/system/etc(开发板目录),内容如下:
<audioPolicyConfiguration>
<globalConfiguration key="attached_input_devices" value="..."/>
<modules>
<module name="primary" halVersion="3.0"> <!-- 音频硬件模块 -->
<attachedDevices>
<item>Speaker</item>
<item>Built-In Mic</item>
<item>Built-In Back Mic</item>
</attachedDevices>
<defaultOutputDevice>speaker</defaultOutputDevice>
<mixPorts> <!-- I/O端口定义 -->
<mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
<profile format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
</mixPorts>
<devicePorts> <!-- 物理/逻辑设备 -->
<devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
<profile.../>
</devicePort>
</devicePorts>
<devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
<profile.../>
</devicePort>
</devicePorts>
<routes> <!-- 路由规则 -->
<route type="mix" sink="Speaker" sources="primary output"/>
</routes>
</module>
<!-- 其他模块(蓝牙/USB等) -->
</modules>
<routingStrategies> <!-- 策略规则 -->
<strategy name="STRATEGY_MEDIA" deviceCategory="DEVICE_CATEGORY_SPEAKER">
<attributes usage="USAGE_MEDIA"/>
</strategy>
</routingStrategies>
</audioPolicyConfiguration>
在上一章提到,在创建AudioPolicyManager对象时,通过loadConfig加载配置文件,解析完成后,xml文件中的元素终究会转化AudioPolicyConfig中的成员。AudioPolicyConfig定义如下:
class AudioPolicyConfig{
...
HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
DeviceVector &mOutputDevices;
DeviceVector &mInputDevices;
sp<DeviceDescriptor> &mDefaultOutputDevice;
}
同时,这四个变量也在AudioPolicyManager中有定义。
mHwModules:保存了配置文件中所有的所有module标签集合,每个module标签对应一个HwModule类。
mAvailableOutputDevices:attchedDevices标签中,设备名称名字和devicePort标签的tagName相同,且type中有OUT字眼的DeviceDescriptor实体类集合,如示例文件中的Speaker设备。
mAvailableInputDevices:同mAvailableOutputDevices类似,换成type中有IN的DeviceDescriptor实体类集合,如上Built-In Mic。
mDefaultOutputDevice:保存defaultOutputDevice标签内名字和devicePort标签的tagName相同,如Speaker。
1.1module标签
每个module标签对应有自己的hal,也就是hal的源码实现都不一样,如primary、usb、a2dp等
<modules>
<!-- Primary Audio HAL -->
<module name="primary" halVersion="3.0">
<mixPorts>
<mixPort name="primary output" role="source" ...>
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT".../>
<profile name="" format="AUDIO_FORMAT_MP3".../>
...
</mixPort>
</mixPorts>
<devicePorts>
<devicePort>... </devicePort>
...
</devicePorts>
<routes>
<route>...</route>
</routes>
</module>
</modules>
对应到实体类:
class HwModule : public RefBase
{
...
const String8 mName; // base name of the audio HW module (primary, a2dp ...)
audio_module_handle_t mHandle;
OutputProfileCollection mOutputProfiles; // output profiles exposed by this module
InputProfileCollection mInputProfiles; // input profiles exposed by this module
uint32_t mHalVersion; // audio HAL API version
DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
DeviceVector mDynamicDevices; /**< devices that can be added/removed at runtime (e.g. rsbumix)*/
AudioRouteVector mRoutes;
PolicyAudioPortVector mPorts;
}
mOutputProfiles:mixport标签role为source类型,对应IOProfle实体类集合
mInputProfiles:mixport标签role为sink的类型,对应IOProfle实体类集合
mDeclaredDevices:所有的deviceport标签,对应DeviceDescriptor实体类的集合
mRoutes:所有的route
mPorts:所有的mixport,deviceport标签对应的实体类,因为IOProfle和DeviceDescriptor都继承了AudioPort,所以相当于这是一个AudioPort集合
1.2MixPort标签
mixPort标签可以理解为stream流,流配置了自己的格式、采样率以及mask,分为输出流和输入流,一个mixport可以有很多个profile,表示支持多少种格式。
<mixPort name="compressed_offload" role="source"
flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
<profile name="" format="AUDIO_FORMAT_MP3"
samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
<profile name="" format="AUDIO_FORMAT_AAC"
samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
</mixPort>
每个mixport标签对应一个IOProfile实体类,IOProfile分别继承于AudioPort(frameworks/av/media/libaudiofoundation/include/media/AudioPort.h)和PolicyAudioPort
class IOProfile : public AudioPort, public PolicyAudioPort
{
// Maximum number of input or output streams that can be simultaneously active for this profile.
// By convention 0 means no limit. To respect legacy behavior, initialized to 0 for output
// profiles and 1 for input profiles
uint32_t maxActiveCount;
private:
DeviceVector mSupportedDevices; // supported devices: this input/output can be routed from/to
}
class AudioPort {
protected:
std::string mName;
audio_port_type_t mType;
audio_port_role_t mRole;
AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
};
class PolicyAudioPort {
uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
sp<HwModule> mModule; // audio HW module exposing this I/O stream
AudioRouteVector mRoutes; // Routes involving this port
}
maxActiveCount:同时存活的流的最大数量,默认为1
标签中flag会影响该值,如果role为sink,且flag标记为AUDIO_INPUT_FLAG_MMAP_NOIRQ,则赋值为0,表示无穷大
mSupportedDevices:当前流支持的设备集合
作为输出流source,mSupportedDevices保存此流可以输出到对应的device,stream -> device
作为输入流sink,mSupportedDevices保存了其他device能输出数据到此流, device -> stream
根据route查找对应的source和sink,例如sink为输入流时对应规则如下:
(1)遍历其父类的成员mRoutes,因为是输入流,所以遍历mRoute集合中sink为自己的route,也就是找有哪些源source设备把数据传给自己。
(2)找到route后,根据route中source保存的对象,且对象type是AUDIO_PORT_TYPE_DEVICE类型(就是devicesPort标签对应的实体类DeviceDescriptor)
(3)把DeviceDescriptor保存在集合中,保存在以下mSupportedDevices中,作为其支持的设备;
MixPort的profile,会单独创建AudioProfile对象
class AudioProfile final : public RefBase, public Parcelable
{
...
private:
std::string mName;
audio_format_t mFormat; // The format for an audio profile should only be set when initialized.
ChannelMaskSet mChannelMasks;
SampleRateSet mSamplingRates;
bool mIsDynamicFormat = false;
bool mIsDynamicChannels = false;
bool mIsDynamicRate = false;
};
1.3Device标签
devicePort标签可以理解为一个device设备。
<devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
</devicePort>
<devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" hannelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</devicePort>
对应实体类DeviceDescriptor
class DeviceDescriptor : public DeviceDescriptorBase,
public PolicyAudioPort, public PolicyAudioPortConfig
{
...
private:
std::string mTagName; // Unique human readable identifier for a device port found in conf file.
FormatVector mEncodedFormats;
audio_format_t mCurrentEncodedFormat;
}
class DeviceDescriptorBase : public AudioPort, public AudioPortConfig
{
}
class PolicyAudioPort {
uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
sp<HwModule> mModule; // audio HW module exposing this I/O stream
AudioRouteVector mRoutes; // Routes involving this port
}
class AudioPort {
protected:
std::string mName;
audio_port_type_t mType;
audio_port_role_t mRole;
AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
}
class PolicyAudioPortConfig : public virtual RefBase
{
union audio_io_flags mFlags = { AUDIO_INPUT_FLAG_NONE };
}
同上MixPort一样,也会在解析内部profile标签,创建新的AudioProfile。
1.4.route标签
route是把deviceport和mixport连接起来的路由,数据由一个stream输出到另一个device(output),或者从一个device输入到另一个stream(input);
<routes>
<route type="mix" sink="Earpiece"
sources="primary output,deep_buffer,BT SCO Headset Mic"/>
<route type="mix" sink="Speaker"
sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
<route type="mix" sink="Wired Headset"
sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
<route type="mix" sink="Wired Headphones"
sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
<route type="mix" sink="primary input"
sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
<route type="mix" sink="Telephony Tx"
sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic, voice_tx"/>
<route type="mix" sink="voice_rx"
sources="Telephony Rx"/>
</routes>
对应的实体类为AudioRoute
class AudioRoute : public virtual RefBase
{
...
private:
PolicyAudioPortVector mSources;
sp<PolicyAudioPort> mSink;
audio_route_type_t mType;
}
| XML 元素 | 内存对象 | 作用 |
|---|---|---|
<module> |
HwModule |
抽象音频硬件模块 |
<mixPort> |
IOProfile |
定义输入/输出端口能力 |
<devicePort> |
DeviceDescriptor |
描述物理设备特性 |
<route> |
AudioRoute |
建立端口与设备连接关系 |
<routingStrategies> |
Engine/ProductStrategy |
音频策略到设备的映射规则 |
内容有点多,下篇文章中继续分析,这篇文章大多参考了@帅气好男人_Jack的讲解audio_policy_configuration.xml文件解析_audio policy config详解-CSDN博客,我是基于Android12代码分析的,有一些出入,请按照自己调试的代码对照分析。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)