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