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