Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "APM::Serializer"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include "Serializer.h"
     21 #include <media/convert.h>
     22 #include "TypeConverter.h"
     23 #include <libxml/parser.h>
     24 #include <libxml/xinclude.h>
     25 #include <string>
     26 #include <sstream>
     27 #include <istream>
     28 
     29 using std::string;
     30 
     31 namespace android {
     32 
     33 string getXmlAttribute(const xmlNode *cur, const char *attribute)
     34 {
     35     xmlChar *xmlValue = xmlGetProp(cur, (const xmlChar*)attribute);
     36     if (xmlValue == NULL) {
     37         return "";
     38     }
     39     string value((const char*)xmlValue);
     40     xmlFree(xmlValue);
     41     return value;
     42 }
     43 
     44 using utilities::convertTo;
     45 
     46 const char *const PolicySerializer::rootName = "audioPolicyConfiguration";
     47 const char *const PolicySerializer::versionAttribute = "version";
     48 const uint32_t PolicySerializer::gMajor = 1;
     49 const uint32_t PolicySerializer::gMinor = 0;
     50 static const char *const gReferenceElementName = "reference";
     51 static const char *const gReferenceAttributeName = "name";
     52 
     53 template <class Trait>
     54 static void getReference(const _xmlNode *root, const _xmlNode *&refNode, const string &refName)
     55 {
     56     const _xmlNode *col = root;
     57     while (col != NULL) {
     58         if (!xmlStrcmp(col->name, (const xmlChar *)Trait::collectionTag)) {
     59             const xmlNode *cur = col->children;
     60             while (cur != NULL) {
     61                 if ((!xmlStrcmp(cur->name, (const xmlChar *)gReferenceElementName))) {
     62                     string name = getXmlAttribute(cur, gReferenceAttributeName);
     63                     if (refName == name) {
     64                         refNode = cur;
     65                         return;
     66                     }
     67                 }
     68                 cur = cur->next;
     69             }
     70         }
     71         col = col->next;
     72     }
     73     return;
     74 }
     75 
     76 template <class Trait>
     77 static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
     78                                       typename Trait::Collection &collection,
     79                                       typename Trait::PtrSerializingCtx serializingContext)
     80 {
     81     const xmlNode *root = cur->xmlChildrenNode;
     82     while (root != NULL) {
     83         if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
     84                 xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
     85             root = root->next;
     86             continue;
     87         }
     88         const xmlNode *child = root;
     89         if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
     90             child = child->xmlChildrenNode;
     91         }
     92         while (child != NULL) {
     93             if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
     94                 typename Trait::PtrElement element;
     95                 status_t status = Trait::deserialize(doc, child, element, serializingContext);
     96                 if (status != NO_ERROR) {
     97                     return status;
     98                 }
     99                 if (collection.add(element) < 0) {
    100                     ALOGE("%s: could not add element to %s collection", __FUNCTION__,
    101                           Trait::collectionTag);
    102                 }
    103             }
    104             child = child->next;
    105         }
    106         if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
    107             return NO_ERROR;
    108         }
    109         root = root->next;
    110     }
    111     return NO_ERROR;
    112 }
    113 
    114 const char *const AudioGainTraits::tag = "gain";
    115 const char *const AudioGainTraits::collectionTag = "gains";
    116 
    117 const char AudioGainTraits::Attributes::mode[] = "mode";
    118 const char AudioGainTraits::Attributes::channelMask[] = "channel_mask";
    119 const char AudioGainTraits::Attributes::minValueMB[] = "minValueMB";
    120 const char AudioGainTraits::Attributes::maxValueMB[] = "maxValueMB";
    121 const char AudioGainTraits::Attributes::defaultValueMB[] = "defaultValueMB";
    122 const char AudioGainTraits::Attributes::stepValueMB[] = "stepValueMB";
    123 const char AudioGainTraits::Attributes::minRampMs[] = "minRampMs";
    124 const char AudioGainTraits::Attributes::maxRampMs[] = "maxRampMs";
    125 
    126 status_t AudioGainTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &gain,
    127                                       PtrSerializingCtx /*serializingContext*/)
    128 {
    129     static uint32_t index = 0;
    130     gain = new Element(index++, true);
    131 
    132     string mode = getXmlAttribute(root, Attributes::mode);
    133     if (!mode.empty()) {
    134         gain->setMode(GainModeConverter::maskFromString(mode));
    135     }
    136 
    137     string channelsLiteral = getXmlAttribute(root, Attributes::channelMask);
    138     if (!channelsLiteral.empty()) {
    139         gain->setChannelMask(channelMaskFromString(channelsLiteral));
    140     }
    141 
    142     string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
    143     int32_t minValueMB;
    144     if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
    145         gain->setMinValueInMb(minValueMB);
    146     }
    147 
    148     string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
    149     int32_t maxValueMB;
    150     if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
    151         gain->setMaxValueInMb(maxValueMB);
    152     }
    153 
    154     string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
    155     int32_t defaultValueMB;
    156     if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
    157         gain->setDefaultValueInMb(defaultValueMB);
    158     }
    159 
    160     string stepValueMBLiteral = getXmlAttribute(root, Attributes::stepValueMB);
    161     uint32_t stepValueMB;
    162     if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
    163         gain->setStepValueInMb(stepValueMB);
    164     }
    165 
    166     string minRampMsLiteral = getXmlAttribute(root, Attributes::minRampMs);
    167     uint32_t minRampMs;
    168     if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
    169         gain->setMinRampInMs(minRampMs);
    170     }
    171 
    172     string maxRampMsLiteral = getXmlAttribute(root, Attributes::maxRampMs);
    173     uint32_t maxRampMs;
    174     if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
    175         gain->setMaxRampInMs(maxRampMs);
    176     }
    177     ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __FUNCTION__,
    178           gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
    179           gain->getMaxValueInMb());
    180 
    181     if (gain->getMode() == 0) {
    182         return BAD_VALUE;
    183     }
    184     return NO_ERROR;
    185 }
    186 
    187 const char *const AudioProfileTraits::collectionTag = "profiles";
    188 const char *const AudioProfileTraits::tag = "profile";
    189 
    190 const char AudioProfileTraits::Attributes::name[] = "name";
    191 const char AudioProfileTraits::Attributes::samplingRates[] = "samplingRates";
    192 const char AudioProfileTraits::Attributes::format[] = "format";
    193 const char AudioProfileTraits::Attributes::channelMasks[] = "channelMasks";
    194 
    195 status_t AudioProfileTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &profile,
    196                                          PtrSerializingCtx /*serializingContext*/)
    197 {
    198     string samplingRates = getXmlAttribute(root, Attributes::samplingRates);
    199     string format = getXmlAttribute(root, Attributes::format);
    200     string channels = getXmlAttribute(root, Attributes::channelMasks);
    201 
    202     profile = new Element(formatFromString(format, gDynamicFormat),
    203                           channelMasksFromString(channels, ","),
    204                           samplingRatesFromString(samplingRates, ","));
    205 
    206     profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
    207     profile->setDynamicChannels(profile->getChannels().isEmpty());
    208     profile->setDynamicRate(profile->getSampleRates().isEmpty());
    209 
    210     return NO_ERROR;
    211 }
    212 
    213 
    214 const char *const MixPortTraits::collectionTag = "mixPorts";
    215 const char *const MixPortTraits::tag = "mixPort";
    216 
    217 const char MixPortTraits::Attributes::name[] = "name";
    218 const char MixPortTraits::Attributes::role[] = "role";
    219 const char MixPortTraits::Attributes::flags[] = "flags";
    220 const char MixPortTraits::Attributes::maxOpenCount[] = "maxOpenCount";
    221 const char MixPortTraits::Attributes::maxActiveCount[] = "maxActiveCount";
    222 
    223 status_t MixPortTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, PtrElement &mixPort,
    224                                     PtrSerializingCtx /*serializingContext*/)
    225 {
    226     string name = getXmlAttribute(child, Attributes::name);
    227     if (name.empty()) {
    228         ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
    229         return BAD_VALUE;
    230     }
    231     ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
    232     string role = getXmlAttribute(child, Attributes::role);
    233     if (role.empty()) {
    234         ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
    235         return BAD_VALUE;
    236     }
    237     ALOGV("%s: Role=%s", __FUNCTION__, role.c_str());
    238     audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
    239 
    240     mixPort = new Element(String8(name.c_str()), portRole);
    241 
    242     AudioProfileTraits::Collection profiles;
    243     deserializeCollection<AudioProfileTraits>(doc, child, profiles, NULL);
    244     if (profiles.isEmpty()) {
    245         sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
    246                                                             ChannelsVector(), SampleRateVector());
    247         dynamicProfile->setDynamicFormat(true);
    248         dynamicProfile->setDynamicChannels(true);
    249         dynamicProfile->setDynamicRate(true);
    250         profiles.add(dynamicProfile);
    251     }
    252     mixPort->setAudioProfiles(profiles);
    253 
    254     string flags = getXmlAttribute(child, Attributes::flags);
    255     if (!flags.empty()) {
    256         // Source role
    257         if (portRole == AUDIO_PORT_ROLE_SOURCE) {
    258             mixPort->setFlags(OutputFlagConverter::maskFromString(flags));
    259         } else {
    260             // Sink role
    261             mixPort->setFlags(InputFlagConverter::maskFromString(flags));
    262         }
    263     }
    264     string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
    265     if (!maxOpenCount.empty()) {
    266         convertTo(maxOpenCount, mixPort->maxOpenCount);
    267     }
    268     string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
    269     if (!maxActiveCount.empty()) {
    270         convertTo(maxActiveCount, mixPort->maxActiveCount);
    271     }
    272     // Deserialize children
    273     AudioGainTraits::Collection gains;
    274     deserializeCollection<AudioGainTraits>(doc, child, gains, NULL);
    275     mixPort->setGains(gains);
    276 
    277     return NO_ERROR;
    278 }
    279 
    280 const char *const DevicePortTraits::tag = "devicePort";
    281 const char *const DevicePortTraits::collectionTag = "devicePorts";
    282 
    283 const char DevicePortTraits::Attributes::tagName[] = "tagName";
    284 const char DevicePortTraits::Attributes::type[] = "type";
    285 const char DevicePortTraits::Attributes::role[] = "role";
    286 const char DevicePortTraits::Attributes::address[] = "address";
    287 const char DevicePortTraits::Attributes::roleSource[] = "source";
    288 
    289 status_t DevicePortTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &deviceDesc,
    290                                        PtrSerializingCtx /*serializingContext*/)
    291 {
    292     string name = getXmlAttribute(root, Attributes::tagName);
    293     if (name.empty()) {
    294         ALOGE("%s: No %s found", __FUNCTION__, Attributes::tagName);
    295         return BAD_VALUE;
    296     }
    297     ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::tagName, name.c_str());
    298     string typeName = getXmlAttribute(root, Attributes::type);
    299     if (typeName.empty()) {
    300         ALOGE("%s: no type for %s", __FUNCTION__, name.c_str());
    301         return BAD_VALUE;
    302     }
    303     ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, typeName.c_str());
    304     string role = getXmlAttribute(root, Attributes::role);
    305     if (role.empty()) {
    306         ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
    307         return BAD_VALUE;
    308     }
    309     ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::role, role.c_str());
    310     audio_port_role_t portRole = (role == Attributes::roleSource) ?
    311                 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
    312 
    313     audio_devices_t type = AUDIO_DEVICE_NONE;
    314     if (!deviceFromString(typeName, type) ||
    315             (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
    316             (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
    317         ALOGW("%s: bad type %08x", __FUNCTION__, type);
    318         return BAD_VALUE;
    319     }
    320     deviceDesc = new Element(type, String8(name.c_str()));
    321 
    322     string address = getXmlAttribute(root, Attributes::address);
    323     if (!address.empty()) {
    324         ALOGV("%s: address=%s for %s", __FUNCTION__, address.c_str(), name.c_str());
    325         deviceDesc->mAddress = String8(address.c_str());
    326     }
    327 
    328     AudioProfileTraits::Collection profiles;
    329     deserializeCollection<AudioProfileTraits>(doc, root, profiles, NULL);
    330     if (profiles.isEmpty()) {
    331         sp <AudioProfile> dynamicProfile = new AudioProfile(gDynamicFormat,
    332                                                             ChannelsVector(), SampleRateVector());
    333         dynamicProfile->setDynamicFormat(true);
    334         dynamicProfile->setDynamicChannels(true);
    335         dynamicProfile->setDynamicRate(true);
    336         profiles.add(dynamicProfile);
    337     }
    338     deviceDesc->setAudioProfiles(profiles);
    339 
    340     // Deserialize AudioGain children
    341     deserializeCollection<AudioGainTraits>(doc, root, deviceDesc->mGains, NULL);
    342     ALOGV("%s: adding device tag %s type %08x address %s", __FUNCTION__,
    343           deviceDesc->getName().string(), type, deviceDesc->mAddress.string());
    344     return NO_ERROR;
    345 }
    346 
    347 const char *const RouteTraits::tag = "route";
    348 const char *const RouteTraits::collectionTag = "routes";
    349 
    350 const char RouteTraits::Attributes::type[] = "type";
    351 const char RouteTraits::Attributes::typeMix[] = "mix";
    352 const char RouteTraits::Attributes::sink[] = "sink";
    353 const char RouteTraits::Attributes::sources[] = "sources";
    354 
    355 
    356 status_t RouteTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &element,
    357                                   PtrSerializingCtx ctx)
    358 {
    359     string type = getXmlAttribute(root, Attributes::type);
    360     if (type.empty()) {
    361         ALOGE("%s: No %s found", __FUNCTION__, Attributes::type);
    362         return BAD_VALUE;
    363     }
    364     audio_route_type_t routeType = (type == Attributes::typeMix) ?
    365                 AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
    366 
    367     ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, type.c_str());
    368     element = new Element(routeType);
    369 
    370     string sinkAttr = getXmlAttribute(root, Attributes::sink);
    371     if (sinkAttr.empty()) {
    372         ALOGE("%s: No %s found", __FUNCTION__, Attributes::sink);
    373         return BAD_VALUE;
    374     }
    375     // Convert Sink name to port pointer
    376     sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
    377     if (sink == NULL) {
    378         ALOGE("%s: no sink found with name=%s", __FUNCTION__, sinkAttr.c_str());
    379         return BAD_VALUE;
    380     }
    381     element->setSink(sink);
    382 
    383     string sourcesAttr = getXmlAttribute(root, Attributes::sources);
    384     if (sourcesAttr.empty()) {
    385         ALOGE("%s: No %s found", __FUNCTION__, Attributes::sources);
    386         return BAD_VALUE;
    387     }
    388     // Tokenize and Convert Sources name to port pointer
    389     AudioPortVector sources;
    390     char *sourcesLiteral = strndup(sourcesAttr.c_str(), strlen(sourcesAttr.c_str()));
    391     char *devTag = strtok(sourcesLiteral, ",");
    392     while (devTag != NULL) {
    393         if (strlen(devTag) != 0) {
    394             sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
    395             if (source == NULL) {
    396                 ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
    397                 free(sourcesLiteral);
    398                 return BAD_VALUE;
    399             }
    400             sources.add(source);
    401         }
    402         devTag = strtok(NULL, ",");
    403     }
    404     free(sourcesLiteral);
    405 
    406     sink->addRoute(element);
    407     for (size_t i = 0; i < sources.size(); i++) {
    408         sp<AudioPort> source = sources.itemAt(i);
    409         source->addRoute(element);
    410     }
    411     element->setSources(sources);
    412     return NO_ERROR;
    413 }
    414 
    415 const char *const ModuleTraits::childAttachedDevicesTag = "attachedDevices";
    416 const char *const ModuleTraits::childAttachedDeviceTag = "item";
    417 const char *const ModuleTraits::childDefaultOutputDeviceTag = "defaultOutputDevice";
    418 
    419 const char *const ModuleTraits::tag = "module";
    420 const char *const ModuleTraits::collectionTag = "modules";
    421 
    422 const char ModuleTraits::Attributes::name[] = "name";
    423 const char ModuleTraits::Attributes::version[] = "halVersion";
    424 
    425 status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
    426                                    PtrSerializingCtx ctx)
    427 {
    428     string name = getXmlAttribute(root, Attributes::name);
    429     if (name.empty()) {
    430         ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
    431         return BAD_VALUE;
    432     }
    433     uint32_t versionMajor = 0, versionMinor = 0;
    434     string versionLiteral = getXmlAttribute(root, Attributes::version);
    435     if (!versionLiteral.empty()) {
    436         sscanf(versionLiteral.c_str(), "%u.%u", &versionMajor, &versionMinor);
    437         ALOGV("%s: mHalVersion = major %u minor %u",  __FUNCTION__,
    438               versionMajor, versionMajor);
    439     }
    440 
    441     ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
    442 
    443     module = new Element(name.c_str(), versionMajor, versionMinor);
    444 
    445     // Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
    446     MixPortTraits::Collection mixPorts;
    447     deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
    448     module->setProfiles(mixPorts);
    449 
    450     DevicePortTraits::Collection devicePorts;
    451     deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
    452     module->setDeclaredDevices(devicePorts);
    453 
    454     RouteTraits::Collection routes;
    455     deserializeCollection<RouteTraits>(doc, root, routes, module.get());
    456     module->setRoutes(routes);
    457 
    458     const xmlNode *children = root->xmlChildrenNode;
    459     while (children != NULL) {
    460         if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
    461             ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
    462             const xmlNode *child = children->xmlChildrenNode;
    463             while (child != NULL) {
    464                 if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
    465                     xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
    466                     if (attachedDevice != NULL) {
    467                         ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
    468                               (const char*)attachedDevice);
    469                         sp<DeviceDescriptor> device =
    470                                 module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
    471                         ctx->addAvailableDevice(device);
    472                         xmlFree(attachedDevice);
    473                     }
    474                 }
    475                 child = child->next;
    476             }
    477         }
    478         if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
    479             xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
    480             if (defaultOutputDevice != NULL) {
    481                 ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
    482                       (const char*)defaultOutputDevice);
    483                 sp<DeviceDescriptor> device =
    484                         module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
    485                 if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
    486                     ctx->setDefaultOutputDevice(device);
    487                     ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
    488                 }
    489                 xmlFree(defaultOutputDevice);
    490             }
    491         }
    492         children = children->next;
    493     }
    494     return NO_ERROR;
    495 }
    496 
    497 const char *const GlobalConfigTraits::tag = "globalConfiguration";
    498 
    499 const char GlobalConfigTraits::Attributes::speakerDrcEnabled[] = "speaker_drc_enabled";
    500 
    501 
    502 status_t GlobalConfigTraits::deserialize(const xmlNode *cur, AudioPolicyConfig &config)
    503 {
    504     const xmlNode *root = cur->xmlChildrenNode;
    505     while (root != NULL) {
    506         if (!xmlStrcmp(root->name, (const xmlChar *)tag)) {
    507             string speakerDrcEnabled =
    508                     getXmlAttribute(root, Attributes::speakerDrcEnabled);
    509             bool isSpeakerDrcEnabled;
    510             if (!speakerDrcEnabled.empty() &&
    511                     convertTo<string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
    512                 config.setSpeakerDrcEnabled(isSpeakerDrcEnabled);
    513             }
    514             return NO_ERROR;
    515         }
    516         root = root->next;
    517     }
    518     return NO_ERROR;
    519 }
    520 
    521 
    522 const char *const VolumeTraits::tag = "volume";
    523 const char *const VolumeTraits::collectionTag = "volumes";
    524 const char *const VolumeTraits::volumePointTag = "point";
    525 
    526 const char VolumeTraits::Attributes::stream[] = "stream";
    527 const char VolumeTraits::Attributes::deviceCategory[] = "deviceCategory";
    528 const char VolumeTraits::Attributes::reference[] = "ref";
    529 
    530 status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
    531                                    PtrSerializingCtx /*serializingContext*/)
    532 {
    533     string streamTypeLiteral = getXmlAttribute(root, Attributes::stream);
    534     if (streamTypeLiteral.empty()) {
    535         ALOGE("%s: No %s found", __FUNCTION__, Attributes::stream);
    536         return BAD_VALUE;
    537     }
    538     audio_stream_type_t streamType;
    539     if (!StreamTypeConverter::fromString(streamTypeLiteral, streamType)) {
    540         ALOGE("%s: Invalid %s", __FUNCTION__, Attributes::stream);
    541         return BAD_VALUE;
    542     }
    543     string deviceCategoryLiteral = getXmlAttribute(root, Attributes::deviceCategory);
    544     if (deviceCategoryLiteral.empty()) {
    545         ALOGE("%s: No %s found", __FUNCTION__, Attributes::deviceCategory);
    546         return BAD_VALUE;
    547     }
    548     device_category deviceCategory;
    549     if (!DeviceCategoryConverter::fromString(deviceCategoryLiteral, deviceCategory)) {
    550         ALOGE("%s: Invalid %s=%s", __FUNCTION__, Attributes::deviceCategory,
    551               deviceCategoryLiteral.c_str());
    552         return BAD_VALUE;
    553     }
    554 
    555     string referenceName = getXmlAttribute(root, Attributes::reference);
    556     const _xmlNode *ref = NULL;
    557     if (!referenceName.empty()) {
    558         getReference<VolumeTraits>(root->parent, ref, referenceName);
    559         if (ref == NULL) {
    560             ALOGE("%s: No reference Ptr found for %s", __FUNCTION__, referenceName.c_str());
    561             return BAD_VALUE;
    562         }
    563     }
    564 
    565     element = new Element(deviceCategory, streamType);
    566 
    567     const xmlNode *child = referenceName.empty() ? root->xmlChildrenNode : ref->xmlChildrenNode;
    568     while (child != NULL) {
    569         if (!xmlStrcmp(child->name, (const xmlChar *)volumePointTag)) {
    570             xmlChar *pointDefinition = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);;
    571             if (pointDefinition == NULL) {
    572                 return BAD_VALUE;
    573             }
    574             ALOGV("%s: %s=%s", __FUNCTION__, tag, (const char*)pointDefinition);
    575             Vector<int32_t> point;
    576             collectionFromString<DefaultTraits<int32_t> >((const char*)pointDefinition, point, ",");
    577             if (point.size() != 2) {
    578                 ALOGE("%s: Invalid %s: %s", __FUNCTION__, volumePointTag,
    579                       (const char*)pointDefinition);
    580                 return BAD_VALUE;
    581             }
    582             element->add(CurvePoint(point[0], point[1]));
    583             xmlFree(pointDefinition);
    584         }
    585         child = child->next;
    586     }
    587     return NO_ERROR;
    588 }
    589 
    590 PolicySerializer::PolicySerializer() : mRootElementName(rootName)
    591 {
    592     std::ostringstream oss;
    593     oss << gMajor << "." << gMinor;
    594     mVersion = oss.str();
    595     ALOGV("%s: Version=%s Root=%s", __FUNCTION__, mVersion.c_str(), mRootElementName.c_str());
    596 }
    597 
    598 status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig &config)
    599 {
    600     xmlDocPtr doc;
    601     doc = xmlParseFile(configFile);
    602     if (doc == NULL) {
    603         ALOGE("%s: Could not parse %s document.", __FUNCTION__, configFile);
    604         return BAD_VALUE;
    605     }
    606     xmlNodePtr cur = xmlDocGetRootElement(doc);
    607     if (cur == NULL) {
    608         ALOGE("%s: Could not parse %s document: empty.", __FUNCTION__, configFile);
    609         xmlFreeDoc(doc);
    610         return BAD_VALUE;
    611     }
    612     if (xmlXIncludeProcess(doc) < 0) {
    613          ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __FUNCTION__, configFile);
    614     }
    615 
    616     if (xmlStrcmp(cur->name, (const xmlChar *) mRootElementName.c_str()))  {
    617         ALOGE("%s: No %s root element found in xml data %s.", __FUNCTION__, mRootElementName.c_str(),
    618               (const char *)cur->name);
    619         xmlFreeDoc(doc);
    620         return BAD_VALUE;
    621     }
    622 
    623     string version = getXmlAttribute(cur, versionAttribute);
    624     if (version.empty()) {
    625         ALOGE("%s: No version found in root node %s", __FUNCTION__, mRootElementName.c_str());
    626         return BAD_VALUE;
    627     }
    628     if (version != mVersion) {
    629         ALOGE("%s: Version does not match; expect %s got %s", __FUNCTION__, mVersion.c_str(),
    630               version.c_str());
    631         return BAD_VALUE;
    632     }
    633     // Lets deserialize children
    634     // Modules
    635     ModuleTraits::Collection modules;
    636     deserializeCollection<ModuleTraits>(doc, cur, modules, &config);
    637     config.setHwModules(modules);
    638 
    639     // deserialize volume section
    640     VolumeTraits::Collection volumes;
    641     deserializeCollection<VolumeTraits>(doc, cur, volumes, &config);
    642     config.setVolumes(volumes);
    643 
    644     // Global Configuration
    645     GlobalConfigTraits::deserialize(cur, config);
    646 
    647     xmlFreeDoc(doc);
    648     return android::OK;
    649 }
    650 
    651 } // namespace android
    652