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