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