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