前言
说 audio_policy_configuration.xml 的解析之前,先熟悉下 audiopolicy 的启动过程,开机时会通过 init.rc 启动 audioservice,audioservice 会启动 AudioPolicyService,而 AudiopolicyService 会创建 AudioPolicyManager,这样 AudioPolicyManager 就被初始化了。感兴趣的可看下这个博客有具体的讲解 https://blog.csdn.net/Qidi_Hu…
正文
回到 AudioPolicyService 的 onFirstRef()函数中有两句代码
mAudioPolicyClient = new AudioPolicyClient(this);
mAudioPolicyManager =createAudioPolicyManager(mAudioPolicyClient);
在 createAudioPolicyManager 函数中会 new AudioPolicyManager(clientInterface)。此刻正式开始了 AudioPolicyManager 的初始化。
我们看下 frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp 的源码
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface): AudioPolicyManager(clientInterface, false /*forTesting*/)
{loadConfig();
initialize();}
void AudioPolicyManager::loadConfig() {
//Android7.0 之后便使用此宏
#ifdef USE_XML_AUDIO_POLICY_CONF
if (deserializeAudioPolicyXmlConfig(getConfig()) != NO_ERROR) {
#else
if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, getConfig()) != NO_ERROR)
&& (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, getConfig()) != NO_ERROR)) {
#endif
ALOGE("could not load audio policy configuration file, setting defaults");
getConfig().setDefault();
}
}
deserializeAudioPolicyXmlConfig 函数的 getConfig()即 AudioPolicyConfig, 函数声明在 AudioPolicyManager.h 文中中
AudioPolicyConfig& getConfig() { return mConfig;}
static status_t deserializeAudioPolicyXmlConfig(AudioPolicyConfig &config) {char audioPolicyXmlConfigFile[AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH];
std::vector<const char*> fileNames;
status_t ret;
if (property_get_bool("ro.bluetooth.a2dp_offload.supported", false) &&
property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
// A2DP offload supported but disabled: try to use special XML file
fileNames.push_back(AUDIO_POLICY_A2DP_OFFLOAD_DISABLED_XML_CONFIG_FILE_NAME);
}
// 文件名 #define AUDIO_POLICY_XML_CONFIG_FILE_NAME "audio_policy_configuration.xml",位于 frameworks/av/services/audiopolicy/config/ 目录下。fileNames.push_back(AUDIO_POLICY_XML_CONFIG_FILE_NAME);
for (const char* fileName : fileNames) {for (int i = 0; i < kConfigLocationListSize; i++) {
PolicySerializer serializer;
snprintf(audioPolicyXmlConfigFile, sizeof(audioPolicyXmlConfigFile),
"%s/%s", kConfigLocationList[i], fileName);
ret = serializer.deserialize(audioPolicyXmlConfigFile, config);
if (ret == NO_ERROR) {return ret;}
}
}
return ret;
}
今天要说的重点就是这个 for 循环了,serializer.deserialize(audioPolicyXmlConfigFile, config)
先看下 PolicySerializer 位于 /frameworks/av/services/audiopolicy/common/managerdefinitions/include/ 目录下
以下举例的所有标签均来自 audio_policy_configuration.x 下对应的第一行标签
status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig &config)
{
xmlDocPtr doc;
doc = xmlParseFile(configFile);
if (doc == NULL) {ALOGE("%s: Could not parse %s document.", __FUNCTION__, configFile);
return BAD_VALUE;
}
xmlNodePtr cur = xmlDocGetRootElement(doc);
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);
}
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;
}
string version = getXmlAttribute(cur, versionAttribute);
if (version.empty()) {ALOGE("%s: No version found in root node %s", __FUNCTION__, mRootElementName.c_str());
return BAD_VALUE;
}
if (version != mVersion) {ALOGE("%s: Version does not match; expect %s got %s", __FUNCTION__, mVersion.c_str(),
version.c_str());
return BAD_VALUE;
}
// 上面都是解析校验 xml 的一些属性标签啥的,此处开始才是正式加载,首先是 module 的加载
// Lets deserialize children
// Modules
ModuleTraits::Collection modules;
deserializeCollection<ModuleTraits>(doc, cur, modules, &config);
config.setHwModules(modules);
// deserialize volume section
VolumeTraits::Collection volumes;
deserializeCollection<VolumeTraits>(doc, cur, volumes, &config);
config.setVolumes(volumes);
// Global Configuration
GlobalConfigTraits::deserialize(cur, config);
xmlFreeDoc(doc);
return android::OK;
}
其中这两行代码便开始了真正的解析
deserializeCollection<ModuleTraits>(doc, cur, modules, &config);
config.setHwModules(modules);
deserializeCollection 是个通用方法
template <class Trait>
static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
typename Trait::Collection &collection,
typename Trait::PtrSerializingCtx serializingContext)
{
const xmlNode *root = cur->xmlChildrenNode;
while (root != NULL) {if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
root = root->next;
continue;
}
const xmlNode *child = root;
if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {child = child->xmlChildrenNode;}
while (child != NULL) {if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
typename Trait::PtrElement element;
status_t status = Trait::deserialize(doc, child, element, serializingContext);
if (status != NO_ERROR) {return status;}
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;
}
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";
status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
PtrSerializingCtx ctx)
{
// 解析 modules 下的 module 标签,我们可以看下 configuration.xml 下 module 的 name 是 primary,当我们如果需要修改时记得 module 标签里的 name 一定不能为空
string name = getXmlAttribute(root, Attributes::name);
if (name.empty()) {ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
return BAD_VALUE;
}
uint32_t versionMajor = 0, versionMinor = 0;
string versionLiteral = getXmlAttribute(root, Attributes::version);
if (!versionLiteral.empty()) {sscanf(versionLiteral.c_str(), "%u.%u", &versionMajor, &versionMinor);
ALOGV("%s: mHalVersion = major %u minor %u", __FUNCTION__,
versionMajor, versionMajor);
}
ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
// 可以看下 Serializer.h 里关于 ModuleTraits 的结构体定义 typedef HwModule Element;
// 因此这 new 了一个 Hwmodule,我们先简单看一下 Hwmodule 的代码,位于 frameworks/av/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
HwModule::HwModule(const char *name, uint32_t halVersionMajor, uint32_t halVersionMinor)
: mName(String8(name)),
mHandle(AUDIO_MODULE_HANDLE_NONE)
{setHalVersion(halVersionMajor, halVersionMinor);
}
// 其实就是把 <module name="primary" halVersion="3.0"> 里的 name 和 halVersion 解析并初始化给了 HwModule
module = new Element(name.c_str(), versionMajor, versionMinor);
// Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
MixPortTraits::Collection mixPorts;
// 我们可以看到 module 下有 <mixPorts> <devicePorts> <routes> 标签,其实也是按着这个顺序解析及的。到这里多少明白了一些 audio_policy_configuration.xml 的解析,那么解析完的数据又
// 是如何初始化的呢,我继续往下看
// 开始解析 <mixPorts> 标签下东西
deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
// 我们继续看下 mixPoritraits
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";
const char MixPortTraits::Attributes::maxOpenCount[] = "maxOpenCount";
const char MixPortTraits::Attributes::maxActiveCount[] = "maxActiveCount";
status_t MixPortTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, PtrElement &mixPort,
PtrSerializingCtx /*serializingContext*/)
{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());
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());
//portRole 分为 sink 和 source sink 可以理解为输入设备比如 mic,source 可以理解为输出设备比如 speaker
audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
// 我们再去头文件里看下发现其实 new 是 IOProfile typedef IOProfile Element; 其实 IOProfile 继承 AudioPort。mixPort = new Element(String8(name.c_str()), portRole);
// 简单看下 IOProfile 的初始化
IOProfile(const String8 &name, audio_port_role_t role)
: AudioPort(name, AUDIO_PORT_TYPE_MIX, role),
maxOpenCount((role == AUDIO_PORT_ROLE_SOURCE) ? 1 : 0),
curOpenCount(0),
maxActiveCount(1),
curActiveCount(0) {}
// 以上把 <mixPort name="primary output" role="source" 中的 name 和 role 解析完并赋值给了 IOProfile。然后继续
AudioProfileTraits::Collection profiles;
deserializeCollection<AudioProfileTraits>(doc, child, profiles, NULL);
// 我们在看下 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";
// 开始解析 <profile name=""format="AUDIO_FORMAT_PCM_16_BIT"samplingRates="48000"channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> 标签下的 samle format 和 chanel
status_t AudioProfileTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &profile,
PtrSerializingCtx /*serializingContext*/)
{string samplingRates = getXmlAttribute(root, Attributes::samplingRates);
string format = getXmlAttribute(root, Attributes::format);
string channels = getXmlAttribute(root, Attributes::channelMasks);
// 再看下头文件的定义 typedef AudioProfile Element 发现 new 的是 AudioProfile, 顺便看下初始化做了什么
// 我们明白了是把 <profile name=""format="AUDIO_FORMAT_PCM_16_BIT"samplingRates="48000"channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> 标签下的 samle format 和 chanel
// 全部赋值给 AudioProfile。AudioProfile(audio_format_t format,
audio_channel_mask_t channelMasks,
uint32_t samplingRate) :
mName(String8("")),
mFormat(format)
{mChannelMasks.add(channelMasks);
mSamplingRates.add(samplingRate);
}
profile = new Element(formatFromString(format, gDynamicFormat),
channelMasksFromString(channels, ","),
samplingRatesFromString(samplingRates, ","));
// 以下 3 个函数调用我们只简单分析一个,逻辑都是一样的
//void setDynamicFormat(bool dynamic) {mIsDynamicFormat = dynamic;}实际就是把 foramte 赋值给我 AudioProfile 下的 mIsDynamicFormat
profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
profile->setDynamicChannels(profile->getChannels().isEmpty());
profile->setDynamicRate(profile->getSampleRates().isEmpty());
return NO_ERROR;
}
// 如果 profiles 是空也会初始化个默认的,也就是每个 <mixPort> 标签下一定要有个 <profile>
if (profiles.isEmpty()) {
sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
ChannelsVector(), SampleRateVector());
dynamicProfile->setDynamicFormat(true);
dynamicProfile->setDynamicChannels(true);
dynamicProfile->setDynamicRate(true);
profiles.add(dynamicProfile);
}
//mixport 即 IOProfile,profiles 即 AudioProfiles,把 AudioProfiles 赋值给了 IOProfile
mixPort->setAudioProfiles(profiles);
string flags = getXmlAttribute(child, Attributes::flags);
// 如果 flag 标签存在,再设置下 flag
if (!flags.empty()) {
// Source role
if (portRole == AUDIO_PORT_ROLE_SOURCE) {mixPort->setFlags(OutputFlagConverter::maskFromString(flags));
} else {
// Sink role
mixPort->setFlags(InputFlagConverter::maskFromString(flags));
}
}
// 下边这俩标签一般都不会使用,解析出来赋给 mixport,一般在使用时如果没有特殊需求,一般使用的都是默认的
string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
if (!maxOpenCount.empty()) {convertTo(maxOpenCount, mixPort->maxOpenCount);
}
string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
if (!maxActiveCount.empty()) {convertTo(maxActiveCount, mixPort->maxActiveCount);
}
// Deserialize children
// 解析 <profile> 下的 <gain> 这个在 mixporit 下通常也是没有的
AudioGainTraits::Collection gains;
deserializeCollection<AudioGainTraits>(doc, child, gains, NULL);
mixPort->setGains(gains);
return NO_ERROR;
}
//moudle 即 HwModule,将解析的 mixPorts(IOProfiles)存储给 module 的 setProfiles,到此 <MixPort> 标签里的内容就全部解析完了
module->setProfiles(mixPorts);
// 说下 setProfiles 这个函数
void HwModule::setProfiles(const IOProfileCollection &profiles)
{for (size_t i = 0; i < profiles.size(); i++) {addProfile(profiles[i]);
}
}
// 调用了 addprofile
status_t HwModule::addProfile(const sp<IOProfile> &profile)
{switch (profile->getRole()) {
case AUDIO_PORT_ROLE_SOURCE:
return addOutputProfile(profile);
case AUDIO_PORT_ROLE_SINK:
return addInputProfile(profile);
case AUDIO_PORT_ROLE_NONE:
return BAD_VALUE;
}
return BAD_VALUE;
}
// 又调用了 addOutputProfile 和 addInputProfile,其实这俩函数最终就是赋值 mInputProfiles 和 mOutputProfiles 这俩集合。mixport 解析结束
// 解析 <devicePorts> 标签,解析原理都相同就不再细说了,只说下每个标签解析完都做了什么。DevicePortTraits::Collection devicePorts;
// 解析的源码由于篇幅原因我就说下重要部分,这个函数会解析 <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink"> 标签下的各属性
deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
//deserializeCollection<DevicePortTraits> 函数中 会 new DeviceDescriptor 并将解析的 tagName 和 type 赋值下去,这里注意 role 这个属性只是在解析时做的容错,真正对判断这个 device 是 sink
// 还是 source 是通过 audio_is_input_device(type)和 audio_is_output_device(type)判断的
deviceDesc = new Element(type, String8(name.c_str()));
//DeviceDescriptor 继承自 AudioPort 和 AudioPortConfig 简单看下 DeviceDescriptor 的初始化
DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const String8 &tagName) :
AudioPort(String8(""), AUDIO_PORT_TYPE_DEVICE,
audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
AUDIO_PORT_ROLE_SOURCE),
mAddress(""), mTagName(tagName), mDeviceType(type), mId(0)
{if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX || type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) {mAddress = String8("0");
}
}
// 最终解析完 device 标签,同样赋值给 hwModule,module->setDeclaredDevices(devicePorts);
// 在这个 set 函数中将解析的 devices 分别赋值给了 mDeclaredDevices 和 mPorts,其中 mDeclaredDevices 是 DeviceDescriptor 的集合 mPorts 是 AudioPort 的集合
void HwModule::setDeclaredDevices(const DeviceVector &devices)
{
mDeclaredDevices = devices;
for (size_t i = 0; i < devices.size(); i++) {mPorts.add(devices[i]);
}
}
// 解析 <routes> 标签,要看到希望了哈,route 很重要主要把 source 和 sink 连接起来
RouteTraits::Collection routes;
deserializeCollection<RouteTraits>(doc, root, routes, module.get());
// 我们来看下解析的源码
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;
}
// 首先看 <route type="mix" 下的 type 属性,一般都是 mix
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());
// new AudioRoute 并将 routeType 传递下来
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
//ctx 就是解析的 HwModule,findPortByTagName 是找到 module 下的 mixport(IOProfile),根据 mixprot 标签 name 找的
sp<AudioPort> 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;
}
// 找到 sink 属性,将 sink 值即 Earpiece 赋值给 AudioRoute 的 setSink 标签 <route type="mix" sink="Earpiece"
element->setSink(sink);
// 解析 sources 属性 <route type="mix" sink="Earpiece"sources="primary output,deep_buffer,BT SCO Headset Mic"/> 我们发现 sources 下有好多因此我们用循环来处理
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) {
// 还记得之前解析的 mixport 实际是 IOProfile,而 IOProfile 继承自 AudioPort,因此这里找的便是之前的 mixport。sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
if (source == NULL) {ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
free(sourcesLiteral);
return BAD_VALUE;
}
sources.add(source);
}
devTag = strtok(NULL, ",");
}
free(sourcesLiteral);
// 将 audioroute 赋值到 audioport 中
sink->addRoute(element);
for (size_t i = 0; i < sources.size(); i++) {sp<AudioPort> source = sources.itemAt(i);
source->addRoute(element);
}
//audioroute 的 setSources
element->setSources(sources);
return NO_ERROR;
}
// 说下 setRoutes 这个函数
module->setRoutes(routes);
// 我们看下 HwModule.cpp 中的实现
void HwModule::setRoutes(const AudioRouteVector &routes)
{
mRoutes = routes;
// Now updating the streams (aka IOProfile until now) supported devices
refreshSupportedDevices();}
// 继续看 refreshSupportedDevices 这个函数
void HwModule::refreshSupportedDevices()
{// Now updating the streams (aka IOProfile until now) supported devices
//mInputProfiles 就是我们解析 mixport 时 setProfiles 时赋值的,因此先遍历所有的 mInputProfiles
for (const auto& stream : mInputProfiles) {
DeviceVector sourceDevices;
// 解析 route 标签时 sink->addRoute(element); 已添加过,这里开始遍历这个 mInputProfile 下的所有 route
for (const auto& route : stream->getRoutes()) {//route->getSink()也是解析 route 标签时 element->setSink(sink)下来的,判断这个 sinkmInputProfiles 中是否同一个,如果相等继续
sp<AudioPort> sink = route->getSink();
if (sink == 0 || stream != sink) {ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
continue;
}
// 先说下 getRouteSourceDevices 函数,找 route 下的 source 标签下的 device,如果是 source 即输出设备,就存入 sourceDevices 集合
DeviceVector HwModule::getRouteSourceDevices(const sp<AudioRoute> &route) const
{
//DeviceVector : public SortedVector<sp<DeviceDescriptor> >
DeviceVector sourceDevices;
for (const auto& source : route->getSources()) {if (source->getType() == AUDIO_PORT_TYPE_DEVICE) {sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(source->getTagName()));
}
}
return sourceDevices;
}
// 继续看 sourceDevicesForRoute 我们知道是 route 标签 source 属性里所有输出 device
DeviceVector sourceDevicesForRoute = getRouteSourceDevices(route);
if (sourceDevicesForRoute.isEmpty()) {ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
continue;
}
sourceDevices.add(sourceDevicesForRoute);
}
if (sourceDevices.isEmpty()) {ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
continue;
}
// 将这些输出 devices 关联到 inputProfile 上,作为 inputProfile 的支持 devices
stream->setSupportedDevices(sourceDevices);
}
// 同理遍历 mOutputProfiles,找到 mOutputProfiles 里和 routes 里匹配的 mOutputProfile 对应的 route,将 route 里 sink 标签里是输入的 devices,作为 mOutputProfile 支持的输入 device
for (const auto& stream : mOutputProfiles) {
DeviceVector sinkDevices;
for (const auto& route : stream->getRoutes()) {sp<AudioPort> source = route->getSources().findByTagName(stream->getTagName());
if (source == 0 || stream != source) {ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
continue;
}
sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(route);
if (sinkDevice == 0) {ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
continue;
}
sinkDevices.add(sinkDevice);
}
stream->setSupportedDevices(sinkDevices);
}
}
// 到此还未结束,回到 module 标签的开始会发现 <attachedDevices> 和 <defaultOutputDevice> 标签还未解析,继续
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);
// 解析 <attachedDevices> 标签找到和 device 标签下 name 相同的 DeviceDescriptor
sp<DeviceDescriptor> device =
module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
//ctx 即 audioPolicyConfig
ctx->addAvailableDevice(device);
// 看下 addAvailableDevice 这个函数,将 <attachedDevices> 标签里的 device 分到 mAvailableOutputDevices 和 mAvailableInputDevices 中
void addAvailableDevice(const sp<DeviceDescriptor> &availableDevice)
{if (audio_is_output_device(availableDevice->type())) {mAvailableOutputDevices.add(availableDevice);
} else if (audio_is_input_device(availableDevice->type())) {mAvailableInputDevices.add(availableDevice);
}
}
xmlFree(attachedDevice);
}
}
child = child->next;
}
}
// 同理解析 <defaultOutputDevice> 后通过 AudioPolicyConfig 设置下默认的输出设备即 mDefaultOutputDevices
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<DeviceDescriptor> 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;
}
最终解析完的所有 module,config.setHwModules(modules)设置下去。到此基本就差不多了,剩下以下的的原理一样就不说了。
// deserialize volume section
deserializeCollection<VolumeTraits>(doc, cur, volumes, &config);
//// Global Configuration
GlobalConfigTraits::deserialize(cur, config);
总结
整个 xml 文件就解析完成了,下一章结合具体的 audio_policy_configuration.xml 在说下解析过程,如果有任何问题欢迎沟通指正。