Home | History | Annotate | Download | only in preprocessing
      1 /*
      2  * Copyright (C) 2011 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 #include <stdlib.h>
     18 #include <string.h>
     19 #define LOG_TAG "PreProcessing"
     20 //#define LOG_NDEBUG 0
     21 #include <utils/Log.h>
     22 #include <utils/Timers.h>
     23 #include <hardware/audio_effect.h>
     24 #include <audio_effects/effect_aec.h>
     25 #include <audio_effects/effect_agc.h>
     26 #include <audio_effects/effect_ns.h>
     27 #include <module_common_types.h>
     28 #include <audio_processing.h>
     29 #include "speex/speex_resampler.h"
     30 
     31 // undefine to perform multi channels API functional tests
     32 //#define DUAL_MIC_TEST
     33 
     34 //------------------------------------------------------------------------------
     35 // local definitions
     36 //------------------------------------------------------------------------------
     37 
     38 // maximum number of sessions
     39 #define PREPROC_NUM_SESSIONS 8
     40 
     41 // types of pre processing modules
     42 enum preproc_id
     43 {
     44     PREPROC_AGC,        // Automatic Gain Control
     45     PREPROC_AEC,        // Acoustic Echo Canceler
     46     PREPROC_NS,         // Noise Suppressor
     47     PREPROC_NUM_EFFECTS
     48 };
     49 
     50 // Session state
     51 enum preproc_session_state {
     52     PREPROC_SESSION_STATE_INIT,        // initialized
     53     PREPROC_SESSION_STATE_CONFIG       // configuration received
     54 };
     55 
     56 // Effect/Preprocessor state
     57 enum preproc_effect_state {
     58     PREPROC_EFFECT_STATE_INIT,         // initialized
     59     PREPROC_EFFECT_STATE_CREATED,      // webRTC engine created
     60     PREPROC_EFFECT_STATE_CONFIG,       // configuration received/disabled
     61     PREPROC_EFFECT_STATE_ACTIVE        // active/enabled
     62 };
     63 
     64 // handle on webRTC engine
     65 typedef void* preproc_fx_handle_t;
     66 
     67 typedef struct preproc_session_s preproc_session_t;
     68 typedef struct preproc_effect_s preproc_effect_t;
     69 typedef struct preproc_ops_s preproc_ops_t;
     70 
     71 // Effect operation table. Functions for all pre processors are declared in sPreProcOps[] table.
     72 // Function pointer can be null if no action required.
     73 struct preproc_ops_s {
     74     int (* create)(preproc_effect_t *fx);
     75     int (* init)(preproc_effect_t *fx);
     76     int (* reset)(preproc_effect_t *fx);
     77     void (* enable)(preproc_effect_t *fx);
     78     void (* disable)(preproc_effect_t *fx);
     79     int (* set_parameter)(preproc_effect_t *fx, void *param, void *value);
     80     int (* get_parameter)(preproc_effect_t *fx, void *param, uint32_t *size, void *value);
     81     int (* set_device)(preproc_effect_t *fx, uint32_t device);
     82 };
     83 
     84 // Effect context
     85 struct preproc_effect_s {
     86     const struct effect_interface_s *itfe;
     87     uint32_t procId;                // type of pre processor (enum preproc_id)
     88     uint32_t state;                 // current state (enum preproc_effect_state)
     89     preproc_session_t *session;     // session the effect is on
     90     const preproc_ops_t *ops;       // effect ops table
     91     preproc_fx_handle_t engine;     // handle on webRTC engine
     92 #ifdef DUAL_MIC_TEST
     93     bool aux_channels_on;           // support auxiliary channels
     94     size_t cur_channel_config;      // current auciliary channel configuration
     95 #endif
     96 };
     97 
     98 // Session context
     99 struct preproc_session_s {
    100     struct preproc_effect_s effects[PREPROC_NUM_EFFECTS]; // effects in this session
    101     uint32_t state;                     // current state (enum preproc_session_state)
    102     int id;                             // audio session ID
    103     int io;                             // handle of input stream this session is on
    104     webrtc::AudioProcessing* apm;       // handle on webRTC audio processing module (APM)
    105     size_t apmFrameCount;               // buffer size for webRTC process (10 ms)
    106     uint32_t apmSamplingRate;           // webRTC APM sampling rate (8/16 or 32 kHz)
    107     size_t frameCount;                  // buffer size before input resampler ( <=> apmFrameCount)
    108     uint32_t samplingRate;              // sampling rate at effect process interface
    109     uint32_t inChannelCount;            // input channel count
    110     uint32_t outChannelCount;           // output channel count
    111     uint32_t createdMsk;                // bit field containing IDs of crested pre processors
    112     uint32_t enabledMsk;                // bit field containing IDs of enabled pre processors
    113     uint32_t processedMsk;              // bit field containing IDs of pre processors already
    114                                         // processed in current round
    115     webrtc::AudioFrame *procFrame;      // audio frame passed to webRTC AMP ProcessStream()
    116     int16_t *inBuf;                     // input buffer used when resampling
    117     size_t inBufSize;                   // input buffer size in frames
    118     size_t framesIn;                    // number of frames in input buffer
    119     SpeexResamplerState *inResampler;   // handle on input speex resampler
    120     int16_t *outBuf;                    // output buffer used when resampling
    121     size_t outBufSize;                  // output buffer size in frames
    122     size_t framesOut;                   // number of frames in output buffer
    123     SpeexResamplerState *outResampler;  // handle on output speex resampler
    124     uint32_t revChannelCount;           // number of channels on reverse stream
    125     uint32_t revEnabledMsk;             // bit field containing IDs of enabled pre processors
    126                                         // with reverse channel
    127     uint32_t revProcessedMsk;           // bit field containing IDs of pre processors with reverse
    128                                         // channel already processed in current round
    129     webrtc::AudioFrame *revFrame;       // audio frame passed to webRTC AMP AnalyzeReverseStream()
    130     int16_t *revBuf;                    // reverse channel input buffer
    131     size_t revBufSize;                  // reverse channel input buffer size
    132     size_t framesRev;                   // number of frames in reverse channel input buffer
    133     SpeexResamplerState *revResampler;  // handle on reverse channel input speex resampler
    134 };
    135 
    136 #ifdef DUAL_MIC_TEST
    137 enum {
    138     PREPROC_CMD_DUAL_MIC_ENABLE = EFFECT_CMD_FIRST_PROPRIETARY, // enable dual mic mode
    139     PREPROC_CMD_DUAL_MIC_PCM_DUMP_START,                        // start pcm capture
    140     PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP                          // stop pcm capture
    141 };
    142 
    143 enum {
    144     CHANNEL_CFG_MONO,
    145     CHANNEL_CFG_STEREO,
    146     CHANNEL_CFG_MONO_AUX,
    147     CHANNEL_CFG_STEREO_AUX,
    148     CHANNEL_CFG_CNT,
    149     CHANNEL_CFG_FIRST_AUX = CHANNEL_CFG_MONO_AUX,
    150 };
    151 
    152 const channel_config_t sDualMicConfigs[CHANNEL_CFG_CNT] = {
    153         {AUDIO_CHANNEL_IN_MONO , 0},
    154         {AUDIO_CHANNEL_IN_STEREO , 0},
    155         {AUDIO_CHANNEL_IN_FRONT , AUDIO_CHANNEL_IN_BACK},
    156         {AUDIO_CHANNEL_IN_STEREO , AUDIO_CHANNEL_IN_RIGHT}
    157 };
    158 
    159 bool sHasAuxChannels[PREPROC_NUM_EFFECTS] = {
    160         false,   // PREPROC_AGC
    161         true,   // PREPROC_AEC
    162         true,   // PREPROC_NS
    163 };
    164 
    165 bool gDualMicEnabled;
    166 FILE *gPcmDumpFh;
    167 static pthread_mutex_t gPcmDumpLock = PTHREAD_MUTEX_INITIALIZER;
    168 #endif
    169 
    170 
    171 //------------------------------------------------------------------------------
    172 // Effect descriptors
    173 //------------------------------------------------------------------------------
    174 
    175 // UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html
    176 // as the pre processing effects are not defined by OpenSL ES
    177 
    178 // Automatic Gain Control
    179 static const effect_descriptor_t sAgcDescriptor = {
    180         { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
    181         { 0xaa8130e0, 0x66fc, 0x11e0, 0xbad0, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
    182         EFFECT_CONTROL_API_VERSION,
    183         (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
    184         0, //FIXME indicate CPU load
    185         0, //FIXME indicate memory usage
    186         "Automatic Gain Control",
    187         "The Android Open Source Project"
    188 };
    189 
    190 // Acoustic Echo Cancellation
    191 static const effect_descriptor_t sAecDescriptor = {
    192         { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
    193         { 0xbb392ec0, 0x8d4d, 0x11e0, 0xa896, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
    194         EFFECT_CONTROL_API_VERSION,
    195         (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
    196         0, //FIXME indicate CPU load
    197         0, //FIXME indicate memory usage
    198         "Acoustic Echo Canceler",
    199         "The Android Open Source Project"
    200 };
    201 
    202 // Noise suppression
    203 static const effect_descriptor_t sNsDescriptor = {
    204         { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
    205         { 0xc06c8400, 0x8e06, 0x11e0, 0x9cb6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
    206         EFFECT_CONTROL_API_VERSION,
    207         (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
    208         0, //FIXME indicate CPU load
    209         0, //FIXME indicate memory usage
    210         "Noise Suppression",
    211         "The Android Open Source Project"
    212 };
    213 
    214 
    215 static const effect_descriptor_t *sDescriptors[PREPROC_NUM_EFFECTS] = {
    216         &sAgcDescriptor,
    217         &sAecDescriptor,
    218         &sNsDescriptor
    219 };
    220 
    221 //------------------------------------------------------------------------------
    222 // Helper functions
    223 //------------------------------------------------------------------------------
    224 
    225 const effect_uuid_t * const sUuidToPreProcTable[PREPROC_NUM_EFFECTS] = {
    226         FX_IID_AGC,
    227         FX_IID_AEC,
    228         FX_IID_NS
    229 };
    230 
    231 
    232 const effect_uuid_t * ProcIdToUuid(int procId)
    233 {
    234     if (procId >= PREPROC_NUM_EFFECTS) {
    235         return EFFECT_UUID_NULL;
    236     }
    237     return sUuidToPreProcTable[procId];
    238 }
    239 
    240 uint32_t UuidToProcId(const effect_uuid_t * uuid)
    241 {
    242     size_t i;
    243     for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
    244         if (memcmp(uuid, sUuidToPreProcTable[i], sizeof(*uuid)) == 0) {
    245             break;
    246         }
    247     }
    248     return i;
    249 }
    250 
    251 bool HasReverseStream(uint32_t procId)
    252 {
    253     if (procId == PREPROC_AEC) {
    254         return true;
    255     }
    256     return false;
    257 }
    258 
    259 
    260 //------------------------------------------------------------------------------
    261 // Automatic Gain Control (AGC)
    262 //------------------------------------------------------------------------------
    263 
    264 static const int kAgcDefaultTargetLevel = 3;
    265 static const int kAgcDefaultCompGain = 9;
    266 static const bool kAgcDefaultLimiter = true;
    267 
    268 int  AgcInit (preproc_effect_t *effect)
    269 {
    270     ALOGV("AgcInit");
    271     webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
    272     agc->set_mode(webrtc::GainControl::kFixedDigital);
    273     agc->set_target_level_dbfs(kAgcDefaultTargetLevel);
    274     agc->set_compression_gain_db(kAgcDefaultCompGain);
    275     agc->enable_limiter(kAgcDefaultLimiter);
    276     return 0;
    277 }
    278 
    279 int  AgcCreate(preproc_effect_t *effect)
    280 {
    281     webrtc::GainControl *agc = effect->session->apm->gain_control();
    282     ALOGV("AgcCreate got agc %p", agc);
    283     if (agc == NULL) {
    284         ALOGW("AgcCreate Error");
    285         return -ENOMEM;
    286     }
    287     effect->engine = static_cast<preproc_fx_handle_t>(agc);
    288     AgcInit(effect);
    289     return 0;
    290 }
    291 
    292 int AgcGetParameter(preproc_effect_t *effect,
    293                     void *pParam,
    294                     uint32_t *pValueSize,
    295                     void *pValue)
    296 {
    297     int status = 0;
    298     uint32_t param = *(uint32_t *)pParam;
    299     t_agc_settings *pProperties = (t_agc_settings *)pValue;
    300     webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
    301 
    302     switch (param) {
    303     case AGC_PARAM_TARGET_LEVEL:
    304     case AGC_PARAM_COMP_GAIN:
    305         if (*pValueSize < sizeof(int16_t)) {
    306             *pValueSize = 0;
    307             return -EINVAL;
    308         }
    309         break;
    310     case AGC_PARAM_LIMITER_ENA:
    311         if (*pValueSize < sizeof(bool)) {
    312             *pValueSize = 0;
    313             return -EINVAL;
    314         }
    315         break;
    316     case AGC_PARAM_PROPERTIES:
    317         if (*pValueSize < sizeof(t_agc_settings)) {
    318             *pValueSize = 0;
    319             return -EINVAL;
    320         }
    321         break;
    322 
    323     default:
    324         ALOGW("AgcGetParameter() unknown param %08x", param);
    325         status = -EINVAL;
    326         break;
    327     }
    328 
    329     switch (param) {
    330     case AGC_PARAM_TARGET_LEVEL:
    331         *(int16_t *) pValue = (int16_t)(agc->target_level_dbfs() * -100);
    332         ALOGV("AgcGetParameter() target level %d milliBels", *(int16_t *) pValue);
    333         break;
    334     case AGC_PARAM_COMP_GAIN:
    335         *(int16_t *) pValue = (int16_t)(agc->compression_gain_db() * 100);
    336         ALOGV("AgcGetParameter() comp gain %d milliBels", *(int16_t *) pValue);
    337         break;
    338     case AGC_PARAM_LIMITER_ENA:
    339         *(bool *) pValue = (bool)agc->is_limiter_enabled();
    340         ALOGV("AgcGetParameter() limiter enabled %s",
    341              (*(int16_t *) pValue != 0) ? "true" : "false");
    342         break;
    343     case AGC_PARAM_PROPERTIES:
    344         pProperties->targetLevel = (int16_t)(agc->target_level_dbfs() * -100);
    345         pProperties->compGain = (int16_t)(agc->compression_gain_db() * 100);
    346         pProperties->limiterEnabled = (bool)agc->is_limiter_enabled();
    347         break;
    348     default:
    349         ALOGW("AgcGetParameter() unknown param %d", param);
    350         status = -EINVAL;
    351         break;
    352     }
    353     return status;
    354 }
    355 
    356 int AgcSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
    357 {
    358     int status = 0;
    359     uint32_t param = *(uint32_t *)pParam;
    360     t_agc_settings *pProperties = (t_agc_settings *)pValue;
    361     webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
    362 
    363     switch (param) {
    364     case AGC_PARAM_TARGET_LEVEL:
    365         ALOGV("AgcSetParameter() target level %d milliBels", *(int16_t *)pValue);
    366         status = agc->set_target_level_dbfs(-(*(int16_t *)pValue / 100));
    367         break;
    368     case AGC_PARAM_COMP_GAIN:
    369         ALOGV("AgcSetParameter() comp gain %d milliBels", *(int16_t *)pValue);
    370         status = agc->set_compression_gain_db(*(int16_t *)pValue / 100);
    371         break;
    372     case AGC_PARAM_LIMITER_ENA:
    373         ALOGV("AgcSetParameter() limiter enabled %s", *(bool *)pValue ? "true" : "false");
    374         status = agc->enable_limiter(*(bool *)pValue);
    375         break;
    376     case AGC_PARAM_PROPERTIES:
    377         ALOGV("AgcSetParameter() properties level %d, gain %d limiter %d",
    378              pProperties->targetLevel,
    379              pProperties->compGain,
    380              pProperties->limiterEnabled);
    381         status = agc->set_target_level_dbfs(-(pProperties->targetLevel / 100));
    382         if (status != 0) break;
    383         status = agc->set_compression_gain_db(pProperties->compGain / 100);
    384         if (status != 0) break;
    385         status = agc->enable_limiter(pProperties->limiterEnabled);
    386         break;
    387     default:
    388         ALOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
    389         status = -EINVAL;
    390         break;
    391     }
    392 
    393     ALOGV("AgcSetParameter() done status %d", status);
    394 
    395     return status;
    396 }
    397 
    398 void AgcEnable(preproc_effect_t *effect)
    399 {
    400     webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
    401     ALOGV("AgcEnable agc %p", agc);
    402     agc->Enable(true);
    403 }
    404 
    405 void AgcDisable(preproc_effect_t *effect)
    406 {
    407     ALOGV("AgcDisable");
    408     webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
    409     agc->Enable(false);
    410 }
    411 
    412 
    413 static const preproc_ops_t sAgcOps = {
    414         AgcCreate,
    415         AgcInit,
    416         NULL,
    417         AgcEnable,
    418         AgcDisable,
    419         AgcSetParameter,
    420         AgcGetParameter,
    421         NULL
    422 };
    423 
    424 
    425 //------------------------------------------------------------------------------
    426 // Acoustic Echo Canceler (AEC)
    427 //------------------------------------------------------------------------------
    428 
    429 static const webrtc::EchoControlMobile::RoutingMode kAecDefaultMode =
    430         webrtc::EchoControlMobile::kEarpiece;
    431 static const bool kAecDefaultComfortNoise = true;
    432 
    433 int  AecInit (preproc_effect_t *effect)
    434 {
    435     ALOGV("AecInit");
    436     webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
    437     aec->set_routing_mode(kAecDefaultMode);
    438     aec->enable_comfort_noise(kAecDefaultComfortNoise);
    439     return 0;
    440 }
    441 
    442 int  AecCreate(preproc_effect_t *effect)
    443 {
    444     webrtc::EchoControlMobile *aec = effect->session->apm->echo_control_mobile();
    445     ALOGV("AecCreate got aec %p", aec);
    446     if (aec == NULL) {
    447         ALOGW("AgcCreate Error");
    448         return -ENOMEM;
    449     }
    450     effect->engine = static_cast<preproc_fx_handle_t>(aec);
    451     AecInit (effect);
    452     return 0;
    453 }
    454 
    455 int AecGetParameter(preproc_effect_t  *effect,
    456                     void              *pParam,
    457                     uint32_t          *pValueSize,
    458                     void              *pValue)
    459 {
    460     int status = 0;
    461     uint32_t param = *(uint32_t *)pParam;
    462 
    463     if (*pValueSize < sizeof(uint32_t)) {
    464         return -EINVAL;
    465     }
    466     switch (param) {
    467     case AEC_PARAM_ECHO_DELAY:
    468     case AEC_PARAM_PROPERTIES:
    469         *(uint32_t *)pValue = 1000 * effect->session->apm->stream_delay_ms();
    470         ALOGV("AecGetParameter() echo delay %d us", *(uint32_t *)pValue);
    471         break;
    472     default:
    473         ALOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
    474         status = -EINVAL;
    475         break;
    476     }
    477     return status;
    478 }
    479 
    480 int AecSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
    481 {
    482     int status = 0;
    483     uint32_t param = *(uint32_t *)pParam;
    484     uint32_t value = *(uint32_t *)pValue;
    485 
    486     switch (param) {
    487     case AEC_PARAM_ECHO_DELAY:
    488     case AEC_PARAM_PROPERTIES:
    489         status = effect->session->apm->set_stream_delay_ms(value/1000);
    490         ALOGV("AecSetParameter() echo delay %d us, status %d", value, status);
    491         break;
    492     default:
    493         ALOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
    494         status = -EINVAL;
    495         break;
    496     }
    497     return status;
    498 }
    499 
    500 void AecEnable(preproc_effect_t *effect)
    501 {
    502     webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
    503     ALOGV("AecEnable aec %p", aec);
    504     aec->Enable(true);
    505 }
    506 
    507 void AecDisable(preproc_effect_t *effect)
    508 {
    509     ALOGV("AecDisable");
    510     webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
    511     aec->Enable(false);
    512 }
    513 
    514 int AecSetDevice(preproc_effect_t *effect, uint32_t device)
    515 {
    516     ALOGV("AecSetDevice %08x", device);
    517     webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
    518     webrtc::EchoControlMobile::RoutingMode mode = webrtc::EchoControlMobile::kQuietEarpieceOrHeadset;
    519 
    520     if (audio_is_input_device(device)) {
    521         return 0;
    522     }
    523 
    524     switch(device) {
    525     case AUDIO_DEVICE_OUT_EARPIECE:
    526         mode = webrtc::EchoControlMobile::kEarpiece;
    527         break;
    528     case AUDIO_DEVICE_OUT_SPEAKER:
    529         mode = webrtc::EchoControlMobile::kSpeakerphone;
    530         break;
    531     case AUDIO_DEVICE_OUT_WIRED_HEADSET:
    532     case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
    533     default:
    534         break;
    535     }
    536     aec->set_routing_mode(mode);
    537     return 0;
    538 }
    539 
    540 static const preproc_ops_t sAecOps = {
    541         AecCreate,
    542         AecInit,
    543         NULL,
    544         AecEnable,
    545         AecDisable,
    546         AecSetParameter,
    547         AecGetParameter,
    548         AecSetDevice
    549 };
    550 
    551 //------------------------------------------------------------------------------
    552 // Noise Suppression (NS)
    553 //------------------------------------------------------------------------------
    554 
    555 static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
    556 
    557 int  NsInit (preproc_effect_t *effect)
    558 {
    559     ALOGV("NsInit");
    560     webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
    561     ns->set_level(kNsDefaultLevel);
    562     return 0;
    563 }
    564 
    565 int  NsCreate(preproc_effect_t *effect)
    566 {
    567     webrtc::NoiseSuppression *ns = effect->session->apm->noise_suppression();
    568     ALOGV("NsCreate got ns %p", ns);
    569     if (ns == NULL) {
    570         ALOGW("AgcCreate Error");
    571         return -ENOMEM;
    572     }
    573     effect->engine = static_cast<preproc_fx_handle_t>(ns);
    574     NsInit (effect);
    575     return 0;
    576 }
    577 
    578 int NsGetParameter(preproc_effect_t  *effect __unused,
    579                    void              *pParam __unused,
    580                    uint32_t          *pValueSize __unused,
    581                    void              *pValue __unused)
    582 {
    583     int status = 0;
    584     return status;
    585 }
    586 
    587 int NsSetParameter (preproc_effect_t *effect __unused,
    588                     void *pParam __unused,
    589                     void *pValue __unused)
    590 {
    591     int status = 0;
    592     return status;
    593 }
    594 
    595 void NsEnable(preproc_effect_t *effect)
    596 {
    597     webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
    598     ALOGV("NsEnable ns %p", ns);
    599     ns->Enable(true);
    600 }
    601 
    602 void NsDisable(preproc_effect_t *effect)
    603 {
    604     ALOGV("NsDisable");
    605     webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
    606     ns->Enable(false);
    607 }
    608 
    609 static const preproc_ops_t sNsOps = {
    610         NsCreate,
    611         NsInit,
    612         NULL,
    613         NsEnable,
    614         NsDisable,
    615         NsSetParameter,
    616         NsGetParameter,
    617         NULL
    618 };
    619 
    620 
    621 static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
    622         &sAgcOps,
    623         &sAecOps,
    624         &sNsOps
    625 };
    626 
    627 
    628 //------------------------------------------------------------------------------
    629 // Effect functions
    630 //------------------------------------------------------------------------------
    631 
    632 void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled);
    633 
    634 extern "C" const struct effect_interface_s sEffectInterface;
    635 extern "C" const struct effect_interface_s sEffectInterfaceReverse;
    636 
    637 #define BAD_STATE_ABORT(from, to) \
    638         LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to);
    639 
    640 int Effect_SetState(preproc_effect_t *effect, uint32_t state)
    641 {
    642     int status = 0;
    643     ALOGV("Effect_SetState proc %d, new %d old %d", effect->procId, state, effect->state);
    644     switch(state) {
    645     case PREPROC_EFFECT_STATE_INIT:
    646         switch(effect->state) {
    647         case PREPROC_EFFECT_STATE_ACTIVE:
    648             effect->ops->disable(effect);
    649             Session_SetProcEnabled(effect->session, effect->procId, false);
    650         case PREPROC_EFFECT_STATE_CONFIG:
    651         case PREPROC_EFFECT_STATE_CREATED:
    652         case PREPROC_EFFECT_STATE_INIT:
    653             break;
    654         default:
    655             BAD_STATE_ABORT(effect->state, state);
    656         }
    657         break;
    658     case PREPROC_EFFECT_STATE_CREATED:
    659         switch(effect->state) {
    660         case PREPROC_EFFECT_STATE_INIT:
    661             status = effect->ops->create(effect);
    662             break;
    663         case PREPROC_EFFECT_STATE_CREATED:
    664         case PREPROC_EFFECT_STATE_ACTIVE:
    665         case PREPROC_EFFECT_STATE_CONFIG:
    666             ALOGE("Effect_SetState invalid transition");
    667             status = -ENOSYS;
    668             break;
    669         default:
    670             BAD_STATE_ABORT(effect->state, state);
    671         }
    672         break;
    673     case PREPROC_EFFECT_STATE_CONFIG:
    674         switch(effect->state) {
    675         case PREPROC_EFFECT_STATE_INIT:
    676             ALOGE("Effect_SetState invalid transition");
    677             status = -ENOSYS;
    678             break;
    679         case PREPROC_EFFECT_STATE_ACTIVE:
    680             effect->ops->disable(effect);
    681             Session_SetProcEnabled(effect->session, effect->procId, false);
    682             break;
    683         case PREPROC_EFFECT_STATE_CREATED:
    684         case PREPROC_EFFECT_STATE_CONFIG:
    685             break;
    686         default:
    687             BAD_STATE_ABORT(effect->state, state);
    688         }
    689         break;
    690     case PREPROC_EFFECT_STATE_ACTIVE:
    691         switch(effect->state) {
    692         case PREPROC_EFFECT_STATE_INIT:
    693         case PREPROC_EFFECT_STATE_CREATED:
    694             ALOGE("Effect_SetState invalid transition");
    695             status = -ENOSYS;
    696             break;
    697         case PREPROC_EFFECT_STATE_ACTIVE:
    698             // enabling an already enabled effect is just ignored
    699             break;
    700         case PREPROC_EFFECT_STATE_CONFIG:
    701             effect->ops->enable(effect);
    702             Session_SetProcEnabled(effect->session, effect->procId, true);
    703             break;
    704         default:
    705             BAD_STATE_ABORT(effect->state, state);
    706         }
    707         break;
    708     default:
    709         BAD_STATE_ABORT(effect->state, state);
    710     }
    711     if (status == 0) {
    712         effect->state = state;
    713     }
    714     return status;
    715 }
    716 
    717 int Effect_Init(preproc_effect_t *effect, uint32_t procId)
    718 {
    719     if (HasReverseStream(procId)) {
    720         effect->itfe = &sEffectInterfaceReverse;
    721     } else {
    722         effect->itfe = &sEffectInterface;
    723     }
    724     effect->ops = sPreProcOps[procId];
    725     effect->procId = procId;
    726     effect->state = PREPROC_EFFECT_STATE_INIT;
    727     return 0;
    728 }
    729 
    730 int Effect_Create(preproc_effect_t *effect,
    731                preproc_session_t *session,
    732                effect_handle_t  *interface)
    733 {
    734     effect->session = session;
    735     *interface = (effect_handle_t)&effect->itfe;
    736     return Effect_SetState(effect, PREPROC_EFFECT_STATE_CREATED);
    737 }
    738 
    739 int Effect_Release(preproc_effect_t *effect)
    740 {
    741     return Effect_SetState(effect, PREPROC_EFFECT_STATE_INIT);
    742 }
    743 
    744 
    745 //------------------------------------------------------------------------------
    746 // Session functions
    747 //------------------------------------------------------------------------------
    748 
    749 #define RESAMPLER_QUALITY SPEEX_RESAMPLER_QUALITY_VOIP
    750 
    751 static const int kPreprocDefaultSr = 16000;
    752 static const int kPreProcDefaultCnl = 1;
    753 
    754 int Session_Init(preproc_session_t *session)
    755 {
    756     size_t i;
    757     int status = 0;
    758 
    759     session->state = PREPROC_SESSION_STATE_INIT;
    760     session->id = 0;
    761     session->io = 0;
    762     session->createdMsk = 0;
    763     session->apm = NULL;
    764     for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
    765         status = Effect_Init(&session->effects[i], i);
    766     }
    767     return status;
    768 }
    769 
    770 
    771 extern "C" int Session_CreateEffect(preproc_session_t *session,
    772                                     int32_t procId,
    773                                     effect_handle_t  *interface)
    774 {
    775     int status = -ENOMEM;
    776 
    777     ALOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
    778 
    779     if (session->createdMsk == 0) {
    780         session->apm = webrtc::AudioProcessing::Create(session->io);
    781         if (session->apm == NULL) {
    782             ALOGW("Session_CreateEffect could not get apm engine");
    783             goto error;
    784         }
    785         session->apm->set_sample_rate_hz(kPreprocDefaultSr);
    786         session->apm->set_num_channels(kPreProcDefaultCnl, kPreProcDefaultCnl);
    787         session->apm->set_num_reverse_channels(kPreProcDefaultCnl);
    788         session->procFrame = new webrtc::AudioFrame();
    789         if (session->procFrame == NULL) {
    790             ALOGW("Session_CreateEffect could not allocate audio frame");
    791             goto error;
    792         }
    793         session->revFrame = new webrtc::AudioFrame();
    794         if (session->revFrame == NULL) {
    795             ALOGW("Session_CreateEffect could not allocate reverse audio frame");
    796             goto error;
    797         }
    798         session->apmSamplingRate = kPreprocDefaultSr;
    799         session->apmFrameCount = (kPreprocDefaultSr) / 100;
    800         session->frameCount = session->apmFrameCount;
    801         session->samplingRate = kPreprocDefaultSr;
    802         session->inChannelCount = kPreProcDefaultCnl;
    803         session->outChannelCount = kPreProcDefaultCnl;
    804         session->procFrame->_frequencyInHz = kPreprocDefaultSr;
    805         session->procFrame->_audioChannel = kPreProcDefaultCnl;
    806         session->revChannelCount = kPreProcDefaultCnl;
    807         session->revFrame->_frequencyInHz = kPreprocDefaultSr;
    808         session->revFrame->_audioChannel = kPreProcDefaultCnl;
    809         session->enabledMsk = 0;
    810         session->processedMsk = 0;
    811         session->revEnabledMsk = 0;
    812         session->revProcessedMsk = 0;
    813         session->inResampler = NULL;
    814         session->inBuf = NULL;
    815         session->inBufSize = 0;
    816         session->outResampler = NULL;
    817         session->outBuf = NULL;
    818         session->outBufSize = 0;
    819         session->revResampler = NULL;
    820         session->revBuf = NULL;
    821         session->revBufSize = 0;
    822     }
    823     status = Effect_Create(&session->effects[procId], session, interface);
    824     if (status < 0) {
    825         goto error;
    826     }
    827     ALOGV("Session_CreateEffect OK");
    828     session->createdMsk |= (1<<procId);
    829     return status;
    830 
    831 error:
    832     if (session->createdMsk == 0) {
    833         delete session->revFrame;
    834         session->revFrame = NULL;
    835         delete session->procFrame;
    836         session->procFrame = NULL;
    837         webrtc::AudioProcessing::Destroy(session->apm);
    838         session->apm = NULL;
    839     }
    840     return status;
    841 }
    842 
    843 int Session_ReleaseEffect(preproc_session_t *session,
    844                           preproc_effect_t *fx)
    845 {
    846     ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
    847     session->createdMsk &= ~(1<<fx->procId);
    848     if (session->createdMsk == 0) {
    849         webrtc::AudioProcessing::Destroy(session->apm);
    850         session->apm = NULL;
    851         delete session->procFrame;
    852         session->procFrame = NULL;
    853         delete session->revFrame;
    854         session->revFrame = NULL;
    855         if (session->inResampler != NULL) {
    856             speex_resampler_destroy(session->inResampler);
    857             session->inResampler = NULL;
    858         }
    859         if (session->outResampler != NULL) {
    860             speex_resampler_destroy(session->outResampler);
    861             session->outResampler = NULL;
    862         }
    863         if (session->revResampler != NULL) {
    864             speex_resampler_destroy(session->revResampler);
    865             session->revResampler = NULL;
    866         }
    867         delete session->inBuf;
    868         session->inBuf = NULL;
    869         delete session->outBuf;
    870         session->outBuf = NULL;
    871         delete session->revBuf;
    872         session->revBuf = NULL;
    873 
    874         session->io = 0;
    875     }
    876 
    877     return 0;
    878 }
    879 
    880 
    881 int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
    882 {
    883     uint32_t sr;
    884     uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
    885     uint32_t outCnl = audio_channel_count_from_out_mask(config->outputCfg.channels);
    886 
    887     if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
    888         config->inputCfg.format != config->outputCfg.format ||
    889         config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
    890         return -EINVAL;
    891     }
    892 
    893     ALOGV("Session_SetConfig sr %d cnl %08x",
    894          config->inputCfg.samplingRate, config->inputCfg.channels);
    895     int status;
    896 
    897     // if at least one process is enabled, do not accept configuration changes
    898     if (session->enabledMsk) {
    899         if (session->samplingRate != config->inputCfg.samplingRate ||
    900                 session->inChannelCount != inCnl ||
    901                 session->outChannelCount != outCnl) {
    902             return -ENOSYS;
    903         } else {
    904             return 0;
    905         }
    906     }
    907 
    908     // AEC implementation is limited to 16kHz
    909     if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
    910         session->apmSamplingRate = 32000;
    911     } else
    912     if (config->inputCfg.samplingRate >= 16000) {
    913         session->apmSamplingRate = 16000;
    914     } else if (config->inputCfg.samplingRate >= 8000) {
    915         session->apmSamplingRate = 8000;
    916     }
    917     status = session->apm->set_sample_rate_hz(session->apmSamplingRate);
    918     if (status < 0) {
    919         return -EINVAL;
    920     }
    921     status = session->apm->set_num_channels(inCnl, outCnl);
    922     if (status < 0) {
    923         return -EINVAL;
    924     }
    925     status = session->apm->set_num_reverse_channels(inCnl);
    926     if (status < 0) {
    927         return -EINVAL;
    928     }
    929 
    930     session->samplingRate = config->inputCfg.samplingRate;
    931     session->apmFrameCount = session->apmSamplingRate / 100;
    932     if (session->samplingRate == session->apmSamplingRate) {
    933         session->frameCount = session->apmFrameCount;
    934     } else {
    935         session->frameCount = (session->apmFrameCount * session->samplingRate) /
    936                 session->apmSamplingRate  + 1;
    937     }
    938     session->inChannelCount = inCnl;
    939     session->outChannelCount = outCnl;
    940     session->procFrame->_audioChannel = inCnl;
    941     session->procFrame->_frequencyInHz = session->apmSamplingRate;
    942 
    943     session->revChannelCount = inCnl;
    944     session->revFrame->_audioChannel = inCnl;
    945     session->revFrame->_frequencyInHz = session->apmSamplingRate;
    946 
    947     // force process buffer reallocation
    948     session->inBufSize = 0;
    949     session->outBufSize = 0;
    950     session->framesIn = 0;
    951     session->framesOut = 0;
    952 
    953 
    954     if (session->inResampler != NULL) {
    955         speex_resampler_destroy(session->inResampler);
    956         session->inResampler = NULL;
    957     }
    958     if (session->outResampler != NULL) {
    959         speex_resampler_destroy(session->outResampler);
    960         session->outResampler = NULL;
    961     }
    962     if (session->revResampler != NULL) {
    963         speex_resampler_destroy(session->revResampler);
    964         session->revResampler = NULL;
    965     }
    966     if (session->samplingRate != session->apmSamplingRate) {
    967         int error;
    968         session->inResampler = speex_resampler_init(session->inChannelCount,
    969                                                     session->samplingRate,
    970                                                     session->apmSamplingRate,
    971                                                     RESAMPLER_QUALITY,
    972                                                     &error);
    973         if (session->inResampler == NULL) {
    974             ALOGW("Session_SetConfig Cannot create speex resampler: %s",
    975                  speex_resampler_strerror(error));
    976             return -EINVAL;
    977         }
    978         session->outResampler = speex_resampler_init(session->outChannelCount,
    979                                                     session->apmSamplingRate,
    980                                                     session->samplingRate,
    981                                                     RESAMPLER_QUALITY,
    982                                                     &error);
    983         if (session->outResampler == NULL) {
    984             ALOGW("Session_SetConfig Cannot create speex resampler: %s",
    985                  speex_resampler_strerror(error));
    986             speex_resampler_destroy(session->inResampler);
    987             session->inResampler = NULL;
    988             return -EINVAL;
    989         }
    990         session->revResampler = speex_resampler_init(session->inChannelCount,
    991                                                     session->samplingRate,
    992                                                     session->apmSamplingRate,
    993                                                     RESAMPLER_QUALITY,
    994                                                     &error);
    995         if (session->revResampler == NULL) {
    996             ALOGW("Session_SetConfig Cannot create speex resampler: %s",
    997                  speex_resampler_strerror(error));
    998             speex_resampler_destroy(session->inResampler);
    999             session->inResampler = NULL;
   1000             speex_resampler_destroy(session->outResampler);
   1001             session->outResampler = NULL;
   1002             return -EINVAL;
   1003         }
   1004     }
   1005 
   1006     session->state = PREPROC_SESSION_STATE_CONFIG;
   1007     return 0;
   1008 }
   1009 
   1010 void Session_GetConfig(preproc_session_t *session, effect_config_t *config)
   1011 {
   1012     memset(config, 0, sizeof(effect_config_t));
   1013     config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
   1014     config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
   1015     config->inputCfg.channels = audio_channel_in_mask_from_count(session->inChannelCount);
   1016     // "out" doesn't mean output device, so this is the correct API to convert channel count to mask
   1017     config->outputCfg.channels = audio_channel_in_mask_from_count(session->outChannelCount);
   1018     config->inputCfg.mask = config->outputCfg.mask =
   1019             (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
   1020 }
   1021 
   1022 int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
   1023 {
   1024     if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
   1025             config->inputCfg.format != config->outputCfg.format ||
   1026             config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
   1027         return -EINVAL;
   1028     }
   1029 
   1030     ALOGV("Session_SetReverseConfig sr %d cnl %08x",
   1031          config->inputCfg.samplingRate, config->inputCfg.channels);
   1032 
   1033     if (session->state < PREPROC_SESSION_STATE_CONFIG) {
   1034         return -ENOSYS;
   1035     }
   1036     if (config->inputCfg.samplingRate != session->samplingRate ||
   1037             config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
   1038         return -EINVAL;
   1039     }
   1040     uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
   1041     int status = session->apm->set_num_reverse_channels(inCnl);
   1042     if (status < 0) {
   1043         return -EINVAL;
   1044     }
   1045     session->revChannelCount = inCnl;
   1046     session->revFrame->_audioChannel = inCnl;
   1047     session->revFrame->_frequencyInHz = session->apmSamplingRate;
   1048     // force process buffer reallocation
   1049     session->revBufSize = 0;
   1050     session->framesRev = 0;
   1051 
   1052     return 0;
   1053 }
   1054 
   1055 void Session_GetReverseConfig(preproc_session_t *session, effect_config_t *config)
   1056 {
   1057     memset(config, 0, sizeof(effect_config_t));
   1058     config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
   1059     config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
   1060     config->inputCfg.channels = config->outputCfg.channels =
   1061             audio_channel_in_mask_from_count(session->revChannelCount);
   1062     config->inputCfg.mask = config->outputCfg.mask =
   1063             (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
   1064 }
   1065 
   1066 void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
   1067 {
   1068     if (enabled) {
   1069         if(session->enabledMsk == 0) {
   1070             session->framesIn = 0;
   1071             if (session->inResampler != NULL) {
   1072                 speex_resampler_reset_mem(session->inResampler);
   1073             }
   1074             session->framesOut = 0;
   1075             if (session->outResampler != NULL) {
   1076                 speex_resampler_reset_mem(session->outResampler);
   1077             }
   1078         }
   1079         session->enabledMsk |= (1 << procId);
   1080         if (HasReverseStream(procId)) {
   1081             session->framesRev = 0;
   1082             if (session->revResampler != NULL) {
   1083                 speex_resampler_reset_mem(session->revResampler);
   1084             }
   1085             session->revEnabledMsk |= (1 << procId);
   1086         }
   1087     } else {
   1088         session->enabledMsk &= ~(1 << procId);
   1089         if (HasReverseStream(procId)) {
   1090             session->revEnabledMsk &= ~(1 << procId);
   1091         }
   1092     }
   1093     ALOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x",
   1094          procId, enabled, session->enabledMsk, session->revEnabledMsk);
   1095     session->processedMsk = 0;
   1096     if (HasReverseStream(procId)) {
   1097         session->revProcessedMsk = 0;
   1098     }
   1099 }
   1100 
   1101 //------------------------------------------------------------------------------
   1102 // Bundle functions
   1103 //------------------------------------------------------------------------------
   1104 
   1105 static int sInitStatus = 1;
   1106 static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
   1107 
   1108 preproc_session_t *PreProc_GetSession(int32_t procId, int32_t  sessionId, int32_t  ioId)
   1109 {
   1110     size_t i;
   1111     int free = -1;
   1112     for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
   1113         if (sSessions[i].io == ioId) {
   1114             if (sSessions[i].createdMsk & (1 << procId)) {
   1115                 return NULL;
   1116             }
   1117             return &sSessions[i];
   1118         }
   1119     }
   1120     for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
   1121         if (sSessions[i].io == 0) {
   1122             sSessions[i].id = sessionId;
   1123             sSessions[i].io = ioId;
   1124             return &sSessions[i];
   1125         }
   1126     }
   1127     return NULL;
   1128 }
   1129 
   1130 
   1131 int PreProc_Init() {
   1132     size_t i;
   1133     int status = 0;
   1134 
   1135     if (sInitStatus <= 0) {
   1136         return sInitStatus;
   1137     }
   1138     for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
   1139         status = Session_Init(&sSessions[i]);
   1140     }
   1141     sInitStatus = status;
   1142     return sInitStatus;
   1143 }
   1144 
   1145 const effect_descriptor_t *PreProc_GetDescriptor(const effect_uuid_t *uuid)
   1146 {
   1147     size_t i;
   1148     for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
   1149         if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
   1150             return sDescriptors[i];
   1151         }
   1152     }
   1153     return NULL;
   1154 }
   1155 
   1156 
   1157 extern "C" {
   1158 
   1159 //------------------------------------------------------------------------------
   1160 // Effect Control Interface Implementation
   1161 //------------------------------------------------------------------------------
   1162 
   1163 int PreProcessingFx_Process(effect_handle_t     self,
   1164                             audio_buffer_t    *inBuffer,
   1165                             audio_buffer_t    *outBuffer)
   1166 {
   1167     preproc_effect_t * effect = (preproc_effect_t *)self;
   1168     int    status = 0;
   1169 
   1170     if (effect == NULL){
   1171         ALOGV("PreProcessingFx_Process() ERROR effect == NULL");
   1172         return -EINVAL;
   1173     }
   1174     preproc_session_t * session = (preproc_session_t *)effect->session;
   1175 
   1176     if (inBuffer == NULL  || inBuffer->raw == NULL  ||
   1177             outBuffer == NULL || outBuffer->raw == NULL){
   1178         ALOGW("PreProcessingFx_Process() ERROR bad pointer");
   1179         return -EINVAL;
   1180     }
   1181 
   1182     session->processedMsk |= (1<<effect->procId);
   1183 
   1184 //    ALOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
   1185 //         inBuffer->frameCount, session->enabledMsk, session->processedMsk);
   1186 
   1187     if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
   1188         effect->session->processedMsk = 0;
   1189         size_t framesRq = outBuffer->frameCount;
   1190         size_t framesWr = 0;
   1191         if (session->framesOut) {
   1192             size_t fr = session->framesOut;
   1193             if (outBuffer->frameCount < fr) {
   1194                 fr = outBuffer->frameCount;
   1195             }
   1196             memcpy(outBuffer->s16,
   1197                   session->outBuf,
   1198                   fr * session->outChannelCount * sizeof(int16_t));
   1199             memcpy(session->outBuf,
   1200                   session->outBuf + fr * session->outChannelCount,
   1201                   (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
   1202             session->framesOut -= fr;
   1203             framesWr += fr;
   1204         }
   1205         outBuffer->frameCount = framesWr;
   1206         if (framesWr == framesRq) {
   1207             inBuffer->frameCount = 0;
   1208             return 0;
   1209         }
   1210 
   1211         if (session->inResampler != NULL) {
   1212             size_t fr = session->frameCount - session->framesIn;
   1213             if (inBuffer->frameCount < fr) {
   1214                 fr = inBuffer->frameCount;
   1215             }
   1216             if (session->inBufSize < session->framesIn + fr) {
   1217                 session->inBufSize = session->framesIn + fr;
   1218                 session->inBuf = (int16_t *)realloc(session->inBuf,
   1219                                  session->inBufSize * session->inChannelCount * sizeof(int16_t));
   1220             }
   1221             memcpy(session->inBuf + session->framesIn * session->inChannelCount,
   1222                    inBuffer->s16,
   1223                    fr * session->inChannelCount * sizeof(int16_t));
   1224 #ifdef DUAL_MIC_TEST
   1225             pthread_mutex_lock(&gPcmDumpLock);
   1226             if (gPcmDumpFh != NULL) {
   1227                 fwrite(inBuffer->raw,
   1228                        fr * session->inChannelCount * sizeof(int16_t), 1, gPcmDumpFh);
   1229             }
   1230             pthread_mutex_unlock(&gPcmDumpLock);
   1231 #endif
   1232 
   1233             session->framesIn += fr;
   1234             inBuffer->frameCount = fr;
   1235             if (session->framesIn < session->frameCount) {
   1236                 return 0;
   1237             }
   1238             spx_uint32_t frIn = session->framesIn;
   1239             spx_uint32_t frOut = session->apmFrameCount;
   1240             if (session->inChannelCount == 1) {
   1241                 speex_resampler_process_int(session->inResampler,
   1242                                             0,
   1243                                             session->inBuf,
   1244                                             &frIn,
   1245                                             session->procFrame->_payloadData,
   1246                                             &frOut);
   1247             } else {
   1248                 speex_resampler_process_interleaved_int(session->inResampler,
   1249                                                         session->inBuf,
   1250                                                         &frIn,
   1251                                                         session->procFrame->_payloadData,
   1252                                                         &frOut);
   1253             }
   1254             memcpy(session->inBuf,
   1255                    session->inBuf + frIn * session->inChannelCount,
   1256                    (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
   1257             session->framesIn -= frIn;
   1258         } else {
   1259             size_t fr = session->frameCount - session->framesIn;
   1260             if (inBuffer->frameCount < fr) {
   1261                 fr = inBuffer->frameCount;
   1262             }
   1263             memcpy(session->procFrame->_payloadData + session->framesIn * session->inChannelCount,
   1264                    inBuffer->s16,
   1265                    fr * session->inChannelCount * sizeof(int16_t));
   1266 
   1267 #ifdef DUAL_MIC_TEST
   1268             pthread_mutex_lock(&gPcmDumpLock);
   1269             if (gPcmDumpFh != NULL) {
   1270                 fwrite(inBuffer->raw,
   1271                        fr * session->inChannelCount * sizeof(int16_t), 1, gPcmDumpFh);
   1272             }
   1273             pthread_mutex_unlock(&gPcmDumpLock);
   1274 #endif
   1275 
   1276             session->framesIn += fr;
   1277             inBuffer->frameCount = fr;
   1278             if (session->framesIn < session->frameCount) {
   1279                 return 0;
   1280             }
   1281             session->framesIn = 0;
   1282         }
   1283         session->procFrame->_payloadDataLengthInSamples =
   1284                 session->apmFrameCount * session->inChannelCount;
   1285 
   1286         effect->session->apm->ProcessStream(session->procFrame);
   1287 
   1288         if (session->outBufSize < session->framesOut + session->frameCount) {
   1289             session->outBufSize = session->framesOut + session->frameCount;
   1290             session->outBuf = (int16_t *)realloc(session->outBuf,
   1291                               session->outBufSize * session->outChannelCount * sizeof(int16_t));
   1292         }
   1293 
   1294         if (session->outResampler != NULL) {
   1295             spx_uint32_t frIn = session->apmFrameCount;
   1296             spx_uint32_t frOut = session->frameCount;
   1297             if (session->inChannelCount == 1) {
   1298                 speex_resampler_process_int(session->outResampler,
   1299                                     0,
   1300                                     session->procFrame->_payloadData,
   1301                                     &frIn,
   1302                                     session->outBuf + session->framesOut * session->outChannelCount,
   1303                                     &frOut);
   1304             } else {
   1305                 speex_resampler_process_interleaved_int(session->outResampler,
   1306                                     session->procFrame->_payloadData,
   1307                                     &frIn,
   1308                                     session->outBuf + session->framesOut * session->outChannelCount,
   1309                                     &frOut);
   1310             }
   1311             session->framesOut += frOut;
   1312         } else {
   1313             memcpy(session->outBuf + session->framesOut * session->outChannelCount,
   1314                    session->procFrame->_payloadData,
   1315                    session->frameCount * session->outChannelCount * sizeof(int16_t));
   1316             session->framesOut += session->frameCount;
   1317         }
   1318         size_t fr = session->framesOut;
   1319         if (framesRq - framesWr < fr) {
   1320             fr = framesRq - framesWr;
   1321         }
   1322         memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
   1323               session->outBuf,
   1324               fr * session->outChannelCount * sizeof(int16_t));
   1325         memcpy(session->outBuf,
   1326               session->outBuf + fr * session->outChannelCount,
   1327               (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
   1328         session->framesOut -= fr;
   1329         outBuffer->frameCount += fr;
   1330 
   1331         return 0;
   1332     } else {
   1333         return -ENODATA;
   1334     }
   1335 }
   1336 
   1337 int PreProcessingFx_Command(effect_handle_t  self,
   1338                             uint32_t            cmdCode,
   1339                             uint32_t            cmdSize,
   1340                             void                *pCmdData,
   1341                             uint32_t            *replySize,
   1342                             void                *pReplyData)
   1343 {
   1344     preproc_effect_t * effect = (preproc_effect_t *) self;
   1345     int retsize;
   1346     int status;
   1347 
   1348     if (effect == NULL){
   1349         return -EINVAL;
   1350     }
   1351 
   1352     //ALOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
   1353 
   1354     switch (cmdCode){
   1355         case EFFECT_CMD_INIT:
   1356             if (pReplyData == NULL || *replySize != sizeof(int)){
   1357                 return -EINVAL;
   1358             }
   1359             if (effect->ops->init) {
   1360                 effect->ops->init(effect);
   1361             }
   1362             *(int *)pReplyData = 0;
   1363             break;
   1364 
   1365         case EFFECT_CMD_SET_CONFIG: {
   1366             if (pCmdData    == NULL||
   1367                 cmdSize     != sizeof(effect_config_t)||
   1368                 pReplyData  == NULL||
   1369                 *replySize  != sizeof(int)){
   1370                 ALOGV("PreProcessingFx_Command cmdCode Case: "
   1371                         "EFFECT_CMD_SET_CONFIG: ERROR");
   1372                 return -EINVAL;
   1373             }
   1374 #ifdef DUAL_MIC_TEST
   1375             // make sure that the config command is accepted by making as if all effects were
   1376             // disabled: this is OK for functional tests
   1377             uint32_t enabledMsk = effect->session->enabledMsk;
   1378             if (gDualMicEnabled) {
   1379                 effect->session->enabledMsk = 0;
   1380             }
   1381 #endif
   1382             *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
   1383 #ifdef DUAL_MIC_TEST
   1384             if (gDualMicEnabled) {
   1385                 effect->session->enabledMsk = enabledMsk;
   1386             }
   1387 #endif
   1388             if (*(int *)pReplyData != 0) {
   1389                 break;
   1390             }
   1391             if (effect->state != PREPROC_EFFECT_STATE_ACTIVE) {
   1392                 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
   1393             }
   1394             } break;
   1395 
   1396         case EFFECT_CMD_GET_CONFIG:
   1397             if (pReplyData == NULL ||
   1398                 *replySize != sizeof(effect_config_t)) {
   1399                 ALOGV("\tLVM_ERROR : PreProcessingFx_Command cmdCode Case: "
   1400                         "EFFECT_CMD_GET_CONFIG: ERROR");
   1401                 return -EINVAL;
   1402             }
   1403 
   1404             Session_GetConfig(effect->session, (effect_config_t *)pReplyData);
   1405             break;
   1406 
   1407         case EFFECT_CMD_SET_CONFIG_REVERSE:
   1408             if (pCmdData == NULL ||
   1409                 cmdSize != sizeof(effect_config_t) ||
   1410                 pReplyData == NULL ||
   1411                 *replySize != sizeof(int)) {
   1412                 ALOGV("PreProcessingFx_Command cmdCode Case: "
   1413                         "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR");
   1414                 return -EINVAL;
   1415             }
   1416             *(int *)pReplyData = Session_SetReverseConfig(effect->session,
   1417                                                           (effect_config_t *)pCmdData);
   1418             if (*(int *)pReplyData != 0) {
   1419                 break;
   1420             }
   1421             break;
   1422 
   1423         case EFFECT_CMD_GET_CONFIG_REVERSE:
   1424             if (pReplyData == NULL ||
   1425                 *replySize != sizeof(effect_config_t)){
   1426                 ALOGV("PreProcessingFx_Command cmdCode Case: "
   1427                         "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR");
   1428                 return -EINVAL;
   1429             }
   1430             Session_GetReverseConfig(effect->session, (effect_config_t *)pCmdData);
   1431             break;
   1432 
   1433         case EFFECT_CMD_RESET:
   1434             if (effect->ops->reset) {
   1435                 effect->ops->reset(effect);
   1436             }
   1437             break;
   1438 
   1439         case EFFECT_CMD_GET_PARAM: {
   1440             effect_param_t *p = (effect_param_t *)pCmdData;
   1441 
   1442             if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
   1443                     cmdSize < (sizeof(effect_param_t) + p->psize) ||
   1444                     pReplyData == NULL || replySize == NULL ||
   1445                     *replySize < (sizeof(effect_param_t) + p->psize)){
   1446                 ALOGV("PreProcessingFx_Command cmdCode Case: "
   1447                         "EFFECT_CMD_GET_PARAM: ERROR");
   1448                 return -EINVAL;
   1449             }
   1450 
   1451             memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
   1452 
   1453             p = (effect_param_t *)pReplyData;
   1454 
   1455             int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
   1456 
   1457             if (effect->ops->get_parameter) {
   1458                 p->status = effect->ops->get_parameter(effect, p->data,
   1459                                                        &p->vsize,
   1460                                                        p->data + voffset);
   1461                 *replySize = sizeof(effect_param_t) + voffset + p->vsize;
   1462             }
   1463         } break;
   1464 
   1465         case EFFECT_CMD_SET_PARAM:{
   1466             if (pCmdData == NULL||
   1467                     cmdSize < sizeof(effect_param_t) ||
   1468                     pReplyData == NULL || replySize == NULL ||
   1469                     *replySize != sizeof(int32_t)){
   1470                 ALOGV("PreProcessingFx_Command cmdCode Case: "
   1471                         "EFFECT_CMD_SET_PARAM: ERROR");
   1472                 return -EINVAL;
   1473             }
   1474             effect_param_t *p = (effect_param_t *) pCmdData;
   1475 
   1476             if (p->psize != sizeof(int32_t)){
   1477                 ALOGV("PreProcessingFx_Command cmdCode Case: "
   1478                         "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
   1479                 return -EINVAL;
   1480             }
   1481             if (effect->ops->set_parameter) {
   1482                 *(int *)pReplyData = effect->ops->set_parameter(effect,
   1483                                                                 (void *)p->data,
   1484                                                                 p->data + p->psize);
   1485             }
   1486         } break;
   1487 
   1488         case EFFECT_CMD_ENABLE:
   1489             if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
   1490                 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
   1491                 return -EINVAL;
   1492             }
   1493             *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
   1494             break;
   1495 
   1496         case EFFECT_CMD_DISABLE:
   1497             if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
   1498                 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
   1499                 return -EINVAL;
   1500             }
   1501             *(int *)pReplyData  = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
   1502             break;
   1503 
   1504         case EFFECT_CMD_SET_DEVICE:
   1505         case EFFECT_CMD_SET_INPUT_DEVICE:
   1506             if (pCmdData == NULL ||
   1507                 cmdSize != sizeof(uint32_t)) {
   1508                 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
   1509                 return -EINVAL;
   1510             }
   1511 
   1512             if (effect->ops->set_device) {
   1513                 effect->ops->set_device(effect, *(uint32_t *)pCmdData);
   1514             }
   1515             break;
   1516 
   1517         case EFFECT_CMD_SET_VOLUME:
   1518         case EFFECT_CMD_SET_AUDIO_MODE:
   1519             break;
   1520 
   1521 #ifdef DUAL_MIC_TEST
   1522         ///// test commands start
   1523         case PREPROC_CMD_DUAL_MIC_ENABLE: {
   1524             if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
   1525                     pReplyData == NULL || replySize == NULL) {
   1526                 ALOGE("PreProcessingFx_Command cmdCode Case: "
   1527                         "PREPROC_CMD_DUAL_MIC_ENABLE: ERROR");
   1528                 *replySize = 0;
   1529                 return -EINVAL;
   1530             }
   1531             gDualMicEnabled = *(bool *)pCmdData;
   1532             if (gDualMicEnabled) {
   1533                 effect->aux_channels_on = sHasAuxChannels[effect->procId];
   1534             } else {
   1535                 effect->aux_channels_on = false;
   1536             }
   1537             effect->cur_channel_config = (effect->session->inChannelCount == 1) ?
   1538                     CHANNEL_CFG_MONO : CHANNEL_CFG_STEREO;
   1539 
   1540             ALOGV("PREPROC_CMD_DUAL_MIC_ENABLE: %s", gDualMicEnabled ? "enabled" : "disabled");
   1541             *replySize = sizeof(int);
   1542             *(int *)pReplyData = 0;
   1543             } break;
   1544         case PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: {
   1545             if (pCmdData == NULL|| pReplyData == NULL || replySize == NULL) {
   1546                 ALOGE("PreProcessingFx_Command cmdCode Case: "
   1547                         "PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: ERROR");
   1548                 *replySize = 0;
   1549                 return -EINVAL;
   1550             }
   1551             pthread_mutex_lock(&gPcmDumpLock);
   1552             if (gPcmDumpFh != NULL) {
   1553                 fclose(gPcmDumpFh);
   1554                 gPcmDumpFh = NULL;
   1555             }
   1556             char *path = strndup((char *)pCmdData, cmdSize);
   1557             gPcmDumpFh = fopen((char *)path, "wb");
   1558             pthread_mutex_unlock(&gPcmDumpLock);
   1559             ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: path %s gPcmDumpFh %p",
   1560                   path, gPcmDumpFh);
   1561             ALOGE_IF(gPcmDumpFh <= 0, "gPcmDumpFh open error %d %s", errno, strerror(errno));
   1562             free(path);
   1563             *replySize = sizeof(int);
   1564             *(int *)pReplyData = 0;
   1565             } break;
   1566         case PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: {
   1567             if (pReplyData == NULL || replySize == NULL) {
   1568                 ALOGE("PreProcessingFx_Command cmdCode Case: "
   1569                         "PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: ERROR");
   1570                 *replySize = 0;
   1571                 return -EINVAL;
   1572             }
   1573             pthread_mutex_lock(&gPcmDumpLock);
   1574             if (gPcmDumpFh != NULL) {
   1575                 fclose(gPcmDumpFh);
   1576                 gPcmDumpFh = NULL;
   1577             }
   1578             pthread_mutex_unlock(&gPcmDumpLock);
   1579             ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP");
   1580             *replySize = sizeof(int);
   1581             *(int *)pReplyData = 0;
   1582             } break;
   1583         ///// test commands end
   1584 
   1585         case EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: {
   1586             if(!gDualMicEnabled) {
   1587                 return -EINVAL;
   1588             }
   1589             if (pCmdData == NULL|| cmdSize != 2 * sizeof(uint32_t) ||
   1590                     pReplyData == NULL || replySize == NULL) {
   1591                 ALOGE("PreProcessingFx_Command cmdCode Case: "
   1592                         "EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: ERROR");
   1593                 *replySize = 0;
   1594                 return -EINVAL;
   1595             }
   1596             if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS ||
   1597                   !effect->aux_channels_on) {
   1598                 ALOGV("PreProcessingFx_Command feature EFFECT_FEATURE_AUX_CHANNELS not supported by"
   1599                         " fx %d", effect->procId);
   1600                 *(uint32_t *)pReplyData = -ENOSYS;
   1601                 *replySize = sizeof(uint32_t);
   1602                 break;
   1603             }
   1604             size_t num_configs = *((uint32_t *)pCmdData + 1);
   1605             if (*replySize < (2 * sizeof(uint32_t) +
   1606                               num_configs * sizeof(channel_config_t))) {
   1607                 *replySize = 0;
   1608                 return -EINVAL;
   1609             }
   1610 
   1611             *((uint32_t *)pReplyData + 1) = CHANNEL_CFG_CNT;
   1612             if (num_configs < CHANNEL_CFG_CNT ||
   1613                     *replySize < (2 * sizeof(uint32_t) +
   1614                                      CHANNEL_CFG_CNT * sizeof(channel_config_t))) {
   1615                 *(uint32_t *)pReplyData = -ENOMEM;
   1616             } else {
   1617                 num_configs = CHANNEL_CFG_CNT;
   1618                 *(uint32_t *)pReplyData = 0;
   1619             }
   1620             ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS num config %d",
   1621                   num_configs);
   1622 
   1623             *replySize = 2 * sizeof(uint32_t) + num_configs * sizeof(channel_config_t);
   1624             *((uint32_t *)pReplyData + 1) = num_configs;
   1625             memcpy((uint32_t *)pReplyData + 2, &sDualMicConfigs, num_configs * sizeof(channel_config_t));
   1626             } break;
   1627         case EFFECT_CMD_GET_FEATURE_CONFIG:
   1628             if(!gDualMicEnabled) {
   1629                 return -EINVAL;
   1630             }
   1631             if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
   1632                     pReplyData == NULL || replySize == NULL ||
   1633                     *replySize < sizeof(uint32_t) + sizeof(channel_config_t)) {
   1634                 ALOGE("PreProcessingFx_Command cmdCode Case: "
   1635                         "EFFECT_CMD_GET_FEATURE_CONFIG: ERROR");
   1636                 return -EINVAL;
   1637             }
   1638             if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
   1639                 *(uint32_t *)pReplyData = -ENOSYS;
   1640                 *replySize = sizeof(uint32_t);
   1641                 break;
   1642             }
   1643             ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_CONFIG");
   1644             *(uint32_t *)pReplyData = 0;
   1645             *replySize = sizeof(uint32_t) + sizeof(channel_config_t);
   1646             memcpy((uint32_t *)pReplyData + 1,
   1647                    &sDualMicConfigs[effect->cur_channel_config],
   1648                    sizeof(channel_config_t));
   1649             break;
   1650         case EFFECT_CMD_SET_FEATURE_CONFIG: {
   1651             ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG: "
   1652                     "gDualMicEnabled %d effect->aux_channels_on %d",
   1653                   gDualMicEnabled, effect->aux_channels_on);
   1654             if(!gDualMicEnabled) {
   1655                 return -EINVAL;
   1656             }
   1657             if (pCmdData == NULL|| cmdSize != (sizeof(uint32_t) + sizeof(channel_config_t)) ||
   1658                     pReplyData == NULL || replySize == NULL ||
   1659                     *replySize < sizeof(uint32_t)) {
   1660                 ALOGE("PreProcessingFx_Command cmdCode Case: "
   1661                         "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
   1662                         "pCmdData %p cmdSize %d pReplyData %p replySize %p *replySize %d",
   1663                         pCmdData, cmdSize, pReplyData, replySize, replySize ? *replySize : -1);
   1664                 return -EINVAL;
   1665             }
   1666             *replySize = sizeof(uint32_t);
   1667             if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
   1668                 *(uint32_t *)pReplyData = -ENOSYS;
   1669                 ALOGV("PreProcessingFx_Command cmdCode Case: "
   1670                                         "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
   1671                                         "CmdData %d effect->aux_channels_on %d",
   1672                                         *(uint32_t *)pCmdData, effect->aux_channels_on);
   1673                 break;
   1674             }
   1675             size_t i;
   1676             for (i = 0; i < CHANNEL_CFG_CNT;i++) {
   1677                 if (memcmp((uint32_t *)pCmdData + 1,
   1678                            &sDualMicConfigs[i], sizeof(channel_config_t)) == 0) {
   1679                     break;
   1680                 }
   1681             }
   1682             if (i == CHANNEL_CFG_CNT) {
   1683                 *(uint32_t *)pReplyData = -EINVAL;
   1684                 ALOGW("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG invalid config"
   1685                         "[%08x].[%08x]", *((uint32_t *)pCmdData + 1), *((uint32_t *)pCmdData + 2));
   1686             } else {
   1687                 effect->cur_channel_config = i;
   1688                 *(uint32_t *)pReplyData = 0;
   1689                 ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG New config"
   1690                         "[%08x].[%08x]", sDualMicConfigs[i].main_channels, sDualMicConfigs[i].aux_channels);
   1691             }
   1692             } break;
   1693 #endif
   1694         default:
   1695             return -EINVAL;
   1696     }
   1697     return 0;
   1698 }
   1699 
   1700 
   1701 int PreProcessingFx_GetDescriptor(effect_handle_t   self,
   1702                                   effect_descriptor_t *pDescriptor)
   1703 {
   1704     preproc_effect_t * effect = (preproc_effect_t *) self;
   1705 
   1706     if (effect == NULL || pDescriptor == NULL) {
   1707         return -EINVAL;
   1708     }
   1709 
   1710     *pDescriptor = *sDescriptors[effect->procId];
   1711 
   1712     return 0;
   1713 }
   1714 
   1715 int PreProcessingFx_ProcessReverse(effect_handle_t     self,
   1716                                    audio_buffer_t    *inBuffer,
   1717                                    audio_buffer_t    *outBuffer __unused)
   1718 {
   1719     preproc_effect_t * effect = (preproc_effect_t *)self;
   1720     int    status = 0;
   1721 
   1722     if (effect == NULL){
   1723         ALOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
   1724         return -EINVAL;
   1725     }
   1726     preproc_session_t * session = (preproc_session_t *)effect->session;
   1727 
   1728     if (inBuffer == NULL  || inBuffer->raw == NULL){
   1729         ALOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
   1730         return -EINVAL;
   1731     }
   1732 
   1733     session->revProcessedMsk |= (1<<effect->procId);
   1734 
   1735 //    ALOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
   1736 //         inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
   1737 
   1738 
   1739     if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
   1740         effect->session->revProcessedMsk = 0;
   1741         if (session->revResampler != NULL) {
   1742             size_t fr = session->frameCount - session->framesRev;
   1743             if (inBuffer->frameCount < fr) {
   1744                 fr = inBuffer->frameCount;
   1745             }
   1746             if (session->revBufSize < session->framesRev + fr) {
   1747                 session->revBufSize = session->framesRev + fr;
   1748                 session->revBuf = (int16_t *)realloc(session->revBuf,
   1749                                   session->revBufSize * session->inChannelCount * sizeof(int16_t));
   1750             }
   1751             memcpy(session->revBuf + session->framesRev * session->inChannelCount,
   1752                    inBuffer->s16,
   1753                    fr * session->inChannelCount * sizeof(int16_t));
   1754 
   1755             session->framesRev += fr;
   1756             inBuffer->frameCount = fr;
   1757             if (session->framesRev < session->frameCount) {
   1758                 return 0;
   1759             }
   1760             spx_uint32_t frIn = session->framesRev;
   1761             spx_uint32_t frOut = session->apmFrameCount;
   1762             if (session->inChannelCount == 1) {
   1763                 speex_resampler_process_int(session->revResampler,
   1764                                             0,
   1765                                             session->revBuf,
   1766                                             &frIn,
   1767                                             session->revFrame->_payloadData,
   1768                                             &frOut);
   1769             } else {
   1770                 speex_resampler_process_interleaved_int(session->revResampler,
   1771                                                         session->revBuf,
   1772                                                         &frIn,
   1773                                                         session->revFrame->_payloadData,
   1774                                                         &frOut);
   1775             }
   1776             memcpy(session->revBuf,
   1777                    session->revBuf + frIn * session->inChannelCount,
   1778                    (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
   1779             session->framesRev -= frIn;
   1780         } else {
   1781             size_t fr = session->frameCount - session->framesRev;
   1782             if (inBuffer->frameCount < fr) {
   1783                 fr = inBuffer->frameCount;
   1784             }
   1785             memcpy(session->revFrame->_payloadData + session->framesRev * session->inChannelCount,
   1786                    inBuffer->s16,
   1787                    fr * session->inChannelCount * sizeof(int16_t));
   1788             session->framesRev += fr;
   1789             inBuffer->frameCount = fr;
   1790             if (session->framesRev < session->frameCount) {
   1791                 return 0;
   1792             }
   1793             session->framesRev = 0;
   1794         }
   1795         session->revFrame->_payloadDataLengthInSamples =
   1796                 session->apmFrameCount * session->inChannelCount;
   1797         effect->session->apm->AnalyzeReverseStream(session->revFrame);
   1798         return 0;
   1799     } else {
   1800         return -ENODATA;
   1801     }
   1802 }
   1803 
   1804 
   1805 // effect_handle_t interface implementation for effect
   1806 const struct effect_interface_s sEffectInterface = {
   1807     PreProcessingFx_Process,
   1808     PreProcessingFx_Command,
   1809     PreProcessingFx_GetDescriptor,
   1810     NULL
   1811 };
   1812 
   1813 const struct effect_interface_s sEffectInterfaceReverse = {
   1814     PreProcessingFx_Process,
   1815     PreProcessingFx_Command,
   1816     PreProcessingFx_GetDescriptor,
   1817     PreProcessingFx_ProcessReverse
   1818 };
   1819 
   1820 //------------------------------------------------------------------------------
   1821 // Effect Library Interface Implementation
   1822 //------------------------------------------------------------------------------
   1823 
   1824 int PreProcessingLib_Create(const effect_uuid_t *uuid,
   1825                             int32_t             sessionId,
   1826                             int32_t             ioId,
   1827                             effect_handle_t  *pInterface)
   1828 {
   1829     ALOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
   1830 
   1831     int status;
   1832     const effect_descriptor_t *desc;
   1833     preproc_session_t *session;
   1834     uint32_t procId;
   1835 
   1836     if (PreProc_Init() != 0) {
   1837         return sInitStatus;
   1838     }
   1839     desc =  PreProc_GetDescriptor(uuid);
   1840     if (desc == NULL) {
   1841         ALOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
   1842         return -EINVAL;
   1843     }
   1844     procId = UuidToProcId(&desc->type);
   1845 
   1846     session = PreProc_GetSession(procId, sessionId, ioId);
   1847     if (session == NULL) {
   1848         ALOGW("EffectCreate: no more session available");
   1849         return -EINVAL;
   1850     }
   1851 
   1852     status = Session_CreateEffect(session, procId, pInterface);
   1853 
   1854     if (status < 0 && session->createdMsk == 0) {
   1855         session->io = 0;
   1856     }
   1857     return status;
   1858 }
   1859 
   1860 int PreProcessingLib_Release(effect_handle_t interface)
   1861 {
   1862     int status;
   1863     ALOGV("EffectRelease start %p", interface);
   1864     if (PreProc_Init() != 0) {
   1865         return sInitStatus;
   1866     }
   1867 
   1868     preproc_effect_t *fx = (preproc_effect_t *)interface;
   1869 
   1870     if (fx->session->io == 0) {
   1871         return -EINVAL;
   1872     }
   1873     return Session_ReleaseEffect(fx->session, fx);
   1874 }
   1875 
   1876 int PreProcessingLib_GetDescriptor(const effect_uuid_t *uuid,
   1877                                    effect_descriptor_t *pDescriptor) {
   1878 
   1879     if (pDescriptor == NULL || uuid == NULL){
   1880         return -EINVAL;
   1881     }
   1882 
   1883     const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
   1884     if (desc == NULL) {
   1885         ALOGV("PreProcessingLib_GetDescriptor() not found");
   1886         return  -EINVAL;
   1887     }
   1888 
   1889     ALOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
   1890 
   1891     *pDescriptor = *desc;
   1892     return 0;
   1893 }
   1894 
   1895 // This is the only symbol that needs to be exported
   1896 __attribute__ ((visibility ("default")))
   1897 audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
   1898     .tag = AUDIO_EFFECT_LIBRARY_TAG,
   1899     .version = EFFECT_LIBRARY_API_VERSION,
   1900     .name = "Audio Preprocessing Library",
   1901     .implementor = "The Android Open Source Project",
   1902     .create_effect = PreProcessingLib_Create,
   1903     .release_effect = PreProcessingLib_Release,
   1904     .get_descriptor = PreProcessingLib_GetDescriptor
   1905 };
   1906 
   1907 }; // extern "C"
   1908