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