Home | History | Annotate | Download | only in factory
      1 /*
      2  * Copyright (C) 2010 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 "EffectsFactory"
     18 //#define LOG_NDEBUG 0
     19 
     20 #include "EffectsFactory.h"
     21 
     22 #include <dlfcn.h>
     23 #include <stdlib.h>
     24 #include <string.h>
     25 #include <unistd.h>
     26 
     27 #include <cutils/config_utils.h>
     28 #include <cutils/misc.h>
     29 #include <cutils/properties.h>
     30 #include <log/log.h>
     31 
     32 #include <system/audio_effects/audio_effects_conf.h>
     33 
     34 static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
     35 static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
     36 static list_elem_t *gSkippedEffects; // list of effects skipped because of duplicate uuid
     37 // list of effect_descriptor and list of sub effects : all currently loaded
     38 // It does not contain effects without sub effects.
     39 static list_sub_elem_t *gSubEffectList;
     40 static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList
     41 static uint32_t gNumEffects;         // total number number of effects
     42 static list_elem_t *gCurLib;    // current library in enumeration process
     43 static list_elem_t *gCurEffect; // current effect in enumeration process
     44 static uint32_t gCurEffectIdx;       // current effect index in enumeration process
     45 static lib_entry_t *gCachedLibrary;  // last library accessed by getLibrary()
     46 
     47 static int gInitDone; // true is global initialization has been preformed
     48 static int gCanQueryEffect; // indicates that call to EffectQueryEffect() is valid, i.e. that the list of effects
     49                           // was not modified since last call to EffectQueryNumberEffects()
     50 
     51 static list_elem_t *gLibraryFailedList;  //list of lib_failed_entry_t: libraries failed to load
     52 
     53 /////////////////////////////////////////////////
     54 //      Local functions prototypes
     55 /////////////////////////////////////////////////
     56 
     57 static int init();
     58 static int loadEffectConfigFile(const char *path);
     59 static int loadLibraries(cnode *root);
     60 static int loadLibrary(cnode *root, const char *name);
     61 static int loadEffects(cnode *root);
     62 static int loadEffect(cnode *node);
     63 // To get and add the effect pointed by the passed node to the gSubEffectList
     64 static int addSubEffect(cnode *root);
     65 static lib_entry_t *getLibrary(const char *path);
     66 static void resetEffectEnumeration();
     67 static uint32_t updateNumEffects();
     68 static int findEffect(const effect_uuid_t *type,
     69                const effect_uuid_t *uuid,
     70                lib_entry_t **lib,
     71                effect_descriptor_t **desc);
     72 // To search a subeffect in the gSubEffectList
     73 static int findSubEffect(const effect_uuid_t *uuid,
     74                lib_entry_t **lib,
     75                effect_descriptor_t **desc);
     76 static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent);
     77 static int stringToUuid(const char *str, effect_uuid_t *uuid);
     78 static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen);
     79 
     80 /////////////////////////////////////////////////
     81 //      Effect Control Interface functions
     82 /////////////////////////////////////////////////
     83 
     84 int Effect_Process(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
     85 {
     86     int ret = init();
     87     if (ret < 0) {
     88         return ret;
     89     }
     90     effect_entry_t *fx = (effect_entry_t *)self;
     91     pthread_mutex_lock(&gLibLock);
     92     if (fx->lib == NULL) {
     93         pthread_mutex_unlock(&gLibLock);
     94         return -EPIPE;
     95     }
     96     pthread_mutex_lock(&fx->lib->lock);
     97     pthread_mutex_unlock(&gLibLock);
     98 
     99     ret = (*fx->subItfe)->process(fx->subItfe, inBuffer, outBuffer);
    100     pthread_mutex_unlock(&fx->lib->lock);
    101     return ret;
    102 }
    103 
    104 int Effect_Command(effect_handle_t self,
    105                    uint32_t cmdCode,
    106                    uint32_t cmdSize,
    107                    void *pCmdData,
    108                    uint32_t *replySize,
    109                    void *pReplyData)
    110 {
    111     int ret = init();
    112     if (ret < 0) {
    113         return ret;
    114     }
    115     effect_entry_t *fx = (effect_entry_t *)self;
    116     pthread_mutex_lock(&gLibLock);
    117     if (fx->lib == NULL) {
    118         pthread_mutex_unlock(&gLibLock);
    119         return -EPIPE;
    120     }
    121     pthread_mutex_lock(&fx->lib->lock);
    122     pthread_mutex_unlock(&gLibLock);
    123 
    124     ret = (*fx->subItfe)->command(fx->subItfe, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
    125     pthread_mutex_unlock(&fx->lib->lock);
    126     return ret;
    127 }
    128 
    129 int Effect_GetDescriptor(effect_handle_t self,
    130                          effect_descriptor_t *desc)
    131 {
    132     int ret = init();
    133     if (ret < 0) {
    134         return ret;
    135     }
    136     effect_entry_t *fx = (effect_entry_t *)self;
    137     pthread_mutex_lock(&gLibLock);
    138     if (fx->lib == NULL) {
    139         pthread_mutex_unlock(&gLibLock);
    140         return -EPIPE;
    141     }
    142     pthread_mutex_lock(&fx->lib->lock);
    143     pthread_mutex_unlock(&gLibLock);
    144 
    145     ret = (*fx->subItfe)->get_descriptor(fx->subItfe, desc);
    146     pthread_mutex_unlock(&fx->lib->lock);
    147     return ret;
    148 }
    149 
    150 int Effect_ProcessReverse(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
    151 {
    152     int ret = init();
    153     if (ret < 0) {
    154         return ret;
    155     }
    156     effect_entry_t *fx = (effect_entry_t *)self;
    157     pthread_mutex_lock(&gLibLock);
    158     if (fx->lib == NULL) {
    159         pthread_mutex_unlock(&gLibLock);
    160         return -EPIPE;
    161     }
    162     pthread_mutex_lock(&fx->lib->lock);
    163     pthread_mutex_unlock(&gLibLock);
    164 
    165     if ((*fx->subItfe)->process_reverse != NULL) {
    166         ret = (*fx->subItfe)->process_reverse(fx->subItfe, inBuffer, outBuffer);
    167     } else {
    168         ret = -ENOSYS;
    169     }
    170     pthread_mutex_unlock(&fx->lib->lock);
    171     return ret;
    172 }
    173 
    174 
    175 const struct effect_interface_s gInterface = {
    176         Effect_Process,
    177         Effect_Command,
    178         Effect_GetDescriptor,
    179         NULL
    180 };
    181 
    182 const struct effect_interface_s gInterfaceWithReverse = {
    183         Effect_Process,
    184         Effect_Command,
    185         Effect_GetDescriptor,
    186         Effect_ProcessReverse
    187 };
    188 
    189 /////////////////////////////////////////////////
    190 //      Effect Factory Interface functions
    191 /////////////////////////////////////////////////
    192 
    193 int EffectQueryNumberEffects(uint32_t *pNumEffects)
    194 {
    195     int ret = init();
    196     if (ret < 0) {
    197         return ret;
    198     }
    199     if (pNumEffects == NULL) {
    200         return -EINVAL;
    201     }
    202 
    203     pthread_mutex_lock(&gLibLock);
    204     *pNumEffects = gNumEffects;
    205     gCanQueryEffect = 1;
    206     pthread_mutex_unlock(&gLibLock);
    207     ALOGV("EffectQueryNumberEffects(): %d", *pNumEffects);
    208     return ret;
    209 }
    210 
    211 int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
    212 {
    213     int ret = init();
    214     if (ret < 0) {
    215         return ret;
    216     }
    217     if (pDescriptor == NULL ||
    218         index >= gNumEffects) {
    219         return -EINVAL;
    220     }
    221     if (gCanQueryEffect == 0) {
    222         return -ENOSYS;
    223     }
    224 
    225     pthread_mutex_lock(&gLibLock);
    226     ret = -ENOENT;
    227     if (index < gCurEffectIdx) {
    228         resetEffectEnumeration();
    229     }
    230     while (gCurLib) {
    231         if (gCurEffect) {
    232             if (index == gCurEffectIdx) {
    233                 *pDescriptor = *(effect_descriptor_t *)gCurEffect->object;
    234                 ret = 0;
    235                 break;
    236             } else {
    237                 gCurEffect = gCurEffect->next;
    238                 gCurEffectIdx++;
    239             }
    240         } else {
    241             gCurLib = gCurLib->next;
    242             gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
    243         }
    244     }
    245 
    246 #if (LOG_NDEBUG == 0)
    247     char str[512];
    248     dumpEffectDescriptor(pDescriptor, str, sizeof(str), 0 /* indent */);
    249     ALOGV("EffectQueryEffect() desc:%s", str);
    250 #endif
    251     pthread_mutex_unlock(&gLibLock);
    252     return ret;
    253 }
    254 
    255 int EffectGetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor)
    256 {
    257     lib_entry_t *l = NULL;
    258     effect_descriptor_t *d = NULL;
    259 
    260     int ret = init();
    261     if (ret < 0) {
    262         return ret;
    263     }
    264     if (pDescriptor == NULL || uuid == NULL) {
    265         return -EINVAL;
    266     }
    267     pthread_mutex_lock(&gLibLock);
    268     ret = findEffect(NULL, uuid, &l, &d);
    269     if (ret == 0) {
    270         *pDescriptor = *d;
    271     }
    272     pthread_mutex_unlock(&gLibLock);
    273     return ret;
    274 }
    275 
    276 int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle)
    277 {
    278     list_elem_t *e = gLibraryList;
    279     lib_entry_t *l = NULL;
    280     effect_descriptor_t *d = NULL;
    281     effect_handle_t itfe;
    282     effect_entry_t *fx;
    283     int found = 0;
    284     int ret;
    285 
    286     if (uuid == NULL || pHandle == NULL) {
    287         return -EINVAL;
    288     }
    289 
    290     ALOGV("EffectCreate() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
    291             uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
    292             uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2],
    293             uuid->node[3],uuid->node[4],uuid->node[5]);
    294 
    295     ret = init();
    296 
    297     if (ret < 0) {
    298         ALOGW("EffectCreate() init error: %d", ret);
    299         return ret;
    300     }
    301 
    302     pthread_mutex_lock(&gLibLock);
    303 
    304     ret = findEffect(NULL, uuid, &l, &d);
    305     if (ret < 0){
    306         // Sub effects are not associated with the library->effects,
    307         // so, findEffect will fail. Search for the effect in gSubEffectList.
    308         ret = findSubEffect(uuid, &l, &d);
    309         if (ret < 0 ) {
    310             goto exit;
    311         }
    312     }
    313 
    314     // create effect in library
    315     ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
    316     if (ret != 0) {
    317         ALOGW("EffectCreate() library %s: could not create fx %s, error %d", l->name, d->name, ret);
    318         goto exit;
    319     }
    320 
    321     // add entry to effect list
    322     fx = (effect_entry_t *)malloc(sizeof(effect_entry_t));
    323     fx->subItfe = itfe;
    324     if ((*itfe)->process_reverse != NULL) {
    325         fx->itfe = (struct effect_interface_s *)&gInterfaceWithReverse;
    326         ALOGV("EffectCreate() gInterfaceWithReverse");
    327     }   else {
    328         fx->itfe = (struct effect_interface_s *)&gInterface;
    329         ALOGV("EffectCreate() gInterface");
    330     }
    331     fx->lib = l;
    332 
    333     e = (list_elem_t *)malloc(sizeof(list_elem_t));
    334     e->object = fx;
    335     e->next = gEffectList;
    336     gEffectList = e;
    337 
    338     *pHandle = (effect_handle_t)fx;
    339 
    340     ALOGV("EffectCreate() created entry %p with sub itfe %p in library %s", *pHandle, itfe, l->name);
    341 
    342 exit:
    343     pthread_mutex_unlock(&gLibLock);
    344     return ret;
    345 }
    346 
    347 int EffectRelease(effect_handle_t handle)
    348 {
    349     effect_entry_t *fx;
    350     list_elem_t *e1;
    351     list_elem_t *e2;
    352 
    353     int ret = init();
    354     if (ret < 0) {
    355         return ret;
    356     }
    357 
    358     // remove effect from effect list
    359     pthread_mutex_lock(&gLibLock);
    360     e1 = gEffectList;
    361     e2 = NULL;
    362     while (e1) {
    363         if (e1->object == handle) {
    364             if (e2) {
    365                 e2->next = e1->next;
    366             } else {
    367                 gEffectList = e1->next;
    368             }
    369             fx = (effect_entry_t *)e1->object;
    370             free(e1);
    371             break;
    372         }
    373         e2 = e1;
    374         e1 = e1->next;
    375     }
    376     if (e1 == NULL) {
    377         ret = -ENOENT;
    378         goto exit;
    379     }
    380 
    381     // release effect in library
    382     if (fx->lib == NULL) {
    383         ALOGW("EffectRelease() fx %p library already unloaded", handle);
    384     } else {
    385         pthread_mutex_lock(&fx->lib->lock);
    386         fx->lib->desc->release_effect(fx->subItfe);
    387         pthread_mutex_unlock(&fx->lib->lock);
    388     }
    389     free(fx);
    390 
    391 exit:
    392     pthread_mutex_unlock(&gLibLock);
    393     return ret;
    394 }
    395 
    396 int EffectIsNullUuid(const effect_uuid_t *uuid)
    397 {
    398     if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) {
    399         return 0;
    400     }
    401     return 1;
    402 }
    403 
    404 // Function to get the sub effect descriptors of the effect whose uuid
    405 // is pointed by the first argument. It searches the gSubEffectList for the
    406 // matching uuid and then copies the corresponding sub effect descriptors
    407 // to the inout param
    408 int EffectGetSubEffects(const effect_uuid_t *uuid, sub_effect_entry_t **pSube,
    409                         size_t size)
    410 {
    411    ALOGV("EffectGetSubEffects() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X"
    412           "%02X\n",uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
    413           uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2],
    414           uuid->node[3],uuid->node[4],uuid->node[5]);
    415 
    416    // Check if the size of the desc buffer is large enough for 2 subeffects
    417    if ((uuid == NULL) || (pSube == NULL) || (size < 2)) {
    418        ALOGW("NULL pointer or insufficient memory. Cannot query subeffects");
    419        return -EINVAL;
    420    }
    421    int ret = init();
    422    if (ret < 0)
    423       return ret;
    424    list_sub_elem_t *e = gSubEffectList;
    425    sub_effect_entry_t *subeffect;
    426    effect_descriptor_t *d;
    427    int count = 0;
    428    while (e != NULL) {
    429        d = (effect_descriptor_t*)e->object;
    430        if (memcmp(uuid, &d->uuid, sizeof(effect_uuid_t)) == 0) {
    431            ALOGV("EffectGetSubEffects: effect found in the list");
    432            list_elem_t *subefx = e->sub_elem;
    433            while (subefx != NULL) {
    434                subeffect = (sub_effect_entry_t*)subefx->object;
    435                pSube[count++] = subeffect;
    436                subefx = subefx->next;
    437            }
    438            ALOGV("EffectGetSubEffects end - copied the sub effect structures");
    439            return count;
    440        }
    441        e = e->next;
    442    }
    443    return -ENOENT;
    444 }
    445 /////////////////////////////////////////////////
    446 //      Local functions
    447 /////////////////////////////////////////////////
    448 
    449 int init() {
    450     int hdl;
    451 
    452     if (gInitDone) {
    453         return 0;
    454     }
    455 
    456     // ignore effects or not?
    457     const bool ignoreFxConfFiles = property_get_bool(PROPERTY_IGNORE_EFFECTS, false);
    458 
    459     pthread_mutex_init(&gLibLock, NULL);
    460 
    461     if (ignoreFxConfFiles) {
    462         ALOGI("Audio effects in configuration files will be ignored");
    463     } else {
    464         if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
    465             loadEffectConfigFile(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
    466         } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
    467             loadEffectConfigFile(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
    468         }
    469     }
    470 
    471     updateNumEffects();
    472     gInitDone = 1;
    473     ALOGV("init() done");
    474     return 0;
    475 }
    476 
    477 int loadEffectConfigFile(const char *path)
    478 {
    479     cnode *root;
    480     char *data;
    481 
    482     data = load_file(path, NULL);
    483     if (data == NULL) {
    484         return -ENODEV;
    485     }
    486     root = config_node("", "");
    487     config_load(root, data);
    488     loadLibraries(root);
    489     loadEffects(root);
    490     config_free(root);
    491     free(root);
    492     free(data);
    493 
    494     return 0;
    495 }
    496 
    497 int loadLibraries(cnode *root)
    498 {
    499     cnode *node;
    500 
    501     node = config_find(root, LIBRARIES_TAG);
    502     if (node == NULL) {
    503         return -ENOENT;
    504     }
    505     node = node->first_child;
    506     while (node) {
    507         loadLibrary(node, node->name);
    508         node = node->next;
    509     }
    510     return 0;
    511 }
    512 
    513 #ifdef __LP64__
    514 // audio_effects.conf always specifies 32 bit lib path: convert to 64 bit path if needed
    515 static const char *kLibraryPathRoot[] =
    516         {"/odm/lib64/soundfx", "/vendor/lib64/soundfx", "/system/lib64/soundfx"};
    517 #else
    518 static const char *kLibraryPathRoot[] =
    519         {"/odm/lib/soundfx", "/vendor/lib/soundfx", "/system/lib/soundfx"};
    520 #endif
    521 
    522 static const int kLibraryPathRootSize =
    523         (sizeof(kLibraryPathRoot) / sizeof(kLibraryPathRoot[0]));
    524 
    525 // Checks if the library path passed as lib_path_in can be opened and if not
    526 // tries in standard effect library directories with just the library name and returns correct path
    527 // in lib_path_out
    528 int checkLibraryPath(const char *lib_path_in, char *lib_path_out) {
    529     char *str;
    530     const char *lib_name;
    531     size_t len;
    532 
    533     if (lib_path_in == NULL || lib_path_out == NULL) {
    534         return -EINVAL;
    535     }
    536 
    537     strlcpy(lib_path_out, lib_path_in, PATH_MAX);
    538 
    539     // Try exact path first
    540     str = strstr(lib_path_out, "/lib/soundfx/");
    541     if (str == NULL) {
    542         return -EINVAL;
    543     }
    544 
    545     // Extract library name from input path
    546     len = str - lib_path_out;
    547     lib_name = lib_path_in + len + strlen("/lib/soundfx/");
    548 
    549     // Then try with library name and standard path names in order of preference
    550     for (int i = 0; i < kLibraryPathRootSize; i++) {
    551         char path[PATH_MAX];
    552 
    553         snprintf(path,
    554                  PATH_MAX,
    555                  "%s/%s",
    556                  kLibraryPathRoot[i],
    557                  lib_name);
    558         if (F_OK == access(path, 0)) {
    559             strcpy(lib_path_out, path);
    560             ALOGW_IF(strncmp(lib_path_out, lib_path_in, PATH_MAX) != 0,
    561                 "checkLibraryPath() corrected library path %s to %s", lib_path_in, lib_path_out);
    562             return 0;
    563         }
    564     }
    565     return -EINVAL;
    566 }
    567 
    568 
    569 
    570 int loadLibrary(cnode *root, const char *name)
    571 {
    572     cnode *node;
    573     void *hdl = NULL;
    574     audio_effect_library_t *desc;
    575     list_elem_t *e;
    576     lib_entry_t *l;
    577     char path[PATH_MAX];
    578 
    579     node = config_find(root, PATH_TAG);
    580     if (node == NULL) {
    581         return -EINVAL;
    582     }
    583 
    584     if (checkLibraryPath((const char *)node->value, path) != 0) {
    585         ALOGW("loadLibrary() could not find library %s", path);
    586         goto error;
    587     }
    588 
    589     hdl = dlopen(path, RTLD_NOW);
    590     if (hdl == NULL) {
    591         ALOGW("loadLibrary() failed to open %s", path);
    592         goto error;
    593     }
    594 
    595     desc = (audio_effect_library_t *)dlsym(hdl, AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
    596     if (desc == NULL) {
    597         ALOGW("loadLibrary() could not find symbol %s", AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR);
    598         goto error;
    599     }
    600 
    601     if (AUDIO_EFFECT_LIBRARY_TAG != desc->tag) {
    602         ALOGW("getLibrary() bad tag %08x in lib info struct", desc->tag);
    603         goto error;
    604     }
    605 
    606     if (EFFECT_API_VERSION_MAJOR(desc->version) !=
    607             EFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION)) {
    608         ALOGW("loadLibrary() bad lib version %08x", desc->version);
    609         goto error;
    610     }
    611 
    612     // add entry for library in gLibraryList
    613     l = malloc(sizeof(lib_entry_t));
    614     l->name = strndup(name, PATH_MAX);
    615     l->path = strndup(path, PATH_MAX);
    616     l->handle = hdl;
    617     l->desc = desc;
    618     l->effects = NULL;
    619     pthread_mutex_init(&l->lock, NULL);
    620 
    621     e = malloc(sizeof(list_elem_t));
    622     e->object = l;
    623     pthread_mutex_lock(&gLibLock);
    624     e->next = gLibraryList;
    625     gLibraryList = e;
    626     pthread_mutex_unlock(&gLibLock);
    627     ALOGV("getLibrary() linked library %p for path %s", l, path);
    628 
    629     return 0;
    630 
    631 error:
    632     if (hdl != NULL) {
    633         dlclose(hdl);
    634     }
    635     //add entry for library errors in gLibraryFailedList
    636     lib_failed_entry_t *fl = malloc(sizeof(lib_failed_entry_t));
    637     fl->name = strndup(name, PATH_MAX);
    638     fl->path = strndup(path, PATH_MAX);
    639 
    640     list_elem_t *fe = malloc(sizeof(list_elem_t));
    641     fe->object = fl;
    642     fe->next = gLibraryFailedList;
    643     gLibraryFailedList = fe;
    644     ALOGV("getLibrary() linked error in library %p for path %s", fl, path);
    645 
    646     return -EINVAL;
    647 }
    648 
    649 // This will find the library and UUID tags of the sub effect pointed by the
    650 // node, gets the effect descriptor and lib_entry_t and adds the subeffect -
    651 // sub_entry_t to the gSubEffectList
    652 int addSubEffect(cnode *root)
    653 {
    654     ALOGV("addSubEffect");
    655     cnode *node;
    656     effect_uuid_t uuid;
    657     effect_descriptor_t *d;
    658     lib_entry_t *l;
    659     list_elem_t *e;
    660     node = config_find(root, LIBRARY_TAG);
    661     if (node == NULL) {
    662         return -EINVAL;
    663     }
    664     l = getLibrary(node->value);
    665     if (l == NULL) {
    666         ALOGW("addSubEffect() could not get library %s", node->value);
    667         return -EINVAL;
    668     }
    669     node = config_find(root, UUID_TAG);
    670     if (node == NULL) {
    671         return -EINVAL;
    672     }
    673     if (stringToUuid(node->value, &uuid) != 0) {
    674         ALOGW("addSubEffect() invalid uuid %s", node->value);
    675         return -EINVAL;
    676     }
    677     d = malloc(sizeof(effect_descriptor_t));
    678     if (l->desc->get_descriptor(&uuid, d) != 0) {
    679         char s[40];
    680         uuidToString(&uuid, s, 40);
    681         ALOGW("Error querying effect %s on lib %s", s, l->name);
    682         free(d);
    683         return -EINVAL;
    684     }
    685 #if (LOG_NDEBUG==0)
    686     char s[512];
    687     dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */);
    688     ALOGV("addSubEffect() read descriptor %p:%s",d, s);
    689 #endif
    690     if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
    691             EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) {
    692         ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name);
    693         free(d);
    694         return -EINVAL;
    695     }
    696     sub_effect_entry_t *sub_effect = malloc(sizeof(sub_effect_entry_t));
    697     sub_effect->object = d;
    698     // lib_entry_t is stored since the sub effects are not linked to the library
    699     sub_effect->lib = l;
    700     e = malloc(sizeof(list_elem_t));
    701     e->object = sub_effect;
    702     e->next = gSubEffectList->sub_elem;
    703     gSubEffectList->sub_elem = e;
    704     ALOGV("addSubEffect end");
    705     return 0;
    706 }
    707 
    708 int loadEffects(cnode *root)
    709 {
    710     cnode *node;
    711 
    712     node = config_find(root, EFFECTS_TAG);
    713     if (node == NULL) {
    714         return -ENOENT;
    715     }
    716     node = node->first_child;
    717     while (node) {
    718         loadEffect(node);
    719         node = node->next;
    720     }
    721     return 0;
    722 }
    723 
    724 int loadEffect(cnode *root)
    725 {
    726     cnode *node;
    727     effect_uuid_t uuid;
    728     lib_entry_t *l;
    729     effect_descriptor_t *d;
    730     list_elem_t *e;
    731 
    732     node = config_find(root, LIBRARY_TAG);
    733     if (node == NULL) {
    734         return -EINVAL;
    735     }
    736 
    737     l = getLibrary(node->value);
    738     if (l == NULL) {
    739         ALOGW("loadEffect() could not get library %s", node->value);
    740         return -EINVAL;
    741     }
    742 
    743     node = config_find(root, UUID_TAG);
    744     if (node == NULL) {
    745         return -EINVAL;
    746     }
    747     if (stringToUuid(node->value, &uuid) != 0) {
    748         ALOGW("loadEffect() invalid uuid %s", node->value);
    749         return -EINVAL;
    750     }
    751     lib_entry_t *tmp;
    752     bool skip = false;
    753     if (findEffect(NULL, &uuid, &tmp, NULL) == 0) {
    754         ALOGW("skipping duplicate uuid %s %s", node->value,
    755                 node->next ? "and its sub-effects" : "");
    756         skip = true;
    757     }
    758 
    759     d = malloc(sizeof(effect_descriptor_t));
    760     if (l->desc->get_descriptor(&uuid, d) != 0) {
    761         char s[40];
    762         uuidToString(&uuid, s, 40);
    763         ALOGW("Error querying effect %s on lib %s", s, l->name);
    764         free(d);
    765         return -EINVAL;
    766     }
    767 #if (LOG_NDEBUG==0)
    768     char s[512];
    769     dumpEffectDescriptor(d, s, sizeof(s), 0 /* indent */);
    770     ALOGV("loadEffect() read descriptor %p:%s",d, s);
    771 #endif
    772     if (EFFECT_API_VERSION_MAJOR(d->apiVersion) !=
    773             EFFECT_API_VERSION_MAJOR(EFFECT_CONTROL_API_VERSION)) {
    774         ALOGW("Bad API version %08x on lib %s", d->apiVersion, l->name);
    775         free(d);
    776         return -EINVAL;
    777     }
    778     e = malloc(sizeof(list_elem_t));
    779     e->object = d;
    780     if (skip) {
    781         e->next = gSkippedEffects;
    782         gSkippedEffects = e;
    783         return -EINVAL;
    784     } else {
    785         e->next = l->effects;
    786         l->effects = e;
    787     }
    788 
    789     // After the UUID node in the config_tree, if node->next is valid,
    790     // that would be sub effect node.
    791     // Find the sub effects and add them to the gSubEffectList
    792     node = node->next;
    793     int count = 2;
    794     bool hwSubefx = false, swSubefx = false;
    795     list_sub_elem_t *sube = NULL;
    796     if (node != NULL) {
    797         ALOGV("Adding the effect to gEffectSubList as there are sub effects");
    798         sube = malloc(sizeof(list_sub_elem_t));
    799         sube->object = d;
    800         sube->sub_elem = NULL;
    801         sube->next = gSubEffectList;
    802         gSubEffectList = sube;
    803     }
    804     while (node != NULL && count) {
    805        if (addSubEffect(node)) {
    806            ALOGW("loadEffect() could not add subEffect %s", node->value);
    807            // Change the gSubEffectList to point to older list;
    808            gSubEffectList = sube->next;
    809            free(sube->sub_elem);// Free an already added sub effect
    810            sube->sub_elem = NULL;
    811            free(sube);
    812            return -ENOENT;
    813        }
    814        sub_effect_entry_t *subEntry = (sub_effect_entry_t*)gSubEffectList->sub_elem->object;
    815        effect_descriptor_t *subEffectDesc = (effect_descriptor_t*)(subEntry->object);
    816        // Since we return a dummy descriptor for the proxy during
    817        // get_descriptor call,we replace it with the correspoding
    818        // sw effect descriptor, but with Proxy UUID
    819        // check for Sw desc
    820         if (!((subEffectDesc->flags & EFFECT_FLAG_HW_ACC_MASK) ==
    821                                            EFFECT_FLAG_HW_ACC_TUNNEL)) {
    822              swSubefx = true;
    823              *d = *subEffectDesc;
    824              d->uuid = uuid;
    825              ALOGV("loadEffect() Changed the Proxy desc");
    826        } else
    827            hwSubefx = true;
    828        count--;
    829        node = node->next;
    830     }
    831     // 1 HW and 1 SW sub effect found. Set the offload flag in the Proxy desc
    832     if (hwSubefx && swSubefx) {
    833         d->flags |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
    834     }
    835     return 0;
    836 }
    837 
    838 // Searches the sub effect matching to the specified uuid
    839 // in the gSubEffectList. It gets the lib_entry_t for
    840 // the matched sub_effect . Used in EffectCreate of sub effects
    841 int findSubEffect(const effect_uuid_t *uuid,
    842                lib_entry_t **lib,
    843                effect_descriptor_t **desc)
    844 {
    845     list_sub_elem_t *e = gSubEffectList;
    846     list_elem_t *subefx;
    847     sub_effect_entry_t *effect;
    848     lib_entry_t *l = NULL;
    849     effect_descriptor_t *d = NULL;
    850     int found = 0;
    851     int ret = 0;
    852 
    853     if (uuid == NULL)
    854         return -EINVAL;
    855 
    856     while (e != NULL && !found) {
    857         subefx = (list_elem_t*)(e->sub_elem);
    858         while (subefx != NULL) {
    859             effect = (sub_effect_entry_t*)subefx->object;
    860             l = (lib_entry_t *)effect->lib;
    861             d = (effect_descriptor_t *)effect->object;
    862             if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
    863                 ALOGV("uuid matched");
    864                 found = 1;
    865                 break;
    866             }
    867             subefx = subefx->next;
    868         }
    869         e = e->next;
    870     }
    871     if (!found) {
    872         ALOGV("findSubEffect() effect not found");
    873         ret = -ENOENT;
    874     } else {
    875         ALOGV("findSubEffect() found effect: %s in lib %s", d->name, l->name);
    876         *lib = l;
    877         if (desc != NULL) {
    878             *desc = d;
    879         }
    880     }
    881     return ret;
    882 }
    883 
    884 lib_entry_t *getLibrary(const char *name)
    885 {
    886     list_elem_t *e;
    887 
    888     if (gCachedLibrary &&
    889             !strncmp(gCachedLibrary->name, name, PATH_MAX)) {
    890         return gCachedLibrary;
    891     }
    892 
    893     e = gLibraryList;
    894     while (e) {
    895         lib_entry_t *l = (lib_entry_t *)e->object;
    896         if (!strcmp(l->name, name)) {
    897             gCachedLibrary = l;
    898             return l;
    899         }
    900         e = e->next;
    901     }
    902 
    903     return NULL;
    904 }
    905 
    906 
    907 void resetEffectEnumeration()
    908 {
    909     gCurLib = gLibraryList;
    910     gCurEffect = NULL;
    911     if (gCurLib) {
    912         gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
    913     }
    914     gCurEffectIdx = 0;
    915 }
    916 
    917 uint32_t updateNumEffects() {
    918     list_elem_t *e;
    919     uint32_t cnt = 0;
    920 
    921     resetEffectEnumeration();
    922 
    923     e = gLibraryList;
    924     while (e) {
    925         lib_entry_t *l = (lib_entry_t *)e->object;
    926         list_elem_t *efx = l->effects;
    927         while (efx) {
    928             cnt++;
    929             efx = efx->next;
    930         }
    931         e = e->next;
    932     }
    933     gNumEffects = cnt;
    934     gCanQueryEffect = 0;
    935     return cnt;
    936 }
    937 
    938 int findEffect(const effect_uuid_t *type,
    939                const effect_uuid_t *uuid,
    940                lib_entry_t **lib,
    941                effect_descriptor_t **desc)
    942 {
    943     list_elem_t *e = gLibraryList;
    944     lib_entry_t *l = NULL;
    945     effect_descriptor_t *d = NULL;
    946     int found = 0;
    947     int ret = 0;
    948 
    949     while (e && !found) {
    950         l = (lib_entry_t *)e->object;
    951         list_elem_t *efx = l->effects;
    952         while (efx) {
    953             d = (effect_descriptor_t *)efx->object;
    954             if (type != NULL && memcmp(&d->type, type, sizeof(effect_uuid_t)) == 0) {
    955                 found = 1;
    956                 break;
    957             }
    958             if (uuid != NULL && memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
    959                 found = 1;
    960                 break;
    961             }
    962             efx = efx->next;
    963         }
    964         e = e->next;
    965     }
    966     if (!found) {
    967         ALOGV("findEffect() effect not found");
    968         ret = -ENOENT;
    969     } else {
    970         ALOGV("findEffect() found effect: %s in lib %s", d->name, l->name);
    971         *lib = l;
    972         if (desc) {
    973             *desc = d;
    974         }
    975     }
    976 
    977     return ret;
    978 }
    979 
    980 void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent) {
    981     char s[256];
    982     char ss[256];
    983     char idt[indent + 1];
    984 
    985     memset(idt, ' ', indent);
    986     idt[indent] = 0;
    987 
    988     str[0] = 0;
    989 
    990     snprintf(s, sizeof(s), "%s%s / %s\n", idt, desc->name, desc->implementor);
    991     strlcat(str, s, len);
    992 
    993     uuidToString(&desc->uuid, s, sizeof(s));
    994     snprintf(ss, sizeof(ss), "%s  UUID: %s\n", idt, s);
    995     strlcat(str, ss, len);
    996 
    997     uuidToString(&desc->type, s, sizeof(s));
    998     snprintf(ss, sizeof(ss), "%s  TYPE: %s\n", idt, s);
    999     strlcat(str, ss, len);
   1000 
   1001     sprintf(s, "%s  apiVersion: %08X\n%s  flags: %08X\n", idt,
   1002             desc->apiVersion, idt, desc->flags);
   1003     strlcat(str, s, len);
   1004 }
   1005 
   1006 int stringToUuid(const char *str, effect_uuid_t *uuid)
   1007 {
   1008     int tmp[10];
   1009 
   1010     if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
   1011             tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
   1012         return -EINVAL;
   1013     }
   1014     uuid->timeLow = (uint32_t)tmp[0];
   1015     uuid->timeMid = (uint16_t)tmp[1];
   1016     uuid->timeHiAndVersion = (uint16_t)tmp[2];
   1017     uuid->clockSeq = (uint16_t)tmp[3];
   1018     uuid->node[0] = (uint8_t)tmp[4];
   1019     uuid->node[1] = (uint8_t)tmp[5];
   1020     uuid->node[2] = (uint8_t)tmp[6];
   1021     uuid->node[3] = (uint8_t)tmp[7];
   1022     uuid->node[4] = (uint8_t)tmp[8];
   1023     uuid->node[5] = (uint8_t)tmp[9];
   1024 
   1025     return 0;
   1026 }
   1027 
   1028 int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen)
   1029 {
   1030 
   1031     snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
   1032             uuid->timeLow,
   1033             uuid->timeMid,
   1034             uuid->timeHiAndVersion,
   1035             uuid->clockSeq,
   1036             uuid->node[0],
   1037             uuid->node[1],
   1038             uuid->node[2],
   1039             uuid->node[3],
   1040             uuid->node[4],
   1041             uuid->node[5]);
   1042 
   1043     return 0;
   1044 }
   1045 
   1046 int EffectDumpEffects(int fd) {
   1047     char s[512];
   1048 
   1049     list_elem_t *fe = gLibraryFailedList;
   1050     lib_failed_entry_t *fl = NULL;
   1051 
   1052     dprintf(fd, "Libraries NOT loaded:\n");
   1053 
   1054     while (fe) {
   1055         fl = (lib_failed_entry_t *)fe->object;
   1056         dprintf(fd, " Library %s\n", fl->name);
   1057         dprintf(fd, "  path: %s\n", fl->path);
   1058         fe = fe->next;
   1059     }
   1060 
   1061     list_elem_t *e = gLibraryList;
   1062     lib_entry_t *l = NULL;
   1063     effect_descriptor_t *d = NULL;
   1064     int found = 0;
   1065     int ret = 0;
   1066 
   1067     dprintf(fd, "Libraries loaded:\n");
   1068     while (e) {
   1069         l = (lib_entry_t *)e->object;
   1070         list_elem_t *efx = l->effects;
   1071         dprintf(fd, " Library %s\n", l->name);
   1072         dprintf(fd, "  path: %s\n", l->path);
   1073         if (!efx) {
   1074             dprintf(fd, "  (no effects)\n");
   1075         }
   1076         while (efx) {
   1077             d = (effect_descriptor_t *)efx->object;
   1078             dumpEffectDescriptor(d, s, sizeof(s), 2);
   1079             dprintf(fd, "%s", s);
   1080             efx = efx->next;
   1081         }
   1082         e = e->next;
   1083     }
   1084 
   1085     e = gSkippedEffects;
   1086     if (e) {
   1087         dprintf(fd, "Skipped effects\n");
   1088         while(e) {
   1089             d = (effect_descriptor_t *)e->object;
   1090             dumpEffectDescriptor(d, s, sizeof(s), 2 /* indent */);
   1091             dprintf(fd, "%s", s);
   1092             e = e->next;
   1093         }
   1094     }
   1095     return ret;
   1096 }
   1097 
   1098