android的audioserver 进程启动时,会创建AudioPolicyManager,
洋洋洒洒数千行的其构造函数,第一步就是加载配置相关的xml。
#define AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH 128
#define AUDIO_POLICY_XML_CONFIG_FILE_NAME "audio_policy_configuration.xml"
……
// Treblized audio policy xml config will be located in /odm/etc or /vendor/etc.
static const char *kConfigLocationList[] =
{"/odm/etc", "/vendor/etc/audio", "/vendor/etc", "/system/etc"};
static const int kConfigLocationListSize =
(sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
static status_t deserializeAudioPolicyXmlConfig(AudioPolicyConfig &config) {
char audioPolicyXmlConfigFile[AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH];
status_t ret;
for (int i = 0; i < kConfigLocationListSize; i++) {
PolicySerializer serializer;
snprintf(audioPolicyXmlConfigFile,
sizeof(audioPolicyXmlConfigFile),
"%s/%s",
kConfigLocationList[i],
AUDIO_POLICY_XML_CONFIG_FILE_NAME);
ret = serializer.deserialize(audioPolicyXmlConfigFile, config);
if (ret == NO_ERROR) {
break;
}
}
return ret;
}
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
:
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mA2dpSuspended(false),
mAudioPortGeneration(1),
mBeaconMuteRefCount(0),
mBeaconPlayingRefCount(0),
mBeaconMuted(false),
mTtsOutputAvailable(false),
mMasterMono(false),
mMusicEffectOutput(AUDIO_IO_HANDLE_NONE),
mTonePlayingCount(0),
mPCMode(MODE_DISCONNECT),
mUseA2dpHal(false),
mHasComputedSoundTriggerSupportsConcurrentCapture(false)
{
mUidCached = getuid();
mpClientInterface = clientInterface;
// TODO: remove when legacy conf file is removed. true on devices that use DRC on the
// DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
// Note: remove also speaker_drc_enabled from global configuration of XML config file.
bool speakerDrcEnabled = false;
AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
mDefaultOutputDevice, speakerDrcEnabled,
static_cast<VolumeCurvesCollection *>(mVolumeCurves));
if (deserializeAudioPolicyXmlConfig(config) != NO_ERROR) {
ALOGE("could not load audio policy configuration file, setting defaults");
config.setDefault();
}
从中可以看出,依次从如下路径查找
“/odm/etc”, “/vendor/etc/audio”, “/vendor/etc”, “/system/etc”
查找audio_policy_configuration.xml,找到后便调用Serializer.cpp中的PolicySerializer::deserialize函数,
去解析xml文件的各个模块.
xml的层级入如下:
1、xml中 包含<modules>和其他模块, 每个<modules>包含了多个 <module> 成员,每个 <module>都是一个 audio hal(对应代码中的HwModule类)。
2、每个<module>中又包含了多个层级, 从PolicySerializer::deserialize函数可以看出,android先解析module, 再解析其他模块,我们着重分析 module 模块的解析过程。
1.解析xml的相关代码
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;
}
// 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;
}
从中可以看出,android依次解析<modules>模块, <volumes> 模块以及其他全局配置的模块。
接下来主要分析<modules>模块的解析过程。
2、解析 <modules> 相关代码
2.1 通用模板函数
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;
}
从中可以看出,解析模块时,先调用一个模板函数 deserializeCollection,从代码中可以看出,依次解析每个子元素<module>时,会依次调用对应 ModuleTraits::deserialize 函数,并add到集合中,最终返回时设置给AudioPolicyConfig &config。
2.2 module解析函数
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)
{
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());
module = new Element(name.c_str(), versionMajor, versionMinor);
// Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
MixPortTraits::Collection mixPorts;
deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
module->setProfiles(mixPorts);
DevicePortTraits::Collection devicePorts;
deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
module->setDeclaredDevices(devicePorts);
RouteTraits::Collection routes;
deserializeCollection<RouteTraits>(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<DeviceDescriptor> 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<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时,依次解析 Audio Mix Port (对应 <mixPorts>), Audio Device Ports (Source/Sink)(对应<devicePorts>), Audio Routes(对应<routes>)。
2.2.1 解析 <mixPorts> 模块
<mixPorts> 中包含了大量的<mixPort>(对应代码中AudioPort的子类IOProfile), 共有两大类role, 一类是"source", 一类是 “sink”。
"source"类的<mixPort> 共同组成了 HwModule 中的mOutputProfiles, "sink"类的<mixPort> 共同组成了 HwModule 中的mInputProfiles, mOutputProfiles + mInputProfiles 共同组成了 HwModule 中的mPorts。
注意此处我特地列出 mOutputProfiles 和 mInputProfiles,之后会使用,之后会被使用的变量,我也会特地列出。
(见ModuleTraits::deserialize函数中的module->setProfiles(mixPorts); )
status_t HwModule::addOutputProfile(const sp<IOProfile> &profile)
{
profile->attach(this);
mOutputProfiles.add(profile);
mPorts.add(profile);
return NO_ERROR;
}
status_t HwModule::addInputProfile(const sp<IOProfile> &profile)
{
profile->attach(this);
mInputProfiles.add(profile);
mPorts.add(profile);
return NO_ERROR;
}
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;
}
void HwModule::setProfiles(const IOProfileCollection &profiles)
{
for (size_t i = 0; i < profiles.size(); i++) {
addProfile(profiles[i]);
}
}
解析<mixPorts>的代码如下:
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";
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());
audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
mixPort = new Element(String8(name.c_str()), portRole);
AudioProfileTraits::Collection profiles;
deserializeCollection<AudioProfileTraits>(doc, child, profiles, NULL);
if (profiles.isEmpty()) {
sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
ChannelsVector(), SampleRateVector());
dynamicProfile->setDynamicFormat(true);
dynamicProfile->setDynamicChannels(true);
dynamicProfile->setDynamicRate(true);
profiles.add(dynamicProfile);
}
mixPort->setAudioProfiles(profiles);
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<AudioGainTraits>(doc, child, gains, NULL);
mixPort->setGains(gains);
return NO_ERROR;
}
2.2.2 解析 <devicePorts> 模块
<devicePorts>包含了许多<devicePort>(对应代码中AudioPort和AudioPortConfig的子类DeviceDescriptor),共同组成了 HwModule中的 mDeclaredDevices, 里面的各个device成员也会加载到先前HwModule类中的mPort。
见ModuleTraits::deserialize函数中的module->setDeclaredDevices(devicePorts);
void HwModule::setDeclaredDevices(const DeviceVector &devices)
{
mDeclaredDevices = devices;
for (size_t i = 0; i < devices.size(); i++) {
mPorts.add(devices[i]);
}
}
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";
status_t DevicePortTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &deviceDesc,
PtrSerializingCtx /*serializingContext*/)
{
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());
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());
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 (!deviceFromString(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()));
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<AudioProfileTraits>(doc, root, profiles, NULL);
if (profiles.isEmpty()) {
sp <AudioProfile> 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<AudioGainTraits>(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;
}
2.2.3 解析 <routes> 模块
<routes>中包含了许多<route>(对应代码中的AudioRoute类),顾名思义,是通路的意思,其连接port和device的作用. 每个<route>实质上是一个MIX或者MUX, 以MIX为例,一个MIX包含一个sink(即AudioRoute的mSink)和多个source(分别add到AudioRoute的mSurce),此时已经将sink和source建立了简单的关系。 最终为函数ModuleTraits::deserialize中的 module->setRoutes(routes);调用做准备。
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<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;
}
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<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);
sink->addRoute(element);
for (size_t i = 0; i < sources.size(); i++) {
sp<AudioPort> source = sources.itemAt(i);
source->addRoute(element);
}
element->setSources(sources);
return NO_ERROR;
}
2.2.4 调用module->setRoutes(routes)
setRoutes 比较重要,这里单独拿出来分析。
void HwModule::setRoutes(const AudioRouteVector &routes)
{
mRoutes = routes;
// Now updating the streams (aka IOProfile until now) supported devices
refreshSupportedDevices();
}
setRoutes中一方面将<routes>中所有的MIX存放到HwModule中的mRoutes,另一方面会refreshSupportedDevices
void HwModule::refreshSupportedDevices()
{
// Now updating the streams (aka IOProfile until now) supported devices
for (size_t i = 0; i < mInputProfiles.size(); i++) {
sp<IOProfile> stream = mInputProfiles[i];
DeviceVector sourceDevices;
const AudioRouteVector &routes = stream->getRoutes();
for (size_t j = 0; j < routes.size(); j++) {
sp<AudioPort> sink = routes[j]->getSink();
if (sink == 0 || stream != sink) {
ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
continue;
}
DeviceVector sourceDevicesForRoute = getRouteSourceDevices(routes[j]);
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;
}
stream->setSupportedDevices(sourceDevices);
}
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
sp<IOProfile> stream = mOutputProfiles[i];
DeviceVector sinkDevices;
const AudioRouteVector &routes = stream->getRoutes();
for (size_t j = 0; j < routes.size(); j++) {
sp<AudioPort> source = routes[j]->getSources().findByTagName(stream->getTagName());
if (source == 0 || stream != source) {
ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
continue;
}
sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(routes[j]);
if (sinkDevice == 0) {
ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
continue;
}
sinkDevices.add(sinkDevice);
}
stream->setSupportedDevices(sinkDevices);
}
}
分别会遍历mInputProfiles中的sink和mOutputProfiles中的source和sink
1、以sink为例
1.1 根据sink的name,找到 <routes>中name一致的 <route>, 即mix (此处是一一对应的);
1.2 此mix中对应的了多种source, 根据每个source的name, 找到<devicePorts>中, tagName 一致的<devicePort>
1.3 分别<devicePort>将添加到此sink (类型为sp<IOProfile>) 的 mSupportedDevices, 表示此sink支持的sourceDevice设备
1.4 继续遍历下一个sink
最后 setSupportedDevices设置此sink支持的devices
2、以source为例
2.1 根据source的name,找到了 <routes>中的多个 <route>,即包含了此source的 mix;
2.2 找到每一个mix对应的唯一的 sink
2.3 添加到此source (类型为sp<IOProfile>) 的 mSupportedDevices, 表示此source支持的sinkDevices设备
2.4 继续遍历下一个source
最后 setSupportedDevices设置此source支持的devices
简单方法:
1、找sink支持的设备, 在xml的<routes>中搜索sink name,查看MIX后面的sources,已经包含了所有支持的device
2、找source支持的设备,在xml的<routes>中搜索source name, 所有包含source name的MIX,其sink name共同组成了此source支持的device
2.2.5 解析 <attachedDevices>和<defaultOutputDevice> 模块
这两个模块解析代码比较简单,如下(整体代码见先前列出的 ModuleTraits::deserialize函数):
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<DeviceDescriptor> 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<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;
}
<attachedDevices>中获取的设备与<devicePorts>中的设备(mDeclaredDevices)取交集,
获得了当前设备默认支持的输入输出设备集,即 mAvailableOutputDevices, mAvailableInputDevices, 为之后播放各种音乐时,选择特定device做铺垫。
之后再插拔usb耳机或者3.5mm耳机时,底层会有上报事件,及时去更新mAvailableOutputDevices和 mAvailableInputDevices。
<defaultOutputDevice>设置为此HwModule中默认的设备,一般为speaker设备.
最后
至此我们简单分析了audio_policy_configuration.xml的module解析模块,其实只是分析了AudioPolicyManager的几行代码而已。
???????
AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
mDefaultOutputDevice, speakerDrcEnabled,
static_cast<VolumeCurvesCollection *>(mVolumeCurves));
if (deserializeAudioPolicyXmlConfig(config) != NO_ERROR) {
……
}