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 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> 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> 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 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 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 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 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 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 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 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 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 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 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