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