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
34static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
35static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
36static 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.
39static list_sub_elem_t *gSubEffectList;
40static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList
41static uint32_t gNumEffects;         // total number number of effects
42static list_elem_t *gCurLib;    // current library in enumeration process
43static list_elem_t *gCurEffect; // current effect in enumeration process
44static uint32_t gCurEffectIdx;       // current effect index in enumeration process
45static lib_entry_t *gCachedLibrary;  // last library accessed by getLibrary()
46
47static int gInitDone; // true is global initialization has been preformed
48static 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
51static list_elem_t *gLibraryFailedList;  //list of lib_failed_entry_t: libraries failed to load
52
53/////////////////////////////////////////////////
54//      Local functions prototypes
55/////////////////////////////////////////////////
56
57static int init();
58static int loadEffectConfigFile(const char *path);
59static int loadLibraries(cnode *root);
60static int loadLibrary(cnode *root, const char *name);
61static int loadEffects(cnode *root);
62static int loadEffect(cnode *node);
63// To get and add the effect pointed by the passed node to the gSubEffectList
64static int addSubEffect(cnode *root);
65static lib_entry_t *getLibrary(const char *path);
66static void resetEffectEnumeration();
67static uint32_t updateNumEffects();
68static 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
73static int findSubEffect(const effect_uuid_t *uuid,
74               lib_entry_t **lib,
75               effect_descriptor_t **desc);
76static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len, int indent);
77static int stringToUuid(const char *str, effect_uuid_t *uuid);
78static int uuidToString(const effect_uuid_t *uuid, char *str, size_t maxLen);
79
80/////////////////////////////////////////////////
81//      Effect Control Interface functions
82/////////////////////////////////////////////////
83
84int 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
104int 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
129int 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
150int 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
175const struct effect_interface_s gInterface = {
176        Effect_Process,
177        Effect_Command,
178        Effect_GetDescriptor,
179        NULL
180};
181
182const 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
193int 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
211int 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
255int 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
276int 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
342exit:
343    pthread_mutex_unlock(&gLibLock);
344    return ret;
345}
346
347int 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
391exit:
392    pthread_mutex_unlock(&gLibLock);
393    return ret;
394}
395
396int 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
408int 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
449int 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
477int 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
497int 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
515static const char *kLibraryPathRoot[] =
516        {"/odm/lib64/soundfx", "/vendor/lib64/soundfx", "/system/lib64/soundfx"};
517#else
518static const char *kLibraryPathRoot[] =
519        {"/odm/lib/soundfx", "/vendor/lib/soundfx", "/system/lib/soundfx"};
520#endif
521
522static 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
528int 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
570int 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
631error:
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
652int 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
708int 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
724int 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
841int 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
884lib_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
907void 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
917uint32_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
938int 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
980void 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
1006int 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
1028int 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
1046int 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