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