Android开发之音频配置文件audio_policy_configuration.xml解析全过程

本文基于android7.0分析

一、前言

audio_policy.conf解析

前面我们已经介绍了audio_policy.conf 的解析全过程,但是,.conf 是一种简单的专有格式,有较大的局限性,无法描述电视和汽车等应用的复杂拓扑。Android 7.0 弃用了audio_policy.conf,并增加了对使用 XML 文件格式来定义音频拓扑的支持,这种文件格式更通俗易懂,具有多种编辑和解析工具,并且足够灵活,可以描述复杂的音频拓扑。

注意Android 7.0 仍支持使用 audio_policy.conf;系统会默认使用这种旧版格式。要使用 XML 文件格式,需要在设备 Makefile 中添加构建选项 USE_XML_AUDIO_POLICY_CONF := 1


二、XML 格式的优势

与在 .conf 文件中一样,新的 XML 文件支持定义输出输入流配置文件、可用于播放和捕获的设备以及音频属性的数量和类型。此外,XML 格式还提供以下增强功能:

  • 音频配置文件目前的结构类似于 HDMI 简单音频描述符,支持每种音频格式使用一组不同的采样率/声道掩码。
  • 设备和流之间所有可能连接的显式定义。以前,借助隐式规则,可以使连接到同一 HAL 模块的所有设备互连,从而阻止音频政策控制使用音频补丁程序 API 请求的连接。现在,在 XML 格式中,拓扑描述定义了连接限制。
  • 对“包含”的支持可避免出现重复的标准 A2DP、USB 或重新导向提交定义。
  • 可自定义的音量曲线。以前,音量表采用硬编码格式。在 XML 格式中,音量表通过描述来定义,并且可自定义。

frameworks/av/services/audiopolicy/config/audio_policy_configuration.xml 中的模板展示了很多已在使用的上述功能。


三、文件格式和位置

新的音频政策配置文件是 audio_policy_configuration.xml,位于 /system/etc。要查看采用新的 XML 文件格式的简单音频政策配置,请查看以下示例。

显示音频政策示例



    
    
        
            
                Speaker
                Earpiece
                Built-In Mic
            
            Speaker
            
                
                    
                
                
                    
                
            
            
                
                   
                
                
                    
                
                
                    
                
                
                    
                
                
                    
                
            
            
                
                
                
                
            
        
        
    

    
    

顶层结构中包含与各个音频 HAL 硬件模块对应的模块,其中每个模块都有一系列混合端口、设备端口和导向:

  • 混合端口描述了可以在音频 HAL 处打开以供播放和捕获的流的可能配置文件。
  • 设备端口描述了可以附上其类型(以及(可选)地址和音频属性,如果相关)的设备。
  • 导向(新)现在已从混合端口描述符中分离出来,支持描述从设备到设备或从流到设备的导向。

显示音量表示例



    
        0,0
        100,0
    
    
        0,-9600
        100,-9600
    
    
        1,-4950
        33,-3350
        66,-1700
        100,0
    

显示音量示例



    
    
    
    

    
    
    
    

    
    
    
    

    
    
        1,-5500
        20,-4300
        86,-1200
        100,0
    
    
    

    
    
    
    

    
    
    
    

    
    
    
    

    
    
    
    

    
    
    
    

    
    
    
    

    
    
    
    

    
    
    
    

    
    
    
    

XML 包含 (XInclude) 方法可用于包含位于其他 XML 文件中的音频政策配置信息。所有包含的文件必须遵循上述结构,同时满足以下限制条件:

  • 文件只能包含顶层元素。
  • 文件不能包含 Xinclude 元素。

使用“包含”可避免将标准 Android 开放源代码项目 (AOSP) 音频 HAL 模块配置信息复制到所有音频政策配置文件(这样做容易出错)google为以下音频 HAL 提供了标准音频政策配置 xml 文件:

  • A2DPa2dp_audio_policy_configuration.xml
  • 重新导向子混音rsubmix_audio_policy_configuration.xml
  • USBusb_audio_policy_configuration.xml

四、解析

以如下audio_policy_configuration.xml为例:






    

    
    


    
    
        
        
            
                Speaker
                Built-In Mic
                Built-In Back Mic
            
            Speaker
            
                
                    
                
                
                    
                
                
                    
                    
                    
                
                
                    
                
                
                    
                
                
                    
                
            
            
                
                
                   
                
                
                    
                    
                        
                    
                
                
                    
                
                
                    
                
                
                    
                
                
                    
                
                
                    
                
                
                    
                             

                
                    
                
                
                    
                
                
                    
                
                
                    
                
                
                    
                
            
            
            
                
                
                
                
                
                
                
                
            

        

        
        
            
                
                    
                
            
            
                
                    
                
            
            
                
            
        

        
        

        
        

        
        

    
    

    

    
    

    



在之前我们已经介绍了的 audio_policy.conf 文章中可以知道,解析音频配置策略文件所处的类文件为 AudioPolicyManager.cpp 构造函数
Android开发之音频配置文件audio_policy_configuration.xml解析全过程_第1张图片
而本章第一小节说了自Android 7.0 开始出现了.xml 音频配置策略文件,并且兼容老的 .conf ,通过宏定义 USE_XML_AUDIO_POLICY_CONF 控制 ,代码位于 AudioPolicyManager.cpp 构造函数 如下:
AudioPolicyManager.cpp 位于 \frameworks\av\services\audiopolicy\managerdefault

#ifdef USE_XML_AUDIO_POLICY_CONF
    mVolumeCurves = new VolumeCurvesCollection();
    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
                             mDefaultOutputDevice, speakerDrcEnabled,
                             static_cast(mVolumeCurves));
    PolicySerializer serializer;
    if (serializer.deserialize(AUDIO_POLICY_XML_CONFIG_FILE, config) != NO_ERROR) {
#else
    mVolumeCurves = new StreamDescriptorCollection();
    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
                             mDefaultOutputDevice, speakerDrcEnabled);
    if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&
            (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {
#endif
        ALOGE("could not load audio policy configuration file, setting defaults");
        config.setDefault();
    }

可以看到首先是定义了 PolicySerializer 对象,
.xml 通过 PolicySerializer 类实现解析,解析入口函数为 deserialize
PolicySerializer对象 定义于 \frameworks\av\services\audiopolicy\common\managerdefinitions\include\Serializer.h
实现位于\frameworks\av\services\audiopolicy\common\managerdefinitions\src\Serializer.cpp
PolicySerializer 构造函数如下:

PolicySerializer::PolicySerializer() : mRootElementName(rootName)
{
    std::ostringstream oss;
    oss << gMajor << "." << gMinor;
    mVersion = oss.str();
    ALOGV("%s: Version=%s Root=%s", __FUNCTION__, mVersion.c_str(), mRootElementName.c_str());
}

可以看到构造函数初始化 变量 mRootElementName = rootName
mVersion =oss.str()= oss << gMajor << "." << gMinor;
rootName、gMajor 、gMinor 定义如下:

const char *const PolicySerializer::rootName = "audioPolicyConfiguration";
const uint32_t PolicySerializer::gMajor = 1;
const uint32_t PolicySerializer::gMinor = 0;

audioPolicyConfiguration 我们可以知道是 .xml的根节点元素字段名,因此 mRootElementName 会用来后面判断.xml的根节点元素字段名是否正确,如果不正确,则解析失败。
mVersion =1.0、mRootElementName=“audioPolicyConfiguration”

Serializer.h 源码如下

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include "AudioPolicyConfig.h"
#include 
#include 
#include 
#include 
#include 
#include 

struct _xmlNode;
struct _xmlDoc;

namespace android {

struct AudioGainTraits
{
    static const char *const tag;
    static const char *const collectionTag;

    struct Attributes
    {
        static const char mode[]; /**< gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
        /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
        static const char channelMask[];
        static const char minValueMB[]; /**< min value in millibel. */
        static const char maxValueMB[]; /**< max value in millibel. */
        static const char defaultValueMB[]; /**< default value in millibel. */
        static const char stepValueMB[]; /**< step value in millibel. */
        static const char minRampMs[]; /**< needed if mode AUDIO_GAIN_MODE_RAMP. */
        static const char maxRampMs[]; /**< .needed if mode AUDIO_GAIN_MODE_RAMP */
    };

    typedef AudioGain Element;
    typedef sp PtrElement;
    typedef AudioGainCollection Collection;
    typedef void *PtrSerializingCtx;

    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);

    // Gain has no child
};

// A profile section contains a name,  one audio format and the list of supported sampling rates
// and channel masks for this format
struct AudioProfileTraits
{
    static const char *const tag;
    static const char *const collectionTag;

    struct Attributes
    {
        static const char name[];
        static const char samplingRates[];
        static const char format[];
        static const char channelMasks[];
    };

    typedef AudioProfile Element;
    typedef sp PtrElement;
    typedef AudioProfileVector Collection;
    typedef void *PtrSerializingCtx;

    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);
};

