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