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