struct MixPortTraits
{
    static const char *const tag;
    static const char *const collectionTag;

    struct Attributes
    {
        static const char name[];
        static const char role[];
        static const char flags[];
    };

    typedef IOProfile Element;
    typedef sp PtrElement;
    typedef IOProfileCollection Collection;
    typedef void *PtrSerializingCtx;

    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);

    // Children are: GainTraits
};

struct DevicePortTraits
{
    static const char *const tag;
    static const char *const collectionTag;

    struct Attributes
    {
        static const char tagName[]; /**<  : any string without space. */
        static const char type[]; /**< . */
        static const char role[]; /**< . */
        static const char roleSource[]; /**< . */
        static const char address[]; /**< optional: device address, char string less than 64. */
    };
    typedef DeviceDescriptor Element;
    typedef sp PtrElement;
    typedef DeviceVector Collection;
    typedef void *PtrSerializingCtx;

    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);
    // Children are: GainTraits (optionnal)
};

struct RouteTraits
{
    static const char *const tag;
    static const char *const collectionTag;

    struct Attributes
    {
        static const char type[]; /**< : mix or mux. */
        static const char typeMix[]; /**< type attribute mix value. */
        static const char sink[]; /**< . */
        static const char sources[]; /**< sources: all source that can be involved in this route. */
    };
    typedef AudioRoute Element;
    typedef sp PtrElement;
    typedef AudioRouteVector Collection;
    typedef HwModule *PtrSerializingCtx;

    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx ctx);
};

struct ModuleTraits
{
    static const char *const tag;
    static const char *const collectionTag;

    static const char *const childAttachedDevicesTag;
    static const char *const childAttachedDeviceTag;
    static const char *const childDefaultOutputDeviceTag;

    struct Attributes
    {
        static const char name[];
        static const char version[];
    };

    typedef HwModule Element;
    typedef sp PtrElement;
    typedef HwModuleCollection Collection;
    typedef AudioPolicyConfig *PtrSerializingCtx;

    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);

    // Children are: mixPortTraits, devicePortTraits and routeTraits
    // Need to call deserialize on each child
};

struct GlobalConfigTraits
{
    static const char *const tag;

    struct Attributes
    {
        static const char speakerDrcEnabled[];
    };

    static status_t deserialize(const _xmlNode *root, AudioPolicyConfig &config);
};

struct VolumeTraits
{
    static const char *const tag;
    static const char *const collectionTag;
    static const char *const volumePointTag;

    struct Attributes
    {
        static const char stream[];
        static const char deviceCategory[];
        static const char reference[];
    };

    typedef VolumeCurve Element;
    typedef sp PtrElement;
    typedef VolumeCurvesCollection Collection;
    typedef void *PtrSerializingCtx;

    static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
                                PtrSerializingCtx serializingContext);

    // No Child
};

class PolicySerializer
{
private:
    static const char *const rootName;

    static const char *const versionAttribute;
    static const uint32_t gMajor; /**< the major number of the policy xml format version. */
    static const uint32_t gMinor; /**< the minor number of the policy xml format version. */

public:
    PolicySerializer();
    status_t deserialize(const char *str, AudioPolicyConfig &config);

private:
    typedef AudioPolicyConfig Element;

    std::string mRootElementName;
    std::string mVersion;

    // Children are: ModulesTraits, VolumeTraits
};

}

定义了 我们待会解析数据时的对象,
其中有 struct AudioGainTraits、struct AudioProfileTraits、struct MixPortTraits、struct DevicePortTraits、struct RouteTraits、struct ModuleTraits、struct GlobalConfigTraits、struct VolumeTraits 和解析入口类 class PolicySerializer
和 声明了解析 xml 的对象 struct _xmlNode、struct _xmlDoc

紧接着我们继续看到 入口函数

status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig &config)
{
    xmlDocPtr doc;
    doc = xmlParseFile(configFile);//将文件内容转换为xml文档
    if (doc == NULL) {
        ALOGE("%s: Could not parse %s document.", __FUNCTION__, configFile);
        return BAD_VALUE;
    }

    /**
         audioPolicyConfiguration{
            ......
         }
	*/
    xmlNodePtr cur = xmlDocGetRootElement(doc);//得到xml的根节点元素
    if (cur == NULL) {
        ALOGE("%s: Could not parse %s document: empty.", __FUNCTION__, configFile);
        xmlFreeDoc(doc);
        return BAD_VALUE;
    }
    if (xmlXIncludeProcess(doc) < 0) {
         ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __FUNCTION__, configFile);
    }

    //mRootElementName="audioPolicyConfiguration"
    if (xmlStrcmp(cur->name, (const xmlChar *) mRootElementName.c_str()))  {
        ALOGE("%s: No %s root element found in xml data %s.", __FUNCTION__, mRootElementName.c_str(),
              (const char *)cur->name);
        xmlFreeDoc(doc);
        return BAD_VALUE;
    }

//versionAttribute = "version";
    string version = getXmlAttribute(cur, versionAttribute);
    if (version.empty()) {
        ALOGE("%s: No version found in root node %s", __FUNCTION__, mRootElementName.c_str());
        return BAD_VALUE;
    }

	//mVersion = 1.0
    if (version != mVersion) {
        ALOGE("%s: Version does not match; expect %s got %s", __FUNCTION__, mVersion.c_str(),
              version.c_str());
        return BAD_VALUE;
    }
	
    // Lets deserialize children
    // Modules
    ModuleTraits::Collection modules;
    deserializeCollection(doc, cur, modules, &config);
    config.setHwModules(modules);

    // deserialize volume section
    VolumeTraits::Collection volumes;
    deserializeCollection(doc, cur, volumes, &config);
    config.setVolumes(volumes);

    // Global Configuration
    GlobalConfigTraits::deserialize(cur, config);

    xmlFreeDoc(doc);
    return android::OK;
}

