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