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