audio_policy_configuration.xml 解析

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
1
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

å¾ç1
2、找source支持的设备,在xml的<routes>中搜索source name, 所有包含source name的MIX,其sink name共同组成了此source支持的device

å¾ç2
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) {
        ……
    }
--------------------- 
作者:少侠的崛起 
来源:CSDN 
原文:https://blog.csdn.net/u012188065/article/details/84104275 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值