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