Android audio_policy_configuration.xml加载流程

目录

一、audio_policy_configuration.xml文件被加载流程

[1、AudioPolicyService 创建阶段](#1、AudioPolicyService 创建阶段)

[2、createAudioPolicyManager 实现](#2、createAudioPolicyManager 实现)

[3、AudioPolicyManager 构造](#3、AudioPolicyManager 构造)

[4、配置文件解析 loadConfig](#4、配置文件解析 loadConfig)

[5、核心解析逻辑 PolicySerializer::deserialize](#5、核心解析逻辑 PolicySerializer::deserialize)

二、AudioPolicyConfig类解析

[1、AudioPolicyConfig 类定义](#1、AudioPolicyConfig 类定义)

2、module标签

3、MixPort标签

4、DevicePort标签

5、route标签


一、audio_policy_configuration.xml文件被加载流程

1、AudioPolicyService 创建阶段

文件路径:frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp

cpp 复制代码
void AudioPolicyService::onFirstRef() {
    mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
}

系统服务启动后,调用 createAudioPolicyManager,创建 AudioPolicyManager 对象。

2、createAudioPolicyManager 实现

cpp 复制代码
extern "C" AudioPolicyInterface* createAudioPolicyManager(
    AudioPolicyClientInterface *clientInterface) {
    AudioPolicyManager *apm = new AudioPolicyManager(clientInterface);
    status_t status = apm->initialize();
    if (status != NO_ERROR) {
        delete apm;
        apm = nullptr;
    }
    return apm;
}

作用

  • 创建 AudioPolicyManager

  • 立即调用 initialize() 初始化流程;

  • 如果失败,释放资源

3、AudioPolicyManager 构造

文件
frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp

cpp 复制代码
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
        : AudioPolicyManager(clientInterface, false /*forTesting*/)
{
    loadConfig();
}

void AudioPolicyManager::loadConfig() {
    if (deserializeAudioPolicyXmlConfig(getConfig()) != NO_ERROR) {
        ALOGE("could not load audio policy configuration file, setting defaults");
        getConfig().setDefault();
    }
}

构造时直接调用 loadConfig(),开始读取音频配置文件。

4、配置文件解析 loadConfig

文件
frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp

cpp 复制代码
status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config) {
    PolicySerializer serializer;
    return serializer.deserialize(fileName, config);
}

调用 PolicySerializer::deserialize,使用 libxml2 解析音频 XML 配置文件。

5、核心解析逻辑 PolicySerializer::deserialize

cpp 复制代码
status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config)
{
    // 使用智能指针包装 libxml2 的解析接口,解析传入的 XML 文件
    auto doc = make_xmlUnique(xmlParseFile(configFile));
    if (doc == nullptr) {
        // 如果解析失败,打印错误并返回 BAD_VALUE
        ALOGE("%s: Could not parse %s document.", __func__, configFile);
        return BAD_VALUE;
    }

    // 获取 XML 文档的根节点
    xmlNodePtr root = xmlDocGetRootElement(doc.get());
    if (root == NULL) {
        // 如果根节点为空,打印错误并返回 BAD_VALUE
        ALOGE("%s: Could not parse %s document: empty.", __func__, configFile);
        return BAD_VALUE;
    }

    // 处理 XInclude(XML文件可以引用其他XML文件的机制)
    if (xmlXIncludeProcess(doc.get()) < 0) {
        // 如果包含文件处理失败,记录错误,但不直接返回
        ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __func__, configFile);
    }

    // 检查根节点名称是否符合预期
    if (xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>(rootName)))  {
        ALOGE("%s: No %s root element found in xml data %s.", __func__, rootName,
                reinterpret_cast<const char*>(root->name));
        return BAD_VALUE;
    }

    // 获取根节点的 version 属性
    std::string version = getXmlAttribute(root, versionAttribute);
    if (version.empty()) {
        // 如果 version 属性不存在,返回错误
        ALOGE("%s: No version found in root node %s", __func__, rootName);
        return BAD_VALUE;
    }

    // 验证版本是否与期望版本一致
    if (version != mVersion) {
        ALOGE("%s: Version does not match; expect %s got %s", __func__, mVersion.c_str(),
              version.c_str());
        return BAD_VALUE;
    }

    // 开始解析子节点
    // Step 1: 解析 Module 列表
    ModuleTraits::Collection modules;
    status_t status = deserializeCollection<ModuleTraits>(root, &modules, config);
    if (status != NO_ERROR) {
        // 如果模块解析失败,直接返回错误状态
        return status;
    }
    // 将解析到的模块设置到 config 对象中
    config->setHwModules(modules);

    // Step 2: 解析全局配置
    GlobalConfigTraits::deseria

功能拆解

  • xmlParseFile:加载并解析 XML 文件。

  • xmlDocGetRootElement:获取根节点,确保结构有效。

  • xmlXIncludeProcess:处理 XInclude,允许配置文件嵌套引用子文件。

  • 验证 root 名称、版本号。

如果通过校验,进入内容解析:

cpp 复制代码
deserializeCollection<ModuleTraits>(root, &modules, config);
config->setHwModules(modules);
GlobalConfigTraits::deserialize(root, config);
SurroundSoundTraits::deserialize(root, config);

经过以上代码之后,最终audio_policy_configuration.xml配置文件会转化为以下的C++类AudioPolicyConfig。

二、AudioPolicyConfig类解析

audio_policy_configuration.xml配置文件配置了Android Audio的设备、流以及设备和流之间的路由等相关信息。写明了Android Audio支持哪些设备、哪些流以及它们支持的编码格式、采样率等信息。文件大致内容如下。

1、AudioPolicyConfig 类定义

cpp 复制代码
class AudioPolicyConfig {
    static const constexpr char* const kDefaultEngineLibraryNameSuffix = "default";
    std::string mSource; //为config字符串目录,一般在odm/etc、/vendor/etc、/system/etc下的audio_policy_configuration.xml
    std::string mEngineLibraryNameSuffix;
    HwModuleCollection &mHwModules; //保存了配置文件中所有的所有module标签集合,每个module标签对应一个HwModule类
    DeviceVector &mOutputDevices; //attchedDevices标签中,设备名称名字和devicePort标签的tagName相同,且type中有OUT字眼的DeviceDescriptor实体类集合
    DeviceVector &mInputDevices; //attchedDevices标签中,设备名称名字和devicePort标签的tagName相同,且type中有in字眼的DeviceDescriptor实体类集合
    sp<DeviceDescriptor> &mDefaultOutputDevice; //保存defaultOutputDevice标签内名字和devicePort标签的tagName相同
    // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
    // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
    // Note: remove also speaker_drc_enabled from global configuration of XML config file.
    bool mIsSpeakerDrcEnabled;
    bool mIsCallScreenModeSupported;
    SurroundFormats mSurroundFormats;
};
XML 复制代码
<modules>
       <!-- Primary Audio HAL -->
       <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>
               ......
           </mixPorts>
           <devicePorts>
               ......
           </devicePorts>
           <!-- route declaration, i.e. list all available sources for a given sink -->
           <routes>
               ......
           </routes>
        </module>
        <!-- A2dp Input Audio HAL -->
        <xi:include href="a2dp_in_audio_policy_configuration.xml"/>
            ......
   </modules>
   <!-- End of Modules section -->

2、module标签

每个module标签对应着相应的hal层实现,如primary、usb、a2dp等

cpp 复制代码
<modules>
       <!-- Primary Audio HAL -->
       <module name="primary" halVersion="3.0">
           <attachedDevices>
               <item>Speaker</item>
               <item>Built-In Mic</item>
               <item>Built-In Back Mic</item>
           </attachedDevices>
               ......
       </module>
       <!-- A2dp Input Audio HAL -->
       <xi:include href="a2dp_in_audio_policy_configuration.xml"/>
            ......
   </modules>
   <!-- End of Modules section -->

module标签对应C++实体类HWModule。

cpp 复制代码
class HwModule {
    const String8 mName; // hal层模块对应的module名字(primary, a2dp ...)
    audio_module_handle_t mHandle;
    OutputProfileCollection mOutputProfiles; // mixport标签role为source类型,对应IOProfle实体类集合
    InputProfileCollection mInputProfiles;  // mixport标签role为sink的类型,对应IOProfle实体类集合
    uint32_t mHalVersion; // hal层模块的版本信息
    DeviceVector mDeclaredDevices; // 所有的deviceport标签,对应DeviceDescriptor实体类的集合
    DeviceVector mDynamicDevices; /**< devices that can be added/removed at runtime (e.g. rsbumix)*/
    AudioRouteVector mRoutes; // 所有的route
    PolicyAudioPortVector mPorts; // 所有的mixport,deviceport标签对应的实体类,因为IOProfle和DeviceDescriptor都继承了AudioPort,所以相当于这是一个AudioPort集合
};

3、MixPort标签

mixport标签可以理解为stream流,配置了相应的格式、采样率以及mask,且分为输出、输入流。一个mixport标签可能有多个profile属性,也就是支持很多编码格式等属性。

XML 复制代码
<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"/>
      <profile name="" format="AUDIO_FORMAT_AAC_LC"
              samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
              channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
</mixPort>

一个mixport标签对应一个IOProfile实体类。

cpp 复制代码
class IOProfile : public AudioPort, public PolicyAudioPort {
    // 可以同时打开的流的最大数量,默认为1。赋值为0时,表示无穷大。
    uint32_t     maxOpenCount;
    // 目前已打开的流的数量。
    uint32_t     curOpenCount;
    // 同时处于活跃状态的流的最大数量,默认为1。赋值为0时,表示无穷大。
    uint32_t     maxActiveCount;
    // 正处于活跃状态的流的数量。 针对于Hal层的流而言。
    uint32_t     curActiveCount;
 
private:
    /** 当前流支持的设备集合;
     * 如果是sink输入流,查找规则如下:
    * 1. 遍历其父类的成员mRoutes,因为是输入流,所以遍历mRoute集合中sink为自己的route,也就是找有哪些源source设备把数据传给自己。
    * 2. 找到route后,根据route中source保存的对象,且对象type是AUDIO_PORT_TYPE_DEVICE类型(就是devicesPort标签对应的实体类DeviceDescriptor)
    * 3. 把DeviceDescriptor保存在集合中,保存在以下mSupportedDevices中,作为其支持的设备;
    * 输出流,同理;最终的结果就是:
    * 作为输出流source,mSupportedDevices保存此流可以输出到对应的device,stream -> device
    * 作为输入流sink,mSupportedDevices保存了其他device能输出数据到此流,  device -> stream
    **/
    DeviceVector mSupportedDevices;
};
 
class AudioPort : public virtual RefBase, public virtual Parcelable
{
    AudioGains mGains; // gain controllers
protected:
    std::string  mName; // 对应mixport的name
    audio_port_type_t mType; // AUDIO_PORT_TYPE_MIX (此处固定)
    audio_port_role_t mRole; // AUDIO_PORT_ROLE_SOURCE/AUDIO_PORT_ROLE_SINK(由mixport的role决定)
    AudioProfileVector mProfiles; // AudioProfile的集合,对应mixport里面的多个profile
 
    // Audio capabilities that are defined by hardware descriptors when the format is unrecognized
    // by the platform, e.g. short audio descriptor in EDID for HDMI.
    std::vector<media::ExtraAudioDescriptor> mExtraAudioDescriptors;
};
 
class PolicyAudioPort : public virtual RefBase, private HandleGenerator<audio_port_handle_t>
{
    uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
    sp<HwModule> mModule;     // 通过attach函数与HwModule绑定
    AudioRouteVector mRoutes; // 相关连的route标签集合
};

mixport内部的Profile标签对应的C++类AudioProfile 如下。在解析以上标签至profile时,会单独创建AudioProfile。

cpp 复制代码
class AudioProfile final : public RefBase, public Parcelable
{
    std::string  mName; // profile的name
    // 以下三个变量对应配置文件中profile中的置,由初始化时进行赋值
    audio_format_t mFormat; // The format for an audio profile should only be set when initialized.
    ChannelMaskSet mChannelMasks;
    SampleRateSet mSamplingRates;
    // 以下三个对应上面三位,如果三位都有值,则为false固定的,如果xml没有指定值,则为true表示是动态的值
    bool mIsDynamicFormat = false;
    bool mIsDynamicChannels = false;
    bool mIsDynamicRate = false;
 
    audio_encapsulation_type_t mEncapsulationType = AUDIO_ENCAPSULATION_TYPE_NONE;
 
    AudioProfile() = default;
    AudioProfile& operator=(const AudioProfile& other);
};

4、DevicePort标签

devicePort标签可以理解为一个device设备,设备也分output和input,以type中的关键字"IN"和"OUT"进行区分。

XML 复制代码
<devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
        <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                    samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
        <gains>
             <gain name="gain_1" mode="AUDIO_GAIN_MODE_JOINT"
                     minValueMB="-8400"
                    maxValueMB="4000"
                    defaultValueMB="0"
                    stepValueMB="100"/>
        </gains>
</devicePort>

一个devicePort对应一个C++类DeviceDescriptor。

cpp 复制代码
class DeviceDescriptor : public DeviceDescriptorBase,
                         public PolicyAudioPort, public PolicyAudioPortConfig
{
    std::string mTagName; // 对应的tagName字段
    FormatVector        mEncodedFormats; // encodedFormats转换的枚举值
    audio_format_t      mCurrentEncodedFormat;
    bool                mIsDynamic = false;
    const std::string   mDeclaredAddress; // address字段对应的地址
};
 
class DeviceDescriptorBase : public AudioPort, public AudioPortConfig
{
    AudioDeviceTypeAddr mDeviceTypeAddr;
    uint32_t mEncapsulationModes = 0;
    uint32_t mEncapsulationMetadataTypes = 0;
};
 
class AudioPort : public virtual RefBase, public virtual Parcelable
{
    AudioGains mGains; // gain controllers
protected:
    std::string  mName; // 对应devicePort的name
    audio_port_type_t mType; // AUDIO_PORT_TYPE_DEVICE(此处固定)
    audio_port_role_t mRole; // AUDIO_PORT_ROLE_SOURCE/AUDIO_PORT_ROLE_SINK(由mixport的role决定)
    AudioProfileVector mProfiles; // AudioProfile的集合,对应devicePort里面的多个profile
 
    // Audio capabilities that are defined by hardware descriptors when the format is unrecognized
    // by the platform, e.g. short audio descriptor in EDID for HDMI.
    std::vector<media::ExtraAudioDescriptor> mExtraAudioDescriptors;
};

同MixPort一样,devicePort也会解析内部的profile标签,创建新的AudioProfile。

cpp 复制代码
class AudioProfile final : public RefBase, public Parcelable
{
    std::string  mName; // profile的name
    // 以下三个变量对应配置文件中profile中的置,由初始化时进行赋值
    audio_format_t mFormat; // The format for an audio profile should only be set when initialized.
    ChannelMaskSet mChannelMasks;
    SampleRateSet mSamplingRates;
    // 以下三个对应上面三位,如果三位都有值,则为false固定的,如果xml没有指定值,则为true表示是动态的值
    bool mIsDynamicFormat = false;
    bool mIsDynamicChannels = false;
    bool mIsDynamicRate = false;
 
    audio_encapsulation_type_t mEncapsulationType = AUDIO_ENCAPSULATION_TYPE_NONE;
 
    AudioProfile() = default;
    AudioProfile& operator=(const AudioProfile& other);
};

5、route标签

route是把deviceport和mixport连接起来的路由,数据由一个stream输出到另一个device,或者从一个device输出到另一个stream。

XML 复制代码
<route type="mix" sink="Speaker"
                    sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>

route标签对应C++的AudioRoute类。

cpp 复制代码
class AudioRoute  : public virtual RefBase
{
    PolicyAudioPortVector mSources; //所有的deviceport、mixport标签转化的实体类都保存到HwModule的mPorts成员了,所以是用name去mPorts里面查找,只是source可能是多个,这里用集合保存
    sp<PolicyAudioPort> mSink; //同上
    audio_route_type_t mType; //AUDIO_ROUTE_MIX/AUDIO_ROUTE_MUX:根据type而定是互斥还是可融合
};

在Primary的module配置文件中通过如下语句去配置a2dp、usb的module。

XML 复制代码
<!-- A2dp Input Audio HAL -->
      <xi:include href="a2dp_in_audio_policy_configuration.xml"/>
相关推荐
铭阳(●´∇`●)31 分钟前
Python内置函数---breakpoint()
笔记·python·学习
月临水1 小时前
软件测试笔记1(测试的概念、测试和开发模型介绍、BUG介绍)
软件测试·笔记·bug
大学生亨亨1 小时前
蓝桥杯之递归
java·笔记·算法·蓝桥杯
姝孟2 小时前
学习笔记(C++篇)--- Day 4
c++·笔记·学习
jackson凌3 小时前
【Java学习笔记】选择结构
java·笔记·学习
chao_7893 小时前
性能测试篇——八股笔记
笔记
DKPT4 小时前
正则表达式与python使用
笔记·python·学习·面试·正则表达式
EQ-雪梨蛋花汤4 小时前
【Unity笔记】Unity音效管理:ScriptableObject配置 + 音量控制 + 编辑器预览播放自动化实现
笔记·unity·编辑器
海绵宝宝的月光宝盒5 小时前
[STM32] 4-1 UART与串口通信
c语言·开发语言·笔记·stm32·单片机