blob: 07c4d80ff7f3d2b33ee53194ab95db0c8f8bba78 [file] [log] [blame]
Eric Laurent135ad072010-05-21 06:05:13 -07001/*
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 <dlfcn.h>
22
23
24static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
25static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
26static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList
27static list_elem_t *gCurLib; // current library in enumeration process
28static list_elem_t *gCurEffect; // current effect in enumeration process
29
30static const char * const gEffectLibPath = "/system/lib/soundfx"; // path to built-in effect libraries
31static int gInitDone; // true is global initialization has been preformed
32
33/////////////////////////////////////////////////
34// Local functions prototypes
35/////////////////////////////////////////////////
36
37static int init();
38static int loadLibrary(const char *libPath, int *handle);
39static int unloadLibrary(int handle);
40static int numEffectModules();
41static int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc);
42static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
43
44/////////////////////////////////////////////////
45// Effect Control Interface functions
46/////////////////////////////////////////////////
47
48int Effect_Process(effect_interface_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
49{
50 int ret = init();
51 if (ret < 0) {
52 return ret;
53 }
54 effect_entry_t *fx = (effect_entry_t *)self;
55 pthread_mutex_lock(&gLibLock);
56 if (fx->lib == NULL) {
57 pthread_mutex_unlock(&gLibLock);
58 return -EPIPE;
59 }
60 pthread_mutex_lock(&fx->lib->lock);
61 pthread_mutex_unlock(&gLibLock);
62
63 ret = (*fx->subItfe)->process(fx->subItfe, inBuffer, outBuffer);
64 pthread_mutex_unlock(&fx->lib->lock);
65 return ret;
66}
67
68int Effect_Command(effect_interface_t self, int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData)
69{
70 int ret = init();
71 if (ret < 0) {
72 return ret;
73 }
74 effect_entry_t *fx = (effect_entry_t *)self;
75 pthread_mutex_lock(&gLibLock);
76 if (fx->lib == NULL) {
77 pthread_mutex_unlock(&gLibLock);
78 return -EPIPE;
79 }
80 pthread_mutex_lock(&fx->lib->lock);
81 pthread_mutex_unlock(&gLibLock);
82
83 ret = (*fx->subItfe)->command(fx->subItfe, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
84 pthread_mutex_unlock(&fx->lib->lock);
85 return ret;
86}
87
88const struct effect_interface_s gInterface = {
89 Effect_Process,
90 Effect_Command
91};
92
93/////////////////////////////////////////////////
94// Effect Factory Interface functions
95/////////////////////////////////////////////////
96
97int EffectQueryNumberEffects(int *pNumEffects)
98{
99 int ret = init();
100 if (ret < 0) {
101 return ret;
102 }
103 if (pNumEffects == NULL) {
104 return -EINVAL;
105 }
106
107 pthread_mutex_lock(&gLibLock);
108 *pNumEffects = numEffectModules();
109 pthread_mutex_unlock(&gLibLock);
110 LOGV("EffectQueryNumberEffects(): %d", *pNumEffects);
111 return ret;
112}
113
114int EffectQueryNext(effect_descriptor_t *pDescriptor)
115{
116 int ret = init();
117 if (ret < 0) {
118 return ret;
119 }
120 if (pDescriptor == NULL) {
121 return -EINVAL;
122 }
123
124 pthread_mutex_lock(&gLibLock);
125 ret = -ENOENT;
126 while (gCurLib) {
127 if (gCurEffect) {
128 memcpy(pDescriptor, gCurEffect->object, sizeof(effect_descriptor_t));
129 gCurEffect = gCurEffect->next;
130 ret = 0;
131 break;
132 } else {
133 gCurLib = gCurLib->next;
134 gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
135 }
136 }
137 char str[256];
138 dumpEffectDescriptor(pDescriptor, str, 256);
139 LOGV("EffectQueryNext() desc:%s", str);
140 pthread_mutex_unlock(&gLibLock);
141 return ret;
142}
143
144int EffectGetDescriptor(effect_uuid_t *uuid, effect_descriptor_t *pDescriptor)
145{
146 lib_entry_t *l = NULL;
147 effect_descriptor_t *d = NULL;
148
149 int ret = init();
150 if (ret < 0) {
151 return ret;
152 }
153 if (pDescriptor == NULL || uuid == NULL) {
154 return -EINVAL;
155 }
156 pthread_mutex_lock(&gLibLock);
157 ret = findEffect(uuid, &l, &d);
158 if (ret == 0) {
159 memcpy(pDescriptor, d, sizeof(effect_descriptor_t));
160 }
161 pthread_mutex_unlock(&gLibLock);
162 return ret;
163}
164
165int EffectCreate(effect_uuid_t *uuid, effect_interface_t *pInterface)
166{
167 list_elem_t *e = gLibraryList;
168 lib_entry_t *l = NULL;
169 effect_descriptor_t *d = NULL;
170 effect_interface_t itfe;
171 effect_entry_t *fx;
172 int found = 0;
173 int ret;
174
175 if (uuid == NULL || pInterface == NULL) {
176 return -EINVAL;
177 }
178
179 LOGV("EffectCreate() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
180 uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
181 uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2],
182 uuid->node[3],uuid->node[4],uuid->node[5]);
183
184 ret = init();
185
186 if (ret < 0) {
187 LOGW("EffectCreate() init error: %d", ret);
188 return ret;
189 }
190
191 pthread_mutex_lock(&gLibLock);
192
193 ret = findEffect(uuid, &l, &d);
194 if (ret < 0){
195 goto exit;
196 }
197
198 // create effect in library
199 ret = l->createFx(uuid, &itfe);
200 if (ret < 0) {
201 LOGW("EffectCreate() library %s: could not create fx %s", l->path, d->name);
202 goto exit;
203 }
204
205 // add entry to effect list
206 fx = (effect_entry_t *)malloc(sizeof(effect_entry_t));
207 fx->subItfe = itfe;
208 fx->itfe = (struct effect_interface_s *)&gInterface;
209 fx->lib = l;
210
211 e = (list_elem_t *)malloc(sizeof(list_elem_t));
212 e->object = fx;
213 e->next = gEffectList;
214 gEffectList = e;
215
216 *pInterface = (effect_interface_t)fx;
217
218 LOGV("EffectCreate() created entry %p with sub itfe %p in library %s", *pInterface, itfe, l->path);
219
220exit:
221 pthread_mutex_unlock(&gLibLock);
222 return ret;
223}
224
225int EffectRelease(effect_interface_t interface)
226{
227 effect_entry_t *fx;
228 list_elem_t *e1;
229 list_elem_t *e2;
230
231 int ret = init();
232 if (ret < 0) {
233 return ret;
234 }
235
236 // remove effect from effect list
237 pthread_mutex_lock(&gLibLock);
238 e1 = gEffectList;
239 e2 = NULL;
240 while (e1) {
241 if (e1->object == interface) {
242 if (e2) {
243 e2->next = e1->next;
244 } else {
245 gEffectList = e1->next;
246 }
247 fx = (effect_entry_t *)e1->object;
248 free(e1);
249 break;
250 }
251 e2 = e1;
252 e1 = e1->next;
253 }
254 if (e1 == NULL) {
255 ret = -ENOENT;
256 goto exit;
257 }
258
259 // release effect in library
260 if (fx->lib == NULL) {
261 LOGW("EffectRelease() fx %p library already unloaded", interface);
262 } else {
263 pthread_mutex_lock(&fx->lib->lock);
264 fx->lib->releaseFx(fx->subItfe);
265 pthread_mutex_unlock(&fx->lib->lock);
266 }
267 free(fx);
268
269exit:
270 pthread_mutex_unlock(&gLibLock);
271 return ret;
272}
273
274int EffectLoadLibrary(const char *libPath, int *handle)
275{
276 int ret = init();
277 if (ret < 0) {
278 return ret;
279 }
280 if (libPath == NULL || strnlen(libPath, PATH_MAX) >= PATH_MAX) {
281 return -EINVAL;
282 }
283 return loadLibrary(libPath, handle);
284}
285
286int EffectUnloadLibrary(int handle)
287{
288 int ret = init();
289 if (ret < 0) {
290 return ret;
291 }
292
293 return unloadLibrary(handle);
294}
295
296int EffectIsNullUuid(effect_uuid_t *uuid)
297{
298 if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) {
299 return 0;
300 }
301 return 1;
302}
303
304/////////////////////////////////////////////////
305// Local functions
306/////////////////////////////////////////////////
307
308int init() {
309 struct dirent *ent;
310 DIR *dir = NULL;
311 char libpath[PATH_MAX];
312 int hdl;
313
314 if (gInitDone) {
315 return 0;
316 }
317
318 pthread_mutex_init(&gLibLock, NULL);
319
320 // load built-in libraries
321 dir = opendir(gEffectLibPath);
322 if (dir == NULL) {
323 return -ENODEV;
324 }
325 while ((ent = readdir(dir)) != NULL) {
326 LOGV("init() reading file %s", ent->d_name);
327 if ((strlen(ent->d_name) < 3) ||
328 strncmp(ent->d_name, "lib", 3) != 0 ||
329 strncmp(ent->d_name + strlen(ent->d_name) - 3, ".so", 3) != 0) {
330 continue;
331 }
332 strcpy(libpath, gEffectLibPath);
333 strcat(libpath, "/");
334 strcat(libpath, ent->d_name);
335 if (loadLibrary(libpath, &hdl) < 0) {
336 LOGW("init() failed to load library %s",libpath);
337 }
338 }
339 closedir(dir);
340
341 gInitDone = 1;
342 LOGV("init() done");
343 return 0;
344}
345
346
347int loadLibrary(const char *libPath, int *handle)
348{
349 void *hdl;
350 effect_QueryNumberEffects_t queryNumFx;
351 effect_QueryNextEffect_t queryFx;
352 effect_CreateEffect_t createFx;
353 effect_ReleaseEffect_t releaseFx;
354 int numFx;
355 int fx;
356 int ret;
357 list_elem_t *e, *descHead = NULL;
358 lib_entry_t *l;
359
360 if (handle == NULL) {
361 return -EINVAL;
362 }
363
364 *handle = 0;
365
366 hdl = dlopen(libPath, RTLD_NOW);
367 if (hdl == 0) {
368 LOGW("could open lib %s", libPath);
369 return -ENODEV;
370 }
371
372 // Check functions availability
373 queryNumFx = (effect_QueryNumberEffects_t)dlsym(hdl, "EffectQueryNumberEffects");
374 if (queryNumFx == NULL) {
375 LOGW("could not get EffectQueryNumberEffects from lib %s", libPath);
376 ret = -ENODEV;
377 goto error;
378 }
379 queryFx = (effect_QueryNextEffect_t)dlsym(hdl, "EffectQueryNext");
380 if (queryFx == NULL) {
381 LOGW("could not get EffectQueryNext from lib %s", libPath);
382 ret = -ENODEV;
383 goto error;
384 }
385 createFx = (effect_CreateEffect_t)dlsym(hdl, "EffectCreate");
386 if (createFx == NULL) {
387 LOGW("could not get EffectCreate from lib %s", libPath);
388 ret = -ENODEV;
389 goto error;
390 }
391 releaseFx = (effect_ReleaseEffect_t)dlsym(hdl, "EffectRelease");
392 if (releaseFx == NULL) {
393 LOGW("could not get EffectRelease from lib %s", libPath);
394 ret = -ENODEV;
395 goto error;
396 }
397
398 // load effect descriptors
399 ret = queryNumFx(&numFx);
400 if (ret) {
401 goto error;
402 }
403
404 for (fx = 0; fx < numFx; fx++) {
405 effect_descriptor_t *d = malloc(sizeof(effect_descriptor_t));
406 if (d == NULL) {
407 ret = -ENOMEM;
408 goto error;
409 }
410 ret = queryFx(d);
411 if (ret == 0) {
412#if (LOG_NDEBUG==0)
413 char s[256];
414 dumpEffectDescriptor(d, s, 256);
415 LOGV("loadLibrary() read descriptor %p:%s",d, s);
416#endif
417 if (d->apiVersion != EFFECT_API_VERSION) {
418 LOGW("Bad API version %04x on lib %s", d->apiVersion, libPath);
419 free(d);
420 continue;
421 }
422 e = malloc(sizeof(list_elem_t));
423 if (e == NULL) {
424 free(d);
425 ret = -ENOMEM;
426 goto error;
427 }
428 e->object = d;
429 e->next = descHead;
430 descHead = e;
431 } else {
432 LOGW("Error querying effect # %d on lib %s", fx, libPath);
433 }
434 }
435 // add entry for library in gLibraryList
436 l = malloc(sizeof(lib_entry_t));
437 l->handle = hdl;
438 strncpy(l->path, libPath, PATH_MAX);
439 l->createFx = createFx;
440 l->releaseFx = releaseFx;
441 l->effects = descHead;
442 pthread_mutex_init(&l->lock, NULL);
443
444 e = malloc(sizeof(list_elem_t));
445 pthread_mutex_lock(&gLibLock);
446 e->next = gLibraryList;
447 e->object = l;
448 gLibraryList = e;
449 pthread_mutex_unlock(&gLibLock);
450 LOGV("loadLibrary() linked library %p", l);
451
452 *handle = (int)hdl;
453
454 return 0;
455
456error:
457 LOGW("loadLibrary() error: %d on lib: %s", ret, libPath);
458 while (descHead) {
459 free(descHead->object);
460 e = descHead->next;
461 free(descHead);
462 descHead = e;;
463 }
464 dlclose(hdl);
465 return ret;
466}
467
468int unloadLibrary(int handle)
469{
470 void *hdl;
471 int ret;
472 list_elem_t *el1, *el2;
473 lib_entry_t *l;
474 effect_entry_t *fx;
475
476 pthread_mutex_lock(&gLibLock);
477 el1 = gLibraryList;
478 el2 = NULL;
479 while (el1) {
480 l = (lib_entry_t *)el1->object;
481 if (handle == (int)l->handle) {
482 if (el2) {
483 el2->next = el1->next;
484 } else {
485 gLibraryList = el1->next;
486 }
487 free(el1);
488 break;
489 }
490 el2 = el1;
491 el1 = el1->next;
492 }
493 pthread_mutex_unlock(&gLibLock);
494 if (el1 == NULL) {
495 return -ENOENT;
496 }
497
498 // clear effect descriptor list
499 el1 = l->effects;
500 while (el1) {
501 free(el1->object);
502 el2 = el1->next;
503 free(el1);
504 el1 = el2;
505 }
506
507 // disable all effects from this library
508 pthread_mutex_lock(&l->lock);
509 el1 = gEffectList;
510 while (el1) {
511 fx = (effect_entry_t *)el1->object;
512 if (fx->lib == l) {
513 fx->lib = NULL;
514 }
515 el1 = el1->next;
516 }
517 pthread_mutex_unlock(&l->lock);
518
519 dlclose(l->handle);
520 free(l);
521 return 0;
522}
523
524
525
526int numEffectModules() {
527 list_elem_t *e = gLibraryList;
528 int cnt = 0;
529
530 // Reset pointers for EffectQueryNext()
531 gCurLib = e;
532 if (e) {
533 gCurEffect = ((lib_entry_t *)e->object)->effects;
534 }
535 while (e) {
536 lib_entry_t *l = (lib_entry_t *)e->object;
537 list_elem_t *efx = l->effects;
538 while (efx) {
539 cnt++;
540 efx = efx->next;
541 }
542 e = e->next;
543 }
544 return cnt;
545}
546
547int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc)
548{
549 list_elem_t *e = gLibraryList;
550 lib_entry_t *l = NULL;
551 effect_descriptor_t *d = NULL;
552 int found = 0;
553 int ret = 0;
554
555 while (e && !found) {
556 l = (lib_entry_t *)e->object;
557 list_elem_t *efx = l->effects;
558 while (efx) {
559 d = (effect_descriptor_t *)efx->object;
560 if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
561 found = 1;
562 break;
563 }
564 efx = efx->next;
565 }
566 e = e->next;
567 }
568 if (!found) {
569 LOGV("findEffect() effect not found");
570 ret = -ENOENT;
571 } else {
572 LOGV("findEffect() found effect: %s in lib %s", d->name, l->path);
573 *lib = l;
574 *desc = d;
575 }
576
577 return ret;
578}
579
580void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len) {
581 char s[256];
582
583 snprintf(str, len, "\nEffect Descriptor %p:\n", desc);
584 sprintf(s, "- UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
585 desc->uuid.timeLow, desc->uuid.timeMid, desc->uuid.timeHiAndVersion,
586 desc->uuid.clockSeq, desc->uuid.node[0], desc->uuid.node[1],desc->uuid.node[2],
587 desc->uuid.node[3],desc->uuid.node[4],desc->uuid.node[5]);
588 strncat(str, s, len);
589 sprintf(s, "- TYPE: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
590 desc->type.timeLow, desc->type.timeMid, desc->type.timeHiAndVersion,
591 desc->type.clockSeq, desc->type.node[0], desc->type.node[1],desc->type.node[2],
592 desc->type.node[3],desc->type.node[4],desc->type.node[5]);
593 strncat(str, s, len);
594 sprintf(s, "- apiVersion: %04X\n- flags: %08X\n",
595 desc->apiVersion, desc->flags);
596 strncat(str, s, len);
597 sprintf(s, "- name: %s\n", desc->name);
598 strncat(str, s, len);
599 sprintf(s, "- implementor: %s\n", desc->implementor);
600 strncat(str, s, len);
601}
602