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
30static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
31static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
32static 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.
35static list_sub_elem_t *gSubEffectList;
36static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList
37static uint32_t gNumEffects;         // total number number of effects
38static list_elem_t *gCurLib;    // current library in enumeration process
39static list_elem_t *gCurEffect; // current effect in enumeration process
40static uint32_t gCurEffectIdx;       // current effect index in enumeration process
41static lib_entry_t *gCachedLibrary;  // last library accessed by getLibrary()
42
43static int gInitDone; // true is global initialization has been preformed
44static 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
52static int init();
53static int loadEffectConfigFile(const char *path);
54static int loadLibraries(cnode *root);
55static int loadLibrary(cnode *root, const char *name);
56static int loadEffects(cnode *root);
57static int loadEffect(cnode *node);
58// To get and add the effect pointed by the passed node to the gSubEffectList
59static int addSubEffect(cnode *root);
60static lib_entry_t *getLibrary(const char *path);
61static void resetEffectEnumeration();
62static uint32_t updateNumEffects();
63static 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
68static int findSubEffect(const effect_uuid_t *uuid,
69               lib_entry_t **lib,
70               effect_descriptor_t **desc);
71static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent);
72static int stringToUuid(const char *str, effect_uuid_t *uuid);
73static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen);
74
75/////////////////////////////////////////////////
76//      Effect Control Interface functions
77/////////////////////////////////////////////////
78
79int 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
99int 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
124int 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
145int 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
170const struct effect_interface_s gInterface = {
171        Effect_Process,
172        Effect_Command,
173        Effect_GetDescriptor,
174        NULL
175};
176
177const 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
188int 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
206int 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
250int 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
271int 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
337exit:
338    pthread_mutex_unlock(&gLibLock);
339    return ret;
340}
341
342int 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
386exit:
387    pthread_mutex_unlock(&gLibLock);
388    return ret;
389}
390
391int 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
403int 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
444int 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
472int 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
492int 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
508int 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
579error:
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
589int 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
645int 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
661int 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
778int 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
821lib_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
844void 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
854uint32_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
875int 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
917void 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
943int 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
965int 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
983int 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