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