PreProcessing.cpp revision 7772e4d03632a5ced3d37749a7aa6d5c793713be
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
42enum 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
51enum preproc_session_state {
52    PREPROC_SESSION_STATE_INIT,        // initialized
53    PREPROC_SESSION_STATE_CONFIG       // configuration received
54};
55
56// Effect/Preprocessor state
57enum 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
65typedef void* preproc_fx_handle_t;
66
67typedef struct preproc_session_s preproc_session_t;
68typedef struct preproc_effect_s preproc_effect_t;
69typedef 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.
73struct 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
85struct 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
99struct 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
137enum {
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
143enum {
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
152const 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
159bool sHasAuxChannels[PREPROC_NUM_EFFECTS] = {
160        false,   // PREPROC_AGC
161        true,   // PREPROC_AEC
162        true,   // PREPROC_NS
163};
164
165bool gDualMicEnabled;
166FILE *gPcmDumpFh;
167static 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
179static 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
191static 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
203static 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
215static const effect_descriptor_t *sDescriptors[PREPROC_NUM_EFFECTS] = {
216        &sAgcDescriptor,
217        &sAecDescriptor,
218        &sNsDescriptor
219};
220
221//------------------------------------------------------------------------------
222// Helper functions
223//------------------------------------------------------------------------------
224
225const effect_uuid_t * const sUuidToPreProcTable[PREPROC_NUM_EFFECTS] = {
226        FX_IID_AGC,
227        FX_IID_AEC,
228        FX_IID_NS
229};
230
231
232const 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
240uint32_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
251bool 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
264static const int kAgcDefaultTargetLevel = 3;
265static const int kAgcDefaultCompGain = 9;
266static const bool kAgcDefaultLimiter = true;
267
268int  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
279int  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
292int 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
356int 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
398void 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
405void 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
413static 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
429static const webrtc::EchoControlMobile::RoutingMode kAecDefaultMode =
430        webrtc::EchoControlMobile::kEarpiece;
431static const bool kAecDefaultComfortNoise = true;
432
433int  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
442int  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
455int 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
480int 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
500void 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
507void 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
514int 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
540static 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
555static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
556
557int  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
565int  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
578int 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
587int NsSetParameter (preproc_effect_t *effect __unused,
588                    void *pParam __unused,
589                    void *pValue __unused)
590{
591    int status = 0;
592    return status;
593}
594
595void 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
602void 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
609static const preproc_ops_t sNsOps = {
610        NsCreate,
611        NsInit,
612        NULL,
613        NsEnable,
614        NsDisable,
615        NsSetParameter,
616        NsGetParameter,
617        NULL
618};
619
620
621static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
622        &sAgcOps,
623        &sAecOps,
624        &sNsOps
625};
626
627
628//------------------------------------------------------------------------------
629// Effect functions
630//------------------------------------------------------------------------------
631
632void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled);
633
634extern "C" const struct effect_interface_s sEffectInterface;
635extern "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
640int 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
717int 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
730int 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
739int 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
751static const int kPreprocDefaultSr = 16000;
752static const int kPreProcDefaultCnl = 1;
753
754int 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
771extern "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->sample_rate_hz_ = kPreprocDefaultSr;
805        session->procFrame->num_channels_ = kPreProcDefaultCnl;
806        session->revChannelCount = kPreProcDefaultCnl;
807        session->revFrame->sample_rate_hz_ = kPreprocDefaultSr;
808        session->revFrame->num_channels_ = 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
831error:
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
843int 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
881int 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->num_channels_ = inCnl;
941    session->procFrame->sample_rate_hz_ = session->apmSamplingRate;
942
943    session->revChannelCount = inCnl;
944    session->revFrame->num_channels_ = inCnl;
945    session->revFrame->sample_rate_hz_ = 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
1010void 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
1022int 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->num_channels_ = inCnl;
1047    session->revFrame->sample_rate_hz_ = session->apmSamplingRate;
1048    // force process buffer reallocation
1049    session->revBufSize = 0;
1050    session->framesRev = 0;
1051
1052    return 0;
1053}
1054
1055void 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
1066void 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
1105static int sInitStatus = 1;
1106static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
1107
1108preproc_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
1131int 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
1145const 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
1157extern "C" {
1158
1159//------------------------------------------------------------------------------
1160// Effect Control Interface Implementation
1161//------------------------------------------------------------------------------
1162
1163int 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                int16_t *buf;
1218                session->inBufSize = session->framesIn + fr;
1219                buf = (int16_t *)realloc(session->inBuf,
1220                                 session->inBufSize * session->inChannelCount * sizeof(int16_t));
1221                if (buf == NULL) {
1222                    session->framesIn = 0;
1223                    free(session->inBuf);
1224                    session->inBuf = NULL;
1225                    return -ENOMEM;
1226                }
1227                session->inBuf = buf;
1228            }
1229            memcpy(session->inBuf + session->framesIn * session->inChannelCount,
1230                   inBuffer->s16,
1231                   fr * session->inChannelCount * sizeof(int16_t));
1232#ifdef DUAL_MIC_TEST
1233            pthread_mutex_lock(&gPcmDumpLock);
1234            if (gPcmDumpFh != NULL) {
1235                fwrite(inBuffer->raw,
1236                       fr * session->inChannelCount * sizeof(int16_t), 1, gPcmDumpFh);
1237            }
1238            pthread_mutex_unlock(&gPcmDumpLock);
1239#endif
1240
1241            session->framesIn += fr;
1242            inBuffer->frameCount = fr;
1243            if (session->framesIn < session->frameCount) {
1244                return 0;
1245            }
1246            spx_uint32_t frIn = session->framesIn;
1247            spx_uint32_t frOut = session->apmFrameCount;
1248            if (session->inChannelCount == 1) {
1249                speex_resampler_process_int(session->inResampler,
1250                                            0,
1251                                            session->inBuf,
1252                                            &frIn,
1253                                            session->procFrame->data_,
1254                                            &frOut);
1255            } else {
1256                speex_resampler_process_interleaved_int(session->inResampler,
1257                                                        session->inBuf,
1258                                                        &frIn,
1259                                                        session->procFrame->data_,
1260                                                        &frOut);
1261            }
1262            memcpy(session->inBuf,
1263                   session->inBuf + frIn * session->inChannelCount,
1264                   (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
1265            session->framesIn -= frIn;
1266        } else {
1267            size_t fr = session->frameCount - session->framesIn;
1268            if (inBuffer->frameCount < fr) {
1269                fr = inBuffer->frameCount;
1270            }
1271            memcpy(session->procFrame->data_ + session->framesIn * session->inChannelCount,
1272                   inBuffer->s16,
1273                   fr * session->inChannelCount * sizeof(int16_t));
1274
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            session->framesIn = 0;
1290        }
1291        session->procFrame->samples_per_channel_ =
1292                session->apmFrameCount * session->inChannelCount;
1293
1294        effect->session->apm->ProcessStream(session->procFrame);
1295
1296        if (session->outBufSize < session->framesOut + session->frameCount) {
1297            int16_t *buf;
1298            session->outBufSize = session->framesOut + session->frameCount;
1299            buf = (int16_t *)realloc(session->outBuf,
1300                             session->outBufSize * session->outChannelCount * sizeof(int16_t));
1301            if (buf == NULL) {
1302                session->framesOut = 0;
1303                free(session->outBuf);
1304                session->outBuf = NULL;
1305                return -ENOMEM;
1306            }
1307            session->outBuf = buf;
1308        }
1309
1310        if (session->outResampler != NULL) {
1311            spx_uint32_t frIn = session->apmFrameCount;
1312            spx_uint32_t frOut = session->frameCount;
1313            if (session->inChannelCount == 1) {
1314                speex_resampler_process_int(session->outResampler,
1315                                    0,
1316                                    session->procFrame->data_,
1317                                    &frIn,
1318                                    session->outBuf + session->framesOut * session->outChannelCount,
1319                                    &frOut);
1320            } else {
1321                speex_resampler_process_interleaved_int(session->outResampler,
1322                                    session->procFrame->data_,
1323                                    &frIn,
1324                                    session->outBuf + session->framesOut * session->outChannelCount,
1325                                    &frOut);
1326            }
1327            session->framesOut += frOut;
1328        } else {
1329            memcpy(session->outBuf + session->framesOut * session->outChannelCount,
1330                   session->procFrame->data_,
1331                   session->frameCount * session->outChannelCount * sizeof(int16_t));
1332            session->framesOut += session->frameCount;
1333        }
1334        size_t fr = session->framesOut;
1335        if (framesRq - framesWr < fr) {
1336            fr = framesRq - framesWr;
1337        }
1338        memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
1339              session->outBuf,
1340              fr * session->outChannelCount * sizeof(int16_t));
1341        memcpy(session->outBuf,
1342              session->outBuf + fr * session->outChannelCount,
1343              (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1344        session->framesOut -= fr;
1345        outBuffer->frameCount += fr;
1346
1347        return 0;
1348    } else {
1349        return -ENODATA;
1350    }
1351}
1352
1353int PreProcessingFx_Command(effect_handle_t  self,
1354                            uint32_t            cmdCode,
1355                            uint32_t            cmdSize,
1356                            void                *pCmdData,
1357                            uint32_t            *replySize,
1358                            void                *pReplyData)
1359{
1360    preproc_effect_t * effect = (preproc_effect_t *) self;
1361    int retsize;
1362    int status;
1363
1364    if (effect == NULL){
1365        return -EINVAL;
1366    }
1367
1368    //ALOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
1369
1370    switch (cmdCode){
1371        case EFFECT_CMD_INIT:
1372            if (pReplyData == NULL || *replySize != sizeof(int)){
1373                return -EINVAL;
1374            }
1375            if (effect->ops->init) {
1376                effect->ops->init(effect);
1377            }
1378            *(int *)pReplyData = 0;
1379            break;
1380
1381        case EFFECT_CMD_SET_CONFIG: {
1382            if (pCmdData    == NULL||
1383                cmdSize     != sizeof(effect_config_t)||
1384                pReplyData  == NULL||
1385                *replySize  != sizeof(int)){
1386                ALOGV("PreProcessingFx_Command cmdCode Case: "
1387                        "EFFECT_CMD_SET_CONFIG: ERROR");
1388                return -EINVAL;
1389            }
1390#ifdef DUAL_MIC_TEST
1391            // make sure that the config command is accepted by making as if all effects were
1392            // disabled: this is OK for functional tests
1393            uint32_t enabledMsk = effect->session->enabledMsk;
1394            if (gDualMicEnabled) {
1395                effect->session->enabledMsk = 0;
1396            }
1397#endif
1398            *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
1399#ifdef DUAL_MIC_TEST
1400            if (gDualMicEnabled) {
1401                effect->session->enabledMsk = enabledMsk;
1402            }
1403#endif
1404            if (*(int *)pReplyData != 0) {
1405                break;
1406            }
1407            if (effect->state != PREPROC_EFFECT_STATE_ACTIVE) {
1408                *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1409            }
1410            } break;
1411
1412        case EFFECT_CMD_GET_CONFIG:
1413            if (pReplyData == NULL ||
1414                *replySize != sizeof(effect_config_t)) {
1415                ALOGV("\tLVM_ERROR : PreProcessingFx_Command cmdCode Case: "
1416                        "EFFECT_CMD_GET_CONFIG: ERROR");
1417                return -EINVAL;
1418            }
1419
1420            Session_GetConfig(effect->session, (effect_config_t *)pReplyData);
1421            break;
1422
1423        case EFFECT_CMD_SET_CONFIG_REVERSE:
1424            if (pCmdData == NULL ||
1425                cmdSize != sizeof(effect_config_t) ||
1426                pReplyData == NULL ||
1427                *replySize != sizeof(int)) {
1428                ALOGV("PreProcessingFx_Command cmdCode Case: "
1429                        "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR");
1430                return -EINVAL;
1431            }
1432            *(int *)pReplyData = Session_SetReverseConfig(effect->session,
1433                                                          (effect_config_t *)pCmdData);
1434            if (*(int *)pReplyData != 0) {
1435                break;
1436            }
1437            break;
1438
1439        case EFFECT_CMD_GET_CONFIG_REVERSE:
1440            if (pReplyData == NULL ||
1441                *replySize != sizeof(effect_config_t)){
1442                ALOGV("PreProcessingFx_Command cmdCode Case: "
1443                        "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR");
1444                return -EINVAL;
1445            }
1446            Session_GetReverseConfig(effect->session, (effect_config_t *)pCmdData);
1447            break;
1448
1449        case EFFECT_CMD_RESET:
1450            if (effect->ops->reset) {
1451                effect->ops->reset(effect);
1452            }
1453            break;
1454
1455        case EFFECT_CMD_GET_PARAM: {
1456            effect_param_t *p = (effect_param_t *)pCmdData;
1457
1458            if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
1459                    cmdSize < (sizeof(effect_param_t) + p->psize) ||
1460                    pReplyData == NULL || replySize == NULL ||
1461                    *replySize < (sizeof(effect_param_t) + p->psize)){
1462                ALOGV("PreProcessingFx_Command cmdCode Case: "
1463                        "EFFECT_CMD_GET_PARAM: ERROR");
1464                return -EINVAL;
1465            }
1466
1467            memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
1468
1469            p = (effect_param_t *)pReplyData;
1470
1471            int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
1472
1473            if (effect->ops->get_parameter) {
1474                p->status = effect->ops->get_parameter(effect, p->data,
1475                                                       &p->vsize,
1476                                                       p->data + voffset);
1477                *replySize = sizeof(effect_param_t) + voffset + p->vsize;
1478            }
1479        } break;
1480
1481        case EFFECT_CMD_SET_PARAM:{
1482            if (pCmdData == NULL||
1483                    cmdSize < sizeof(effect_param_t) ||
1484                    pReplyData == NULL || replySize == NULL ||
1485                    *replySize != sizeof(int32_t)){
1486                ALOGV("PreProcessingFx_Command cmdCode Case: "
1487                        "EFFECT_CMD_SET_PARAM: ERROR");
1488                return -EINVAL;
1489            }
1490            effect_param_t *p = (effect_param_t *) pCmdData;
1491
1492            if (p->psize != sizeof(int32_t)){
1493                ALOGV("PreProcessingFx_Command cmdCode Case: "
1494                        "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
1495                return -EINVAL;
1496            }
1497            if (effect->ops->set_parameter) {
1498                *(int *)pReplyData = effect->ops->set_parameter(effect,
1499                                                                (void *)p->data,
1500                                                                p->data + p->psize);
1501            }
1502        } break;
1503
1504        case EFFECT_CMD_ENABLE:
1505            if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
1506                ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
1507                return -EINVAL;
1508            }
1509            *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
1510            break;
1511
1512        case EFFECT_CMD_DISABLE:
1513            if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
1514                ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
1515                return -EINVAL;
1516            }
1517            *(int *)pReplyData  = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1518            break;
1519
1520        case EFFECT_CMD_SET_DEVICE:
1521        case EFFECT_CMD_SET_INPUT_DEVICE:
1522            if (pCmdData == NULL ||
1523                cmdSize != sizeof(uint32_t)) {
1524                ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
1525                return -EINVAL;
1526            }
1527
1528            if (effect->ops->set_device) {
1529                effect->ops->set_device(effect, *(uint32_t *)pCmdData);
1530            }
1531            break;
1532
1533        case EFFECT_CMD_SET_VOLUME:
1534        case EFFECT_CMD_SET_AUDIO_MODE:
1535            break;
1536
1537#ifdef DUAL_MIC_TEST
1538        ///// test commands start
1539        case PREPROC_CMD_DUAL_MIC_ENABLE: {
1540            if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
1541                    pReplyData == NULL || replySize == NULL) {
1542                ALOGE("PreProcessingFx_Command cmdCode Case: "
1543                        "PREPROC_CMD_DUAL_MIC_ENABLE: ERROR");
1544                *replySize = 0;
1545                return -EINVAL;
1546            }
1547            gDualMicEnabled = *(bool *)pCmdData;
1548            if (gDualMicEnabled) {
1549                effect->aux_channels_on = sHasAuxChannels[effect->procId];
1550            } else {
1551                effect->aux_channels_on = false;
1552            }
1553            effect->cur_channel_config = (effect->session->inChannelCount == 1) ?
1554                    CHANNEL_CFG_MONO : CHANNEL_CFG_STEREO;
1555
1556            ALOGV("PREPROC_CMD_DUAL_MIC_ENABLE: %s", gDualMicEnabled ? "enabled" : "disabled");
1557            *replySize = sizeof(int);
1558            *(int *)pReplyData = 0;
1559            } break;
1560        case PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: {
1561            if (pCmdData == NULL|| pReplyData == NULL || replySize == NULL) {
1562                ALOGE("PreProcessingFx_Command cmdCode Case: "
1563                        "PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: ERROR");
1564                *replySize = 0;
1565                return -EINVAL;
1566            }
1567            pthread_mutex_lock(&gPcmDumpLock);
1568            if (gPcmDumpFh != NULL) {
1569                fclose(gPcmDumpFh);
1570                gPcmDumpFh = NULL;
1571            }
1572            char *path = strndup((char *)pCmdData, cmdSize);
1573            gPcmDumpFh = fopen((char *)path, "wb");
1574            pthread_mutex_unlock(&gPcmDumpLock);
1575            ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: path %s gPcmDumpFh %p",
1576                  path, gPcmDumpFh);
1577            ALOGE_IF(gPcmDumpFh <= 0, "gPcmDumpFh open error %d %s", errno, strerror(errno));
1578            free(path);
1579            *replySize = sizeof(int);
1580            *(int *)pReplyData = 0;
1581            } break;
1582        case PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: {
1583            if (pReplyData == NULL || replySize == NULL) {
1584                ALOGE("PreProcessingFx_Command cmdCode Case: "
1585                        "PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: ERROR");
1586                *replySize = 0;
1587                return -EINVAL;
1588            }
1589            pthread_mutex_lock(&gPcmDumpLock);
1590            if (gPcmDumpFh != NULL) {
1591                fclose(gPcmDumpFh);
1592                gPcmDumpFh = NULL;
1593            }
1594            pthread_mutex_unlock(&gPcmDumpLock);
1595            ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP");
1596            *replySize = sizeof(int);
1597            *(int *)pReplyData = 0;
1598            } break;
1599        ///// test commands end
1600
1601        case EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: {
1602            if(!gDualMicEnabled) {
1603                return -EINVAL;
1604            }
1605            if (pCmdData == NULL|| cmdSize != 2 * sizeof(uint32_t) ||
1606                    pReplyData == NULL || replySize == NULL) {
1607                ALOGE("PreProcessingFx_Command cmdCode Case: "
1608                        "EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: ERROR");
1609                *replySize = 0;
1610                return -EINVAL;
1611            }
1612            if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS ||
1613                  !effect->aux_channels_on) {
1614                ALOGV("PreProcessingFx_Command feature EFFECT_FEATURE_AUX_CHANNELS not supported by"
1615                        " fx %d", effect->procId);
1616                *(uint32_t *)pReplyData = -ENOSYS;
1617                *replySize = sizeof(uint32_t);
1618                break;
1619            }
1620            size_t num_configs = *((uint32_t *)pCmdData + 1);
1621            if (*replySize < (2 * sizeof(uint32_t) +
1622                              num_configs * sizeof(channel_config_t))) {
1623                *replySize = 0;
1624                return -EINVAL;
1625            }
1626
1627            *((uint32_t *)pReplyData + 1) = CHANNEL_CFG_CNT;
1628            if (num_configs < CHANNEL_CFG_CNT ||
1629                    *replySize < (2 * sizeof(uint32_t) +
1630                                     CHANNEL_CFG_CNT * sizeof(channel_config_t))) {
1631                *(uint32_t *)pReplyData = -ENOMEM;
1632            } else {
1633                num_configs = CHANNEL_CFG_CNT;
1634                *(uint32_t *)pReplyData = 0;
1635            }
1636            ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS num config %d",
1637                  num_configs);
1638
1639            *replySize = 2 * sizeof(uint32_t) + num_configs * sizeof(channel_config_t);
1640            *((uint32_t *)pReplyData + 1) = num_configs;
1641            memcpy((uint32_t *)pReplyData + 2, &sDualMicConfigs, num_configs * sizeof(channel_config_t));
1642            } break;
1643        case EFFECT_CMD_GET_FEATURE_CONFIG:
1644            if(!gDualMicEnabled) {
1645                return -EINVAL;
1646            }
1647            if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
1648                    pReplyData == NULL || replySize == NULL ||
1649                    *replySize < sizeof(uint32_t) + sizeof(channel_config_t)) {
1650                ALOGE("PreProcessingFx_Command cmdCode Case: "
1651                        "EFFECT_CMD_GET_FEATURE_CONFIG: ERROR");
1652                return -EINVAL;
1653            }
1654            if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1655                *(uint32_t *)pReplyData = -ENOSYS;
1656                *replySize = sizeof(uint32_t);
1657                break;
1658            }
1659            ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_CONFIG");
1660            *(uint32_t *)pReplyData = 0;
1661            *replySize = sizeof(uint32_t) + sizeof(channel_config_t);
1662            memcpy((uint32_t *)pReplyData + 1,
1663                   &sDualMicConfigs[effect->cur_channel_config],
1664                   sizeof(channel_config_t));
1665            break;
1666        case EFFECT_CMD_SET_FEATURE_CONFIG: {
1667            ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG: "
1668                    "gDualMicEnabled %d effect->aux_channels_on %d",
1669                  gDualMicEnabled, effect->aux_channels_on);
1670            if(!gDualMicEnabled) {
1671                return -EINVAL;
1672            }
1673            if (pCmdData == NULL|| cmdSize != (sizeof(uint32_t) + sizeof(channel_config_t)) ||
1674                    pReplyData == NULL || replySize == NULL ||
1675                    *replySize < sizeof(uint32_t)) {
1676                ALOGE("PreProcessingFx_Command cmdCode Case: "
1677                        "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1678                        "pCmdData %p cmdSize %d pReplyData %p replySize %p *replySize %d",
1679                        pCmdData, cmdSize, pReplyData, replySize, replySize ? *replySize : -1);
1680                return -EINVAL;
1681            }
1682            *replySize = sizeof(uint32_t);
1683            if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1684                *(uint32_t *)pReplyData = -ENOSYS;
1685                ALOGV("PreProcessingFx_Command cmdCode Case: "
1686                                        "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1687                                        "CmdData %d effect->aux_channels_on %d",
1688                                        *(uint32_t *)pCmdData, effect->aux_channels_on);
1689                break;
1690            }
1691            size_t i;
1692            for (i = 0; i < CHANNEL_CFG_CNT;i++) {
1693                if (memcmp((uint32_t *)pCmdData + 1,
1694                           &sDualMicConfigs[i], sizeof(channel_config_t)) == 0) {
1695                    break;
1696                }
1697            }
1698            if (i == CHANNEL_CFG_CNT) {
1699                *(uint32_t *)pReplyData = -EINVAL;
1700                ALOGW("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG invalid config"
1701                        "[%08x].[%08x]", *((uint32_t *)pCmdData + 1), *((uint32_t *)pCmdData + 2));
1702            } else {
1703                effect->cur_channel_config = i;
1704                *(uint32_t *)pReplyData = 0;
1705                ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG New config"
1706                        "[%08x].[%08x]", sDualMicConfigs[i].main_channels, sDualMicConfigs[i].aux_channels);
1707            }
1708            } break;
1709#endif
1710        default:
1711            return -EINVAL;
1712    }
1713    return 0;
1714}
1715
1716
1717int PreProcessingFx_GetDescriptor(effect_handle_t   self,
1718                                  effect_descriptor_t *pDescriptor)
1719{
1720    preproc_effect_t * effect = (preproc_effect_t *) self;
1721
1722    if (effect == NULL || pDescriptor == NULL) {
1723        return -EINVAL;
1724    }
1725
1726    *pDescriptor = *sDescriptors[effect->procId];
1727
1728    return 0;
1729}
1730
1731int PreProcessingFx_ProcessReverse(effect_handle_t     self,
1732                                   audio_buffer_t    *inBuffer,
1733                                   audio_buffer_t    *outBuffer __unused)
1734{
1735    preproc_effect_t * effect = (preproc_effect_t *)self;
1736    int    status = 0;
1737
1738    if (effect == NULL){
1739        ALOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
1740        return -EINVAL;
1741    }
1742    preproc_session_t * session = (preproc_session_t *)effect->session;
1743
1744    if (inBuffer == NULL  || inBuffer->raw == NULL){
1745        ALOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
1746        return -EINVAL;
1747    }
1748
1749    session->revProcessedMsk |= (1<<effect->procId);
1750
1751//    ALOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
1752//         inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
1753
1754
1755    if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
1756        effect->session->revProcessedMsk = 0;
1757        if (session->revResampler != NULL) {
1758            size_t fr = session->frameCount - session->framesRev;
1759            if (inBuffer->frameCount < fr) {
1760                fr = inBuffer->frameCount;
1761            }
1762            if (session->revBufSize < session->framesRev + fr) {
1763                int16_t *buf;
1764                session->revBufSize = session->framesRev + fr;
1765                buf = (int16_t *)realloc(session->revBuf,
1766                                 session->revBufSize * session->inChannelCount * sizeof(int16_t));
1767                if (buf == NULL) {
1768                    session->framesRev = 0;
1769                    free(session->revBuf);
1770                    session->revBuf = NULL;
1771                    return -ENOMEM;
1772                }
1773                session->revBuf = buf;
1774            }
1775            memcpy(session->revBuf + session->framesRev * session->inChannelCount,
1776                   inBuffer->s16,
1777                   fr * session->inChannelCount * sizeof(int16_t));
1778
1779            session->framesRev += fr;
1780            inBuffer->frameCount = fr;
1781            if (session->framesRev < session->frameCount) {
1782                return 0;
1783            }
1784            spx_uint32_t frIn = session->framesRev;
1785            spx_uint32_t frOut = session->apmFrameCount;
1786            if (session->inChannelCount == 1) {
1787                speex_resampler_process_int(session->revResampler,
1788                                            0,
1789                                            session->revBuf,
1790                                            &frIn,
1791                                            session->revFrame->data_,
1792                                            &frOut);
1793            } else {
1794                speex_resampler_process_interleaved_int(session->revResampler,
1795                                                        session->revBuf,
1796                                                        &frIn,
1797                                                        session->revFrame->data_,
1798                                                        &frOut);
1799            }
1800            memcpy(session->revBuf,
1801                   session->revBuf + frIn * session->inChannelCount,
1802                   (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
1803            session->framesRev -= frIn;
1804        } else {
1805            size_t fr = session->frameCount - session->framesRev;
1806            if (inBuffer->frameCount < fr) {
1807                fr = inBuffer->frameCount;
1808            }
1809            memcpy(session->revFrame->data_ + session->framesRev * session->inChannelCount,
1810                   inBuffer->s16,
1811                   fr * session->inChannelCount * sizeof(int16_t));
1812            session->framesRev += fr;
1813            inBuffer->frameCount = fr;
1814            if (session->framesRev < session->frameCount) {
1815                return 0;
1816            }
1817            session->framesRev = 0;
1818        }
1819        session->revFrame->samples_per_channel_ =
1820                session->apmFrameCount * session->inChannelCount;
1821        effect->session->apm->AnalyzeReverseStream(session->revFrame);
1822        return 0;
1823    } else {
1824        return -ENODATA;
1825    }
1826}
1827
1828
1829// effect_handle_t interface implementation for effect
1830const struct effect_interface_s sEffectInterface = {
1831    PreProcessingFx_Process,
1832    PreProcessingFx_Command,
1833    PreProcessingFx_GetDescriptor,
1834    NULL
1835};
1836
1837const struct effect_interface_s sEffectInterfaceReverse = {
1838    PreProcessingFx_Process,
1839    PreProcessingFx_Command,
1840    PreProcessingFx_GetDescriptor,
1841    PreProcessingFx_ProcessReverse
1842};
1843
1844//------------------------------------------------------------------------------
1845// Effect Library Interface Implementation
1846//------------------------------------------------------------------------------
1847
1848int PreProcessingLib_Create(const effect_uuid_t *uuid,
1849                            int32_t             sessionId,
1850                            int32_t             ioId,
1851                            effect_handle_t  *pInterface)
1852{
1853    ALOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
1854
1855    int status;
1856    const effect_descriptor_t *desc;
1857    preproc_session_t *session;
1858    uint32_t procId;
1859
1860    if (PreProc_Init() != 0) {
1861        return sInitStatus;
1862    }
1863    desc =  PreProc_GetDescriptor(uuid);
1864    if (desc == NULL) {
1865        ALOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
1866        return -EINVAL;
1867    }
1868    procId = UuidToProcId(&desc->type);
1869
1870    session = PreProc_GetSession(procId, sessionId, ioId);
1871    if (session == NULL) {
1872        ALOGW("EffectCreate: no more session available");
1873        return -EINVAL;
1874    }
1875
1876    status = Session_CreateEffect(session, procId, pInterface);
1877
1878    if (status < 0 && session->createdMsk == 0) {
1879        session->io = 0;
1880    }
1881    return status;
1882}
1883
1884int PreProcessingLib_Release(effect_handle_t interface)
1885{
1886    int status;
1887    ALOGV("EffectRelease start %p", interface);
1888    if (PreProc_Init() != 0) {
1889        return sInitStatus;
1890    }
1891
1892    preproc_effect_t *fx = (preproc_effect_t *)interface;
1893
1894    if (fx->session->io == 0) {
1895        return -EINVAL;
1896    }
1897    return Session_ReleaseEffect(fx->session, fx);
1898}
1899
1900int PreProcessingLib_GetDescriptor(const effect_uuid_t *uuid,
1901                                   effect_descriptor_t *pDescriptor) {
1902
1903    if (pDescriptor == NULL || uuid == NULL){
1904        return -EINVAL;
1905    }
1906
1907    const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
1908    if (desc == NULL) {
1909        ALOGV("PreProcessingLib_GetDescriptor() not found");
1910        return  -EINVAL;
1911    }
1912
1913    ALOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
1914
1915    *pDescriptor = *desc;
1916    return 0;
1917}
1918
1919// This is the only symbol that needs to be exported
1920__attribute__ ((visibility ("default")))
1921audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
1922    .tag = AUDIO_EFFECT_LIBRARY_TAG,
1923    .version = EFFECT_LIBRARY_API_VERSION,
1924    .name = "Audio Preprocessing Library",
1925    .implementor = "The Android Open Source Project",
1926    .create_effect = PreProcessingLib_Create,
1927    .release_effect = PreProcessingLib_Release,
1928    .get_descriptor = PreProcessingLib_GetDescriptor
1929};
1930
1931}; // extern "C"
1932