deserialize 函数有两个参数

const char *configFile //文件路径
#define AUDIO_POLICY_XML_CONFIG_FILE "/system/etc/audio_policy_configuration.xml"

AudioPolicyConfig &config //用于封装的整个.xml数据结构的对象。

参数类型跟我们解析.conf是一样的,

AudioPolicyConfig.h 源码位于: \frameworks\av\services\audiopolicy\common\managerdefinitions\include
源码如下:

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

namespace android {

class AudioPolicyConfig
{
public:
    AudioPolicyConfig(HwModuleCollection &hwModules,
                      DeviceVector &availableOutputDevices,
                      DeviceVector &availableInputDevices,
                      sp &defaultOutputDevices,
                      bool &isSpeakerDrcEnabled,
                      VolumeCurvesCollection *volumes = nullptr)
        : mHwModules(hwModules),
          mAvailableOutputDevices(availableOutputDevices),
          mAvailableInputDevices(availableInputDevices),
          mDefaultOutputDevices(defaultOutputDevices),
          mVolumeCurves(volumes),
          mIsSpeakerDrcEnabled(isSpeakerDrcEnabled)
    {}

    void setVolumes(const VolumeCurvesCollection &volumes)
    {
        if (mVolumeCurves != nullptr) {
            *mVolumeCurves = volumes;
        }
    }

    void setHwModules(const HwModuleCollection &hwModules)
    {
        mHwModules = hwModules;
    }

    void addAvailableDevice(const sp &availableDevice)
    {
        if (audio_is_output_device(availableDevice->type())) {
            mAvailableOutputDevices.add(availableDevice);
        } else if (audio_is_input_device(availableDevice->type())) {
            mAvailableInputDevices.add(availableDevice);
        }
    }

    void addAvailableInputDevices(const DeviceVector &availableInputDevices)
    {
        mAvailableInputDevices.add(availableInputDevices);
    }

    void addAvailableOutputDevices(const DeviceVector &availableOutputDevices)
    {
        mAvailableOutputDevices.add(availableOutputDevices);
    }

    void setSpeakerDrcEnabled(bool isSpeakerDrcEnabled)
    {
        mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
    }

    const HwModuleCollection getHwModules() const { return mHwModules; }

    const DeviceVector &getAvailableInputDevices() const
    {
        return mAvailableInputDevices;
    }

    const DeviceVector &getAvailableOutputDevices() const
    {
        return mAvailableOutputDevices;
    }

    void setDefaultOutputDevice(const sp &defaultDevice)
    {
        mDefaultOutputDevices = defaultDevice;
    }

    const sp &getDefaultOutputDevice() const { return mDefaultOutputDevices; }

    void setDefault(void)
    {
        mDefaultOutputDevices = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
        sp module;
        sp defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
        mAvailableOutputDevices.add(mDefaultOutputDevices);
        mAvailableInputDevices.add(defaultInputDevice);

        module = new HwModule("primary");

        sp outProfile;
        outProfile = new OutputProfile(String8("primary"));
        outProfile->attach(module);
        outProfile->addAudioProfile(
                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
        outProfile->addSupportedDevice(mDefaultOutputDevices);
        outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
        module->mOutputProfiles.add(outProfile);

        sp inProfile;
        inProfile = new InputProfile(String8("primary"));
        inProfile->attach(module);
        inProfile->addAudioProfile(
                new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000));
        inProfile->addSupportedDevice(defaultInputDevice);
        module->mInputProfiles.add(inProfile);

        mHwModules.add(module);
    }

private:
    HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
    DeviceVector &mAvailableOutputDevices;
    DeviceVector &mAvailableInputDevices;
    sp &mDefaultOutputDevices;
    VolumeCurvesCollection *mVolumeCurves;
    bool &mIsSpeakerDrcEnabled;
};

}; // namespace android

之前解析audio_policy.conf中我们已经知道通过AudioPolicyConfig类来装载整个音频策略文件数据,这里也是一样,通过AudioPolicyConfig 来封装audio_policy_configuration.xml所包含的策略数据,包含如下属性变量

HwModuleCollection &mHwModules;
/**< Collection of Module, with
    Profiles, i.e. Mix Ports.*/
.xml中所有module模块的集合
DeviceVector &mAvailableOutputDevices; .xml中所有output devices模块的集合
DeviceVector &mAvailableInputDevices; .xml中所有input devices模块的集合
sp &mDefaultOutputDevices; .xml中默认output device
VolumeCurvesCollection *mVolumeCurves; .xml中音量集合

接着通过
1、通过 xmlParseFile 函数将整个 .xml解析后转换成 数据类型为 xmlDocPtr doc;
2、通过 xmlDocGetRootElement 函数获取到 根节点所有的元素,以数据类型为 xmlNodePtr cur 接收,也就是 audioPolicyConfiguration 开始包含的所有的元素
3、通过 if (xmlStrcmp(cur->name, (const xmlChar *) mRootElementName.c_str())) {},判断上面获取所有元素cur->name是否是以mRootElementName 作为根元素名字,通过前面解析PolicySerializer 构造函数我们知道mRootElementName=“audioPolicyConfiguration”,如果cur->name!=audioPolicyConfiguratio的话,则return BAD_VALUE,否则继续解析
4、接着通过函数 string version = getXmlAttribute(cur, versionAttribute); 获取 versionAttribute 版本号,

const char *const PolicySerializer::versionAttribute = "version";

string getXmlAttribute(const xmlNode *cur, const char *attribute)
{
    xmlChar *xmlValue = xmlGetProp(cur, (const xmlChar*)attribute);
    if (xmlValue == NULL) {
        return "";
    }
    string value((const char*)xmlValue);
    xmlFree(xmlValue);
    return value;
}

如果version.empty()return BAD_VALUE
如果version != mVersionreturn BAD_VALUE,前面在PolicySerializer 构造函数我们已经初始化
mVersion =1.0、mRootElementName=“audioPolicyConfiguration”
否则继续解析
5、进过一些列校验进入了正式解析,通过函数

ModuleTraits::Collection modules;
deserializeCollection(doc, cur, modules, &config);
config.setHwModules(modules);  

前面我们在介绍 Serializer.h 已经说明了它声明了一些列 ****Traits ,用来解析过程中作为数据类型封装数据,待会我们解析时一个一个再来看他们的实现,首先我们这里用到了ModuleTraits,在Serializer.cpp中找到它的实现,源码如下:

const char *const ModuleTraits::childAttachedDevicesTag = "attachedDevices";
const char *const ModuleTraits::childAttachedDeviceTag = "item";
const char *const ModuleTraits::childDefaultOutputDeviceTag = "defaultOutputDevice";

const char *const ModuleTraits::tag = "module";
const char *const ModuleTraits::collectionTag = "modules";

const char ModuleTraits::Attributes::name[] = "name";
const char ModuleTraits::Attributes::version[] = "halVersion";


