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