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