/**
root = moudle {} /moudle
module = HwModule
ctx = AudioPolicyConfig*

*/
status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
                                   PtrSerializingCtx ctx)
{

    /**
            1. name= primary  Attributes::name = "name"
	*/
    string name = getXmlAttribute(root, Attributes::name);
    if (name.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
        return BAD_VALUE;
    }
    uint32_t version = AUDIO_DEVICE_API_VERSION_MIN;//AUDIO_DEVICE_API_VERSION_2_0
    /**
        1. versionLiteral = 3.0 Attributes::version = "halVersion"


	*/
    string versionLiteral = getXmlAttribute(root, Attributes::version);//3
    if (!versionLiteral.empty()) {
        uint32_t major, minor;

		/**
                 1.  major = 3  minor = 0

		 */
        sscanf(versionLiteral.c_str(), "%u.%u", &major, &minor);
        version = HARDWARE_DEVICE_API_VERSION(major, minor);
        ALOGV("%s: mHalVersion = %04x major %u minor %u",  __FUNCTION__,
              version, major, minor);
    }

    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());

      /**
          1. Element = HwModule

	  */
    module = new Element(name.c_str(), version);

    // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
    MixPortTraits::Collection mixPorts;
    deserializeCollection(doc, root, mixPorts, NULL);
    module->setProfiles(mixPorts);

    DevicePortTraits::Collection devicePorts;
    deserializeCollection(doc, root, devicePorts, NULL);
    module->setDeclaredDevices(devicePorts);

    RouteTraits::Collection routes;
    deserializeCollection(doc, root, routes, module.get());
    module->setRoutes(routes);

    const xmlNode *children = root->xmlChildrenNode;
    while (children != NULL) {
        if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
            ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
            const xmlNode *child = children->xmlChildrenNode;
            while (child != NULL) {
                if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
                    xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
                    if (attachedDevice != NULL) {
                        ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
                              (const char*)attachedDevice);
                        sp device =
                                module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
                        ctx->addAvailableDevice(device);
                        xmlFree(attachedDevice);
                    }
                }
                child = child->next;
            }
        }
        if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
            xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
            if (defaultOutputDevice != NULL) {
                ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
                      (const char*)defaultOutputDevice);
                sp device =
                        module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
                if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
                    ctx->setDefaultOutputDevice(device);
                    ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
                }
                xmlFree(defaultOutputDevice);
            }
        }
        children = children->next;
    }
    return NO_ERROR;
}

可以看到初始化了其内部所携带的属性,和实现了 deserialize 函数

我们接着继续看到 deserializeCollection(doc, cur, modules, &config); 函数,源码如下:

/**
       1. Collection = HwModuleCollection PtrSerializingCtx = AudioPolicyConfig*
           cur = audioPolicyConfiguration {} /audioPolicyConfiguration
       2. Collection = IOProfileCollection PtrSerializingCtx = void *
           cur = moudle {} /moudle
       3. Collection = AudioProfileVector PtrSerializingCtx = void *
           cur = mixPort {} /mixPort
       4. Collection = AudioGainCollection PtrSerializingCtx = void *
           cur = mixPort {} /mixPort
       5. Collection = DeviceVector PtrSerializingCtx = void *
           cur = moudle {} /moudle
       6. Collection = AudioProfileVector PtrSerializingCtx = void *
           cur = devicePort {} /devicePort
       7. Collection = AudioGainCollection PtrSerializingCtx = void *
           cur = devicePort {} /devicePort

*/
template 
static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
                                      typename Trait::Collection &collection,
                                      typename Trait::PtrSerializingCtx serializingContext)
{
/**
1. Trait == ModuleTraits
2. Trait == MixPortTraits
3. Trait == AudioProfileTraits
4. Trait == AudioGainTraits
5. Trait == DevicePortTraits
6. Trait == AudioProfileTraits
7. Trait == AudioGainTraits
*/

    /**
         1.cur->xmlChildrenNode == globalConfiguration {} /globalConfiguration
         2.cur->xmlChildrenNode == attachedDevices {} /attachedDevices
         3.cur->xmlChildrenNode == profile {} /profile
         4.cur->xmlChildrenNode == profile {} /profile
         5.cur->xmlChildrenNode == attachedDevices {} /attachedDevices
         6.cur->xmlChildrenNode == profile {} /profile
    */

    const xmlNode *root = cur->xmlChildrenNode;
    while (root != NULL) {

	 /**
           1. collectionTag = modules   tag = moudle
           2. collectionTag = mixPorts   tag = mixPort
           3. collectionTag = profiles  tag = profile
           4. collectionTag = gains tag = gain
           5. collectionTag = devicePorts tag = devicePort
           6. collectionTag = profiles  tag = profile
	*/
        if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
                xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
            /**
                 1.root->next = moudles {} /moudles
                 2.root->next = defaultOutputDevice {} /defaultOutputDevice
                 3.root->next = mixPorts {} /mixPorts
                 4.root->next = profile {} /profile
                 5.root->next = defaultOutputDevice {} /defaultOutputDevice
                 6.root->next = mixPorts {} /mixPorts
                 7.root->next = devicePorts {} /devicePorts
	      */
				
            root = root->next;
            continue;
        }
        const xmlNode *child = root;

	/**
           1. collectionTag = modules  child->name = modules
           2. collectionTag = mixPorts  child->name = mixPorts
           3. collectionTag = devicePorts  child->name = devicePorts
	*/
        if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {

	     /**
               1. child->xmlChildrenNode = moudle {} /moudle
               2. child->xmlChildrenNode = mixPort {} /mixPort
               3. child->xmlChildrenNode = devicePort {} /devicePort
		 */
            child = child->xmlChildrenNode;
        }
        while (child != NULL) {
		/**
                  1. tag = moudle
                  2. tag = mixPort
                  3. tag = profile
                  4. tag = devicePort
                  5. tag = profile
		*/
            if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
                /**
                     1. PtrElement = HwModule
                     2. PtrElement = IOProfile
                     3. PtrElement = sp
                     4. PtrElement = sp
                     5. PtrElement = sp
		   */
                typename Trait::PtrElement element;
                status_t status = Trait::deserialize(doc, child, element, serializingContext);
                if (status != NO_ERROR) {
                    return status;
                }

		/**
                 1. element = sp
                 2. element = IOProfile
                 3. element = sp
		*/
                if (collection.add(element) < 0) {
                    ALOGE("%s: could not add element to %s collection", __FUNCTION__,
                          Trait::collectionTag);
                }
            }
            child = child->next;
        }
        if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
            return NO_ERROR;
        }
        root = root->next;
    }
    return NO_ERROR;
}

首先可以看到 deserializeCollection 函数通过模板类定义的 Trait,因此以后每次解析 ***Trait 都会是通过这个函数去解析,

这个函数中
1、 const xmlNode *root = cur->xmlChildrenNode; 获取到cur的子节点 root ,对应.xml中的
root=
2、通过root!=NULL建立一个while循环,遍历root 中所有child node
3、然后root->name跟当前的模板类 template collectionTagtag值比较,也就是目前传入的ModuleTraits定义的

