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    if (audio_is_input_device(device)) {
521        return 0;
522    }
523
524    switch(device) {
525    case AUDIO_DEVICE_OUT_EARPIECE:
526        mode = webrtc::EchoControlMobile::kEarpiece;
527        break;
528    case AUDIO_DEVICE_OUT_SPEAKER:
529        mode = webrtc::EchoControlMobile::kSpeakerphone;
530        break;
531    case AUDIO_DEVICE_OUT_WIRED_HEADSET:
532    case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
533    default:
534        break;
535    }
536    aec->set_routing_mode(mode);
537    return 0;
538}
539
540static const preproc_ops_t sAecOps = {
541        AecCreate,
542        AecInit,
543        NULL,
544        AecEnable,
545        AecDisable,
546        AecSetParameter,
547        AecGetParameter,
548        AecSetDevice
549};
550
551//------------------------------------------------------------------------------
552// Noise Suppression (NS)
553//------------------------------------------------------------------------------
554
555static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
556
557int  NsInit (preproc_effect_t *effect)
558{
559    ALOGV("NsInit");
560    webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
561    ns->set_level(kNsDefaultLevel);
562    return 0;
563}
564
565int  NsCreate(preproc_effect_t *effect)
566{
567    webrtc::NoiseSuppression *ns = effect->session->apm->noise_suppression();
568    ALOGV("NsCreate got ns %p", ns);
569    if (ns == NULL) {
570        ALOGW("AgcCreate Error");
571        return -ENOMEM;
572    }
573    effect->engine = static_cast<preproc_fx_handle_t>(ns);
574    NsInit (effect);
575    return 0;
576}
577
578int NsGetParameter(preproc_effect_t     *effect,
579                   void              *pParam,
580                   size_t            *pValueSize,
581                   void              *pValue)
582{
583    int status = 0;
584    return status;
585}
586
587int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
588{
589    int status = 0;
590    return status;
591}
592
593void NsEnable(preproc_effect_t *effect)
594{
595    webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
596    ALOGV("NsEnable ns %p", ns);
597    ns->Enable(true);
598}
599
600void NsDisable(preproc_effect_t *effect)
601{
602    ALOGV("NsDisable");
603    webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
604    ns->Enable(false);
605}
606
607static const preproc_ops_t sNsOps = {
608        NsCreate,
609        NsInit,
610        NULL,
611        NsEnable,
612        NsDisable,
613        NsSetParameter,
614        NsGetParameter,
615        NULL
616};
617
618
619static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
620        &sAgcOps,
621        &sAecOps,
622        &sNsOps
623};
624
625
626//------------------------------------------------------------------------------
627// Effect functions
628//------------------------------------------------------------------------------
629
630void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled);
631
632extern "C" const struct effect_interface_s sEffectInterface;
633extern "C" const struct effect_interface_s sEffectInterfaceReverse;
634
635#define BAD_STATE_ABORT(from, to) \
636        LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to);
637
638int Effect_SetState(preproc_effect_t *effect, uint32_t state)
639{
640    int status = 0;
641    ALOGV("Effect_SetState proc %d, new %d old %d", effect->procId, state, effect->state);
642    switch(state) {
643    case PREPROC_EFFECT_STATE_INIT:
644        switch(effect->state) {
645        case PREPROC_EFFECT_STATE_ACTIVE:
646            effect->ops->disable(effect);
647            Session_SetProcEnabled(effect->session, effect->procId, false);
648        case PREPROC_EFFECT_STATE_CONFIG:
649        case PREPROC_EFFECT_STATE_CREATED:
650        case PREPROC_EFFECT_STATE_INIT:
651            break;
652        default:
653            BAD_STATE_ABORT(effect->state, state);
654        }
655        break;
656    case PREPROC_EFFECT_STATE_CREATED:
657        switch(effect->state) {
658        case PREPROC_EFFECT_STATE_INIT:
659            status = effect->ops->create(effect);
660            break;
661        case PREPROC_EFFECT_STATE_CREATED:
662        case PREPROC_EFFECT_STATE_ACTIVE:
663        case PREPROC_EFFECT_STATE_CONFIG:
664            ALOGE("Effect_SetState invalid transition");
665            status = -ENOSYS;
666            break;
667        default:
668            BAD_STATE_ABORT(effect->state, state);
669        }
670        break;
671    case PREPROC_EFFECT_STATE_CONFIG:
672        switch(effect->state) {
673        case PREPROC_EFFECT_STATE_INIT:
674            ALOGE("Effect_SetState invalid transition");
675            status = -ENOSYS;
676            break;
677        case PREPROC_EFFECT_STATE_ACTIVE:
678            effect->ops->disable(effect);
679            Session_SetProcEnabled(effect->session, effect->procId, false);
680            break;
681        case PREPROC_EFFECT_STATE_CREATED:
682        case PREPROC_EFFECT_STATE_CONFIG:
683            break;
684        default:
685            BAD_STATE_ABORT(effect->state, state);
686        }
687        break;
688    case PREPROC_EFFECT_STATE_ACTIVE:
689        switch(effect->state) {
690        case PREPROC_EFFECT_STATE_INIT:
691        case PREPROC_EFFECT_STATE_CREATED:
692            ALOGE("Effect_SetState invalid transition");
693            status = -ENOSYS;
694            break;
695        case PREPROC_EFFECT_STATE_ACTIVE:
696            // enabling an already enabled effect is just ignored
697            break;
698        case PREPROC_EFFECT_STATE_CONFIG:
699            effect->ops->enable(effect);
700            Session_SetProcEnabled(effect->session, effect->procId, true);
701            break;
702        default:
703            BAD_STATE_ABORT(effect->state, state);
704        }
705        break;
706    default:
707        BAD_STATE_ABORT(effect->state, state);
708    }
709    if (status == 0) {
710        effect->state = state;
711    }
712    return status;
713}
714
715int Effect_Init(preproc_effect_t *effect, uint32_t procId)
716{
717    if (HasReverseStream(procId)) {
718        effect->itfe = &sEffectInterfaceReverse;
719    } else {
720        effect->itfe = &sEffectInterface;
721    }
722    effect->ops = sPreProcOps[procId];
723    effect->procId = procId;
724    effect->state = PREPROC_EFFECT_STATE_INIT;
725    return 0;
726}
727
728int Effect_Create(preproc_effect_t *effect,
729               preproc_session_t *session,
730               effect_handle_t  *interface)
731{
732    effect->session = session;
733    *interface = (effect_handle_t)&effect->itfe;
734    return Effect_SetState(effect, PREPROC_EFFECT_STATE_CREATED);
735}
736
737int Effect_Release(preproc_effect_t *effect)
738{
739    return Effect_SetState(effect, PREPROC_EFFECT_STATE_INIT);
740}
741
742
743//------------------------------------------------------------------------------
744// Session functions
745//------------------------------------------------------------------------------
746
747#define RESAMPLER_QUALITY SPEEX_RESAMPLER_QUALITY_VOIP
748
749static const int kPreprocDefaultSr = 16000;
750static const int kPreProcDefaultCnl = 1;
751
752int Session_Init(preproc_session_t *session)
753{
754    size_t i;
755    int status = 0;
756
757    session->state = PREPROC_SESSION_STATE_INIT;
758    session->id = 0;
759    session->io = 0;
760    session->createdMsk = 0;
761    session->apm = NULL;
762    for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
763        status = Effect_Init(&session->effects[i], i);
764    }
765    return status;
766}
767
768
769extern "C" int Session_CreateEffect(preproc_session_t *session,
770                                    int32_t procId,
771                                    effect_handle_t  *interface)
772{
773    int status = -ENOMEM;
774
775    ALOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
776
777    if (session->createdMsk == 0) {
778        session->apm = webrtc::AudioProcessing::Create(session->io);
779        if (session->apm == NULL) {
780            ALOGW("Session_CreateEffect could not get apm engine");
781            goto error;
782        }
783        session->apm->set_sample_rate_hz(kPreprocDefaultSr);
784        session->apm->set_num_channels(kPreProcDefaultCnl, kPreProcDefaultCnl);
785        session->apm->set_num_reverse_channels(kPreProcDefaultCnl);
786        session->procFrame = new webrtc::AudioFrame();
787        if (session->procFrame == NULL) {
788            ALOGW("Session_CreateEffect could not allocate audio frame");
789            goto error;
790        }
791        session->revFrame = new webrtc::AudioFrame();
792        if (session->revFrame == NULL) {
793            ALOGW("Session_CreateEffect could not allocate reverse audio frame");
794            goto error;
795        }
796        session->apmSamplingRate = kPreprocDefaultSr;
797        session->apmFrameCount = (kPreprocDefaultSr) / 100;
798        session->frameCount = session->apmFrameCount;
799        session->samplingRate = kPreprocDefaultSr;
800        session->inChannelCount = kPreProcDefaultCnl;
801        session->outChannelCount = kPreProcDefaultCnl;
802        session->procFrame->_frequencyInHz = kPreprocDefaultSr;
803        session->procFrame->_audioChannel = kPreProcDefaultCnl;
804        session->revChannelCount = kPreProcDefaultCnl;
805        session->revFrame->_frequencyInHz = kPreprocDefaultSr;
806        session->revFrame->_audioChannel = kPreProcDefaultCnl;
807        session->enabledMsk = 0;
808        session->processedMsk = 0;
809        session->revEnabledMsk = 0;
810        session->revProcessedMsk = 0;
811        session->inResampler = NULL;
812        session->inBuf = NULL;
813        session->inBufSize = 0;
814        session->outResampler = NULL;
815        session->outBuf = NULL;
816        session->outBufSize = 0;
817        session->revResampler = NULL;
818        session->revBuf = NULL;
819        session->revBufSize = 0;
820    }
821    status = Effect_Create(&session->effects[procId], session, interface);
822    if (status < 0) {
823        goto error;
824    }
825    ALOGV("Session_CreateEffect OK");
826    session->createdMsk |= (1<<procId);
827    return status;
828
829error:
830    if (session->createdMsk == 0) {
831        delete session->revFrame;
832        session->revFrame = NULL;
833        delete session->procFrame;
834        session->procFrame = NULL;
835        webrtc::AudioProcessing::Destroy(session->apm);
836        session->apm = NULL;
837    }
838    return status;
839}
840
841int Session_ReleaseEffect(preproc_session_t *session,
842                          preproc_effect_t *fx)
843{
844    ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
845    session->createdMsk &= ~(1<<fx->procId);
846    if (session->createdMsk == 0) {
847        webrtc::AudioProcessing::Destroy(session->apm);
848        session->apm = NULL;
849        delete session->procFrame;
850        session->procFrame = NULL;
851        delete session->revFrame;
852        session->revFrame = NULL;
853        if (session->inResampler != NULL) {
854            speex_resampler_destroy(session->inResampler);
855            session->inResampler = NULL;
856        }
857        if (session->outResampler != NULL) {
858            speex_resampler_destroy(session->outResampler);
859            session->outResampler = NULL;
860        }
861        if (session->revResampler != NULL) {
862            speex_resampler_destroy(session->revResampler);
863            session->revResampler = NULL;
864        }
865        delete session->inBuf;
866        session->inBuf = NULL;
867        delete session->outBuf;
868        session->outBuf = NULL;
869        delete session->revBuf;
870        session->revBuf = NULL;
871
872        session->io = 0;
873    }
874
875    return 0;
876}
877
878
879int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
880{
881    uint32_t sr;
882    uint32_t inCnl = popcount(config->inputCfg.channels);
883    uint32_t outCnl = popcount(config->outputCfg.channels);
884
885    if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
886        config->inputCfg.format != config->outputCfg.format ||
887        config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
888        return -EINVAL;
889    }
890
891    ALOGV("Session_SetConfig sr %d cnl %08x",
892         config->inputCfg.samplingRate, config->inputCfg.channels);
893    int status;
894
895    // if at least one process is enabled, do not accept configuration changes
896    if (session->enabledMsk) {
897        if (session->samplingRate != config->inputCfg.samplingRate ||
898                session->inChannelCount != inCnl ||
899                session->outChannelCount != outCnl) {
900            return -ENOSYS;
901        } else {
902            return 0;
903        }
904    }
905
906    // AEC implementation is limited to 16kHz
907    if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
908        session->apmSamplingRate = 32000;
909    } else
910    if (config->inputCfg.samplingRate >= 16000) {
911        session->apmSamplingRate = 16000;
912    } else if (config->inputCfg.samplingRate >= 8000) {
913        session->apmSamplingRate = 8000;
914    }
915    status = session->apm->set_sample_rate_hz(session->apmSamplingRate);
916    if (status < 0) {
917        return -EINVAL;
918    }
919    status = session->apm->set_num_channels(inCnl, outCnl);
920    if (status < 0) {
921        return -EINVAL;
922    }
923    status = session->apm->set_num_reverse_channels(inCnl);
924    if (status < 0) {
925        return -EINVAL;
926    }
927
928    session->samplingRate = config->inputCfg.samplingRate;
929    session->apmFrameCount = session->apmSamplingRate / 100;
930    if (session->samplingRate == session->apmSamplingRate) {
931        session->frameCount = session->apmFrameCount;
932    } else {
933        session->frameCount = (session->apmFrameCount * session->samplingRate) /
934                session->apmSamplingRate  + 1;
935    }
936    session->inChannelCount = inCnl;
937    session->outChannelCount = outCnl;
938    session->procFrame->_audioChannel = inCnl;
939    session->procFrame->_frequencyInHz = session->apmSamplingRate;
940
941    session->revChannelCount = inCnl;
942    session->revFrame->_audioChannel = inCnl;
943    session->revFrame->_frequencyInHz = session->apmSamplingRate;
944
945    // force process buffer reallocation
946    session->inBufSize = 0;
947    session->outBufSize = 0;
948    session->framesIn = 0;
949    session->framesOut = 0;
950
951
952    if (session->inResampler != NULL) {
953        speex_resampler_destroy(session->inResampler);
954        session->inResampler = NULL;
955    }
956    if (session->outResampler != NULL) {
957        speex_resampler_destroy(session->outResampler);
958        session->outResampler = NULL;
959    }
960    if (session->revResampler != NULL) {
961        speex_resampler_destroy(session->revResampler);
962        session->revResampler = NULL;
963    }
964    if (session->samplingRate != session->apmSamplingRate) {
965        int error;
966        session->inResampler = speex_resampler_init(session->inChannelCount,
967                                                    session->samplingRate,
968                                                    session->apmSamplingRate,
969                                                    RESAMPLER_QUALITY,
970                                                    &error);
971        if (session->inResampler == NULL) {
972            ALOGW("Session_SetConfig Cannot create speex resampler: %s",
973                 speex_resampler_strerror(error));
974            return -EINVAL;
975        }
976        session->outResampler = speex_resampler_init(session->outChannelCount,
977                                                    session->apmSamplingRate,
978                                                    session->samplingRate,
979                                                    RESAMPLER_QUALITY,
980                                                    &error);
981        if (session->outResampler == NULL) {
982            ALOGW("Session_SetConfig Cannot create speex resampler: %s",
983                 speex_resampler_strerror(error));
984            speex_resampler_destroy(session->inResampler);
985            session->inResampler = NULL;
986            return -EINVAL;
987        }
988        session->revResampler = speex_resampler_init(session->inChannelCount,
989                                                    session->samplingRate,
990                                                    session->apmSamplingRate,
991                                                    RESAMPLER_QUALITY,
992                                                    &error);
993        if (session->revResampler == NULL) {
994            ALOGW("Session_SetConfig Cannot create speex resampler: %s",
995                 speex_resampler_strerror(error));
996            speex_resampler_destroy(session->inResampler);
997            session->inResampler = NULL;
998            speex_resampler_destroy(session->outResampler);
999            session->outResampler = NULL;
1000            return -EINVAL;
1001        }
1002    }
1003
1004    session->state = PREPROC_SESSION_STATE_CONFIG;
1005    return 0;
1006}
1007
1008void Session_GetConfig(preproc_session_t *session, effect_config_t *config)
1009{
1010    memset(config, 0, sizeof(effect_config_t));
1011    config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
1012    config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
1013    config->inputCfg.channels = audio_channel_in_mask_from_count(session->inChannelCount);
1014    // "out" doesn't mean output device, so this is the correct API to convert channel count to mask
1015    config->outputCfg.channels = audio_channel_in_mask_from_count(session->outChannelCount);
1016    config->inputCfg.mask = config->outputCfg.mask =
1017            (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
1018}
1019
1020int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
1021{
1022    if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
1023            config->inputCfg.format != config->outputCfg.format ||
1024            config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
1025        return -EINVAL;
1026    }
1027
1028    ALOGV("Session_SetReverseConfig sr %d cnl %08x",
1029         config->inputCfg.samplingRate, config->inputCfg.channels);
1030
1031    if (session->state < PREPROC_SESSION_STATE_CONFIG) {
1032        return -ENOSYS;
1033    }
1034    if (config->inputCfg.samplingRate != session->samplingRate ||
1035            config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
1036        return -EINVAL;
1037    }
1038    uint32_t inCnl = popcount(config->inputCfg.channels);
1039    int status = session->apm->set_num_reverse_channels(inCnl);
1040    if (status < 0) {
1041        return -EINVAL;
1042    }
1043    session->revChannelCount = inCnl;
1044    session->revFrame->_audioChannel = inCnl;
1045    session->revFrame->_frequencyInHz = session->apmSamplingRate;
1046    // force process buffer reallocation
1047    session->revBufSize = 0;
1048    session->framesRev = 0;
1049
1050    return 0;
1051}
1052
1053void Session_GetReverseConfig(preproc_session_t *session, effect_config_t *config)
1054{
1055    memset(config, 0, sizeof(effect_config_t));
1056    config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
1057    config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
1058    config->inputCfg.channels = config->outputCfg.channels =
1059            audio_channel_in_mask_from_count(session->revChannelCount);
1060    config->inputCfg.mask = config->outputCfg.mask =
1061            (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
1062}
1063
1064void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
1065{
1066    if (enabled) {
1067        if(session->enabledMsk == 0) {
1068            session->framesIn = 0;
1069            if (session->inResampler != NULL) {
1070                speex_resampler_reset_mem(session->inResampler);
1071            }
1072            session->framesOut = 0;
1073            if (session->outResampler != NULL) {
1074                speex_resampler_reset_mem(session->outResampler);
1075            }
1076        }
1077        session->enabledMsk |= (1 << procId);
1078        if (HasReverseStream(procId)) {
1079            session->framesRev = 0;
1080            if (session->revResampler != NULL) {
1081                speex_resampler_reset_mem(session->revResampler);
1082            }
1083            session->revEnabledMsk |= (1 << procId);
1084        }
1085    } else {
1086        session->enabledMsk &= ~(1 << procId);
1087        if (HasReverseStream(procId)) {
1088            session->revEnabledMsk &= ~(1 << procId);
1089        }
1090    }
1091    ALOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x",
1092         procId, enabled, session->enabledMsk, session->revEnabledMsk);
1093    session->processedMsk = 0;
1094    if (HasReverseStream(procId)) {
1095        session->revProcessedMsk = 0;
1096    }
1097}
1098
1099//------------------------------------------------------------------------------
1100// Bundle functions
1101//------------------------------------------------------------------------------
1102
1103static int sInitStatus = 1;
1104static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
1105
1106preproc_session_t *PreProc_GetSession(int32_t procId, int32_t  sessionId, int32_t  ioId)
1107{
1108    size_t i;
1109    int free = -1;
1110    for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1111        if (sSessions[i].io == ioId) {
1112            if (sSessions[i].createdMsk & (1 << procId)) {
1113                return NULL;
1114            }
1115            return &sSessions[i];
1116        }
1117    }
1118    for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1119        if (sSessions[i].io == 0) {
1120            sSessions[i].id = sessionId;
1121            sSessions[i].io = ioId;
1122            return &sSessions[i];
1123        }
1124    }
1125    return NULL;
1126}
1127
1128
1129int PreProc_Init() {
1130    size_t i;
1131    int status = 0;
1132
1133    if (sInitStatus <= 0) {
1134        return sInitStatus;
1135    }
1136    for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
1137        status = Session_Init(&sSessions[i]);
1138    }
1139    sInitStatus = status;
1140    return sInitStatus;
1141}
1142
1143const effect_descriptor_t *PreProc_GetDescriptor(const effect_uuid_t *uuid)
1144{
1145    size_t i;
1146    for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
1147        if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
1148            return sDescriptors[i];
1149        }
1150    }
1151    return NULL;
1152}
1153
1154
1155extern "C" {
1156
1157//------------------------------------------------------------------------------
1158// Effect Control Interface Implementation
1159//------------------------------------------------------------------------------
1160
1161int PreProcessingFx_Process(effect_handle_t     self,
1162                            audio_buffer_t    *inBuffer,
1163                            audio_buffer_t    *outBuffer)
1164{
1165    preproc_effect_t * effect = (preproc_effect_t *)self;
1166    int    status = 0;
1167
1168    if (effect == NULL){
1169        ALOGV("PreProcessingFx_Process() ERROR effect == NULL");
1170        return -EINVAL;
1171    }
1172    preproc_session_t * session = (preproc_session_t *)effect->session;
1173
1174    if (inBuffer == NULL  || inBuffer->raw == NULL  ||
1175            outBuffer == NULL || outBuffer->raw == NULL){
1176        ALOGW("PreProcessingFx_Process() ERROR bad pointer");
1177        return -EINVAL;
1178    }
1179
1180    session->processedMsk |= (1<<effect->procId);
1181
1182//    ALOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
1183//         inBuffer->frameCount, session->enabledMsk, session->processedMsk);
1184
1185    if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
1186        effect->session->processedMsk = 0;
1187        size_t framesRq = outBuffer->frameCount;
1188        size_t framesWr = 0;
1189        if (session->framesOut) {
1190            size_t fr = session->framesOut;
1191            if (outBuffer->frameCount < fr) {
1192                fr = outBuffer->frameCount;
1193            }
1194            memcpy(outBuffer->s16,
1195                  session->outBuf,
1196                  fr * session->outChannelCount * sizeof(int16_t));
1197            memcpy(session->outBuf,
1198                  session->outBuf + fr * session->outChannelCount,
1199                  (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1200            session->framesOut -= fr;
1201            framesWr += fr;
1202        }
1203        outBuffer->frameCount = framesWr;
1204        if (framesWr == framesRq) {
1205            inBuffer->frameCount = 0;
1206            return 0;
1207        }
1208
1209        if (session->inResampler != NULL) {
1210            size_t fr = session->frameCount - session->framesIn;
1211            if (inBuffer->frameCount < fr) {
1212                fr = inBuffer->frameCount;
1213            }
1214            if (session->inBufSize < session->framesIn + fr) {
1215                session->inBufSize = session->framesIn + fr;
1216                session->inBuf = (int16_t *)realloc(session->inBuf,
1217                                 session->inBufSize * session->inChannelCount * sizeof(int16_t));
1218            }
1219            memcpy(session->inBuf + session->framesIn * session->inChannelCount,
1220                   inBuffer->s16,
1221                   fr * session->inChannelCount * sizeof(int16_t));
1222#ifdef DUAL_MIC_TEST
1223            pthread_mutex_lock(&gPcmDumpLock);
1224            if (gPcmDumpFh != NULL) {
1225                fwrite(inBuffer->raw,
1226                       fr * session->inChannelCount * sizeof(int16_t), 1, gPcmDumpFh);
1227            }
1228            pthread_mutex_unlock(&gPcmDumpLock);
1229#endif
1230
1231            session->framesIn += fr;
1232            inBuffer->frameCount = fr;
1233            if (session->framesIn < session->frameCount) {
1234                return 0;
1235            }
1236            size_t frIn = session->framesIn;
1237            size_t frOut = session->apmFrameCount;
1238            if (session->inChannelCount == 1) {
1239                speex_resampler_process_int(session->inResampler,
1240                                            0,
1241                                            session->inBuf,
1242                                            &frIn,
1243                                            session->procFrame->_payloadData,
1244                                            &frOut);
1245            } else {
1246                speex_resampler_process_interleaved_int(session->inResampler,
1247                                                        session->inBuf,
1248                                                        &frIn,
1249                                                        session->procFrame->_payloadData,
1250                                                        &frOut);
1251            }
1252            memcpy(session->inBuf,
1253                   session->inBuf + frIn * session->inChannelCount,
1254                   (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
1255            session->framesIn -= frIn;
1256        } else {
1257            size_t fr = session->frameCount - session->framesIn;
1258            if (inBuffer->frameCount < fr) {
1259                fr = inBuffer->frameCount;
1260            }
1261            memcpy(session->procFrame->_payloadData + session->framesIn * session->inChannelCount,
1262                   inBuffer->s16,
1263                   fr * session->inChannelCount * sizeof(int16_t));
1264
1265#ifdef DUAL_MIC_TEST
1266            pthread_mutex_lock(&gPcmDumpLock);
1267            if (gPcmDumpFh != NULL) {
1268                fwrite(inBuffer->raw,
1269                       fr * session->inChannelCount * sizeof(int16_t), 1, gPcmDumpFh);
1270            }
1271            pthread_mutex_unlock(&gPcmDumpLock);
1272#endif
1273
1274            session->framesIn += fr;
1275            inBuffer->frameCount = fr;
1276            if (session->framesIn < session->frameCount) {
1277                return 0;
1278            }
1279            session->framesIn = 0;
1280        }
1281        session->procFrame->_payloadDataLengthInSamples =
1282                session->apmFrameCount * session->inChannelCount;
1283
1284        effect->session->apm->ProcessStream(session->procFrame);
1285
1286        if (session->outBufSize < session->framesOut + session->frameCount) {
1287            session->outBufSize = session->framesOut + session->frameCount;
1288            session->outBuf = (int16_t *)realloc(session->outBuf,
1289                              session->outBufSize * session->outChannelCount * sizeof(int16_t));
1290        }
1291
1292        if (session->outResampler != NULL) {
1293            size_t frIn = session->apmFrameCount;
1294            size_t frOut = session->frameCount;
1295            if (session->inChannelCount == 1) {
1296                speex_resampler_process_int(session->outResampler,
1297                                    0,
1298                                    session->procFrame->_payloadData,
1299                                    &frIn,
1300                                    session->outBuf + session->framesOut * session->outChannelCount,
1301                                    &frOut);
1302            } else {
1303                speex_resampler_process_interleaved_int(session->outResampler,
1304                                    session->procFrame->_payloadData,
1305                                    &frIn,
1306                                    session->outBuf + session->framesOut * session->outChannelCount,
1307                                    &frOut);
1308            }
1309            session->framesOut += frOut;
1310        } else {
1311            memcpy(session->outBuf + session->framesOut * session->outChannelCount,
1312                   session->procFrame->_payloadData,
1313                   session->frameCount * session->outChannelCount * sizeof(int16_t));
1314            session->framesOut += session->frameCount;
1315        }
1316        size_t fr = session->framesOut;
1317        if (framesRq - framesWr < fr) {
1318            fr = framesRq - framesWr;
1319        }
1320        memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
1321              session->outBuf,
1322              fr * session->outChannelCount * sizeof(int16_t));
1323        memcpy(session->outBuf,
1324              session->outBuf + fr * session->outChannelCount,
1325              (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1326        session->framesOut -= fr;
1327        outBuffer->frameCount += fr;
1328
1329        return 0;
1330    } else {
1331        return -ENODATA;
1332    }
1333}
1334
1335int PreProcessingFx_Command(effect_handle_t  self,
1336                            uint32_t            cmdCode,
1337                            uint32_t            cmdSize,
1338                            void                *pCmdData,
1339                            uint32_t            *replySize,
1340                            void                *pReplyData)
1341{
1342    preproc_effect_t * effect = (preproc_effect_t *) self;
1343    int retsize;
1344    int status;
1345
1346    if (effect == NULL){
1347        return -EINVAL;
1348    }
1349
1350    //ALOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
1351
1352    switch (cmdCode){
1353        case EFFECT_CMD_INIT:
1354            if (pReplyData == NULL || *replySize != sizeof(int)){
1355                return -EINVAL;
1356            }
1357            if (effect->ops->init) {
1358                effect->ops->init(effect);
1359            }
1360            *(int *)pReplyData = 0;
1361            break;
1362
1363        case EFFECT_CMD_SET_CONFIG: {
1364            if (pCmdData    == NULL||
1365                cmdSize     != sizeof(effect_config_t)||
1366                pReplyData  == NULL||
1367                *replySize  != sizeof(int)){
1368                ALOGV("PreProcessingFx_Command cmdCode Case: "
1369                        "EFFECT_CMD_SET_CONFIG: ERROR");
1370                return -EINVAL;
1371            }
1372#ifdef DUAL_MIC_TEST
1373            // make sure that the config command is accepted by making as if all effects were
1374            // disabled: this is OK for functional tests
1375            uint32_t enabledMsk = effect->session->enabledMsk;
1376            if (gDualMicEnabled) {
1377                effect->session->enabledMsk = 0;
1378            }
1379#endif
1380            *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
1381#ifdef DUAL_MIC_TEST
1382            if (gDualMicEnabled) {
1383                effect->session->enabledMsk = enabledMsk;
1384            }
1385#endif
1386            if (*(int *)pReplyData != 0) {
1387                break;
1388            }
1389            if (effect->state != PREPROC_EFFECT_STATE_ACTIVE) {
1390                *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1391            }
1392            } break;
1393
1394        case EFFECT_CMD_GET_CONFIG:
1395            if (pReplyData == NULL ||
1396                *replySize != sizeof(effect_config_t)) {
1397                ALOGV("\tLVM_ERROR : PreProcessingFx_Command cmdCode Case: "
1398                        "EFFECT_CMD_GET_CONFIG: ERROR");
1399                return -EINVAL;
1400            }
1401
1402            Session_GetConfig(effect->session, (effect_config_t *)pReplyData);
1403            break;
1404
1405        case EFFECT_CMD_SET_CONFIG_REVERSE:
1406            if (pCmdData == NULL ||
1407                cmdSize != sizeof(effect_config_t) ||
1408                pReplyData == NULL ||
1409                *replySize != sizeof(int)) {
1410                ALOGV("PreProcessingFx_Command cmdCode Case: "
1411                        "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR");
1412                return -EINVAL;
1413            }
1414            *(int *)pReplyData = Session_SetReverseConfig(effect->session,
1415                                                          (effect_config_t *)pCmdData);
1416            if (*(int *)pReplyData != 0) {
1417                break;
1418            }
1419            break;
1420
1421        case EFFECT_CMD_GET_CONFIG_REVERSE:
1422            if (pReplyData == NULL ||
1423                *replySize != sizeof(effect_config_t)){
1424                ALOGV("PreProcessingFx_Command cmdCode Case: "
1425                        "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR");
1426                return -EINVAL;
1427            }
1428            Session_GetReverseConfig(effect->session, (effect_config_t *)pCmdData);
1429            break;
1430
1431        case EFFECT_CMD_RESET:
1432            if (effect->ops->reset) {
1433                effect->ops->reset(effect);
1434            }
1435            break;
1436
1437        case EFFECT_CMD_GET_PARAM:{
1438            if (pCmdData == NULL ||
1439                    cmdSize < (int)sizeof(effect_param_t) ||
1440                    pReplyData == NULL ||
1441                    *replySize < (int)sizeof(effect_param_t)){
1442                ALOGV("PreProcessingFx_Command cmdCode Case: "
1443                        "EFFECT_CMD_GET_PARAM: ERROR");
1444                return -EINVAL;
1445            }
1446            effect_param_t *p = (effect_param_t *)pCmdData;
1447
1448            memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
1449
1450            p = (effect_param_t *)pReplyData;
1451
1452            int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
1453
1454            if (effect->ops->get_parameter) {
1455                p->status = effect->ops->get_parameter(effect, p->data,
1456                                                       (size_t  *)&p->vsize,
1457                                                       p->data + voffset);
1458                *replySize = sizeof(effect_param_t) + voffset + p->vsize;
1459            }
1460        } break;
1461
1462        case EFFECT_CMD_SET_PARAM:{
1463            if (pCmdData == NULL||
1464                    cmdSize < (int)sizeof(effect_param_t) ||
1465                    pReplyData == NULL ||
1466                    *replySize != sizeof(int32_t)){
1467                ALOGV("PreProcessingFx_Command cmdCode Case: "
1468                        "EFFECT_CMD_SET_PARAM: ERROR");
1469                return -EINVAL;
1470            }
1471            effect_param_t *p = (effect_param_t *) pCmdData;
1472
1473            if (p->psize != sizeof(int32_t)){
1474                ALOGV("PreProcessingFx_Command cmdCode Case: "
1475                        "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
1476                return -EINVAL;
1477            }
1478            if (effect->ops->set_parameter) {
1479                *(int *)pReplyData = effect->ops->set_parameter(effect,
1480                                                                (void *)p->data,
1481                                                                p->data + p->psize);
1482            }
1483        } break;
1484
1485        case EFFECT_CMD_ENABLE:
1486            if (pReplyData == NULL || *replySize != sizeof(int)){
1487                ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
1488                return -EINVAL;
1489            }
1490            *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
1491            break;
1492
1493        case EFFECT_CMD_DISABLE:
1494            if (pReplyData == NULL || *replySize != sizeof(int)){
1495                ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
1496                return -EINVAL;
1497            }
1498            *(int *)pReplyData  = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1499            break;
1500
1501        case EFFECT_CMD_SET_DEVICE:
1502        case EFFECT_CMD_SET_INPUT_DEVICE:
1503            if (pCmdData == NULL ||
1504                cmdSize != sizeof(uint32_t)) {
1505                ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
1506                return -EINVAL;
1507            }
1508
1509            if (effect->ops->set_device) {
1510                effect->ops->set_device(effect, *(uint32_t *)pCmdData);
1511            }
1512            break;
1513
1514        case EFFECT_CMD_SET_VOLUME:
1515        case EFFECT_CMD_SET_AUDIO_MODE:
1516            break;
1517
1518#ifdef DUAL_MIC_TEST
1519        ///// test commands start
1520        case PREPROC_CMD_DUAL_MIC_ENABLE: {
1521            if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
1522                    pReplyData == NULL || replySize == NULL) {
1523                ALOGE("PreProcessingFx_Command cmdCode Case: "
1524                        "PREPROC_CMD_DUAL_MIC_ENABLE: ERROR");
1525                *replySize = 0;
1526                return -EINVAL;
1527            }
1528            gDualMicEnabled = *(bool *)pCmdData;
1529            if (gDualMicEnabled) {
1530                effect->aux_channels_on = sHasAuxChannels[effect->procId];
1531            } else {
1532                effect->aux_channels_on = false;
1533            }
1534            effect->cur_channel_config = (effect->session->inChannelCount == 1) ?
1535                    CHANNEL_CFG_MONO : CHANNEL_CFG_STEREO;
1536
1537            ALOGV("PREPROC_CMD_DUAL_MIC_ENABLE: %s", gDualMicEnabled ? "enabled" : "disabled");
1538            *replySize = sizeof(int);
1539            *(int *)pReplyData = 0;
1540            } break;
1541        case PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: {
1542            if (pCmdData == NULL|| pReplyData == NULL || replySize == NULL) {
1543                ALOGE("PreProcessingFx_Command cmdCode Case: "
1544                        "PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: ERROR");
1545                *replySize = 0;
1546                return -EINVAL;
1547            }
1548            pthread_mutex_lock(&gPcmDumpLock);
1549            if (gPcmDumpFh != NULL) {
1550                fclose(gPcmDumpFh);
1551                gPcmDumpFh = NULL;
1552            }
1553            char *path = strndup((char *)pCmdData, cmdSize);
1554            gPcmDumpFh = fopen((char *)path, "wb");
1555            pthread_mutex_unlock(&gPcmDumpLock);
1556            ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: path %s gPcmDumpFh %p",
1557                  path, gPcmDumpFh);
1558            ALOGE_IF(gPcmDumpFh <= 0, "gPcmDumpFh open error %d %s", errno, strerror(errno));
1559            free(path);
1560            *replySize = sizeof(int);
1561            *(int *)pReplyData = 0;
1562            } break;
1563        case PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: {
1564            if (pReplyData == NULL || replySize == NULL) {
1565                ALOGE("PreProcessingFx_Command cmdCode Case: "
1566                        "PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: ERROR");
1567                *replySize = 0;
1568                return -EINVAL;
1569            }
1570            pthread_mutex_lock(&gPcmDumpLock);
1571            if (gPcmDumpFh != NULL) {
1572                fclose(gPcmDumpFh);
1573                gPcmDumpFh = NULL;
1574            }
1575            pthread_mutex_unlock(&gPcmDumpLock);
1576            ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP");
1577            *replySize = sizeof(int);
1578            *(int *)pReplyData = 0;
1579            } break;
1580        ///// test commands end
1581
1582        case EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: {
1583            if(!gDualMicEnabled) {
1584                return -EINVAL;
1585            }
1586            if (pCmdData == NULL|| cmdSize != 2 * sizeof(uint32_t) ||
1587                    pReplyData == NULL || replySize == NULL) {
1588                ALOGE("PreProcessingFx_Command cmdCode Case: "
1589                        "EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: ERROR");
1590                *replySize = 0;
1591                return -EINVAL;
1592            }
1593            if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS ||
1594                  !effect->aux_channels_on) {
1595                ALOGV("PreProcessingFx_Command feature EFFECT_FEATURE_AUX_CHANNELS not supported by"
1596                        " fx %d", effect->procId);
1597                *(uint32_t *)pReplyData = -ENOSYS;
1598                *replySize = sizeof(uint32_t);
1599                break;
1600            }
1601            size_t num_configs = *((uint32_t *)pCmdData + 1);
1602            if (*replySize < (2 * sizeof(uint32_t) +
1603                              num_configs * sizeof(channel_config_t))) {
1604                *replySize = 0;
1605                return -EINVAL;
1606            }
1607
1608            *((uint32_t *)pReplyData + 1) = CHANNEL_CFG_CNT;
1609            if (num_configs < CHANNEL_CFG_CNT ||
1610                    *replySize < (2 * sizeof(uint32_t) +
1611                                     CHANNEL_CFG_CNT * sizeof(channel_config_t))) {
1612                *(uint32_t *)pReplyData = -ENOMEM;
1613            } else {
1614                num_configs = CHANNEL_CFG_CNT;
1615                *(uint32_t *)pReplyData = 0;
1616            }
1617            ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS num config %d",
1618                  num_configs);
1619
1620            *replySize = 2 * sizeof(uint32_t) + num_configs * sizeof(channel_config_t);
1621            *((uint32_t *)pReplyData + 1) = num_configs;
1622            memcpy((uint32_t *)pReplyData + 2, &sDualMicConfigs, num_configs * sizeof(channel_config_t));
1623            } break;
1624        case EFFECT_CMD_GET_FEATURE_CONFIG:
1625            if(!gDualMicEnabled) {
1626                return -EINVAL;
1627            }
1628            if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
1629                    pReplyData == NULL || replySize == NULL ||
1630                    *replySize < sizeof(uint32_t) + sizeof(channel_config_t)) {
1631                ALOGE("PreProcessingFx_Command cmdCode Case: "
1632                        "EFFECT_CMD_GET_FEATURE_CONFIG: ERROR");
1633                return -EINVAL;
1634            }
1635            if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1636                *(uint32_t *)pReplyData = -ENOSYS;
1637                *replySize = sizeof(uint32_t);
1638                break;
1639            }
1640            ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_CONFIG");
1641            *(uint32_t *)pReplyData = 0;
1642            *replySize = sizeof(uint32_t) + sizeof(channel_config_t);
1643            memcpy((uint32_t *)pReplyData + 1,
1644                   &sDualMicConfigs[effect->cur_channel_config],
1645                   sizeof(channel_config_t));
1646            break;
1647        case EFFECT_CMD_SET_FEATURE_CONFIG: {
1648            ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG: "
1649                    "gDualMicEnabled %d effect->aux_channels_on %d",
1650                  gDualMicEnabled, effect->aux_channels_on);
1651            if(!gDualMicEnabled) {
1652                return -EINVAL;
1653            }
1654            if (pCmdData == NULL|| cmdSize != (sizeof(uint32_t) + sizeof(channel_config_t)) ||
1655                    pReplyData == NULL || replySize == NULL ||
1656                    *replySize < sizeof(uint32_t)) {
1657                ALOGE("PreProcessingFx_Command cmdCode Case: "
1658                        "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1659                        "pCmdData %p cmdSize %d pReplyData %p replySize %p *replySize %d",
1660                        pCmdData, cmdSize, pReplyData, replySize, replySize ? *replySize : -1);
1661                return -EINVAL;
1662            }
1663            *replySize = sizeof(uint32_t);
1664            if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1665                *(uint32_t *)pReplyData = -ENOSYS;
1666                ALOGV("PreProcessingFx_Command cmdCode Case: "
1667                                        "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1668                                        "CmdData %d effect->aux_channels_on %d",
1669                                        *(uint32_t *)pCmdData, effect->aux_channels_on);
1670                break;
1671            }
1672            size_t i;
1673            for (i = 0; i < CHANNEL_CFG_CNT;i++) {
1674                if (memcmp((uint32_t *)pCmdData + 1,
1675                           &sDualMicConfigs[i], sizeof(channel_config_t)) == 0) {
1676                    break;
1677                }
1678            }
1679            if (i == CHANNEL_CFG_CNT) {
1680                *(uint32_t *)pReplyData = -EINVAL;
1681                ALOGW("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG invalid config"
1682                        "[%08x].[%08x]", *((uint32_t *)pCmdData + 1), *((uint32_t *)pCmdData + 2));
1683            } else {
1684                effect->cur_channel_config = i;
1685                *(uint32_t *)pReplyData = 0;
1686                ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG New config"
1687                        "[%08x].[%08x]", sDualMicConfigs[i].main_channels, sDualMicConfigs[i].aux_channels);
1688            }
1689            } break;
1690#endif
1691        default:
1692            return -EINVAL;
1693    }
1694    return 0;
1695}
1696
1697
1698int PreProcessingFx_GetDescriptor(effect_handle_t   self,
1699                                  effect_descriptor_t *pDescriptor)
1700{
1701    preproc_effect_t * effect = (preproc_effect_t *) self;
1702
1703    if (effect == NULL || pDescriptor == NULL) {
1704        return -EINVAL;
1705    }
1706
1707    *pDescriptor = *sDescriptors[effect->procId];
1708
1709    return 0;
1710}
1711
1712int PreProcessingFx_ProcessReverse(effect_handle_t     self,
1713                                   audio_buffer_t    *inBuffer,
1714                                   audio_buffer_t    *outBuffer)
1715{
1716    preproc_effect_t * effect = (preproc_effect_t *)self;
1717    int    status = 0;
1718
1719    if (effect == NULL){
1720        ALOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
1721        return -EINVAL;
1722    }
1723    preproc_session_t * session = (preproc_session_t *)effect->session;
1724
1725    if (inBuffer == NULL  || inBuffer->raw == NULL){
1726        ALOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
1727        return -EINVAL;
1728    }
1729
1730    session->revProcessedMsk |= (1<<effect->procId);
1731
1732//    ALOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
1733//         inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
1734
1735
1736    if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
1737        effect->session->revProcessedMsk = 0;
1738        if (session->revResampler != NULL) {
1739            size_t fr = session->frameCount - session->framesRev;
1740            if (inBuffer->frameCount < fr) {
1741                fr = inBuffer->frameCount;
1742            }
1743            if (session->revBufSize < session->framesRev + fr) {
1744                session->revBufSize = session->framesRev + fr;
1745                session->revBuf = (int16_t *)realloc(session->revBuf,
1746                                  session->revBufSize * session->inChannelCount * sizeof(int16_t));
1747            }
1748            memcpy(session->revBuf + session->framesRev * session->inChannelCount,
1749                   inBuffer->s16,
1750                   fr * session->inChannelCount * sizeof(int16_t));
1751
1752            session->framesRev += fr;
1753            inBuffer->frameCount = fr;
1754            if (session->framesRev < session->frameCount) {
1755                return 0;
1756            }
1757            size_t frIn = session->framesRev;
1758            size_t frOut = session->apmFrameCount;
1759            if (session->inChannelCount == 1) {
1760                speex_resampler_process_int(session->revResampler,
1761                                            0,
1762                                            session->revBuf,
1763                                            &frIn,
1764                                            session->revFrame->_payloadData,
1765                                            &frOut);
1766            } else {
1767                speex_resampler_process_interleaved_int(session->revResampler,
1768                                                        session->revBuf,
1769                                                        &frIn,
1770                                                        session->revFrame->_payloadData,
1771                                                        &frOut);
1772            }
1773            memcpy(session->revBuf,
1774                   session->revBuf + frIn * session->inChannelCount,
1775                   (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
1776            session->framesRev -= frIn;
1777        } else {
1778            size_t fr = session->frameCount - session->framesRev;
1779            if (inBuffer->frameCount < fr) {
1780                fr = inBuffer->frameCount;
1781            }
1782            memcpy(session->revFrame->_payloadData + session->framesRev * session->inChannelCount,
1783                   inBuffer->s16,
1784                   fr * session->inChannelCount * sizeof(int16_t));
1785            session->framesRev += fr;
1786            inBuffer->frameCount = fr;
1787            if (session->framesRev < session->frameCount) {
1788                return 0;
1789            }
1790            session->framesRev = 0;
1791        }
1792        session->revFrame->_payloadDataLengthInSamples =
1793                session->apmFrameCount * session->inChannelCount;
1794        effect->session->apm->AnalyzeReverseStream(session->revFrame);
1795        return 0;
1796    } else {
1797        return -ENODATA;
1798    }
1799}
1800
1801
1802// effect_handle_t interface implementation for effect
1803const struct effect_interface_s sEffectInterface = {
1804    PreProcessingFx_Process,
1805    PreProcessingFx_Command,
1806    PreProcessingFx_GetDescriptor,
1807    NULL
1808};
1809
1810const struct effect_interface_s sEffectInterfaceReverse = {
1811    PreProcessingFx_Process,
1812    PreProcessingFx_Command,
1813    PreProcessingFx_GetDescriptor,
1814    PreProcessingFx_ProcessReverse
1815};
1816
1817//------------------------------------------------------------------------------
1818// Effect Library Interface Implementation
1819//------------------------------------------------------------------------------
1820
1821int PreProcessingLib_QueryNumberEffects(uint32_t *pNumEffects)
1822{
1823    if (PreProc_Init() != 0) {
1824        return sInitStatus;
1825    }
1826    if (pNumEffects == NULL) {
1827        return -EINVAL;
1828    }
1829    *pNumEffects = PREPROC_NUM_EFFECTS;
1830    return sInitStatus;
1831}
1832
1833int PreProcessingLib_QueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
1834{
1835    if (PreProc_Init() != 0) {
1836        return sInitStatus;
1837    }
1838    if (index >= PREPROC_NUM_EFFECTS) {
1839        return -EINVAL;
1840    }
1841    *pDescriptor = *sDescriptors[index];
1842    return 0;
1843}
1844
1845int PreProcessingLib_Create(const effect_uuid_t *uuid,
1846                            int32_t             sessionId,
1847                            int32_t             ioId,
1848                            effect_handle_t  *pInterface)
1849{
1850    ALOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
1851
1852    int status;
1853    const effect_descriptor_t *desc;
1854    preproc_session_t *session;
1855    uint32_t procId;
1856
1857    if (PreProc_Init() != 0) {
1858        return sInitStatus;
1859    }
1860    desc =  PreProc_GetDescriptor(uuid);
1861    if (desc == NULL) {
1862        ALOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
1863        return -EINVAL;
1864    }
1865    procId = UuidToProcId(&desc->type);
1866
1867    session = PreProc_GetSession(procId, sessionId, ioId);
1868    if (session == NULL) {
1869        ALOGW("EffectCreate: no more session available");
1870        return -EINVAL;
1871    }
1872
1873    status = Session_CreateEffect(session, procId, pInterface);
1874
1875    if (status < 0 && session->createdMsk == 0) {
1876        session->io = 0;
1877    }
1878    return status;
1879}
1880
1881int PreProcessingLib_Release(effect_handle_t interface)
1882{
1883    int status;
1884    ALOGV("EffectRelease start %p", interface);
1885    if (PreProc_Init() != 0) {
1886        return sInitStatus;
1887    }
1888
1889    preproc_effect_t *fx = (preproc_effect_t *)interface;
1890
1891    if (fx->session->io == 0) {
1892        return -EINVAL;
1893    }
1894    return Session_ReleaseEffect(fx->session, fx);
1895}
1896
1897int PreProcessingLib_GetDescriptor(const effect_uuid_t *uuid,
1898                                   effect_descriptor_t *pDescriptor) {
1899
1900    if (pDescriptor == NULL || uuid == NULL){
1901        return -EINVAL;
1902    }
1903
1904    const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
1905    if (desc == NULL) {
1906        ALOGV("PreProcessingLib_GetDescriptor() not found");
1907        return  -EINVAL;
1908    }
1909
1910    ALOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
1911
1912    *pDescriptor = *desc;
1913    return 0;
1914}
1915
1916audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
1917    tag : AUDIO_EFFECT_LIBRARY_TAG,
1918    version : EFFECT_LIBRARY_API_VERSION,
1919    name : "Audio Preprocessing Library",
1920    implementor : "The Android Open Source Project",
1921    query_num_effects : PreProcessingLib_QueryNumberEffects,
1922    query_effect : PreProcessingLib_QueryEffect,
1923    create_effect : PreProcessingLib_Create,
1924    release_effect : PreProcessingLib_Release,
1925    get_descriptor : PreProcessingLib_GetDescriptor
1926};
1927
1928}; // extern "C"
1929