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