const char *const ModuleTraits::tag = "module";
const char *const ModuleTraits::collectionTag = "modules";
 /**
           1. collectionTag = modules   tag = moudle
           2. collectionTag = mixPorts   tag = mixPort
           3. collectionTag = profiles  tag = profile
           4. collectionTag = gains tag = gain
           5. collectionTag = devicePorts tag = devicePort
           6. collectionTag = profiles  tag = profile
	*/
        if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
                xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
            /**
                 1.root->next = moudles {} /moudles
                 2.root->next = defaultOutputDevice {} /defaultOutputDevice
                 3.root->next = mixPorts {} /mixPorts
                 4.root->next = profile {} /profile
                 5.root->next = defaultOutputDevice {} /defaultOutputDevice
                 6.root->next = mixPorts {} /mixPorts
                 7.root->next = devicePorts {} /devicePorts
	      */
				
            root = root->next;
            continue;
        }
           const xmlNode *child = root;

如果 root->name 跟两者都不同相等,则进入该判断 root = root->next;
直到 root->nextroot->nameTrait 中的collectionTag 或者tag相等,此时如果我们这里的ModuleTraits与我们解析的collectionTag 相等,所以解析到对应.xml 获取到 child=root->next = moudles {} /moudles 就结束这个判断
4、接着又比较 child->namecollectionTag ,这个时候相等,则
child = child->xmlChildrenNode;

/**
           1. collectionTag = modules  child->name = modules
           2. collectionTag = mixPorts  child->name = mixPorts
           3. collectionTag = devicePorts  child->name = devicePorts
	*/
        if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {

	     /**
               1. child->xmlChildrenNode = moudle {} /moudle
               2. child->xmlChildrenNode = mixPort {} /mixPort
               3. child->xmlChildrenNode = devicePort {} /devicePort
		 */
            child = child->xmlChildrenNode;
        }

因为这个时候 collectionTag = moudles = child->name,所以 这个时候又获取到其子节点进行解析,child = child->xmlChildrenNode = moudle {} /moudle
5、接着又 通过child != NULL建立一个while循环,进行解析 moudle {} /moudle其内部所有子节点
6、接着 child->nametag 比较,跟模板类的 Trait tag值比较,此时相等,则进入模板类的Traitdeserialize进行解析其子模块,
7、循环遍历 child 中所有的 child = child->next;child->nametag相等的模块,并且添加到 模板类的TraitCollection

现在我们总结下这个函数:

1. 首先循环遍历传入的 const _xmlNode * cur中找到 cur->name 与 传入的 模板类TraitcollectionTag 相同的模块,
2. 如果找到则循环遍历 child = cur->xmlChildrenNode; 中找到所有 child ->name 与 传入的
模板类Traittag 相同的模块
3. 如果找到,则将 child 通过 传入的 模板类Traitdeserialize 继续进行明确解析,将解析的数据存入
模板类TraitPtrElement
5. 将所有 找到的 child 添加到 模板类Trait 的集合 Collection

通过上面的分析,我们可以知道 ModuleTraits 用来解析 模块,那现在我们接下看到解析ModuleTraitsdeserialize怎么解析 模块,在回顾到 ModuleTraitsdeserialize源码

/**
root = moudle {} /moudle
module = HwModule
ctx = AudioPolicyConfig*

*/
status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
                                   PtrSerializingCtx ctx)
{

    /**
            1. name= primary  Attributes::name = "name"
	*/
    string name = getXmlAttribute(root, Attributes::name);
    if (name.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
        return BAD_VALUE;
    }
    uint32_t version = AUDIO_DEVICE_API_VERSION_MIN;//AUDIO_DEVICE_API_VERSION_2_0
    /**
        1. versionLiteral = 3.0 Attributes::version = "halVersion"


	*/
    string versionLiteral = getXmlAttribute(root, Attributes::version);//3
    if (!versionLiteral.empty()) {
        uint32_t major, minor;
		/**
                 1.  major = 3  minor = 0

		 */
        sscanf(versionLiteral.c_str(), "%u.%u", &major, &minor);
        version = HARDWARE_DEVICE_API_VERSION(major, minor);
        ALOGV("%s: mHalVersion = %04x major %u minor %u",  __FUNCTION__,
              version, major, minor);
    }

    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());

      /**
          1. Element = HwModule

	  */
    module = new Element(name.c_str(), version);

    // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
    MixPortTraits::Collection mixPorts;
    deserializeCollection(doc, root, mixPorts, NULL);
    module->setProfiles(mixPorts);

    DevicePortTraits::Collection devicePorts;
    deserializeCollection(doc, root, devicePorts, NULL);
    module->setDeclaredDevices(devicePorts);

    RouteTraits::Collection routes;
    deserializeCollection(doc, root, routes, module.get());
    module->setRoutes(routes);

    const xmlNode *children = root->xmlChildrenNode;
    while (children != NULL) {
        if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
            ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
            const xmlNode *child = children->xmlChildrenNode;
            while (child != NULL) {
                if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
                    xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
                    if (attachedDevice != NULL) {
                        ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
                              (const char*)attachedDevice);
                        sp device =
                                module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
                        ctx->addAvailableDevice(device);
                        xmlFree(attachedDevice);
                    }
                }
                child = child->next;
            }
        }
        if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
            xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
            if (defaultOutputDevice != NULL) {
                ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
                      (const char*)defaultOutputDevice);
                sp device =
                        module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
                if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
                    ctx->setDefaultOutputDevice(device);
                    ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
                }
                xmlFree(defaultOutputDevice);
            }
        }
        children = children->next;
    }
    return NO_ERROR;
}

1、首先判断了 {} 中的nameversion字段,有效的话继续解析,判断这里比较简单,就不仔细说了。
2、然后创建了 module 对象,用来封装每一个 {} 的数据,构造函数传入步骤1 的nameversion ,module 类型为 HwModule, 声明位于:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\HwModule.h
源码如下:

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include "DeviceDescriptor.h"
#include "AudioRoute.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

namespace android {

class IOProfile;
class InputProfile;
class OutputProfile;

typedef Vector > InputProfileCollection;
typedef Vector > OutputProfileCollection;
typedef Vector > IOProfileCollection;

class HwModule : public RefBase
{
public:
    HwModule(const char *name, uint32_t halVersion = AUDIO_DEVICE_API_VERSION_MIN);
    ~HwModule();

    const char *getName() const { return mName.string(); }


    const DeviceVector &getDeclaredDevices() const { return mDeclaredDevices; }
    void setDeclaredDevices(const DeviceVector &devices);

    const InputProfileCollection &getInputProfiles() const { return mInputProfiles; }

    const OutputProfileCollection &getOutputProfiles() const { return mOutputProfiles; }

    void setProfiles(const IOProfileCollection &profiles);

    void setHalVersion(uint32_t halVersion) { mHalVersion = halVersion; }
    uint32_t getHalVersion() const { return mHalVersion; }

    sp getRouteSinkDevice(const sp &route) const;
    DeviceVector getRouteSourceDevices(const sp &route) const;
    void setRoutes(const AudioRouteVector &routes);

    status_t addOutputProfile(const sp &profile);
    status_t addInputProfile(const sp &profile);
    status_t addProfile(const sp &profile);

    status_t addOutputProfile(String8 name, const audio_config_t *config,
            audio_devices_t device, String8 address);
    status_t removeOutputProfile(String8 name);
    status_t addInputProfile(String8 name, const audio_config_t *config,
            audio_devices_t device, String8 address);
    status_t removeInputProfile(String8 name);

    audio_module_handle_t getHandle() const { return mHandle; }

