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