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