    sp findPortByTagName(const String8 &tagName) const
    {
        return mPorts.findByTagName(tagName);
    }

    // TODO remove from here (split serialization)
    void dump(int fd);

    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

private:
    void refreshSupportedDevices();

    uint32_t mHalVersion; // audio HAL API version
    DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
    AudioRouteVector mRoutes;
    AudioPortVector mPorts;
};

class HwModuleCollection : public Vector >
{
public:
    sp getModuleFromName(const char *name) const;

    sp getModuleForDevice(audio_devices_t device) const;

    sp getDeviceDescriptor(const audio_devices_t device,
                                             const char *device_address,
                                             const char *device_name,
                                             bool matchAdress = true) const;

    status_t dump(int fd) const;
};

}; // namespace android

现在我们知道 {} 通过HwModule对象去封装,
HwModule源码我们可以知道 {} 包含

OutputProfileCollection mOutputProfiles; // output profiles exposed by this module
InputProfileCollection mInputProfiles;  // input profiles exposed by this module
DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
AudioRouteVector mRoutes;

3、创建了HwModule 就可以开始解析 {} ,首先解析的是

  // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
    MixPortTraits::Collection mixPorts;
    deserializeCollection(doc, root, mixPorts, NULL);
    module->setProfiles(mixPorts);

也就是对应.xml

{

{
{}
}

}
,通过 MixPortTraits 去解析
MixPortTraits 实现源码如下:

const char *const MixPortTraits::collectionTag = "mixPorts";
const char *const MixPortTraits::tag = "mixPort";

const char MixPortTraits::Attributes::name[] = "name";
const char MixPortTraits::Attributes::role[] = "role";
const char MixPortTraits::Attributes::flags[] = "flags";

/**
child = mixPort {} /mixPort
mixPort = IOProfile
PtrSerializingCtx = void *
*/
status_t MixPortTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, PtrElement &mixPort,
                                    PtrSerializingCtx /*serializingContext*/)
{
    /**
        Attributes::name = "name"; name = "primary output"


	*/
    string name = getXmlAttribute(child, Attributes::name);
    if (name.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
        return BAD_VALUE;
    }
    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());

	/**
          Attributes::role = "role"; role = "source"
	*/
    string role = getXmlAttribute(child, Attributes::role);
    if (role.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
        return BAD_VALUE;
    }
    ALOGV("%s: Role=%s", __FUNCTION__, role.c_str());
    audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;

    /**
        mixPort = IOProfile 

	*/
    mixPort = new Element(String8(name.c_str()), portRole);

    AudioProfileTraits::Collection profiles;
    deserializeCollection(doc, child, profiles, NULL);
    if (profiles.isEmpty()) {
        sp  dynamicProfile = new AudioProfile(gDynamicFormat,
                                                            ChannelsVector(), SampleRateVector());
        dynamicProfile->setDynamicFormat(true);
        dynamicProfile->setDynamicChannels(true);
        dynamicProfile->setDynamicRate(true);
        profiles.add(dynamicProfile);
    }
    mixPort->setAudioProfiles(profiles);

    /**
         Attributes::flags = "flags"; flags = "AUDIO_OUTPUT_FLAG_PRIMARY"
         
	*/
    string flags = getXmlAttribute(child, Attributes::flags);
    if (!flags.empty()) {
        // Source role
        if (portRole == AUDIO_PORT_ROLE_SOURCE) {
            mixPort->setFlags(OutputFlagConverter::maskFromString(flags));
        } else {
            // Sink role
            mixPort->setFlags(InputFlagConverter::maskFromString(flags));
        }
    }
    // Deserialize children
    AudioGainTraits::Collection gains;
    deserializeCollection(doc, child, gains, NULL);
    mixPort->setGains(gains);

    return NO_ERROR;
}

3.1、MixPortTraits首先判断了namerole 的值,这里比较简单,就不细说怎么获取和判断了、
3.2、MixPortTraits 创建了 mixPort 对象,其对象类型为 IOProfile,将nameportRole传入构造函数
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\IOProfile.h
IOProfile 继承自AudioPort,位于
\frameworks\av\services\audiopolicy\common\managerdefinitions\src\AudioPort.h
现在我们可以知道 .{} 通过 IOProfile 继承自AudioPort 去封装
3.3 mixPort 对象创建完之后,便可以开始解析 {}

AudioProfileTraits::Collection profiles;
    deserializeCollection(doc, child, profiles, NULL);
    if (profiles.isEmpty()) {
        sp  dynamicProfile = new AudioProfile(gDynamicFormat,
                                                            ChannelsVector(), SampleRateVector());
        dynamicProfile->setDynamicFormat(true);
        dynamicProfile->setDynamicChannels(true);
        dynamicProfile->setDynamicRate(true);
        profiles.add(dynamicProfile);
    }
    mixPort->setAudioProfiles(profiles);

也就是对应.xml

{

{

{

}

}

}
,通过 AudioProfileTraits 去解析AudioProfileTraits 实现源码如下:

const char *const AudioProfileTraits::collectionTag = "profiles";
const char *const AudioProfileTraits::tag = "profile";

const char AudioProfileTraits::Attributes::name[] = "name";
const char AudioProfileTraits::Attributes::samplingRates[] = "samplingRates";
const char AudioProfileTraits::Attributes::format[] = "format";
const char AudioProfileTraits::Attributes::channelMasks[] = "channelMasks";

/**
root = profile {} /profile
profile = sp
PtrSerializingCtx = void*

2.
root = profile {} /profile
profile = sp
PtrSerializingCtx = void*
*/
status_t AudioProfileTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &profile,
                                         PtrSerializingCtx /*serializingContext*/)
{
    /** 
        Attributes::samplingRates = "samplingRates"; samplingRates = "48000"
        Attributes::format = "format"; format = "AUDIO_FORMAT_PCM_16_BIT"
        Attributes::channelMasks = "channelMasks"; channels = "AUDIO_CHANNEL_OUT_STEREO"

        2.
         Attributes::samplingRates = "samplingRates"; samplingRates = "48000"
        Attributes::format = "format"; format = "AUDIO_FORMAT_PCM_16_BIT"
        Attributes::channelMasks = "channelMasks"; channels = "AUDIO_CHANNEL_IN_MONO"
	*/
    string samplingRates = getXmlAttribute(root, Attributes::samplingRates);
    string format = getXmlAttribute(root, Attributes::format);
    string channels = getXmlAttribute(root, Attributes::channelMasks);

    profile = new Element(formatFromString(format), channelMasksFromString(channels, ","),
                          samplingRatesFromString(samplingRates, ","));

    profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
    profile->setDynamicChannels(profile->getChannels().isEmpty());
    profile->setDynamicRate(profile->getSampleRates().isEmpty());

    return NO_ERROR;
}

通过AudioPort去封装{},又接着通过代码获取flag属性的值

/**
         Attributes::flags = "flags"; flags = "AUDIO_OUTPUT_FLAG_PRIMARY"
         
	*/
    string flags = getXmlAttribute(child, Attributes::flags);
    if (!flags.empty()) {
        // Source role
        if (portRole == AUDIO_PORT_ROLE_SOURCE) {
            mixPort->setFlags(OutputFlagConverter::maskFromString(flags));
        } else {
            // Sink role
            mixPort->setFlags(InputFlagConverter::maskFromString(flags));
        }
    }

