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 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), 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 213 const char *const MixPortTraits::collectionTag = "mixPorts"; 214 const char *const MixPortTraits::tag = "mixPort"; 215 216 const char MixPortTraits::Attributes::name[] = "name"; 217 const char MixPortTraits::Attributes::role[] = "role"; 218 const char MixPortTraits::Attributes::flags[] = "flags"; 219 220 status_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 269 const char *const DevicePortTraits::tag = "devicePort"; 270 const char *const DevicePortTraits::collectionTag = "devicePorts"; 271 272 const char DevicePortTraits::Attributes::tagName[] = "tagName"; 273 const char DevicePortTraits::Attributes::type[] = "type"; 274 const char DevicePortTraits::Attributes::role[] = "role"; 275 const char DevicePortTraits::Attributes::address[] = "address"; 276 const char DevicePortTraits::Attributes::roleSource[] = "source"; 277 278 status_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 336 const char *const RouteTraits::tag = "route"; 337 const char *const RouteTraits::collectionTag = "routes"; 338 339 const char RouteTraits::Attributes::type[] = "type"; 340 const char RouteTraits::Attributes::typeMix[] = "mix"; 341 const char RouteTraits::Attributes::sink[] = "sink"; 342 const char RouteTraits::Attributes::sources[] = "sources"; 343 344 345 status_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 return BAD_VALUE; 387 } 388 sources.add(source); 389 } 390 devTag = strtok(NULL, ","); 391 } 392 free(sourcesLiteral); 393 394 sink->addRoute(element); 395 for (size_t i = 0; i < sources.size(); i++) { 396 sp<AudioPort> source = sources.itemAt(i); 397 source->addRoute(element); 398 } 399 element->setSources(sources); 400 return NO_ERROR; 401 } 402 403 const char *const ModuleTraits::childAttachedDevicesTag = "attachedDevices"; 404 const char *const ModuleTraits::childAttachedDeviceTag = "item"; 405 const char *const ModuleTraits::childDefaultOutputDeviceTag = "defaultOutputDevice"; 406 407 const char *const ModuleTraits::tag = "module"; 408 const char *const ModuleTraits::collectionTag = "modules"; 409 410 const char ModuleTraits::Attributes::name[] = "name"; 411 const char ModuleTraits::Attributes::version[] = "halVersion"; 412 413 status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module, 414 PtrSerializingCtx ctx) 415 { 416 string name = getXmlAttribute(root, Attributes::name); 417 if (name.empty()) { 418 ALOGE("%s: No %s found", __FUNCTION__, Attributes::name); 419 return BAD_VALUE; 420 } 421 uint32_t version = AUDIO_DEVICE_API_VERSION_MIN; 422 string versionLiteral = getXmlAttribute(root, Attributes::version); 423 if (!versionLiteral.empty()) { 424 uint32_t major, minor; 425 sscanf(versionLiteral.c_str(), "%u.%u", &major, &minor); 426 version = HARDWARE_DEVICE_API_VERSION(major, minor); 427 ALOGV("%s: mHalVersion = %04x major %u minor %u", __FUNCTION__, 428 version, major, minor); 429 } 430 431 ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str()); 432 433 module = new Element(name.c_str(), version); 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