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