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 <stdlib.h>
     21 #include <string.h>
     22 #include <unistd.h>
     23 
     24 #include <cutils/properties.h>
     25 #include <log/log.h>
     26 
     27 #include <media/EffectsFactoryApi.h>
     28 
     29 #include "EffectsConfigLoader.h"
     30 #include "EffectsFactoryState.h"
     31 #include "EffectsXmlConfigLoader.h"
     32 
     33 #include "EffectsFactory.h"
     34 
     35 static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
     36 static uint32_t gNumEffects;         // total number number of effects
     37 static list_elem_t *gCurLib;    // current library in enumeration process
     38 static list_elem_t *gCurEffect; // current effect in enumeration process
     39 static uint32_t gCurEffectIdx;       // current effect index in enumeration process
     40 /** Number of elements skipped during the effects configuration loading.
     41  *  -1 if the config loader failed
     42  *  -2 if config load was skipped
     43  */
     44 static ssize_t gConfigNbElemSkipped = -2;
     45 
     46 static int gInitDone; // true is global initialization has been preformed
     47 static int gCanQueryEffect; // indicates that call to EffectQueryEffect() is valid, i.e. that the list of effects
     48                           // was not modified since last call to EffectQueryNumberEffects()
     49 /////////////////////////////////////////////////
     50 //      Local functions prototypes
     51 /////////////////////////////////////////////////
     52 
     53 static int init();
     54 static void resetEffectEnumeration();
     55 static uint32_t updateNumEffects();
     56 // To search a subeffect in the gSubEffectList
     57 static int findSubEffect(const effect_uuid_t *uuid,
     58                lib_entry_t **lib,
     59                effect_descriptor_t **desc);
     60 
     61 /////////////////////////////////////////////////
     62 //      Effect Control Interface functions
     63 /////////////////////////////////////////////////
     64 
     65 int Effect_Process(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
     66 {
     67     int ret = init();
     68     if (ret < 0) {
     69         return ret;
     70     }
     71     effect_entry_t *fx = (effect_entry_t *)self;
     72     pthread_mutex_lock(&gLibLock);
     73     if (fx->lib == NULL) {
     74         pthread_mutex_unlock(&gLibLock);
     75         return -EPIPE;
     76     }
     77     pthread_mutex_lock(&fx->lib->lock);
     78     pthread_mutex_unlock(&gLibLock);
     79 
     80     ret = (*fx->subItfe)->process(fx->subItfe, inBuffer, outBuffer);
     81     pthread_mutex_unlock(&fx->lib->lock);
     82     return ret;
     83 }
     84 
     85 int Effect_Command(effect_handle_t self,
     86                    uint32_t cmdCode,
     87                    uint32_t cmdSize,
     88                    void *pCmdData,
     89                    uint32_t *replySize,
     90                    void *pReplyData)
     91 {
     92     int ret = init();
     93     if (ret < 0) {
     94         return ret;
     95     }
     96     effect_entry_t *fx = (effect_entry_t *)self;
     97     pthread_mutex_lock(&gLibLock);
     98     if (fx->lib == NULL) {
     99         pthread_mutex_unlock(&gLibLock);
    100         return -EPIPE;
    101     }
    102     pthread_mutex_lock(&fx->lib->lock);
    103     pthread_mutex_unlock(&gLibLock);
    104 
    105     ret = (*fx->subItfe)->command(fx->subItfe, cmdCode, cmdSize, pCmdData, replySize, pReplyData);
    106     pthread_mutex_unlock(&fx->lib->lock);
    107     return ret;
    108 }
    109 
    110 int Effect_GetDescriptor(effect_handle_t self,
    111                          effect_descriptor_t *desc)
    112 {
    113     int ret = init();
    114     if (ret < 0) {
    115         return ret;
    116     }
    117     effect_entry_t *fx = (effect_entry_t *)self;
    118     pthread_mutex_lock(&gLibLock);
    119     if (fx->lib == NULL) {
    120         pthread_mutex_unlock(&gLibLock);
    121         return -EPIPE;
    122     }
    123     pthread_mutex_lock(&fx->lib->lock);
    124     pthread_mutex_unlock(&gLibLock);
    125 
    126     ret = (*fx->subItfe)->get_descriptor(fx->subItfe, desc);
    127     pthread_mutex_unlock(&fx->lib->lock);
    128     return ret;
    129 }
    130 
    131 int Effect_ProcessReverse(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
    132 {
    133     int ret = init();
    134     if (ret < 0) {
    135         return ret;
    136     }
    137     effect_entry_t *fx = (effect_entry_t *)self;
    138     pthread_mutex_lock(&gLibLock);
    139     if (fx->lib == NULL) {
    140         pthread_mutex_unlock(&gLibLock);
    141         return -EPIPE;
    142     }
    143     pthread_mutex_lock(&fx->lib->lock);
    144     pthread_mutex_unlock(&gLibLock);
    145 
    146     if ((*fx->subItfe)->process_reverse != NULL) {
    147         ret = (*fx->subItfe)->process_reverse(fx->subItfe, inBuffer, outBuffer);
    148     } else {
    149         ret = -ENOSYS;
    150     }
    151     pthread_mutex_unlock(&fx->lib->lock);
    152     return ret;
    153 }
    154 
    155 
    156 const struct effect_interface_s gInterface = {
    157         Effect_Process,
    158         Effect_Command,
    159         Effect_GetDescriptor,
    160         NULL
    161 };
    162 
    163 const struct effect_interface_s gInterfaceWithReverse = {
    164         Effect_Process,
    165         Effect_Command,
    166         Effect_GetDescriptor,
    167         Effect_ProcessReverse
    168 };
    169 
    170 /////////////////////////////////////////////////
    171 //      Effect Factory Interface functions
    172 /////////////////////////////////////////////////
    173 
    174 int EffectQueryNumberEffects(uint32_t *pNumEffects)
    175 {
    176     int ret = init();
    177     if (ret < 0) {
    178         return ret;
    179     }
    180     if (pNumEffects == NULL) {
    181         return -EINVAL;
    182     }
    183 
    184     pthread_mutex_lock(&gLibLock);
    185     *pNumEffects = gNumEffects;
    186     gCanQueryEffect = 1;
    187     pthread_mutex_unlock(&gLibLock);
    188     ALOGV("EffectQueryNumberEffects(): %d", *pNumEffects);
    189     return ret;
    190 }
    191 
    192 int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
    193 {
    194     int ret = init();
    195     if (ret < 0) {
    196         return ret;
    197     }
    198     if (pDescriptor == NULL ||
    199         index >= gNumEffects) {
    200         return -EINVAL;
    201     }
    202     if (gCanQueryEffect == 0) {
    203         return -ENOSYS;
    204     }
    205 
    206     pthread_mutex_lock(&gLibLock);
    207     ret = -ENOENT;
    208     if (index < gCurEffectIdx) {
    209         resetEffectEnumeration();
    210     }
    211     while (gCurLib) {
    212         if (gCurEffect) {
    213             if (index == gCurEffectIdx) {
    214                 *pDescriptor = *(effect_descriptor_t *)gCurEffect->object;
    215                 ret = 0;
    216                 break;
    217             } else {
    218                 gCurEffect = gCurEffect->next;
    219                 gCurEffectIdx++;
    220             }
    221         } else {
    222             gCurLib = gCurLib->next;
    223             gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
    224         }
    225     }
    226 
    227 #if (LOG_NDEBUG == 0)
    228     char str[512];
    229     dumpEffectDescriptor(pDescriptor, str, sizeof(str), 0 /* indent */);
    230     ALOGV("EffectQueryEffect() desc:%s", str);
    231 #endif
    232     pthread_mutex_unlock(&gLibLock);
    233     return ret;
    234 }
    235 
    236 int EffectGetDescriptor(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor)
    237 {
    238     lib_entry_t *l = NULL;
    239     effect_descriptor_t *d = NULL;
    240 
    241     int ret = init();
    242     if (ret < 0) {
    243         return ret;
    244     }
    245     if (pDescriptor == NULL || uuid == NULL) {
    246         return -EINVAL;
    247     }
    248     pthread_mutex_lock(&gLibLock);
    249     ret = findEffect(NULL, uuid, &l, &d);
    250     if (ret == 0) {
    251         *pDescriptor = *d;
    252     }
    253     pthread_mutex_unlock(&gLibLock);
    254     return ret;
    255 }
    256 
    257 int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle)
    258 {
    259     list_elem_t *e = gLibraryList;
    260     lib_entry_t *l = NULL;
    261     effect_descriptor_t *d = NULL;
    262     effect_handle_t itfe;
    263     effect_entry_t *fx;
    264     int found = 0;
    265     int ret;
    266 
    267     if (uuid == NULL || pHandle == NULL) {
    268         return -EINVAL;
    269     }
    270 
    271     ALOGV("EffectCreate() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X%02X\n",
    272             uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
    273             uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2],
    274             uuid->node[3],uuid->node[4],uuid->node[5]);
    275 
    276     ret = init();
    277 
    278     if (ret < 0) {
    279         ALOGW("EffectCreate() init error: %d", ret);
    280         return ret;
    281     }
    282 
    283     pthread_mutex_lock(&gLibLock);
    284 
    285     ret = findEffect(NULL, uuid, &l, &d);
    286     if (ret < 0){
    287         // Sub effects are not associated with the library->effects,
    288         // so, findEffect will fail. Search for the effect in gSubEffectList.
    289         ret = findSubEffect(uuid, &l, &d);
    290         if (ret < 0 ) {
    291             goto exit;
    292         }
    293     }
    294 
    295     // create effect in library
    296     ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
    297     if (ret != 0) {
    298         ALOGW("EffectCreate() library %s: could not create fx %s, error %d", l->name, d->name, ret);
    299         goto exit;
    300     }
    301 
    302     // add entry to effect list
    303     fx = (effect_entry_t *)malloc(sizeof(effect_entry_t));
    304     fx->subItfe = itfe;
    305     if ((*itfe)->process_reverse != NULL) {
    306         fx->itfe = (struct effect_interface_s *)&gInterfaceWithReverse;
    307         ALOGV("EffectCreate() gInterfaceWithReverse");
    308     }   else {
    309         fx->itfe = (struct effect_interface_s *)&gInterface;
    310         ALOGV("EffectCreate() gInterface");
    311     }
    312     fx->lib = l;
    313 
    314     e = (list_elem_t *)malloc(sizeof(list_elem_t));
    315     e->object = fx;
    316     e->next = gEffectList;
    317     gEffectList = e;
    318 
    319     *pHandle = (effect_handle_t)fx;
    320 
    321     ALOGV("EffectCreate() created entry %p with sub itfe %p in library %s", *pHandle, itfe, l->name);
    322 
    323 exit:
    324     pthread_mutex_unlock(&gLibLock);
    325     return ret;
    326 }
    327 
    328 int EffectRelease(effect_handle_t handle)
    329 {
    330     effect_entry_t *fx;
    331     list_elem_t *e1;
    332     list_elem_t *e2;
    333 
    334     int ret = init();
    335     if (ret < 0) {
    336         return ret;
    337     }
    338 
    339     // remove effect from effect list
    340     pthread_mutex_lock(&gLibLock);
    341     e1 = gEffectList;
    342     e2 = NULL;
    343     while (e1) {
    344         if (e1->object == handle) {
    345             if (e2) {
    346                 e2->next = e1->next;
    347             } else {
    348                 gEffectList = e1->next;
    349             }
    350             fx = (effect_entry_t *)e1->object;
    351             free(e1);
    352             break;
    353         }
    354         e2 = e1;
    355         e1 = e1->next;
    356     }
    357     if (e1 == NULL) {
    358         ret = -ENOENT;
    359         goto exit;
    360     }
    361 
    362     // release effect in library
    363     if (fx->lib == NULL) {
    364         ALOGW("EffectRelease() fx %p library already unloaded", handle);
    365     } else {
    366         pthread_mutex_lock(&fx->lib->lock);
    367         fx->lib->desc->release_effect(fx->subItfe);
    368         pthread_mutex_unlock(&fx->lib->lock);
    369     }
    370     free(fx);
    371 
    372 exit:
    373     pthread_mutex_unlock(&gLibLock);
    374     return ret;
    375 }
    376 
    377 int EffectIsNullUuid(const effect_uuid_t *uuid)
    378 {
    379     if (memcmp(uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t))) {
    380         return 0;
    381     }
    382     return 1;
    383 }
    384 
    385 // Function to get the sub effect descriptors of the effect whose uuid
    386 // is pointed by the first argument. It searches the gSubEffectList for the
    387 // matching uuid and then copies the corresponding sub effect descriptors
    388 // to the inout param
    389 int EffectGetSubEffects(const effect_uuid_t *uuid, sub_effect_entry_t **pSube,
    390                         size_t size)
    391 {
    392    ALOGV("EffectGetSubEffects() UUID: %08X-%04X-%04X-%04X-%02X%02X%02X%02X%02X"
    393           "%02X\n",uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
    394           uuid->clockSeq, uuid->node[0], uuid->node[1],uuid->node[2],
    395           uuid->node[3],uuid->node[4],uuid->node[5]);
    396 
    397    // Check if the size of the desc buffer is large enough for 2 subeffects
    398    if ((uuid == NULL) || (pSube == NULL) || (size < 2)) {
    399        ALOGW("NULL pointer or insufficient memory. Cannot query subeffects");
    400        return -EINVAL;
    401    }
    402    int ret = init();
    403    if (ret < 0)
    404       return ret;
    405    list_sub_elem_t *e = gSubEffectList;
    406    sub_effect_entry_t *subeffect;
    407    effect_descriptor_t *d;
    408    int count = 0;
    409    while (e != NULL) {
    410        d = (effect_descriptor_t*)e->object;
    411        if (memcmp(uuid, &d->uuid, sizeof(effect_uuid_t)) == 0) {
    412            ALOGV("EffectGetSubEffects: effect found in the list");
    413            list_elem_t *subefx = e->sub_elem;
    414            while (subefx != NULL) {
    415                subeffect = (sub_effect_entry_t*)subefx->object;
    416                pSube[count++] = subeffect;
    417                subefx = subefx->next;
    418            }
    419            ALOGV("EffectGetSubEffects end - copied the sub effect structures");
    420            return count;
    421        }
    422        e = e->next;
    423    }
    424    return -ENOENT;
    425 }
    426 /////////////////////////////////////////////////
    427 //      Local functions
    428 /////////////////////////////////////////////////
    429 
    430 int init() {
    431     int hdl;
    432 
    433     if (gInitDone) {
    434         return 0;
    435     }
    436 
    437     // ignore effects or not?
    438     const bool ignoreFxConfFiles = property_get_bool(PROPERTY_IGNORE_EFFECTS, false);
    439 
    440     pthread_mutex_init(&gLibLock, NULL);
    441 
    442     if (ignoreFxConfFiles) {
    443         ALOGI("Audio effects in configuration files will be ignored");
    444     } else {
    445         gConfigNbElemSkipped = EffectLoadXmlEffectConfig(NULL);
    446         if (gConfigNbElemSkipped < 0) {
    447             ALOGW("Failed to load XML effect configuration, fallback to .conf");
    448             EffectLoadEffectConfig();
    449         } else if (gConfigNbElemSkipped > 0) {
    450             ALOGE("Effect config is partially invalid, skipped %zd elements", gConfigNbElemSkipped);
    451         }
    452     }
    453 
    454     updateNumEffects();
    455     gInitDone = 1;
    456     ALOGV("init() done");
    457     return 0;
    458 }
    459 
    460 // Searches the sub effect matching to the specified uuid
    461 // in the gSubEffectList. It gets the lib_entry_t for
    462 // the matched sub_effect . Used in EffectCreate of sub effects
    463 int findSubEffect(const effect_uuid_t *uuid,
    464                lib_entry_t **lib,
    465                effect_descriptor_t **desc)
    466 {
    467     list_sub_elem_t *e = gSubEffectList;
    468     list_elem_t *subefx;
    469     sub_effect_entry_t *effect;
    470     lib_entry_t *l = NULL;
    471     effect_descriptor_t *d = NULL;
    472     int found = 0;
    473     int ret = 0;
    474 
    475     if (uuid == NULL)
    476         return -EINVAL;
    477 
    478     while (e != NULL && !found) {
    479         subefx = (list_elem_t*)(e->sub_elem);
    480         while (subefx != NULL) {
    481             effect = (sub_effect_entry_t*)subefx->object;
    482             l = (lib_entry_t *)effect->lib;
    483             d = (effect_descriptor_t *)effect->object;
    484             if (memcmp(&d->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
    485                 ALOGV("uuid matched");
    486                 found = 1;
    487                 break;
    488             }
    489             subefx = subefx->next;
    490         }
    491         e = e->next;
    492     }
    493     if (!found) {
    494         ALOGV("findSubEffect() effect not found");
    495         ret = -ENOENT;
    496     } else {
    497         ALOGV("findSubEffect() found effect: %s in lib %s", d->name, l->name);
    498         *lib = l;
    499         if (desc != NULL) {
    500             *desc = d;
    501         }
    502     }
    503     return ret;
    504 }
    505 
    506 void resetEffectEnumeration()
    507 {
    508     gCurLib = gLibraryList;
    509     gCurEffect = NULL;
    510     if (gCurLib) {
    511         gCurEffect = ((lib_entry_t *)gCurLib->object)->effects;
    512     }
    513     gCurEffectIdx = 0;
    514 }
    515 
    516 uint32_t updateNumEffects() {
    517     list_elem_t *e;
    518     uint32_t cnt = 0;
    519 
    520     resetEffectEnumeration();
    521 
    522     e = gLibraryList;
    523     while (e) {
    524         lib_entry_t *l = (lib_entry_t *)e->object;
    525         list_elem_t *efx = l->effects;
    526         while (efx) {
    527             cnt++;
    528             efx = efx->next;
    529         }
    530         e = e->next;
    531     }
    532     gNumEffects = cnt;
    533     gCanQueryEffect = 0;
    534     return cnt;
    535 }
    536 
    537 int EffectDumpEffects(int fd) {
    538     char s[512];
    539 
    540     list_elem_t *fe = gLibraryFailedList;
    541     lib_failed_entry_t *fl = NULL;
    542 
    543     dprintf(fd, "Libraries NOT loaded:\n");
    544 
    545     while (fe) {
    546         fl = (lib_failed_entry_t *)fe->object;
    547         dprintf(fd, " Library %s\n", fl->name);
    548         dprintf(fd, "  path: %s\n", fl->path);
    549         fe = fe->next;
    550     }
    551 
    552     list_elem_t *e = gLibraryList;
    553     lib_entry_t *l = NULL;
    554     effect_descriptor_t *d = NULL;
    555     int found = 0;
    556     int ret = 0;
    557 
    558     dprintf(fd, "Libraries loaded:\n");
    559     while (e) {
    560         l = (lib_entry_t *)e->object;
    561         list_elem_t *efx = l->effects;
    562         dprintf(fd, " Library %s\n", l->name);
    563         dprintf(fd, "  path: %s\n", l->path);
    564         if (!efx) {
    565             dprintf(fd, "  (no effects)\n");
    566         }
    567         while (efx) {
    568             d = (effect_descriptor_t *)efx->object;
    569             dumpEffectDescriptor(d, s, sizeof(s), 2);
    570             dprintf(fd, "%s", s);
    571             efx = efx->next;
    572         }
    573         e = e->next;
    574     }
    575 
    576     e = gSkippedEffects;
    577     if (e) {
    578         dprintf(fd, "Skipped effects\n");
    579         while(e) {
    580             d = (effect_descriptor_t *)e->object;
    581             dumpEffectDescriptor(d, s, sizeof(s), 2 /* indent */);
    582             dprintf(fd, "%s", s);
    583             e = e->next;
    584         }
    585     }
    586     switch (gConfigNbElemSkipped) {
    587     case -2:
    588         dprintf(fd, "Effect configuration loading skipped.\n");
    589         break;
    590     case -1:
    591         dprintf(fd, "XML effect configuration failed to load.\n");
    592         break;
    593     case 0:
    594         dprintf(fd, "XML effect configuration loaded successfully.\n");
    595         break;
    596     default:
    597         dprintf(fd, "XML effect configuration partially loaded, skipped %zd elements.\n",
    598                 gConfigNbElemSkipped);
    599     }
    600     return ret;
    601 }
    602 
    603