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 
getXmlAttribute(const xmlNode * cur,const char * attribute)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>
getReference(const _xmlNode * root,const _xmlNode * & refNode,const string & refName)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>
deserializeCollection(_xmlDoc * doc,const _xmlNode * cur,typename Trait::Collection & collection,typename Trait::PtrSerializingCtx serializingContext)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 
deserialize(_xmlDoc *,const _xmlNode * root,PtrElement & gain,PtrSerializingCtx)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 
deserialize(_xmlDoc *,const _xmlNode * root,PtrElement & profile,PtrSerializingCtx)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 
deserialize(_xmlDoc * doc,const _xmlNode * child,PtrElement & mixPort,PtrSerializingCtx)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 
deserialize(_xmlDoc * doc,const _xmlNode * root,PtrElement & deviceDesc,PtrSerializingCtx)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 
deserialize(_xmlDoc *,const _xmlNode * root,PtrElement & element,PtrSerializingCtx ctx)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 
deserialize(xmlDocPtr doc,const xmlNode * root,PtrElement & module,PtrSerializingCtx ctx)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 
deserialize(const xmlNode * cur,AudioPolicyConfig & config)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 
deserialize(_xmlDoc * doc,const _xmlNode * root,PtrElement & element,PtrSerializingCtx)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 
PolicySerializer()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 
deserialize(const char * configFile,AudioPolicyConfig & config)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