Home | History | Annotate | Download | only in voice_processing
      1 /*
      2  * Copyright (C) 2013 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 "voice_processing"
     18 /*#define LOG_NDEBUG 0*/
     19 #include <stdlib.h>
     20 #include <dlfcn.h>
     21 #include <unistd.h>
     22 
     23 #include <cutils/log.h>
     24 #include <cutils/list.h>
     25 #include <hardware/audio_effect.h>
     26 #include <audio_effects/effect_aec.h>
     27 #include <audio_effects/effect_agc.h>
     28 #include <audio_effects/effect_ns.h>
     29 
     30 
     31 //------------------------------------------------------------------------------
     32 // local definitions
     33 //------------------------------------------------------------------------------
     34 
     35 #define EFFECTS_DESCRIPTOR_LIBRARY_PATH "/vendor/lib/soundfx/libqcomvoiceprocessingdescriptors.so"
     36 #define EFFECTS_DESCRIPTOR_LIBRARY_PATH2 "/system/lib/soundfx/libqcomvoiceprocessingdescriptors.so"
     37 
     38 // types of pre processing modules
     39 enum effect_id
     40 {
     41     AEC_ID,        // Acoustic Echo Canceler
     42     NS_ID,         // Noise Suppressor
     43 //ENABLE_AGC    AGC_ID,        // Automatic Gain Control
     44     NUM_ID
     45 };
     46 
     47 // Session state
     48 enum session_state {
     49     SESSION_STATE_INIT,        // initialized
     50     SESSION_STATE_CONFIG       // configuration received
     51 };
     52 
     53 // Effect/Preprocessor state
     54 enum effect_state {
     55     EFFECT_STATE_INIT,         // initialized
     56     EFFECT_STATE_CREATED,      // webRTC engine created
     57     EFFECT_STATE_CONFIG,       // configuration received/disabled
     58     EFFECT_STATE_ACTIVE        // active/enabled
     59 };
     60 
     61 // Effect context
     62 struct effect_s {
     63     const struct effect_interface_s *itfe;
     64     uint32_t id;                // type of pre processor (enum effect_id)
     65     uint32_t state;             // current state (enum effect_state)
     66     struct session_s *session;  // session the effect is on
     67 };
     68 
     69 // Session context
     70 struct session_s {
     71     struct listnode node;
     72     effect_config_t config;
     73     struct effect_s effects[NUM_ID]; // effects in this session
     74     uint32_t state;                  // current state (enum session_state)
     75     int id;                          // audio session ID
     76     int io;                          // handle of input stream this session is on
     77     uint32_t created_msk;            // bit field containing IDs of crested pre processors
     78     uint32_t enabled_msk;            // bit field containing IDs of enabled pre processors
     79     uint32_t processed_msk;          // bit field containing IDs of pre processors already
     80 };
     81 
     82 
     83 //------------------------------------------------------------------------------
     84 // Default Effect descriptors. Device specific descriptors should be defined in
     85 // libqcomvoiceprocessing.<product_name>.so if needed.
     86 //------------------------------------------------------------------------------
     87 
     88 // UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html
     89 // as the pre processing effects are not defined by OpenSL ES
     90 
     91 // Acoustic Echo Cancellation
     92 static const effect_descriptor_t qcom_default_aec_descriptor = {
     93         { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
     94         { 0x0f8d0d2a, 0x59e5, 0x45fe, 0xb6e4, { 0x24, 0x8c, 0x8a, 0x79, 0x91, 0x09 } }, // uuid
     95         EFFECT_CONTROL_API_VERSION,
     96         (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND|EFFECT_FLAG_HW_ACC_TUNNEL),
     97         0,
     98         0,
     99         "Acoustic Echo Canceler",
    100         "Qualcomm Fluence"
    101 };
    102 
    103 // Noise suppression
    104 static const effect_descriptor_t qcom_default_ns_descriptor = {
    105         { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
    106         { 0x1d97bb0b, 0x9e2f, 0x4403, 0x9ae3, { 0x58, 0xc2, 0x55, 0x43, 0x06, 0xf8 } }, // uuid
    107         EFFECT_CONTROL_API_VERSION,
    108         (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND|EFFECT_FLAG_HW_ACC_TUNNEL),
    109         0,
    110         0,
    111         "Noise Suppression",
    112         "Qualcomm Fluence"
    113 };
    114 
    115 //ENABLE_AGC
    116 // Automatic Gain Control
    117 //static const effect_descriptor_t qcom_default_agc_descriptor = {
    118 //        { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
    119 //        { 0x0dd49521, 0x8c59, 0x40b1, 0xb403, { 0xe0, 0x8d, 0x5f, 0x01, 0x87, 0x5e } }, // uuid
    120 //        EFFECT_CONTROL_API_VERSION,
    121 //        (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND|EFFECT_FLAG_HW_ACC_TUNNEL),
    122 //        0,
    123 //        0,
    124 //        "Automatic Gain Control",
    125 //        "Qualcomm Fluence"
    126 //};
    127 
    128 const effect_descriptor_t *descriptors[NUM_ID] = {
    129         &qcom_default_aec_descriptor,
    130         &qcom_default_ns_descriptor,
    131 //ENABLE_AGC       &qcom_default_agc_descriptor,
    132 };
    133 
    134 
    135 static int init_status = 1;
    136 struct listnode session_list;
    137 static const struct effect_interface_s effect_interface;
    138 static const effect_uuid_t * uuid_to_id_table[NUM_ID];
    139 
    140 //------------------------------------------------------------------------------
    141 // Helper functions
    142 //------------------------------------------------------------------------------
    143 
    144 static const effect_uuid_t * id_to_uuid(int id)
    145 {
    146     if (id >= NUM_ID)
    147         return EFFECT_UUID_NULL;
    148 
    149     return uuid_to_id_table[id];
    150 }
    151 
    152 static uint32_t uuid_to_id(const effect_uuid_t * uuid)
    153 {
    154     size_t i;
    155     for (i = 0; i < NUM_ID; i++)
    156         if (memcmp(uuid, uuid_to_id_table[i], sizeof(*uuid)) == 0)
    157             break;
    158 
    159     return i;
    160 }
    161 
    162 //------------------------------------------------------------------------------
    163 // Effect functions
    164 //------------------------------------------------------------------------------
    165 
    166 static void session_set_fx_enabled(struct session_s *session, uint32_t id, bool enabled);
    167 
    168 #define BAD_STATE_ABORT(from, to) \
    169         LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to);
    170 
    171 static int effect_set_state(struct effect_s *effect, uint32_t state)
    172 {
    173     int status = 0;
    174     ALOGV("effect_set_state() id %d, new %d old %d", effect->id, state, effect->state);
    175     switch(state) {
    176     case EFFECT_STATE_INIT:
    177         switch(effect->state) {
    178         case EFFECT_STATE_ACTIVE:
    179             session_set_fx_enabled(effect->session, effect->id, false);
    180         case EFFECT_STATE_CONFIG:
    181         case EFFECT_STATE_CREATED:
    182         case EFFECT_STATE_INIT:
    183             break;
    184         default:
    185             BAD_STATE_ABORT(effect->state, state);
    186         }
    187         break;
    188     case EFFECT_STATE_CREATED:
    189         switch(effect->state) {
    190         case EFFECT_STATE_INIT:
    191             break;
    192         case EFFECT_STATE_CREATED:
    193         case EFFECT_STATE_ACTIVE:
    194         case EFFECT_STATE_CONFIG:
    195             ALOGE("effect_set_state() invalid transition");
    196             status = -ENOSYS;
    197             break;
    198         default:
    199             BAD_STATE_ABORT(effect->state, state);
    200         }
    201         break;
    202     case EFFECT_STATE_CONFIG:
    203         switch(effect->state) {
    204         case EFFECT_STATE_INIT:
    205             ALOGE("effect_set_state() invalid transition");
    206             status = -ENOSYS;
    207             break;
    208         case EFFECT_STATE_ACTIVE:
    209             session_set_fx_enabled(effect->session, effect->id, false);
    210             break;
    211         case EFFECT_STATE_CREATED:
    212         case EFFECT_STATE_CONFIG:
    213             break;
    214         default:
    215             BAD_STATE_ABORT(effect->state, state);
    216         }
    217         break;
    218     case EFFECT_STATE_ACTIVE:
    219         switch(effect->state) {
    220         case EFFECT_STATE_INIT:
    221         case EFFECT_STATE_CREATED:
    222             ALOGE("effect_set_state() invalid transition");
    223             status = -ENOSYS;
    224             break;
    225         case EFFECT_STATE_ACTIVE:
    226             // enabling an already enabled effect is just ignored
    227             break;
    228         case EFFECT_STATE_CONFIG:
    229             session_set_fx_enabled(effect->session, effect->id, true);
    230             break;
    231         default:
    232             BAD_STATE_ABORT(effect->state, state);
    233         }
    234         break;
    235     default:
    236         BAD_STATE_ABORT(effect->state, state);
    237     }
    238 
    239     if (status == 0)
    240         effect->state = state;
    241 
    242     return status;
    243 }
    244 
    245 static int effect_init(struct effect_s *effect, uint32_t id)
    246 {
    247     effect->itfe = &effect_interface;
    248     effect->id = id;
    249     effect->state = EFFECT_STATE_INIT;
    250     return 0;
    251 }
    252 
    253 static int effect_create(struct effect_s *effect,
    254                struct session_s *session,
    255                effect_handle_t  *interface)
    256 {
    257     effect->session = session;
    258     *interface = (effect_handle_t)&effect->itfe;
    259     return effect_set_state(effect, EFFECT_STATE_CREATED);
    260 }
    261 
    262 static int effect_release(struct effect_s *effect)
    263 {
    264     return effect_set_state(effect, EFFECT_STATE_INIT);
    265 }
    266 
    267 
    268 //------------------------------------------------------------------------------
    269 // Session functions
    270 //------------------------------------------------------------------------------
    271 
    272 static int session_init(struct session_s *session)
    273 {
    274     size_t i;
    275     int status = 0;
    276 
    277     session->state = SESSION_STATE_INIT;
    278     session->id = 0;
    279     session->io = 0;
    280     session->created_msk = 0;
    281     for (i = 0; i < NUM_ID && status == 0; i++)
    282         status = effect_init(&session->effects[i], i);
    283 
    284     return status;
    285 }
    286 
    287 
    288 static int session_create_effect(struct session_s *session,
    289                                  int32_t id,
    290                                  effect_handle_t  *interface)
    291 {
    292     int status = -ENOMEM;
    293 
    294     ALOGV("session_create_effect() %s, created_msk %08x",
    295           id == AEC_ID ? "AEC" : id == NS_ID ? "NS" : "?", session->created_msk);
    296 
    297     if (session->created_msk == 0) {
    298         session->config.inputCfg.samplingRate = 16000;
    299         session->config.inputCfg.channels = AUDIO_CHANNEL_IN_MONO;
    300         session->config.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
    301         session->config.outputCfg.samplingRate = 16000;
    302         session->config.outputCfg.channels = AUDIO_CHANNEL_IN_MONO;
    303         session->config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
    304         session->enabled_msk = 0;
    305         session->processed_msk = 0;
    306     }
    307     status = effect_create(&session->effects[id], session, interface);
    308     if (status < 0)
    309         goto error;
    310 
    311     ALOGV("session_create_effect() OK");
    312     session->created_msk |= (1<<id);
    313     return status;
    314 
    315 error:
    316     return status;
    317 }
    318 
    319 static int session_release_effect(struct session_s *session,
    320                                   struct effect_s *fx)
    321 {
    322     ALOGW_IF(effect_release(fx) != 0, " session_release_effect() failed for id %d", fx->id);
    323 
    324     session->created_msk &= ~(1<<fx->id);
    325     if (session->created_msk == 0)
    326     {
    327         ALOGV("session_release_effect() last effect: removing session");
    328         list_remove(&session->node);
    329         free(session);
    330     }
    331 
    332     return 0;
    333 }
    334 
    335 
    336 static int session_set_config(struct session_s *session, effect_config_t *config)
    337 {
    338     int status;
    339 
    340     if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
    341             config->inputCfg.format != config->outputCfg.format ||
    342             config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT)
    343         return -EINVAL;
    344 
    345     ALOGV("session_set_config() sampling rate %d channels %08x",
    346          config->inputCfg.samplingRate, config->inputCfg.channels);
    347 
    348     // if at least one process is enabled, do not accept configuration changes
    349     if (session->enabled_msk) {
    350         if (session->config.inputCfg.samplingRate != config->inputCfg.samplingRate ||
    351                 session->config.inputCfg.channels != config->inputCfg.channels ||
    352                 session->config.outputCfg.channels != config->outputCfg.channels)
    353             return -ENOSYS;
    354         else
    355             return 0;
    356     }
    357 
    358     memcpy(&session->config, config, sizeof(effect_config_t));
    359 
    360     session->state = SESSION_STATE_CONFIG;
    361     return 0;
    362 }
    363 
    364 static void session_get_config(struct session_s *session, effect_config_t *config)
    365 {
    366     memcpy(config, &session->config, sizeof(effect_config_t));
    367 
    368     config->inputCfg.mask = config->outputCfg.mask =
    369             (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
    370 }
    371 
    372 
    373 static void session_set_fx_enabled(struct session_s *session, uint32_t id, bool enabled)
    374 {
    375     if (enabled) {
    376         if(session->enabled_msk == 0) {
    377             /* do first enable here */
    378         }
    379         session->enabled_msk |= (1 << id);
    380     } else {
    381         session->enabled_msk &= ~(1 << id);
    382         if(session->enabled_msk == 0) {
    383             /* do last enable here */
    384         }
    385     }
    386     ALOGV("session_set_fx_enabled() id %d, enabled %d enabled_msk %08x",
    387          id, enabled, session->enabled_msk);
    388     session->processed_msk = 0;
    389 }
    390 
    391 //------------------------------------------------------------------------------
    392 // Global functions
    393 //------------------------------------------------------------------------------
    394 
    395 static struct session_s *get_session(int32_t id, int32_t  sessionId, int32_t  ioId)
    396 {
    397     size_t i;
    398     int free = -1;
    399     struct listnode *node;
    400     struct session_s *session;
    401 
    402     list_for_each(node, &session_list) {
    403         session = node_to_item(node, struct session_s, node);
    404         if (session->io == ioId) {
    405             if (session->created_msk & (1 << id)) {
    406                 ALOGV("get_session() effect %d already created", id);
    407                 return NULL;
    408             }
    409             ALOGV("get_session() found session %p", session);
    410             return session;
    411         }
    412     }
    413 
    414     session = (struct session_s *)calloc(1, sizeof(struct session_s));
    415     session_init(session);
    416     session->id = sessionId;
    417     session->io = ioId;
    418     list_add_tail(&session_list, &session->node);
    419 
    420     ALOGV("get_session() created session %p", session);
    421 
    422     return session;
    423 }
    424 
    425 static int init() {
    426     void *lib_handle;
    427     const effect_descriptor_t *desc;
    428 
    429     if (init_status <= 0)
    430         return init_status;
    431 
    432     const char *path = EFFECTS_DESCRIPTOR_LIBRARY_PATH;
    433     int result = access(path, R_OK);
    434 
    435     if (result != 0) {
    436         path = EFFECTS_DESCRIPTOR_LIBRARY_PATH2;
    437         result = access(path, R_OK);
    438     }
    439 
    440     if (result == 0) {
    441         lib_handle = dlopen(path, RTLD_NOW);
    442         if (lib_handle == NULL) {
    443             ALOGE("%s: DLOPEN failed for %s", __func__, path);
    444         } else {
    445             ALOGV("%s: DLOPEN successful for %s", __func__, path);
    446             desc = (const effect_descriptor_t *)dlsym(lib_handle,
    447                                                         "qcom_product_aec_descriptor");
    448             if (desc)
    449                 descriptors[AEC_ID] = desc;
    450 
    451             desc = (const effect_descriptor_t *)dlsym(lib_handle,
    452                                                         "qcom_product_ns_descriptor");
    453             if (desc)
    454                 descriptors[NS_ID] = desc;
    455 
    456 //ENABLE_AGC
    457 //            desc = (const effect_descriptor_t *)dlsym(lib_handle,
    458 //                                                        "qcom_product_agc_descriptor");
    459 //            if (desc)
    460 //                descriptors[AGC_ID] = desc;
    461         }
    462     } else {
    463         ALOGE("%s: can't find %s", __func__, path);
    464     }
    465 
    466     uuid_to_id_table[AEC_ID] = FX_IID_AEC;
    467     uuid_to_id_table[NS_ID] = FX_IID_NS;
    468 //ENABLE_AGC uuid_to_id_table[AGC_ID] = FX_IID_AGC;
    469 
    470     list_init(&session_list);
    471 
    472     init_status = 0;
    473     return init_status;
    474 }
    475 
    476 static const effect_descriptor_t *get_descriptor(const effect_uuid_t *uuid)
    477 {
    478     size_t i;
    479     for (i = 0; i < NUM_ID; i++)
    480         if (memcmp(&descriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0)
    481             return descriptors[i];
    482 
    483     return NULL;
    484 }
    485 
    486 
    487 //------------------------------------------------------------------------------
    488 // Effect Control Interface Implementation
    489 //------------------------------------------------------------------------------
    490 
    491 static int fx_process(effect_handle_t     self,
    492                             audio_buffer_t    *inBuffer,
    493                             audio_buffer_t    *outBuffer)
    494 {
    495     struct effect_s *effect = (struct effect_s *)self;
    496     struct session_s *session;
    497 
    498     if (effect == NULL) {
    499         ALOGV("fx_process() ERROR effect == NULL");
    500         return -EINVAL;
    501     }
    502 
    503     if (inBuffer == NULL  || inBuffer->raw == NULL  ||
    504             outBuffer == NULL || outBuffer->raw == NULL) {
    505         ALOGW("fx_process() ERROR bad pointer");
    506         return -EINVAL;
    507     }
    508 
    509     session = (struct session_s *)effect->session;
    510 
    511     session->processed_msk |= (1<<effect->id);
    512 
    513     if ((session->processed_msk & session->enabled_msk) == session->enabled_msk) {
    514         effect->session->processed_msk = 0;
    515         return 0;
    516     } else
    517         return -ENODATA;
    518 }
    519 
    520 static int fx_command(effect_handle_t  self,
    521                             uint32_t            cmdCode,
    522                             uint32_t            cmdSize,
    523                             void                *pCmdData,
    524                             uint32_t            *replySize,
    525                             void                *pReplyData)
    526 {
    527     struct effect_s *effect = (struct effect_s *)self;
    528 
    529     if (effect == NULL)
    530         return -EINVAL;
    531 
    532     //ALOGV("fx_command: command %d cmdSize %d",cmdCode, cmdSize);
    533 
    534     switch (cmdCode) {
    535         case EFFECT_CMD_INIT:
    536             if (pReplyData == NULL || *replySize != sizeof(int))
    537                 return -EINVAL;
    538 
    539             *(int *)pReplyData = 0;
    540             break;
    541 
    542         case EFFECT_CMD_SET_CONFIG: {
    543             if (pCmdData    == NULL||
    544                     cmdSize     != sizeof(effect_config_t)||
    545                     pReplyData  == NULL||
    546                     *replySize  != sizeof(int)) {
    547                 ALOGV("fx_command() EFFECT_CMD_SET_CONFIG invalid args");
    548                 return -EINVAL;
    549             }
    550             *(int *)pReplyData = session_set_config(effect->session, (effect_config_t *)pCmdData);
    551             if (*(int *)pReplyData != 0)
    552                 break;
    553 
    554             if (effect->state != EFFECT_STATE_ACTIVE)
    555                 *(int *)pReplyData = effect_set_state(effect, EFFECT_STATE_CONFIG);
    556 
    557         } break;
    558 
    559         case EFFECT_CMD_GET_CONFIG:
    560             if (pReplyData == NULL ||
    561                     *replySize != sizeof(effect_config_t)) {
    562                 ALOGV("fx_command() EFFECT_CMD_GET_CONFIG invalid args");
    563                 return -EINVAL;
    564             }
    565 
    566             session_get_config(effect->session, (effect_config_t *)pReplyData);
    567             break;
    568 
    569         case EFFECT_CMD_RESET:
    570             break;
    571 
    572         case EFFECT_CMD_GET_PARAM: {
    573             if (pCmdData == NULL ||
    574                     cmdSize < (int)sizeof(effect_param_t) ||
    575                     pReplyData == NULL ||
    576                     *replySize < (int)sizeof(effect_param_t) ||
    577                     // constrain memcpy below
    578                     ((effect_param_t *)pCmdData)->psize > *replySize - sizeof(effect_param_t)) {
    579                 ALOGV("fx_command() EFFECT_CMD_GET_PARAM invalid args");
    580                 return -EINVAL;
    581             }
    582             effect_param_t *p = (effect_param_t *)pCmdData;
    583 
    584             memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
    585             p = (effect_param_t *)pReplyData;
    586             p->status = -ENOSYS;
    587 
    588         } break;
    589 
    590         case EFFECT_CMD_SET_PARAM: {
    591             if (pCmdData == NULL||
    592                     cmdSize < (int)sizeof(effect_param_t) ||
    593                     pReplyData == NULL ||
    594                     *replySize != sizeof(int32_t)) {
    595                 ALOGV("fx_command() EFFECT_CMD_SET_PARAM invalid args");
    596                 return -EINVAL;
    597             }
    598             effect_param_t *p = (effect_param_t *) pCmdData;
    599 
    600             if (p->psize != sizeof(int32_t)) {
    601                 ALOGV("fx_command() EFFECT_CMD_SET_PARAM invalid param format");
    602                 return -EINVAL;
    603             }
    604             *(int *)pReplyData = -ENOSYS;
    605         } break;
    606 
    607         case EFFECT_CMD_ENABLE:
    608             if (pReplyData == NULL || *replySize != sizeof(int)) {
    609                 ALOGV("fx_command() EFFECT_CMD_ENABLE invalid args");
    610                 return -EINVAL;
    611             }
    612             *(int *)pReplyData = effect_set_state(effect, EFFECT_STATE_ACTIVE);
    613             break;
    614 
    615         case EFFECT_CMD_DISABLE:
    616             if (pReplyData == NULL || *replySize != sizeof(int)) {
    617                 ALOGV("fx_command() EFFECT_CMD_DISABLE invalid args");
    618                 return -EINVAL;
    619             }
    620             *(int *)pReplyData  = effect_set_state(effect, EFFECT_STATE_CONFIG);
    621             break;
    622 
    623         case EFFECT_CMD_SET_DEVICE:
    624         case EFFECT_CMD_SET_INPUT_DEVICE:
    625         case EFFECT_CMD_SET_VOLUME:
    626         case EFFECT_CMD_SET_AUDIO_MODE:
    627             if (pCmdData == NULL ||
    628                     cmdSize != sizeof(uint32_t)) {
    629                 ALOGV("fx_command() %s invalid args",
    630                       cmdCode == EFFECT_CMD_SET_DEVICE ? "EFFECT_CMD_SET_DEVICE" :
    631                       cmdCode == EFFECT_CMD_SET_INPUT_DEVICE ? "EFFECT_CMD_SET_INPUT_DEVICE" :
    632                       cmdCode == EFFECT_CMD_SET_VOLUME ? "EFFECT_CMD_SET_VOLUME" :
    633                       cmdCode == EFFECT_CMD_SET_AUDIO_MODE ? "EFFECT_CMD_SET_AUDIO_MODE" :
    634                        "");
    635                 return -EINVAL;
    636             }
    637             ALOGV("fx_command() %s value %08x",
    638                   cmdCode == EFFECT_CMD_SET_DEVICE ? "EFFECT_CMD_SET_DEVICE" :
    639                   cmdCode == EFFECT_CMD_SET_INPUT_DEVICE ? "EFFECT_CMD_SET_INPUT_DEVICE" :
    640                   cmdCode == EFFECT_CMD_SET_VOLUME ? "EFFECT_CMD_SET_VOLUME" :
    641                   cmdCode == EFFECT_CMD_SET_AUDIO_MODE ? "EFFECT_CMD_SET_AUDIO_MODE":
    642                   "",
    643                   *(int *)pCmdData);
    644             break;
    645 
    646         default:
    647             return -EINVAL;
    648     }
    649     return 0;
    650 }
    651 
    652 
    653 static int fx_get_descriptor(effect_handle_t   self,
    654                                   effect_descriptor_t *pDescriptor)
    655 {
    656     struct effect_s *effect = (struct effect_s *)self;
    657 
    658     if (effect == NULL || pDescriptor == NULL)
    659         return -EINVAL;
    660 
    661     *pDescriptor = *descriptors[effect->id];
    662 
    663     return 0;
    664 }
    665 
    666 
    667 // effect_handle_t interface implementation for effect
    668 static const struct effect_interface_s effect_interface = {
    669     fx_process,
    670     fx_command,
    671     fx_get_descriptor,
    672     NULL
    673 };
    674 
    675 //------------------------------------------------------------------------------
    676 // Effect Library Interface Implementation
    677 //------------------------------------------------------------------------------
    678 
    679 static int lib_create(const effect_uuid_t *uuid,
    680                             int32_t             sessionId,
    681                             int32_t             ioId,
    682                             effect_handle_t  *pInterface)
    683 {
    684     ALOGV("lib_create: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
    685 
    686     int status;
    687     const effect_descriptor_t *desc;
    688     struct session_s *session;
    689     uint32_t id;
    690 
    691     if (init() != 0)
    692         return init_status;
    693 
    694     desc =  get_descriptor(uuid);
    695 
    696     if (desc == NULL) {
    697         ALOGW("lib_create: fx not found uuid: %08x", uuid->timeLow);
    698         return -EINVAL;
    699     }
    700     id = uuid_to_id(&desc->type);
    701 
    702     session = get_session(id, sessionId, ioId);
    703 
    704     if (session == NULL) {
    705         ALOGW("lib_create: no more session available");
    706         return -EINVAL;
    707     }
    708 
    709     status = session_create_effect(session, id, pInterface);
    710 
    711     if (status < 0 && session->created_msk == 0) {
    712         list_remove(&session->node);
    713         free(session);
    714     }
    715     return status;
    716 }
    717 
    718 static int lib_release(effect_handle_t interface)
    719 {
    720     struct listnode *node;
    721     struct session_s *session;
    722 
    723     ALOGV("lib_release %p", interface);
    724     if (init() != 0)
    725         return init_status;
    726 
    727     struct effect_s *fx = (struct effect_s *)interface;
    728 
    729     list_for_each(node, &session_list) {
    730         session = node_to_item(node, struct session_s, node);
    731         if (session == fx->session) {
    732             session_release_effect(fx->session, fx);
    733             return 0;
    734         }
    735     }
    736 
    737     return -EINVAL;
    738 }
    739 
    740 static int lib_get_descriptor(const effect_uuid_t *uuid,
    741                                    effect_descriptor_t *pDescriptor)
    742 {
    743     const effect_descriptor_t *desc;
    744 
    745     if (pDescriptor == NULL || uuid == NULL)
    746         return -EINVAL;
    747 
    748     if (init() != 0)
    749         return init_status;
    750 
    751     desc = get_descriptor(uuid);
    752     if (desc == NULL) {
    753         ALOGV("lib_get_descriptor() not found");
    754         return  -EINVAL;
    755     }
    756 
    757     ALOGV("lib_get_descriptor() got fx %s", desc->name);
    758 
    759     *pDescriptor = *desc;
    760     return 0;
    761 }
    762 
    763 // This is the only symbol that needs to be exported
    764 __attribute__ ((visibility ("default")))
    765 audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
    766     .tag = AUDIO_EFFECT_LIBRARY_TAG,
    767     .version = EFFECT_LIBRARY_API_VERSION,
    768     .name = "MSM8960 Audio Preprocessing Library",
    769     .implementor = "The Android Open Source Project",
    770     .create_effect = lib_create,
    771     .release_effect = lib_release,
    772     .get_descriptor = lib_get_descriptor
    773 };
    774