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