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