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