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