1 /* 2 * Copyright (C) 2014 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 "AudioPolicyEffects" 18 //#define LOG_NDEBUG 0 19 20 #include <stdlib.h> 21 #include <stdio.h> 22 #include <string.h> 23 #include <memory> 24 #include <cutils/misc.h> 25 #include <media/AudioEffect.h> 26 #include <media/EffectsConfig.h> 27 #include <system/audio.h> 28 #include <system/audio_effects/audio_effects_conf.h> 29 #include <utils/Vector.h> 30 #include <utils/SortedVector.h> 31 #include <cutils/config_utils.h> 32 #include <binder/IPCThreadState.h> 33 #include "AudioPolicyEffects.h" 34 #include "ServiceUtilities.h" 35 36 namespace android { 37 38 // ---------------------------------------------------------------------------- 39 // AudioPolicyEffects Implementation 40 // ---------------------------------------------------------------------------- 41 42 AudioPolicyEffects::AudioPolicyEffects() 43 { 44 status_t loadResult = loadAudioEffectXmlConfig(); 45 if (loadResult < 0) { 46 ALOGW("Failed to load XML effect configuration, fallback to .conf"); 47 // load automatic audio effect modules 48 if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) { 49 loadAudioEffectConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE); 50 } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) { 51 loadAudioEffectConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE); 52 } 53 } else if (loadResult > 0) { 54 ALOGE("Effect config is partially invalid, skipped %d elements", loadResult); 55 } 56 } 57 58 59 AudioPolicyEffects::~AudioPolicyEffects() 60 { 61 size_t i = 0; 62 // release audio input processing resources 63 for (i = 0; i < mInputSources.size(); i++) { 64 delete mInputSources.valueAt(i); 65 } 66 mInputSources.clear(); 67 68 for (i = 0; i < mInputSessions.size(); i++) { 69 mInputSessions.valueAt(i)->mEffects.clear(); 70 delete mInputSessions.valueAt(i); 71 } 72 mInputSessions.clear(); 73 74 // release audio output processing resources 75 for (i = 0; i < mOutputStreams.size(); i++) { 76 delete mOutputStreams.valueAt(i); 77 } 78 mOutputStreams.clear(); 79 80 for (i = 0; i < mOutputSessions.size(); i++) { 81 mOutputSessions.valueAt(i)->mEffects.clear(); 82 delete mOutputSessions.valueAt(i); 83 } 84 mOutputSessions.clear(); 85 } 86 87 88 status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input, 89 audio_source_t inputSource, 90 audio_session_t audioSession) 91 { 92 status_t status = NO_ERROR; 93 94 // create audio pre processors according to input source 95 audio_source_t aliasSource = (inputSource == AUDIO_SOURCE_HOTWORD) ? 96 AUDIO_SOURCE_VOICE_RECOGNITION : inputSource; 97 98 Mutex::Autolock _l(mLock); 99 ssize_t index = mInputSources.indexOfKey(aliasSource); 100 if (index < 0) { 101 ALOGV("addInputEffects(): no processing needs to be attached to this source"); 102 return status; 103 } 104 ssize_t idx = mInputSessions.indexOfKey(audioSession); 105 EffectVector *sessionDesc; 106 if (idx < 0) { 107 sessionDesc = new EffectVector(audioSession); 108 mInputSessions.add(audioSession, sessionDesc); 109 } else { 110 // EffectVector is existing and we just need to increase ref count 111 sessionDesc = mInputSessions.valueAt(idx); 112 } 113 sessionDesc->mRefCount++; 114 115 ALOGV("addInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount); 116 if (sessionDesc->mRefCount == 1) { 117 int64_t token = IPCThreadState::self()->clearCallingIdentity(); 118 Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects; 119 for (size_t i = 0; i < effects.size(); i++) { 120 EffectDesc *effect = effects[i]; 121 sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, -1, 0, 122 0, audioSession, input); 123 status_t status = fx->initCheck(); 124 if (status != NO_ERROR && status != ALREADY_EXISTS) { 125 ALOGW("addInputEffects(): failed to create Fx %s on source %d", 126 effect->mName, (int32_t)aliasSource); 127 // fx goes out of scope and strong ref on AudioEffect is released 128 continue; 129 } 130 for (size_t j = 0; j < effect->mParams.size(); j++) { 131 fx->setParameter(effect->mParams[j]); 132 } 133 ALOGV("addInputEffects(): added Fx %s on source: %d", 134 effect->mName, (int32_t)aliasSource); 135 sessionDesc->mEffects.add(fx); 136 } 137 sessionDesc->setProcessorEnabled(true); 138 IPCThreadState::self()->restoreCallingIdentity(token); 139 } 140 return status; 141 } 142 143 144 status_t AudioPolicyEffects::releaseInputEffects(audio_io_handle_t input, 145 audio_session_t audioSession) 146 { 147 status_t status = NO_ERROR; 148 149 Mutex::Autolock _l(mLock); 150 ssize_t index = mInputSessions.indexOfKey(audioSession); 151 if (index < 0) { 152 return status; 153 } 154 EffectVector *sessionDesc = mInputSessions.valueAt(index); 155 sessionDesc->mRefCount--; 156 ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount); 157 if (sessionDesc->mRefCount == 0) { 158 sessionDesc->setProcessorEnabled(false); 159 delete sessionDesc; 160 mInputSessions.removeItemsAt(index); 161 ALOGV("releaseInputEffects(): all effects released"); 162 } 163 return status; 164 } 165 166 status_t AudioPolicyEffects::queryDefaultInputEffects(audio_session_t audioSession, 167 effect_descriptor_t *descriptors, 168 uint32_t *count) 169 { 170 status_t status = NO_ERROR; 171 172 Mutex::Autolock _l(mLock); 173 size_t index; 174 for (index = 0; index < mInputSessions.size(); index++) { 175 if (mInputSessions.valueAt(index)->mSessionId == audioSession) { 176 break; 177 } 178 } 179 if (index == mInputSessions.size()) { 180 *count = 0; 181 return BAD_VALUE; 182 } 183 Vector< sp<AudioEffect> > effects = mInputSessions.valueAt(index)->mEffects; 184 185 for (size_t i = 0; i < effects.size(); i++) { 186 effect_descriptor_t desc = effects[i]->descriptor(); 187 if (i < *count) { 188 descriptors[i] = desc; 189 } 190 } 191 if (effects.size() > *count) { 192 status = NO_MEMORY; 193 } 194 *count = effects.size(); 195 return status; 196 } 197 198 199 status_t AudioPolicyEffects::queryDefaultOutputSessionEffects(audio_session_t audioSession, 200 effect_descriptor_t *descriptors, 201 uint32_t *count) 202 { 203 status_t status = NO_ERROR; 204 205 Mutex::Autolock _l(mLock); 206 size_t index; 207 for (index = 0; index < mOutputSessions.size(); index++) { 208 if (mOutputSessions.valueAt(index)->mSessionId == audioSession) { 209 break; 210 } 211 } 212 if (index == mOutputSessions.size()) { 213 *count = 0; 214 return BAD_VALUE; 215 } 216 Vector< sp<AudioEffect> > effects = mOutputSessions.valueAt(index)->mEffects; 217 218 for (size_t i = 0; i < effects.size(); i++) { 219 effect_descriptor_t desc = effects[i]->descriptor(); 220 if (i < *count) { 221 descriptors[i] = desc; 222 } 223 } 224 if (effects.size() > *count) { 225 status = NO_MEMORY; 226 } 227 *count = effects.size(); 228 return status; 229 } 230 231 232 status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, 233 audio_stream_type_t stream, 234 audio_session_t audioSession) 235 { 236 status_t status = NO_ERROR; 237 238 Mutex::Autolock _l(mLock); 239 // create audio processors according to stream 240 // FIXME: should we have specific post processing settings for internal streams? 241 // default to media for now. 242 if (stream >= AUDIO_STREAM_PUBLIC_CNT) { 243 stream = AUDIO_STREAM_MUSIC; 244 } 245 ssize_t index = mOutputStreams.indexOfKey(stream); 246 if (index < 0) { 247 ALOGV("addOutputSessionEffects(): no output processing needed for this stream"); 248 return NO_ERROR; 249 } 250 251 ssize_t idx = mOutputSessions.indexOfKey(audioSession); 252 EffectVector *procDesc; 253 if (idx < 0) { 254 procDesc = new EffectVector(audioSession); 255 mOutputSessions.add(audioSession, procDesc); 256 } else { 257 // EffectVector is existing and we just need to increase ref count 258 procDesc = mOutputSessions.valueAt(idx); 259 } 260 procDesc->mRefCount++; 261 262 ALOGV("addOutputSessionEffects(): session: %d, refCount: %d", 263 audioSession, procDesc->mRefCount); 264 if (procDesc->mRefCount == 1) { 265 // make sure effects are associated to audio server even if we are executing a binder call 266 int64_t token = IPCThreadState::self()->clearCallingIdentity(); 267 Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects; 268 for (size_t i = 0; i < effects.size(); i++) { 269 EffectDesc *effect = effects[i]; 270 sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, 0, 0, 0, 271 audioSession, output); 272 status_t status = fx->initCheck(); 273 if (status != NO_ERROR && status != ALREADY_EXISTS) { 274 ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d", 275 effect->mName, audioSession); 276 // fx goes out of scope and strong ref on AudioEffect is released 277 continue; 278 } 279 ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d", 280 effect->mName, audioSession, (int32_t)stream); 281 procDesc->mEffects.add(fx); 282 } 283 284 procDesc->setProcessorEnabled(true); 285 IPCThreadState::self()->restoreCallingIdentity(token); 286 } 287 return status; 288 } 289 290 status_t AudioPolicyEffects::releaseOutputSessionEffects(audio_io_handle_t output, 291 audio_stream_type_t stream, 292 audio_session_t audioSession) 293 { 294 status_t status = NO_ERROR; 295 (void) output; // argument not used for now 296 (void) stream; // argument not used for now 297 298 Mutex::Autolock _l(mLock); 299 ssize_t index = mOutputSessions.indexOfKey(audioSession); 300 if (index < 0) { 301 ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream"); 302 return NO_ERROR; 303 } 304 305 EffectVector *procDesc = mOutputSessions.valueAt(index); 306 procDesc->mRefCount--; 307 ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d", 308 audioSession, procDesc->mRefCount); 309 if (procDesc->mRefCount == 0) { 310 procDesc->setProcessorEnabled(false); 311 procDesc->mEffects.clear(); 312 delete procDesc; 313 mOutputSessions.removeItemsAt(index); 314 ALOGV("releaseOutputSessionEffects(): output processing released from session: %d", 315 audioSession); 316 } 317 return status; 318 } 319 320 321 void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled) 322 { 323 for (size_t i = 0; i < mEffects.size(); i++) { 324 mEffects.itemAt(i)->setEnabled(enabled); 325 } 326 } 327 328 329 // ---------------------------------------------------------------------------- 330 // Audio processing configuration 331 // ---------------------------------------------------------------------------- 332 333 /*static*/ const char * const AudioPolicyEffects::kInputSourceNames[AUDIO_SOURCE_CNT -1] = { 334 MIC_SRC_TAG, 335 VOICE_UL_SRC_TAG, 336 VOICE_DL_SRC_TAG, 337 VOICE_CALL_SRC_TAG, 338 CAMCORDER_SRC_TAG, 339 VOICE_REC_SRC_TAG, 340 VOICE_COMM_SRC_TAG, 341 UNPROCESSED_SRC_TAG 342 }; 343 344 // returns the audio_source_t enum corresponding to the input source name or 345 // AUDIO_SOURCE_CNT is no match found 346 /*static*/ audio_source_t AudioPolicyEffects::inputSourceNameToEnum(const char *name) 347 { 348 int i; 349 for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) { 350 if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) { 351 ALOGV("inputSourceNameToEnum found source %s %d", name, i); 352 break; 353 } 354 } 355 return (audio_source_t)i; 356 } 357 358 const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_PUBLIC_CNT+1] = { 359 AUDIO_STREAM_DEFAULT_TAG, 360 AUDIO_STREAM_VOICE_CALL_TAG, 361 AUDIO_STREAM_SYSTEM_TAG, 362 AUDIO_STREAM_RING_TAG, 363 AUDIO_STREAM_MUSIC_TAG, 364 AUDIO_STREAM_ALARM_TAG, 365 AUDIO_STREAM_NOTIFICATION_TAG, 366 AUDIO_STREAM_BLUETOOTH_SCO_TAG, 367 AUDIO_STREAM_ENFORCED_AUDIBLE_TAG, 368 AUDIO_STREAM_DTMF_TAG, 369 AUDIO_STREAM_TTS_TAG 370 }; 371 372 // returns the audio_stream_t enum corresponding to the output stream name or 373 // AUDIO_STREAM_PUBLIC_CNT is no match found 374 audio_stream_type_t AudioPolicyEffects::streamNameToEnum(const char *name) 375 { 376 int i; 377 for (i = AUDIO_STREAM_DEFAULT; i < AUDIO_STREAM_PUBLIC_CNT; i++) { 378 if (strcmp(name, kStreamNames[i - AUDIO_STREAM_DEFAULT]) == 0) { 379 ALOGV("streamNameToEnum found stream %s %d", name, i); 380 break; 381 } 382 } 383 return (audio_stream_type_t)i; 384 } 385 386 // ---------------------------------------------------------------------------- 387 // Audio Effect Config parser 388 // ---------------------------------------------------------------------------- 389 390 size_t AudioPolicyEffects::growParamSize(char **param, 391 size_t size, 392 size_t *curSize, 393 size_t *totSize) 394 { 395 // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int) 396 size_t pos = ((*curSize - 1 ) / size + 1) * size; 397 398 if (pos + size > *totSize) { 399 while (pos + size > *totSize) { 400 *totSize += ((*totSize + 7) / 8) * 4; 401 } 402 char *newParam = (char *)realloc(*param, *totSize); 403 if (newParam == NULL) { 404 ALOGE("%s realloc error for size %zu", __func__, *totSize); 405 return 0; 406 } 407 *param = newParam; 408 } 409 *curSize = pos + size; 410 return pos; 411 } 412 413 414 size_t AudioPolicyEffects::readParamValue(cnode *node, 415 char **param, 416 size_t *curSize, 417 size_t *totSize) 418 { 419 size_t len = 0; 420 size_t pos; 421 422 if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) { 423 pos = growParamSize(param, sizeof(short), curSize, totSize); 424 if (pos == 0) { 425 goto exit; 426 } 427 *(short *)(*param + pos) = (short)atoi(node->value); 428 ALOGV("readParamValue() reading short %d", *(short *)(*param + pos)); 429 len = sizeof(short); 430 } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) { 431 pos = growParamSize(param, sizeof(int), curSize, totSize); 432 if (pos == 0) { 433 goto exit; 434 } 435 *(int *)(*param + pos) = atoi(node->value); 436 ALOGV("readParamValue() reading int %d", *(int *)(*param + pos)); 437 len = sizeof(int); 438 } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) { 439 pos = growParamSize(param, sizeof(float), curSize, totSize); 440 if (pos == 0) { 441 goto exit; 442 } 443 *(float *)(*param + pos) = (float)atof(node->value); 444 ALOGV("readParamValue() reading float %f",*(float *)(*param + pos)); 445 len = sizeof(float); 446 } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) { 447 pos = growParamSize(param, sizeof(bool), curSize, totSize); 448 if (pos == 0) { 449 goto exit; 450 } 451 if (strncmp(node->value, "true", strlen("true") + 1) == 0) { 452 *(bool *)(*param + pos) = true; 453 } else { 454 *(bool *)(*param + pos) = false; 455 } 456 ALOGV("readParamValue() reading bool %s", 457 *(bool *)(*param + pos) ? "true" : "false"); 458 len = sizeof(bool); 459 } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) { 460 len = strnlen(node->value, EFFECT_STRING_LEN_MAX); 461 if (*curSize + len + 1 > *totSize) { 462 *totSize = *curSize + len + 1; 463 *param = (char *)realloc(*param, *totSize); 464 if (*param == NULL) { 465 len = 0; 466 ALOGE("%s realloc error for string len %zu", __func__, *totSize); 467 goto exit; 468 } 469 } 470 strncpy(*param + *curSize, node->value, len); 471 *curSize += len; 472 (*param)[*curSize] = '\0'; 473 ALOGV("readParamValue() reading string %s", *param + *curSize - len); 474 } else { 475 ALOGW("readParamValue() unknown param type %s", node->name); 476 } 477 exit: 478 return len; 479 } 480 481 effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root) 482 { 483 cnode *param; 484 cnode *value; 485 size_t curSize = sizeof(effect_param_t); 486 size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int); 487 effect_param_t *fx_param = (effect_param_t *)malloc(totSize); 488 489 if (fx_param == NULL) { 490 ALOGE("%s malloc error for effect structure of size %zu", 491 __func__, totSize); 492 return NULL; 493 } 494 495 param = config_find(root, PARAM_TAG); 496 value = config_find(root, VALUE_TAG); 497 if (param == NULL && value == NULL) { 498 // try to parse simple parameter form {int int} 499 param = root->first_child; 500 if (param != NULL) { 501 // Note: that a pair of random strings is read as 0 0 502 int *ptr = (int *)fx_param->data; 503 #if LOG_NDEBUG == 0 504 int *ptr2 = (int *)((char *)param + sizeof(effect_param_t)); 505 ALOGV("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2); 506 #endif 507 *ptr++ = atoi(param->name); 508 *ptr = atoi(param->value); 509 fx_param->psize = sizeof(int); 510 fx_param->vsize = sizeof(int); 511 return fx_param; 512 } 513 } 514 if (param == NULL || value == NULL) { 515 ALOGW("loadEffectParameter() invalid parameter description %s", 516 root->name); 517 goto error; 518 } 519 520 fx_param->psize = 0; 521 param = param->first_child; 522 while (param) { 523 ALOGV("loadEffectParameter() reading param of type %s", param->name); 524 size_t size = 525 readParamValue(param, (char **)&fx_param, &curSize, &totSize); 526 if (size == 0) { 527 goto error; 528 } 529 fx_param->psize += size; 530 param = param->next; 531 } 532 533 // align start of value field on 32 bit boundary 534 curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int); 535 536 fx_param->vsize = 0; 537 value = value->first_child; 538 while (value) { 539 ALOGV("loadEffectParameter() reading value of type %s", value->name); 540 size_t size = 541 readParamValue(value, (char **)&fx_param, &curSize, &totSize); 542 if (size == 0) { 543 goto error; 544 } 545 fx_param->vsize += size; 546 value = value->next; 547 } 548 549 return fx_param; 550 551 error: 552 free(fx_param); 553 return NULL; 554 } 555 556 void AudioPolicyEffects::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params) 557 { 558 cnode *node = root->first_child; 559 while (node) { 560 ALOGV("loadEffectParameters() loading param %s", node->name); 561 effect_param_t *param = loadEffectParameter(node); 562 if (param != NULL) { 563 params.add(param); 564 } 565 node = node->next; 566 } 567 } 568 569 570 AudioPolicyEffects::EffectDescVector *AudioPolicyEffects::loadEffectConfig( 571 cnode *root, 572 const Vector <EffectDesc *>& effects) 573 { 574 cnode *node = root->first_child; 575 if (node == NULL) { 576 ALOGW("loadInputSource() empty element %s", root->name); 577 return NULL; 578 } 579 EffectDescVector *desc = new EffectDescVector(); 580 while (node) { 581 size_t i; 582 583 for (i = 0; i < effects.size(); i++) { 584 if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) { 585 ALOGV("loadEffectConfig() found effect %s in list", node->name); 586 break; 587 } 588 } 589 if (i == effects.size()) { 590 ALOGV("loadEffectConfig() effect %s not in list", node->name); 591 node = node->next; 592 continue; 593 } 594 EffectDesc *effect = new EffectDesc(*effects[i]); // deep copy 595 loadEffectParameters(node, effect->mParams); 596 ALOGV("loadEffectConfig() adding effect %s uuid %08x", 597 effect->mName, effect->mUuid.timeLow); 598 desc->mEffects.add(effect); 599 node = node->next; 600 } 601 if (desc->mEffects.size() == 0) { 602 ALOGW("loadEffectConfig() no valid effects found in config %s", root->name); 603 delete desc; 604 return NULL; 605 } 606 return desc; 607 } 608 609 status_t AudioPolicyEffects::loadInputEffectConfigurations(cnode *root, 610 const Vector <EffectDesc *>& effects) 611 { 612 cnode *node = config_find(root, PREPROCESSING_TAG); 613 if (node == NULL) { 614 return -ENOENT; 615 } 616 node = node->first_child; 617 while (node) { 618 audio_source_t source = inputSourceNameToEnum(node->name); 619 if (source == AUDIO_SOURCE_CNT) { 620 ALOGW("loadInputSources() invalid input source %s", node->name); 621 node = node->next; 622 continue; 623 } 624 ALOGV("loadInputSources() loading input source %s", node->name); 625 EffectDescVector *desc = loadEffectConfig(node, effects); 626 if (desc == NULL) { 627 node = node->next; 628 continue; 629 } 630 mInputSources.add(source, desc); 631 node = node->next; 632 } 633 return NO_ERROR; 634 } 635 636 status_t AudioPolicyEffects::loadStreamEffectConfigurations(cnode *root, 637 const Vector <EffectDesc *>& effects) 638 { 639 cnode *node = config_find(root, OUTPUT_SESSION_PROCESSING_TAG); 640 if (node == NULL) { 641 return -ENOENT; 642 } 643 node = node->first_child; 644 while (node) { 645 audio_stream_type_t stream = streamNameToEnum(node->name); 646 if (stream == AUDIO_STREAM_PUBLIC_CNT) { 647 ALOGW("loadStreamEffectConfigurations() invalid output stream %s", node->name); 648 node = node->next; 649 continue; 650 } 651 ALOGV("loadStreamEffectConfigurations() loading output stream %s", node->name); 652 EffectDescVector *desc = loadEffectConfig(node, effects); 653 if (desc == NULL) { 654 node = node->next; 655 continue; 656 } 657 mOutputStreams.add(stream, desc); 658 node = node->next; 659 } 660 return NO_ERROR; 661 } 662 663 AudioPolicyEffects::EffectDesc *AudioPolicyEffects::loadEffect(cnode *root) 664 { 665 cnode *node = config_find(root, UUID_TAG); 666 if (node == NULL) { 667 return NULL; 668 } 669 effect_uuid_t uuid; 670 if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) { 671 ALOGW("loadEffect() invalid uuid %s", node->value); 672 return NULL; 673 } 674 return new EffectDesc(root->name, uuid); 675 } 676 677 status_t AudioPolicyEffects::loadEffects(cnode *root, Vector <EffectDesc *>& effects) 678 { 679 cnode *node = config_find(root, EFFECTS_TAG); 680 if (node == NULL) { 681 return -ENOENT; 682 } 683 node = node->first_child; 684 while (node) { 685 ALOGV("loadEffects() loading effect %s", node->name); 686 EffectDesc *effect = loadEffect(node); 687 if (effect == NULL) { 688 node = node->next; 689 continue; 690 } 691 effects.add(effect); 692 node = node->next; 693 } 694 return NO_ERROR; 695 } 696 697 status_t AudioPolicyEffects::loadAudioEffectXmlConfig() { 698 auto result = effectsConfig::parse(); 699 if (result.parsedConfig == nullptr) { 700 return -ENOENT; 701 } 702 703 auto loadProcessingChain = [](auto& processingChain, auto& streams) { 704 for (auto& stream : processingChain) { 705 auto effectDescs = std::make_unique<EffectDescVector>(); 706 for (auto& effect : stream.effects) { 707 effectDescs->mEffects.add( 708 new EffectDesc{effect.get().name.c_str(), effect.get().uuid}); 709 } 710 streams.add(stream.type, effectDescs.release()); 711 } 712 }; 713 loadProcessingChain(result.parsedConfig->preprocess, mInputSources); 714 loadProcessingChain(result.parsedConfig->postprocess, mOutputStreams); 715 // Casting from ssize_t to status_t is probably safe, there should not be more than 2^31 errors 716 return result.nbSkippedElement; 717 } 718 719 status_t AudioPolicyEffects::loadAudioEffectConfig(const char *path) 720 { 721 cnode *root; 722 char *data; 723 724 data = (char *)load_file(path, NULL); 725 if (data == NULL) { 726 return -ENODEV; 727 } 728 root = config_node("", ""); 729 config_load(root, data); 730 731 Vector <EffectDesc *> effects; 732 loadEffects(root, effects); 733 loadInputEffectConfigurations(root, effects); 734 loadStreamEffectConfigurations(root, effects); 735 736 for (size_t i = 0; i < effects.size(); i++) { 737 delete effects[i]; 738 } 739 740 config_free(root); 741 free(root); 742 free(data); 743 744 return NO_ERROR; 745 } 746 747 748 } // namespace android 749