本文基于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
。
与在 .conf
文件中一样,新的 XML 文件
支持定义输出输入流配置文件、可用于播放和捕获的设备以及音频属性的数量和类型。此外,XML
格式还提供以下增强功能:
frameworks/av/services/audiopolicy/config/audio_policy_configuration.xml
中的模板展示了很多已在使用的上述功能。
新的音频政策配置文件是 audio_policy_configuration.xml
,位于 /system/etc
。要查看采用新的 XML 文件
格式的简单音频政策配置,请查看以下示例。
显示音频政策示例
- Speaker
- Earpiece
- Built-In Mic
Speaker
顶层结构中包含与各个音频 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 文件中的音频政策配置信息。所有包含的文件必须遵循上述结构,同时满足以下限制条件:
使用“包含”可避免将标准 Android 开放源代码项目 (AOSP) 音频 HAL 模块配置信息复制到所有音频政策配置文件(这样做容易出错)google为以下音频 HAL 提供了标准音频政策配置 xml 文件:
a2dp_audio_policy_configuration.xml
rsubmix_audio_policy_configuration.xml
usb_audio_policy_configuration.xml
以如下audio_policy_configuration.xml
为例:
- Speaker
- Built-In Mic
- Built-In Back Mic
Speaker
在之前我们已经介绍了的 audio_policy.conf 文章中可以知道,解析音频配置策略文件所处的类文件为 AudioPolicyManager.cpp 构造函数
而本章第一小节说了自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 |
.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 != mVersion
则return 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
函数,源码如下:
/**
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
的collectionTag
与tag
值比较,也就是目前传入的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->next
中 root->name
与 Trait
中的collectionTag
或者tag
相等,此时如果我们这里的ModuleTraits
与我们解析的collectionTag
相等,所以解析到对应.xml
获取到 child=root->next = moudles {} /moudles
就结束这个判断
4、接着又比较 child->name
与 collectionTag
,这个时候相等,则
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->name
与 tag
比较,跟模板类的 Trait tag
值比较,此时相等,则进入模板类的Trait
的deserialize
进行解析其子模块,
7、循环遍历 child
中所有的 child = child->next;
中 child->name
与 tag
相等的模块,并且添加到 模板类的Trait
的Collection
现在我们总结下这个函数:
1. 首先循环遍历传入的 const _xmlNode * cur
中找到 cur->name
与 传入的 模板类Trait
的collectionTag
相同的模块,
2. 如果找到则循环遍历 child = cur->xmlChildrenNode;
中找到所有 child ->name
与 传入的
模板类Trait
的 tag
相同的模块
3. 如果找到,则将 child
通过 传入的 模板类Trait
的 deserialize
继续进行明确解析,将解析的数据存入
模板类Trait
的 PtrElement
5. 将所有 找到的 child
添加到 模板类Trait
的集合 Collection
通过上面的分析,我们可以知道 ModuleTraits
用来解析
模块,那现在我们接下看到解析ModuleTraits
的 deserialize
怎么解析
模块,在回顾到 ModuleTraits
的 deserialize
源码
/**
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、首先判断了
中的name
与version
字段,有效的话继续解析,判断这里比较简单,就不仔细说了。
2、然后创建了 module
对象,用来封装每一个
的数据,构造函数传入步骤1 的name
与version
,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
首先判断了name
和role
的值,这里比较简单,就不细说怎么获取和判断了、
3.2、MixPortTraits
创建了 mixPort
对象,其对象类型为 IOProfile
,将name
和portRole
传入构造函数
\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
开始也是获取 tagName
、type
、role
属性的值,
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
,在获取属性 sink
、sources
的值, 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);
......
......
......
......