最后通过AudioGainTraits解析{}

// Deserialize children
    AudioGainTraits::Collection gains;
    deserializeCollection(doc, child, gains, NULL);
    mixPort->setGains(gains);

AudioGainTraits实现源码如下:

const char *const AudioGainTraits::tag = "gain";
const char *const AudioGainTraits::collectionTag = "gains";

const char AudioGainTraits::Attributes::mode[] = "mode";
const char AudioGainTraits::Attributes::channelMask[] = "channel_mask";
const char AudioGainTraits::Attributes::minValueMB[] = "minValueMB";
const char AudioGainTraits::Attributes::maxValueMB[] = "maxValueMB";
const char AudioGainTraits::Attributes::defaultValueMB[] = "defaultValueMB";
const char AudioGainTraits::Attributes::stepValueMB[] = "stepValueMB";
const char AudioGainTraits::Attributes::minRampMs[] = "minRampMs";
const char AudioGainTraits::Attributes::maxRampMs[] = "maxRampMs";

status_t AudioGainTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &gain,
                                      PtrSerializingCtx /*serializingContext*/)
{
    static uint32_t index = 0;
    gain = new Element(index++, true);

    string mode = getXmlAttribute(root, Attributes::mode);
    if (!mode.empty()) {
        gain->setMode(GainModeConverter::maskFromString(mode));
    }

    string channelsLiteral = getXmlAttribute(root, Attributes::channelMask);
    if (!channelsLiteral.empty()) {
        gain->setChannelMask(channelMaskFromString(channelsLiteral));
    }

    string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
    uint32_t minValueMB;
    if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
        gain->setMinValueInMb(minValueMB);
    }

    string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
    uint32_t maxValueMB;
    if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
        gain->setMaxValueInMb(maxValueMB);
    }

    string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
    uint32_t defaultValueMB;
    if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
        gain->setDefaultValueInMb(defaultValueMB);
    }

    string stepValueMBLiteral = getXmlAttribute(root, Attributes::stepValueMB);
    uint32_t stepValueMB;
    if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
        gain->setStepValueInMb(stepValueMB);
    }

    string minRampMsLiteral = getXmlAttribute(root, Attributes::minRampMs);
    uint32_t minRampMs;
    if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
        gain->setMinRampInMs(minRampMs);
    }

    string maxRampMsLiteral = getXmlAttribute(root, Attributes::maxRampMs);
    uint32_t maxRampMs;
    if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
        gain->setMaxRampInMs(maxRampMs);
    }
    ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __FUNCTION__,
          gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
          gain->getMaxValueInMb());

    if (gain->getMode() == 0) {
        return BAD_VALUE;
    }
    return NO_ERROR;
}

通过 AudioGain去封装{}
位于\frameworks\av\services\audiopolicy\common\managerdefinitions\include\AudioGain.h

到这里就解析完了。

4、接着回到代码ModuleTraits

 DevicePortTraits::Collection devicePorts;
    deserializeCollection(doc, root, devicePorts, NULL);
    module->setDeclaredDevices(devicePorts);

开始解析

{

{}

}
,
通过DevicePortTraits去解析,实现源码如下:

const char *const DevicePortTraits::tag = "devicePort";
const char *const DevicePortTraits::collectionTag = "devicePorts";

const char DevicePortTraits::Attributes::tagName[] = "tagName";
const char DevicePortTraits::Attributes::type[] = "type";
const char DevicePortTraits::Attributes::role[] = "role";
const char DevicePortTraits::Attributes::address[] = "address";
const char DevicePortTraits::Attributes::roleSource[] = "source";

/**
root = devicePort {} /devicePort
deviceDesc = sp
PtrSerializingCtx = void*
*/
status_t DevicePortTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &deviceDesc,
                                       PtrSerializingCtx /*serializingContext*/)
{
   /**
       Attributes::tagName = "tagName"; name = "Earpiece"
   */

    string name = getXmlAttribute(root, Attributes::tagName);
    if (name.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::tagName);
        return BAD_VALUE;
    }
    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::tagName, name.c_str());

	/**
          Attributes::type =  "type" typeName = "AUDIO_DEVICE_OUT_EARPIECE"
	*/
    string typeName = getXmlAttribute(root, Attributes::type);
    if (typeName.empty()) {
        ALOGE("%s: no type for %s", __FUNCTION__, name.c_str());
        return BAD_VALUE;
    }
    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, typeName.c_str());

	/**
          Attributes::role = "role"; role = "sink"
          
	*/
    string role = getXmlAttribute(root, Attributes::role);
    if (role.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
        return BAD_VALUE;
    }
    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::role, role.c_str());
    audio_port_role_t portRole = (role == Attributes::roleSource) ?
                AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
                
    audio_devices_t type = AUDIO_DEVICE_NONE;
    if (!DeviceConverter::fromString(typeName, type) ||
            (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
            (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
        ALOGW("%s: bad type %08x", __FUNCTION__, type);
        return BAD_VALUE;
    }
    deviceDesc = new Element(type, String8(name.c_str()));

      /**
          Attributes::address = "address"; address = ""
	  */
    string address = getXmlAttribute(root, Attributes::address);
    if (!address.empty()) {
        ALOGV("%s: address=%s for %s", __FUNCTION__, address.c_str(), name.c_str());
        deviceDesc->mAddress = String8(address.c_str());
    }

    AudioProfileTraits::Collection profiles;
    deserializeCollection(doc, root, profiles, NULL);
    if (profiles.isEmpty()) {
        sp  dynamicProfile = new AudioProfile(gDynamicFormat,
                                                            ChannelsVector(), SampleRateVector());
        dynamicProfile->setDynamicFormat(true);
        dynamicProfile->setDynamicChannels(true);
        dynamicProfile->setDynamicRate(true);
        profiles.add(dynamicProfile);
    }
    deviceDesc->setAudioProfiles(profiles);

    // Deserialize AudioGain children
    deserializeCollection(doc, root, deviceDesc->mGains, NULL);
    ALOGV("%s: adding device tag %s type %08x address %s", __FUNCTION__,
          deviceDesc->getName().string(), type, deviceDesc->mAddress.string());
    return NO_ERROR;
}

经过前面那么多的介绍,其实会发现每个Traits都是类似的,

  • 都是开始获取当前节点的一些属性值判断,
  • 创建一个特定的父对象,
  • 然后再去获取子节点,通过特定的子对象再封装起来,进行解析。

4.1、DevicePortTraits开始也是获取 tagNametyperole属性的值,
4.2、然后创建了一个deviceDesc对象,类型为 DeviceDescriptor 去封装
DeviceDescriptor 继承自AudioPort,声明位于:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\DeviceDescriptor.h
4.3、获取子节点解析,即

{

{

}

}
,
这里也是跟前面mixPort子节点 一样通过 AudioProfileTraits去解析,这不在累赘
4.4、再获取子节点解析,即

{

{

}

}
,
,这里也是跟前面mixPort子节点 一样通过 AudioGainTraits去解析,这不在累赘.

到这里就解析完了。

5、接着回到代码ModuleTraits

RouteTraits::Collection routes;
    deserializeCollection(doc, root, routes, module.get());
    module->setRoutes(routes);

接着通过 RouteTraits 解析

{

{}

}
, RouteTraits 实现源码如下:

const char *const RouteTraits::tag = "route";
const char *const RouteTraits::collectionTag = "routes";

const char RouteTraits::Attributes::type[] = "type";
const char RouteTraits::Attributes::typeMix[] = "mix";
const char RouteTraits::Attributes::sink[] = "sink";
const char RouteTraits::Attributes::sources[] = "sources";


status_t RouteTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &element,
                                  PtrSerializingCtx ctx)
{
    string type = getXmlAttribute(root, Attributes::type);
    if (type.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::type);
        return BAD_VALUE;
    }
    audio_route_type_t routeType = (type == Attributes::typeMix) ?
                AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;

    ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, type.c_str());
    element = new Element(routeType);

    string sinkAttr = getXmlAttribute(root, Attributes::sink);
    if (sinkAttr.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::sink);
        return BAD_VALUE;
    }
    // Convert Sink name to port pointer
    sp sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
    if (sink == NULL) {
        ALOGE("%s: no sink found with name=%s", __FUNCTION__, sinkAttr.c_str());
        return BAD_VALUE;
    }
    element->setSink(sink);

    string sourcesAttr = getXmlAttribute(root, Attributes::sources);
    if (sourcesAttr.empty()) {
        ALOGE("%s: No %s found", __FUNCTION__, Attributes::sources);
        return BAD_VALUE;
    }
    // Tokenize and Convert Sources name to port pointer
    AudioPortVector sources;
    char *sourcesLiteral = strndup(sourcesAttr.c_str(), strlen(sourcesAttr.c_str()));
    char *devTag = strtok(sourcesLiteral, ",");
    while (devTag != NULL) {
        if (strlen(devTag) != 0) {
            sp source = ctx->findPortByTagName(String8(devTag));
            if (source == NULL) {
                ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
                return BAD_VALUE;
            }
            sources.add(source);
        }
        devTag = strtok(NULL, ",");
    }
    free(sourcesLiteral);

    sink->addRoute(element);
    for (size_t i = 0; i < sources.size(); i++) {
        sp source = sources.itemAt(i);
        source->addRoute(element);
    }
    element->setSources(sources);
    return NO_ERROR;
}

