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