Home | History | Annotate | Download | only in factory
      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 
     26 static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
     27 static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
     28 static pthread_mutex_t gLibLock = PTHREAD_MUTEX_INITIALIZER; // controls access to gLibraryList
     29 static uint32_t gNumEffects;         // total number number of effects
     30 static list_elem_t *gCurLib;    // current library in enumeration process
     31 static list_elem_t *gCurEffect; // current effect in enumeration process
     32 static uint32_t gCurEffectIdx;       // current effect index in enumeration process
     33 
     34 const char * const gEffectLibPath = "/system/lib/soundfx"; // path to built-in effect libraries
     35 static int gInitDone; // true is global initialization has been preformed
     36 static int gNextLibId; // used by loadLibrary() to allocate unique library handles
     37 static 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 
     44 static int init();
     45 static int loadLibrary(const char *libPath, int *handle);
     46 static int unloadLibrary(int handle);
     47 static void resetEffectEnumeration();
     48 static uint32_t updateNumEffects();
     49 static int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc);
     50 static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
     51 
     52 /////////////////////////////////////////////////
     53 //      Effect Control Interface functions
     54 /////////////////////////////////////////////////
     55 
     56 int 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 
     76 int 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 
    101 const struct effect_interface_s gInterface = {
    102         Effect_Process,
    103         Effect_Command
    104 };
    105 
    106 /////////////////////////////////////////////////
    107 //      Effect Factory Interface functions
    108 /////////////////////////////////////////////////
    109 
    110 int 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 
    128 int 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 
    172 int 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 
    193 int 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 
    248 exit:
    249     pthread_mutex_unlock(&gLibLock);
    250     return ret;
    251 }
    252 
    253 int 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 
    297 exit:
    298     pthread_mutex_unlock(&gLibLock);
    299     return ret;
    300 }
    301 
    302 int 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 
    317 int 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 
    329 int 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 
    341 int 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 
    380 int 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 
    492 error:
    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 
    504 int 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 
    561 void 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 
    571 uint32_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 
    592 int 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 
    625 void 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