Home | History | Annotate | Download | only in service
      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