5.1首先获取属性 type 的值,创建 element 对象,其类型为 AudioRoute,在获取属性 sinksources 的值, sources属性的值可以通过,分开有多个, 对象通过 AudioRoute分装起来
AudioRoute 声明位于:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\AudioRoute .h
到这里就解析完了。

6、接着回到代码ModuleTraits

const xmlNode *children = root->xmlChildrenNode;
    while (children != NULL) {
        if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
            ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
            const xmlNode *child = children->xmlChildrenNode;
            while (child != NULL) {
                if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
                    xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
                    if (attachedDevice != NULL) {
                        ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
                              (const char*)attachedDevice);
                        sp device =
                                module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
                        ctx->addAvailableDevice(device);
                        xmlFree(attachedDevice);
                    }
                }
                child = child->next;
            }
        }
        if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
            xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
            if (defaultOutputDevice != NULL) {
                ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
                      (const char*)defaultOutputDevice);
                sp device =
                        module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
                if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
                    ctx->setDefaultOutputDevice(device);
                    ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
                }
                xmlFree(defaultOutputDevice);
            }
        }
        children = children->next;
    }

6.1首先找到 名字为节点,如果找到再去解析字节点 并获取其值,通过
module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice)); 找到其中对用的DeviceDescriptor
6.2找到 名字为节点,并获取其值,通过
module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice)); 找到其中对用的DeviceDescriptor
最后一个完整的 就解析完成了

我们最后接着回到 PolicySerializer 类的解析入口函数

// deserialize volume section
    VolumeTraits::Collection volumes;
    deserializeCollection(doc, cur, volumes, &config);
    config.setVolumes(volumes);

    // Global Configuration
    GlobalConfigTraits::deserialize(cur, config);

最后两个一个是解析音量,一个是全局配置,解析的方式都是跟modules一样,这里就不累赘了,最后我门再跟之前.conf文章中一样,总结一下,

//AudioPolicyConfig


......

//HwModuleCollection--->AudioPolicyConfig.setHwModules(HwModuleCollection);

	
		......
	
		
		/**
			name="primary" 
			halVersion="2.0"
		*/
		// HwModule(name,version )   -->HwModuleCollection.add(HwModule)
        

			......
        
            
            // sp device=HwModule->getDeclaredDevices().getDeviceFromTagName(Earpiece)
            //AudioPolicyConfig->addAvailableDevice(device);
                Earpiece
                ....
            
            
            //sp device=HwModule->getDeclaredDevices().getDeviceFromTagName(Speaker)
            //AudioPolicyConfig->setDefaultOutputDevice(device);
            Speaker
            
            //IOProfileCollection-->HwModule->setProfiles(IOProfileCollection);
            
            /**
				name="primary output"
				 role="source"
				     audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;

			*/
            //IOProfile(name,portRole) extends AudioPort     -->IOProfileCollection.add(IOProfile ); 
                
                 /**
				AudioProfile.setDynamicFormat(format)
				AudioProfile->setDynamicChannels(channelMasks);
				AudioProfile->setDynamicRate(samplingRates);
				*/
                //sp   -->AudioProfileVector.add(AudioProfile);  --> IOProfile ->setAudioProfiles(AudioProfileVector);
                    
                             
                           .....
                           
                
                
                ......
                
            
            
            //DeviceVector   --> HwModule->setDeclaredDevices(DeviceVector)
            
                
                //typeName="AUDIO_DEVICE_OUT_EARPIECE"  role="sink"
                /**
				audio_port_role_t portRole = (role == Attributes::roleSource) ?
                AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
    			audio_devices_t type = AUDIO_DEVICE_NONE;
   			 	if (!DeviceConverter::fromString(typeName, type) ||
           	 		(!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
            		(!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
        				ALOGW("%s: bad type %08x", __FUNCTION__, type);
       					 return BAD_VALUE;
   				 }
				*/
                //DeviceDescriptor(type,name)  extends AudioPort,AudioPortConfig   --> DeviceVector.add(DeviceDescriptor)
                
                /**
				AudioProfile.setDynamicFormat(format)
				AudioProfile->setDynamicChannels(channelMasks);
				AudioProfile->setDynamicRate(samplingRates);
				*/
                //sp   -->AudioProfileVector.add(AudioProfile);  --> DeviceDescriptor  ->setAudioProfiles(profiles);
                   
                            
                            ......
                

				......

           
           
            
            //AudioRouteVector   --> HwModule->setRoutes(AudioRouteVector)
            
            //type="mix"
            //AudioRoute(type)  -->  AudioRouteVector.add(AudioRoute);
            //sink="Earpiece"  --->  sp sink = AudioPolicyConfig->findPortByTagName(sink);
            //sink->addRoute(AudioRoute);  -->   AudioRoute->setSink(AudioPort);
            //sources=""primary output,......"    ->  AudioPortVector.add(sp source = AudioPolicyConfig->findPortByTagName("primary output");)  -->   AudioRoute  ->setSources(AudioPortVector);
                
                       
                       ......
                       
            

			......

        
        
        ......
        


......


你可能感兴趣的:(音频相关,Android系统,Android知识汇总)