blob: ccfd29c82da7fcbbfc9e0eac353faf21614ae05c [file] [log] [blame]
Eric Laurenta9390d42011-06-17 20:17:17 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19#define LOG_TAG "PreProcessing"
20//#define LOG_NDEBUG 0
21#include <utils/Log.h>
22#include <utils/Timers.h>
23#include <hardware/audio_effect.h>
24#include <audio_effects/effect_aec.h>
25#include <audio_effects/effect_agc.h>
26#include <audio_effects/effect_ns.h>
Eric Laurent53876962012-01-31 12:35:20 -080027#include <module_common_types.h>
28#include <audio_processing.h>
Eric Laurenta9390d42011-06-17 20:17:17 -070029#include "speex/speex_resampler.h"
30
Eric Laurent3f9c84c2012-04-03 15:36:53 -070031// undefine to perform multi channels API functional tests
32//#define DUAL_MIC_TEST
Eric Laurenta9390d42011-06-17 20:17:17 -070033
34//------------------------------------------------------------------------------
35// local definitions
36//------------------------------------------------------------------------------
37
38// maximum number of sessions
39#define PREPROC_NUM_SESSIONS 8
40
41// types of pre processing modules
42enum preproc_id
43{
44 PREPROC_AGC, // Automatic Gain Control
45 PREPROC_AEC, // Acoustic Echo Canceler
46 PREPROC_NS, // Noise Suppressor
47 PREPROC_NUM_EFFECTS
48};
49
50// Session state
51enum preproc_session_state {
52 PREPROC_SESSION_STATE_INIT, // initialized
53 PREPROC_SESSION_STATE_CONFIG // configuration received
54};
55
56// Effect/Preprocessor state
57enum preproc_effect_state {
58 PREPROC_EFFECT_STATE_INIT, // initialized
59 PREPROC_EFFECT_STATE_CREATED, // webRTC engine created
60 PREPROC_EFFECT_STATE_CONFIG, // configuration received/disabled
61 PREPROC_EFFECT_STATE_ACTIVE // active/enabled
62};
63
64// handle on webRTC engine
65typedef void* preproc_fx_handle_t;
66
67typedef struct preproc_session_s preproc_session_t;
68typedef struct preproc_effect_s preproc_effect_t;
69typedef struct preproc_ops_s preproc_ops_t;
70
71// Effect operation table. Functions for all pre processors are declared in sPreProcOps[] table.
72// Function pointer can be null if no action required.
73struct preproc_ops_s {
74 int (* create)(preproc_effect_t *fx);
75 int (* init)(preproc_effect_t *fx);
76 int (* reset)(preproc_effect_t *fx);
77 void (* enable)(preproc_effect_t *fx);
78 void (* disable)(preproc_effect_t *fx);
79 int (* set_parameter)(preproc_effect_t *fx, void *param, void *value);
Ashok Bhatb302bd52014-02-18 11:40:00 +000080 int (* get_parameter)(preproc_effect_t *fx, void *param, uint32_t *size, void *value);
Eric Laurenta9390d42011-06-17 20:17:17 -070081 int (* set_device)(preproc_effect_t *fx, uint32_t device);
82};
83
84// Effect context
85struct preproc_effect_s {
86 const struct effect_interface_s *itfe;
87 uint32_t procId; // type of pre processor (enum preproc_id)
88 uint32_t state; // current state (enum preproc_effect_state)
89 preproc_session_t *session; // session the effect is on
90 const preproc_ops_t *ops; // effect ops table
91 preproc_fx_handle_t engine; // handle on webRTC engine
Alex Luebs766bf732015-12-14 21:32:13 -080092 uint32_t type; // subtype of effect
Eric Laurent3f9c84c2012-04-03 15:36:53 -070093#ifdef DUAL_MIC_TEST
94 bool aux_channels_on; // support auxiliary channels
95 size_t cur_channel_config; // current auciliary channel configuration
96#endif
Eric Laurenta9390d42011-06-17 20:17:17 -070097};
98
99// Session context
100struct preproc_session_s {
101 struct preproc_effect_s effects[PREPROC_NUM_EFFECTS]; // effects in this session
102 uint32_t state; // current state (enum preproc_session_state)
103 int id; // audio session ID
104 int io; // handle of input stream this session is on
105 webrtc::AudioProcessing* apm; // handle on webRTC audio processing module (APM)
106 size_t apmFrameCount; // buffer size for webRTC process (10 ms)
107 uint32_t apmSamplingRate; // webRTC APM sampling rate (8/16 or 32 kHz)
108 size_t frameCount; // buffer size before input resampler ( <=> apmFrameCount)
109 uint32_t samplingRate; // sampling rate at effect process interface
110 uint32_t inChannelCount; // input channel count
111 uint32_t outChannelCount; // output channel count
112 uint32_t createdMsk; // bit field containing IDs of crested pre processors
113 uint32_t enabledMsk; // bit field containing IDs of enabled pre processors
114 uint32_t processedMsk; // bit field containing IDs of pre processors already
115 // processed in current round
116 webrtc::AudioFrame *procFrame; // audio frame passed to webRTC AMP ProcessStream()
117 int16_t *inBuf; // input buffer used when resampling
118 size_t inBufSize; // input buffer size in frames
119 size_t framesIn; // number of frames in input buffer
120 SpeexResamplerState *inResampler; // handle on input speex resampler
121 int16_t *outBuf; // output buffer used when resampling
122 size_t outBufSize; // output buffer size in frames
123 size_t framesOut; // number of frames in output buffer
124 SpeexResamplerState *outResampler; // handle on output speex resampler
125 uint32_t revChannelCount; // number of channels on reverse stream
126 uint32_t revEnabledMsk; // bit field containing IDs of enabled pre processors
127 // with reverse channel
128 uint32_t revProcessedMsk; // bit field containing IDs of pre processors with reverse
129 // channel already processed in current round
130 webrtc::AudioFrame *revFrame; // audio frame passed to webRTC AMP AnalyzeReverseStream()
131 int16_t *revBuf; // reverse channel input buffer
132 size_t revBufSize; // reverse channel input buffer size
133 size_t framesRev; // number of frames in reverse channel input buffer
134 SpeexResamplerState *revResampler; // handle on reverse channel input speex resampler
135};
136
Eric Laurent3f9c84c2012-04-03 15:36:53 -0700137#ifdef DUAL_MIC_TEST
138enum {
139 PREPROC_CMD_DUAL_MIC_ENABLE = EFFECT_CMD_FIRST_PROPRIETARY, // enable dual mic mode
140 PREPROC_CMD_DUAL_MIC_PCM_DUMP_START, // start pcm capture
141 PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP // stop pcm capture
142};
143
144enum {
145 CHANNEL_CFG_MONO,
146 CHANNEL_CFG_STEREO,
147 CHANNEL_CFG_MONO_AUX,
148 CHANNEL_CFG_STEREO_AUX,
149 CHANNEL_CFG_CNT,
150 CHANNEL_CFG_FIRST_AUX = CHANNEL_CFG_MONO_AUX,
151};
152
153const channel_config_t sDualMicConfigs[CHANNEL_CFG_CNT] = {
154 {AUDIO_CHANNEL_IN_MONO , 0},
155 {AUDIO_CHANNEL_IN_STEREO , 0},
156 {AUDIO_CHANNEL_IN_FRONT , AUDIO_CHANNEL_IN_BACK},
157 {AUDIO_CHANNEL_IN_STEREO , AUDIO_CHANNEL_IN_RIGHT}
158};
159
160bool sHasAuxChannels[PREPROC_NUM_EFFECTS] = {
161 false, // PREPROC_AGC
162 true, // PREPROC_AEC
163 true, // PREPROC_NS
164};
165
166bool gDualMicEnabled;
167FILE *gPcmDumpFh;
168static pthread_mutex_t gPcmDumpLock = PTHREAD_MUTEX_INITIALIZER;
169#endif
170
171
Eric Laurenta9390d42011-06-17 20:17:17 -0700172//------------------------------------------------------------------------------
173// Effect descriptors
174//------------------------------------------------------------------------------
175
176// UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html
177// as the pre processing effects are not defined by OpenSL ES
178
179// Automatic Gain Control
180static const effect_descriptor_t sAgcDescriptor = {
181 { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
182 { 0xaa8130e0, 0x66fc, 0x11e0, 0xbad0, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
183 EFFECT_CONTROL_API_VERSION,
184 (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
185 0, //FIXME indicate CPU load
186 0, //FIXME indicate memory usage
187 "Automatic Gain Control",
188 "The Android Open Source Project"
189};
190
191// Acoustic Echo Cancellation
192static const effect_descriptor_t sAecDescriptor = {
193 { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
194 { 0xbb392ec0, 0x8d4d, 0x11e0, 0xa896, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
195 EFFECT_CONTROL_API_VERSION,
196 (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
197 0, //FIXME indicate CPU load
198 0, //FIXME indicate memory usage
199 "Acoustic Echo Canceler",
200 "The Android Open Source Project"
201};
202
203// Noise suppression
204static const effect_descriptor_t sNsDescriptor = {
205 { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
206 { 0xc06c8400, 0x8e06, 0x11e0, 0x9cb6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
207 EFFECT_CONTROL_API_VERSION,
208 (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
209 0, //FIXME indicate CPU load
210 0, //FIXME indicate memory usage
211 "Noise Suppression",
212 "The Android Open Source Project"
213};
214
215
216static const effect_descriptor_t *sDescriptors[PREPROC_NUM_EFFECTS] = {
217 &sAgcDescriptor,
218 &sAecDescriptor,
219 &sNsDescriptor
220};
221
222//------------------------------------------------------------------------------
223// Helper functions
224//------------------------------------------------------------------------------
225
226const effect_uuid_t * const sUuidToPreProcTable[PREPROC_NUM_EFFECTS] = {
227 FX_IID_AGC,
228 FX_IID_AEC,
229 FX_IID_NS
230};
231
232
233const effect_uuid_t * ProcIdToUuid(int procId)
234{
235 if (procId >= PREPROC_NUM_EFFECTS) {
236 return EFFECT_UUID_NULL;
237 }
238 return sUuidToPreProcTable[procId];
239}
240
241uint32_t UuidToProcId(const effect_uuid_t * uuid)
242{
243 size_t i;
244 for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
245 if (memcmp(uuid, sUuidToPreProcTable[i], sizeof(*uuid)) == 0) {
246 break;
247 }
248 }
249 return i;
250}
251
252bool HasReverseStream(uint32_t procId)
253{
254 if (procId == PREPROC_AEC) {
255 return true;
256 }
257 return false;
258}
259
260
261//------------------------------------------------------------------------------
262// Automatic Gain Control (AGC)
263//------------------------------------------------------------------------------
264
Eric Laurent53876962012-01-31 12:35:20 -0800265static const int kAgcDefaultTargetLevel = 3;
266static const int kAgcDefaultCompGain = 9;
Eric Laurenta9390d42011-06-17 20:17:17 -0700267static const bool kAgcDefaultLimiter = true;
268
269int AgcInit (preproc_effect_t *effect)
270{
Steve Block3856b092011-10-20 11:56:00 +0100271 ALOGV("AgcInit");
Eric Laurenta9390d42011-06-17 20:17:17 -0700272 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
273 agc->set_mode(webrtc::GainControl::kFixedDigital);
274 agc->set_target_level_dbfs(kAgcDefaultTargetLevel);
275 agc->set_compression_gain_db(kAgcDefaultCompGain);
276 agc->enable_limiter(kAgcDefaultLimiter);
277 return 0;
278}
279
280int AgcCreate(preproc_effect_t *effect)
281{
282 webrtc::GainControl *agc = effect->session->apm->gain_control();
Steve Block3856b092011-10-20 11:56:00 +0100283 ALOGV("AgcCreate got agc %p", agc);
Eric Laurenta9390d42011-06-17 20:17:17 -0700284 if (agc == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000285 ALOGW("AgcCreate Error");
Eric Laurenta9390d42011-06-17 20:17:17 -0700286 return -ENOMEM;
287 }
288 effect->engine = static_cast<preproc_fx_handle_t>(agc);
289 AgcInit(effect);
290 return 0;
291}
292
293int AgcGetParameter(preproc_effect_t *effect,
294 void *pParam,
Ashok Bhatb302bd52014-02-18 11:40:00 +0000295 uint32_t *pValueSize,
Eric Laurenta9390d42011-06-17 20:17:17 -0700296 void *pValue)
297{
298 int status = 0;
299 uint32_t param = *(uint32_t *)pParam;
300 t_agc_settings *pProperties = (t_agc_settings *)pValue;
301 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
302
303 switch (param) {
304 case AGC_PARAM_TARGET_LEVEL:
305 case AGC_PARAM_COMP_GAIN:
306 if (*pValueSize < sizeof(int16_t)) {
307 *pValueSize = 0;
308 return -EINVAL;
309 }
310 break;
311 case AGC_PARAM_LIMITER_ENA:
312 if (*pValueSize < sizeof(bool)) {
313 *pValueSize = 0;
314 return -EINVAL;
315 }
316 break;
317 case AGC_PARAM_PROPERTIES:
318 if (*pValueSize < sizeof(t_agc_settings)) {
319 *pValueSize = 0;
320 return -EINVAL;
321 }
322 break;
323
324 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000325 ALOGW("AgcGetParameter() unknown param %08x", param);
Eric Laurenta9390d42011-06-17 20:17:17 -0700326 status = -EINVAL;
327 break;
328 }
329
330 switch (param) {
331 case AGC_PARAM_TARGET_LEVEL:
332 *(int16_t *) pValue = (int16_t)(agc->target_level_dbfs() * -100);
Steve Block3856b092011-10-20 11:56:00 +0100333 ALOGV("AgcGetParameter() target level %d milliBels", *(int16_t *) pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700334 break;
335 case AGC_PARAM_COMP_GAIN:
336 *(int16_t *) pValue = (int16_t)(agc->compression_gain_db() * 100);
Steve Block3856b092011-10-20 11:56:00 +0100337 ALOGV("AgcGetParameter() comp gain %d milliBels", *(int16_t *) pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700338 break;
339 case AGC_PARAM_LIMITER_ENA:
340 *(bool *) pValue = (bool)agc->is_limiter_enabled();
Steve Block3856b092011-10-20 11:56:00 +0100341 ALOGV("AgcGetParameter() limiter enabled %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700342 (*(int16_t *) pValue != 0) ? "true" : "false");
343 break;
344 case AGC_PARAM_PROPERTIES:
345 pProperties->targetLevel = (int16_t)(agc->target_level_dbfs() * -100);
346 pProperties->compGain = (int16_t)(agc->compression_gain_db() * 100);
347 pProperties->limiterEnabled = (bool)agc->is_limiter_enabled();
348 break;
349 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000350 ALOGW("AgcGetParameter() unknown param %d", param);
Eric Laurenta9390d42011-06-17 20:17:17 -0700351 status = -EINVAL;
352 break;
353 }
354 return status;
355}
356
357int AgcSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
358{
359 int status = 0;
360 uint32_t param = *(uint32_t *)pParam;
361 t_agc_settings *pProperties = (t_agc_settings *)pValue;
362 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
363
364 switch (param) {
365 case AGC_PARAM_TARGET_LEVEL:
Steve Block3856b092011-10-20 11:56:00 +0100366 ALOGV("AgcSetParameter() target level %d milliBels", *(int16_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700367 status = agc->set_target_level_dbfs(-(*(int16_t *)pValue / 100));
368 break;
369 case AGC_PARAM_COMP_GAIN:
Steve Block3856b092011-10-20 11:56:00 +0100370 ALOGV("AgcSetParameter() comp gain %d milliBels", *(int16_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700371 status = agc->set_compression_gain_db(*(int16_t *)pValue / 100);
372 break;
373 case AGC_PARAM_LIMITER_ENA:
Steve Block3856b092011-10-20 11:56:00 +0100374 ALOGV("AgcSetParameter() limiter enabled %s", *(bool *)pValue ? "true" : "false");
Eric Laurenta9390d42011-06-17 20:17:17 -0700375 status = agc->enable_limiter(*(bool *)pValue);
376 break;
377 case AGC_PARAM_PROPERTIES:
Steve Block3856b092011-10-20 11:56:00 +0100378 ALOGV("AgcSetParameter() properties level %d, gain %d limiter %d",
Eric Laurenta9390d42011-06-17 20:17:17 -0700379 pProperties->targetLevel,
380 pProperties->compGain,
381 pProperties->limiterEnabled);
382 status = agc->set_target_level_dbfs(-(pProperties->targetLevel / 100));
383 if (status != 0) break;
384 status = agc->set_compression_gain_db(pProperties->compGain / 100);
385 if (status != 0) break;
386 status = agc->enable_limiter(pProperties->limiterEnabled);
387 break;
388 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000389 ALOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700390 status = -EINVAL;
391 break;
392 }
393
Steve Block3856b092011-10-20 11:56:00 +0100394 ALOGV("AgcSetParameter() done status %d", status);
Eric Laurenta9390d42011-06-17 20:17:17 -0700395
396 return status;
397}
398
399void AgcEnable(preproc_effect_t *effect)
400{
401 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
Steve Block3856b092011-10-20 11:56:00 +0100402 ALOGV("AgcEnable agc %p", agc);
Eric Laurenta9390d42011-06-17 20:17:17 -0700403 agc->Enable(true);
404}
405
406void AgcDisable(preproc_effect_t *effect)
407{
Steve Block3856b092011-10-20 11:56:00 +0100408 ALOGV("AgcDisable");
Eric Laurenta9390d42011-06-17 20:17:17 -0700409 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
410 agc->Enable(false);
411}
412
413
414static const preproc_ops_t sAgcOps = {
415 AgcCreate,
416 AgcInit,
417 NULL,
418 AgcEnable,
419 AgcDisable,
420 AgcSetParameter,
421 AgcGetParameter,
422 NULL
423};
424
425
426//------------------------------------------------------------------------------
427// Acoustic Echo Canceler (AEC)
428//------------------------------------------------------------------------------
429
430static const webrtc::EchoControlMobile::RoutingMode kAecDefaultMode =
431 webrtc::EchoControlMobile::kEarpiece;
432static const bool kAecDefaultComfortNoise = true;
433
434int AecInit (preproc_effect_t *effect)
435{
Steve Block3856b092011-10-20 11:56:00 +0100436 ALOGV("AecInit");
Eric Laurenta9390d42011-06-17 20:17:17 -0700437 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
438 aec->set_routing_mode(kAecDefaultMode);
439 aec->enable_comfort_noise(kAecDefaultComfortNoise);
440 return 0;
441}
442
443int AecCreate(preproc_effect_t *effect)
444{
445 webrtc::EchoControlMobile *aec = effect->session->apm->echo_control_mobile();
Steve Block3856b092011-10-20 11:56:00 +0100446 ALOGV("AecCreate got aec %p", aec);
Eric Laurenta9390d42011-06-17 20:17:17 -0700447 if (aec == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000448 ALOGW("AgcCreate Error");
Eric Laurenta9390d42011-06-17 20:17:17 -0700449 return -ENOMEM;
450 }
451 effect->engine = static_cast<preproc_fx_handle_t>(aec);
452 AecInit (effect);
453 return 0;
454}
455
Ashok Bhatb302bd52014-02-18 11:40:00 +0000456int AecGetParameter(preproc_effect_t *effect,
Eric Laurenta9390d42011-06-17 20:17:17 -0700457 void *pParam,
Ashok Bhatb302bd52014-02-18 11:40:00 +0000458 uint32_t *pValueSize,
Eric Laurenta9390d42011-06-17 20:17:17 -0700459 void *pValue)
460{
461 int status = 0;
462 uint32_t param = *(uint32_t *)pParam;
463
464 if (*pValueSize < sizeof(uint32_t)) {
465 return -EINVAL;
466 }
467 switch (param) {
468 case AEC_PARAM_ECHO_DELAY:
469 case AEC_PARAM_PROPERTIES:
470 *(uint32_t *)pValue = 1000 * effect->session->apm->stream_delay_ms();
Steve Block3856b092011-10-20 11:56:00 +0100471 ALOGV("AecGetParameter() echo delay %d us", *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700472 break;
473 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000474 ALOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700475 status = -EINVAL;
476 break;
477 }
478 return status;
479}
480
481int AecSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
482{
483 int status = 0;
484 uint32_t param = *(uint32_t *)pParam;
485 uint32_t value = *(uint32_t *)pValue;
486
487 switch (param) {
488 case AEC_PARAM_ECHO_DELAY:
489 case AEC_PARAM_PROPERTIES:
490 status = effect->session->apm->set_stream_delay_ms(value/1000);
Steve Block3856b092011-10-20 11:56:00 +0100491 ALOGV("AecSetParameter() echo delay %d us, status %d", value, status);
Eric Laurenta9390d42011-06-17 20:17:17 -0700492 break;
493 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000494 ALOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700495 status = -EINVAL;
496 break;
497 }
498 return status;
499}
500
501void AecEnable(preproc_effect_t *effect)
502{
503 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
Steve Block3856b092011-10-20 11:56:00 +0100504 ALOGV("AecEnable aec %p", aec);
Eric Laurenta9390d42011-06-17 20:17:17 -0700505 aec->Enable(true);
506}
507
508void AecDisable(preproc_effect_t *effect)
509{
Steve Block3856b092011-10-20 11:56:00 +0100510 ALOGV("AecDisable");
Eric Laurenta9390d42011-06-17 20:17:17 -0700511 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
512 aec->Enable(false);
513}
514
515int AecSetDevice(preproc_effect_t *effect, uint32_t device)
516{
Steve Block3856b092011-10-20 11:56:00 +0100517 ALOGV("AecSetDevice %08x", device);
Eric Laurenta9390d42011-06-17 20:17:17 -0700518 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
519 webrtc::EchoControlMobile::RoutingMode mode = webrtc::EchoControlMobile::kQuietEarpieceOrHeadset;
520
Eric Laurent88959252012-08-28 14:26:53 -0700521 if (audio_is_input_device(device)) {
522 return 0;
523 }
524
Eric Laurenta9390d42011-06-17 20:17:17 -0700525 switch(device) {
526 case AUDIO_DEVICE_OUT_EARPIECE:
527 mode = webrtc::EchoControlMobile::kEarpiece;
528 break;
529 case AUDIO_DEVICE_OUT_SPEAKER:
530 mode = webrtc::EchoControlMobile::kSpeakerphone;
531 break;
532 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
533 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
534 default:
535 break;
536 }
537 aec->set_routing_mode(mode);
538 return 0;
539}
540
541static const preproc_ops_t sAecOps = {
542 AecCreate,
543 AecInit,
544 NULL,
545 AecEnable,
546 AecDisable,
547 AecSetParameter,
548 AecGetParameter,
549 AecSetDevice
550};
551
552//------------------------------------------------------------------------------
553// Noise Suppression (NS)
554//------------------------------------------------------------------------------
555
556static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
557
558int NsInit (preproc_effect_t *effect)
559{
Steve Block3856b092011-10-20 11:56:00 +0100560 ALOGV("NsInit");
Eric Laurenta9390d42011-06-17 20:17:17 -0700561 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
562 ns->set_level(kNsDefaultLevel);
Alex Luebs766bf732015-12-14 21:32:13 -0800563 webrtc::Config config;
564 std::vector<webrtc::Point> geometry;
565 // TODO(aluebs): Make the geometry settable.
566 geometry.push_back(webrtc::Point(-0.03f, 0.f, 0.f));
567 geometry.push_back(webrtc::Point(-0.01f, 0.f, 0.f));
568 geometry.push_back(webrtc::Point(0.01f, 0.f, 0.f));
569 geometry.push_back(webrtc::Point(0.03f, 0.f, 0.f));
570 // The geometry needs to be set with Beamforming enabled.
571 config.Set<webrtc::Beamforming>(
572 new webrtc::Beamforming(true, geometry));
573 effect->session->apm->SetExtraOptions(config);
574 config.Set<webrtc::Beamforming>(
575 new webrtc::Beamforming(false, geometry));
576 effect->session->apm->SetExtraOptions(config);
577 effect->type = NS_TYPE_SINGLE_CHANNEL;
Eric Laurenta9390d42011-06-17 20:17:17 -0700578 return 0;
579}
580
581int NsCreate(preproc_effect_t *effect)
582{
583 webrtc::NoiseSuppression *ns = effect->session->apm->noise_suppression();
Steve Block3856b092011-10-20 11:56:00 +0100584 ALOGV("NsCreate got ns %p", ns);
Eric Laurenta9390d42011-06-17 20:17:17 -0700585 if (ns == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000586 ALOGW("AgcCreate Error");
Eric Laurenta9390d42011-06-17 20:17:17 -0700587 return -ENOMEM;
588 }
589 effect->engine = static_cast<preproc_fx_handle_t>(ns);
590 NsInit (effect);
591 return 0;
592}
593
Eric Laurent0f714a42015-06-19 15:33:57 -0700594int NsGetParameter(preproc_effect_t *effect __unused,
595 void *pParam __unused,
596 uint32_t *pValueSize __unused,
597 void *pValue __unused)
Eric Laurenta9390d42011-06-17 20:17:17 -0700598{
599 int status = 0;
600 return status;
601}
602
Alex Luebs766bf732015-12-14 21:32:13 -0800603int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
Eric Laurenta9390d42011-06-17 20:17:17 -0700604{
605 int status = 0;
Alex Luebs766bf732015-12-14 21:32:13 -0800606 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
607 uint32_t param = *(uint32_t *)pParam;
608 uint32_t value = *(uint32_t *)pValue;
609 switch(param) {
610 case NS_PARAM_LEVEL:
611 ns->set_level((webrtc::NoiseSuppression::Level)value);
612 ALOGV("NsSetParameter() level %d", value);
613 break;
614 case NS_PARAM_TYPE:
615 {
616 webrtc::Config config;
617 std::vector<webrtc::Point> geometry;
618 bool is_beamforming_enabled =
619 value == NS_TYPE_MULTI_CHANNEL && ns->is_enabled();
620 config.Set<webrtc::Beamforming>(
621 new webrtc::Beamforming(is_beamforming_enabled, geometry));
622 effect->session->apm->SetExtraOptions(config);
623 effect->type = value;
624 ALOGV("NsSetParameter() type %d", value);
625 break;
626 }
627 default:
628 ALOGW("NsSetParameter() unknown param %08x value %08x", param, value);
629 status = -EINVAL;
630 }
631
Eric Laurenta9390d42011-06-17 20:17:17 -0700632 return status;
633}
634
635void NsEnable(preproc_effect_t *effect)
636{
637 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
Steve Block3856b092011-10-20 11:56:00 +0100638 ALOGV("NsEnable ns %p", ns);
Eric Laurenta9390d42011-06-17 20:17:17 -0700639 ns->Enable(true);
Alex Luebs766bf732015-12-14 21:32:13 -0800640 if (effect->type == NS_TYPE_MULTI_CHANNEL) {
641 webrtc::Config config;
642 std::vector<webrtc::Point> geometry;
643 config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry));
644 effect->session->apm->SetExtraOptions(config);
645 }
Eric Laurenta9390d42011-06-17 20:17:17 -0700646}
647
648void NsDisable(preproc_effect_t *effect)
649{
Steve Block3856b092011-10-20 11:56:00 +0100650 ALOGV("NsDisable");
Eric Laurenta9390d42011-06-17 20:17:17 -0700651 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
652 ns->Enable(false);
Alex Luebs766bf732015-12-14 21:32:13 -0800653 webrtc::Config config;
654 std::vector<webrtc::Point> geometry;
655 config.Set<webrtc::Beamforming>(new webrtc::Beamforming(false, geometry));
656 effect->session->apm->SetExtraOptions(config);
Eric Laurenta9390d42011-06-17 20:17:17 -0700657}
658
659static const preproc_ops_t sNsOps = {
660 NsCreate,
661 NsInit,
662 NULL,
663 NsEnable,
664 NsDisable,
665 NsSetParameter,
666 NsGetParameter,
667 NULL
668};
669
670
671static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
672 &sAgcOps,
673 &sAecOps,
674 &sNsOps
675};
676
677
678//------------------------------------------------------------------------------
679// Effect functions
680//------------------------------------------------------------------------------
681
682void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled);
683
684extern "C" const struct effect_interface_s sEffectInterface;
685extern "C" const struct effect_interface_s sEffectInterfaceReverse;
686
687#define BAD_STATE_ABORT(from, to) \
688 LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to);
689
690int Effect_SetState(preproc_effect_t *effect, uint32_t state)
691{
692 int status = 0;
Steve Block3856b092011-10-20 11:56:00 +0100693 ALOGV("Effect_SetState proc %d, new %d old %d", effect->procId, state, effect->state);
Eric Laurenta9390d42011-06-17 20:17:17 -0700694 switch(state) {
695 case PREPROC_EFFECT_STATE_INIT:
696 switch(effect->state) {
697 case PREPROC_EFFECT_STATE_ACTIVE:
698 effect->ops->disable(effect);
699 Session_SetProcEnabled(effect->session, effect->procId, false);
700 case PREPROC_EFFECT_STATE_CONFIG:
701 case PREPROC_EFFECT_STATE_CREATED:
702 case PREPROC_EFFECT_STATE_INIT:
703 break;
704 default:
705 BAD_STATE_ABORT(effect->state, state);
706 }
707 break;
708 case PREPROC_EFFECT_STATE_CREATED:
709 switch(effect->state) {
710 case PREPROC_EFFECT_STATE_INIT:
711 status = effect->ops->create(effect);
712 break;
713 case PREPROC_EFFECT_STATE_CREATED:
714 case PREPROC_EFFECT_STATE_ACTIVE:
715 case PREPROC_EFFECT_STATE_CONFIG:
Steve Block29357bc2012-01-06 19:20:56 +0000716 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700717 status = -ENOSYS;
718 break;
719 default:
720 BAD_STATE_ABORT(effect->state, state);
721 }
722 break;
723 case PREPROC_EFFECT_STATE_CONFIG:
724 switch(effect->state) {
725 case PREPROC_EFFECT_STATE_INIT:
Steve Block29357bc2012-01-06 19:20:56 +0000726 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700727 status = -ENOSYS;
728 break;
729 case PREPROC_EFFECT_STATE_ACTIVE:
730 effect->ops->disable(effect);
731 Session_SetProcEnabled(effect->session, effect->procId, false);
732 break;
733 case PREPROC_EFFECT_STATE_CREATED:
734 case PREPROC_EFFECT_STATE_CONFIG:
735 break;
736 default:
737 BAD_STATE_ABORT(effect->state, state);
738 }
739 break;
740 case PREPROC_EFFECT_STATE_ACTIVE:
741 switch(effect->state) {
742 case PREPROC_EFFECT_STATE_INIT:
743 case PREPROC_EFFECT_STATE_CREATED:
Steve Block29357bc2012-01-06 19:20:56 +0000744 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700745 status = -ENOSYS;
746 break;
Eric Laurent3f9c84c2012-04-03 15:36:53 -0700747 case PREPROC_EFFECT_STATE_ACTIVE:
748 // enabling an already enabled effect is just ignored
749 break;
Eric Laurenta9390d42011-06-17 20:17:17 -0700750 case PREPROC_EFFECT_STATE_CONFIG:
751 effect->ops->enable(effect);
752 Session_SetProcEnabled(effect->session, effect->procId, true);
753 break;
754 default:
755 BAD_STATE_ABORT(effect->state, state);
756 }
757 break;
758 default:
759 BAD_STATE_ABORT(effect->state, state);
760 }
761 if (status == 0) {
762 effect->state = state;
763 }
764 return status;
765}
766
767int Effect_Init(preproc_effect_t *effect, uint32_t procId)
768{
769 if (HasReverseStream(procId)) {
770 effect->itfe = &sEffectInterfaceReverse;
771 } else {
772 effect->itfe = &sEffectInterface;
773 }
774 effect->ops = sPreProcOps[procId];
775 effect->procId = procId;
776 effect->state = PREPROC_EFFECT_STATE_INIT;
777 return 0;
778}
779
780int Effect_Create(preproc_effect_t *effect,
781 preproc_session_t *session,
782 effect_handle_t *interface)
783{
784 effect->session = session;
785 *interface = (effect_handle_t)&effect->itfe;
786 return Effect_SetState(effect, PREPROC_EFFECT_STATE_CREATED);
787}
788
789int Effect_Release(preproc_effect_t *effect)
790{
791 return Effect_SetState(effect, PREPROC_EFFECT_STATE_INIT);
792}
793
794
795//------------------------------------------------------------------------------
796// Session functions
797//------------------------------------------------------------------------------
798
799#define RESAMPLER_QUALITY SPEEX_RESAMPLER_QUALITY_VOIP
800
801static const int kPreprocDefaultSr = 16000;
802static const int kPreProcDefaultCnl = 1;
803
804int Session_Init(preproc_session_t *session)
805{
806 size_t i;
807 int status = 0;
808
809 session->state = PREPROC_SESSION_STATE_INIT;
810 session->id = 0;
811 session->io = 0;
812 session->createdMsk = 0;
813 session->apm = NULL;
814 for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
815 status = Effect_Init(&session->effects[i], i);
816 }
817 return status;
818}
819
820
821extern "C" int Session_CreateEffect(preproc_session_t *session,
822 int32_t procId,
823 effect_handle_t *interface)
824{
825 int status = -ENOMEM;
826
Steve Block3856b092011-10-20 11:56:00 +0100827 ALOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
Eric Laurenta9390d42011-06-17 20:17:17 -0700828
829 if (session->createdMsk == 0) {
Alex Luebs9718b7d2015-11-24 14:33:14 -0800830 session->apm = webrtc::AudioProcessing::Create();
Eric Laurenta9390d42011-06-17 20:17:17 -0700831 if (session->apm == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000832 ALOGW("Session_CreateEffect could not get apm engine");
Eric Laurenta9390d42011-06-17 20:17:17 -0700833 goto error;
834 }
Alex Luebs9718b7d2015-11-24 14:33:14 -0800835 const webrtc::ProcessingConfig processing_config = {
836 {{kPreprocDefaultSr, kPreProcDefaultCnl},
837 {kPreprocDefaultSr, kPreProcDefaultCnl},
838 {kPreprocDefaultSr, kPreProcDefaultCnl},
839 {kPreprocDefaultSr, kPreProcDefaultCnl}}};
840 session->apm->Initialize(processing_config);
Eric Laurenta9390d42011-06-17 20:17:17 -0700841 session->procFrame = new webrtc::AudioFrame();
842 if (session->procFrame == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000843 ALOGW("Session_CreateEffect could not allocate audio frame");
Eric Laurenta9390d42011-06-17 20:17:17 -0700844 goto error;
845 }
846 session->revFrame = new webrtc::AudioFrame();
847 if (session->revFrame == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000848 ALOGW("Session_CreateEffect could not allocate reverse audio frame");
Eric Laurenta9390d42011-06-17 20:17:17 -0700849 goto error;
850 }
851 session->apmSamplingRate = kPreprocDefaultSr;
852 session->apmFrameCount = (kPreprocDefaultSr) / 100;
853 session->frameCount = session->apmFrameCount;
854 session->samplingRate = kPreprocDefaultSr;
855 session->inChannelCount = kPreProcDefaultCnl;
856 session->outChannelCount = kPreProcDefaultCnl;
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -0700857 session->procFrame->sample_rate_hz_ = kPreprocDefaultSr;
858 session->procFrame->num_channels_ = kPreProcDefaultCnl;
Eric Laurenta9390d42011-06-17 20:17:17 -0700859 session->revChannelCount = kPreProcDefaultCnl;
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -0700860 session->revFrame->sample_rate_hz_ = kPreprocDefaultSr;
861 session->revFrame->num_channels_ = kPreProcDefaultCnl;
Eric Laurenta9390d42011-06-17 20:17:17 -0700862 session->enabledMsk = 0;
863 session->processedMsk = 0;
864 session->revEnabledMsk = 0;
865 session->revProcessedMsk = 0;
866 session->inResampler = NULL;
867 session->inBuf = NULL;
868 session->inBufSize = 0;
869 session->outResampler = NULL;
870 session->outBuf = NULL;
871 session->outBufSize = 0;
872 session->revResampler = NULL;
873 session->revBuf = NULL;
874 session->revBufSize = 0;
875 }
876 status = Effect_Create(&session->effects[procId], session, interface);
877 if (status < 0) {
878 goto error;
879 }
Steve Block3856b092011-10-20 11:56:00 +0100880 ALOGV("Session_CreateEffect OK");
Eric Laurenta9390d42011-06-17 20:17:17 -0700881 session->createdMsk |= (1<<procId);
882 return status;
883
884error:
885 if (session->createdMsk == 0) {
886 delete session->revFrame;
887 session->revFrame = NULL;
888 delete session->procFrame;
889 session->procFrame = NULL;
Alex Luebs9718b7d2015-11-24 14:33:14 -0800890 delete session->apm;
Eric Laurenta9390d42011-06-17 20:17:17 -0700891 session->apm = NULL;
892 }
893 return status;
894}
895
896int Session_ReleaseEffect(preproc_session_t *session,
897 preproc_effect_t *fx)
898{
Steve Block5ff1dd52012-01-05 23:22:43 +0000899 ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
Eric Laurenta9390d42011-06-17 20:17:17 -0700900 session->createdMsk &= ~(1<<fx->procId);
901 if (session->createdMsk == 0) {
Alex Luebs9718b7d2015-11-24 14:33:14 -0800902 delete session->apm;
Eric Laurenta9390d42011-06-17 20:17:17 -0700903 session->apm = NULL;
904 delete session->procFrame;
905 session->procFrame = NULL;
906 delete session->revFrame;
907 session->revFrame = NULL;
908 if (session->inResampler != NULL) {
909 speex_resampler_destroy(session->inResampler);
910 session->inResampler = NULL;
911 }
912 if (session->outResampler != NULL) {
913 speex_resampler_destroy(session->outResampler);
914 session->outResampler = NULL;
915 }
916 if (session->revResampler != NULL) {
917 speex_resampler_destroy(session->revResampler);
918 session->revResampler = NULL;
919 }
920 delete session->inBuf;
921 session->inBuf = NULL;
922 delete session->outBuf;
923 session->outBuf = NULL;
924 delete session->revBuf;
925 session->revBuf = NULL;
926
927 session->io = 0;
928 }
929
930 return 0;
931}
932
933
934int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
935{
Alex Luebs3f11ef02016-01-15 15:51:58 -0800936 uint32_t inCnl = audio_channel_count_from_in_mask(config->inputCfg.channels);
937 uint32_t outCnl = audio_channel_count_from_in_mask(config->outputCfg.channels);
Eric Laurenta9390d42011-06-17 20:17:17 -0700938
939 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
940 config->inputCfg.format != config->outputCfg.format ||
941 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
942 return -EINVAL;
943 }
944
Steve Block3856b092011-10-20 11:56:00 +0100945 ALOGV("Session_SetConfig sr %d cnl %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -0700946 config->inputCfg.samplingRate, config->inputCfg.channels);
947 int status;
948
949 // AEC implementation is limited to 16kHz
950 if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
951 session->apmSamplingRate = 32000;
952 } else
953 if (config->inputCfg.samplingRate >= 16000) {
954 session->apmSamplingRate = 16000;
955 } else if (config->inputCfg.samplingRate >= 8000) {
956 session->apmSamplingRate = 8000;
957 }
Alex Luebs9718b7d2015-11-24 14:33:14 -0800958
959 const webrtc::ProcessingConfig processing_config = {
Alex Luebs3f11ef02016-01-15 15:51:58 -0800960 {{static_cast<int>(session->apmSamplingRate), inCnl},
961 {static_cast<int>(session->apmSamplingRate), outCnl},
962 {static_cast<int>(session->apmSamplingRate), inCnl},
963 {static_cast<int>(session->apmSamplingRate), inCnl}}};
Alex Luebs9718b7d2015-11-24 14:33:14 -0800964 status = session->apm->Initialize(processing_config);
Eric Laurenta9390d42011-06-17 20:17:17 -0700965 if (status < 0) {
966 return -EINVAL;
967 }
968
969 session->samplingRate = config->inputCfg.samplingRate;
970 session->apmFrameCount = session->apmSamplingRate / 100;
971 if (session->samplingRate == session->apmSamplingRate) {
972 session->frameCount = session->apmFrameCount;
973 } else {
974 session->frameCount = (session->apmFrameCount * session->samplingRate) /
975 session->apmSamplingRate + 1;
976 }
977 session->inChannelCount = inCnl;
978 session->outChannelCount = outCnl;
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -0700979 session->procFrame->num_channels_ = inCnl;
980 session->procFrame->sample_rate_hz_ = session->apmSamplingRate;
Eric Laurenta9390d42011-06-17 20:17:17 -0700981
982 session->revChannelCount = inCnl;
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -0700983 session->revFrame->num_channels_ = inCnl;
984 session->revFrame->sample_rate_hz_ = session->apmSamplingRate;
Eric Laurenta9390d42011-06-17 20:17:17 -0700985
Eric Laurent3f9c84c2012-04-03 15:36:53 -0700986 // force process buffer reallocation
987 session->inBufSize = 0;
988 session->outBufSize = 0;
989 session->framesIn = 0;
990 session->framesOut = 0;
991
992
Eric Laurenta9390d42011-06-17 20:17:17 -0700993 if (session->inResampler != NULL) {
994 speex_resampler_destroy(session->inResampler);
995 session->inResampler = NULL;
996 }
997 if (session->outResampler != NULL) {
998 speex_resampler_destroy(session->outResampler);
999 session->outResampler = NULL;
1000 }
1001 if (session->revResampler != NULL) {
1002 speex_resampler_destroy(session->revResampler);
1003 session->revResampler = NULL;
1004 }
1005 if (session->samplingRate != session->apmSamplingRate) {
1006 int error;
1007 session->inResampler = speex_resampler_init(session->inChannelCount,
1008 session->samplingRate,
1009 session->apmSamplingRate,
1010 RESAMPLER_QUALITY,
1011 &error);
1012 if (session->inResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +00001013 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -07001014 speex_resampler_strerror(error));
1015 return -EINVAL;
1016 }
1017 session->outResampler = speex_resampler_init(session->outChannelCount,
1018 session->apmSamplingRate,
1019 session->samplingRate,
1020 RESAMPLER_QUALITY,
1021 &error);
1022 if (session->outResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +00001023 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -07001024 speex_resampler_strerror(error));
1025 speex_resampler_destroy(session->inResampler);
1026 session->inResampler = NULL;
1027 return -EINVAL;
1028 }
1029 session->revResampler = speex_resampler_init(session->inChannelCount,
1030 session->samplingRate,
1031 session->apmSamplingRate,
1032 RESAMPLER_QUALITY,
1033 &error);
1034 if (session->revResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +00001035 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -07001036 speex_resampler_strerror(error));
1037 speex_resampler_destroy(session->inResampler);
1038 session->inResampler = NULL;
1039 speex_resampler_destroy(session->outResampler);
1040 session->outResampler = NULL;
1041 return -EINVAL;
1042 }
1043 }
1044
1045 session->state = PREPROC_SESSION_STATE_CONFIG;
1046 return 0;
1047}
1048
Eric Laurent3d5188b2011-12-16 15:30:36 -08001049void Session_GetConfig(preproc_session_t *session, effect_config_t *config)
1050{
1051 memset(config, 0, sizeof(effect_config_t));
1052 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
1053 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Glenn Kastenab334fd2012-03-14 12:56:06 -07001054 config->inputCfg.channels = audio_channel_in_mask_from_count(session->inChannelCount);
1055 // "out" doesn't mean output device, so this is the correct API to convert channel count to mask
1056 config->outputCfg.channels = audio_channel_in_mask_from_count(session->outChannelCount);
Eric Laurent3d5188b2011-12-16 15:30:36 -08001057 config->inputCfg.mask = config->outputCfg.mask =
1058 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
1059}
1060
Eric Laurenta9390d42011-06-17 20:17:17 -07001061int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
1062{
1063 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
1064 config->inputCfg.format != config->outputCfg.format ||
1065 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
1066 return -EINVAL;
1067 }
1068
Steve Block3856b092011-10-20 11:56:00 +01001069 ALOGV("Session_SetReverseConfig sr %d cnl %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001070 config->inputCfg.samplingRate, config->inputCfg.channels);
1071
1072 if (session->state < PREPROC_SESSION_STATE_CONFIG) {
1073 return -ENOSYS;
1074 }
1075 if (config->inputCfg.samplingRate != session->samplingRate ||
1076 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
1077 return -EINVAL;
1078 }
Andy Hunge5412692014-05-16 11:25:07 -07001079 uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
Alex Luebs9718b7d2015-11-24 14:33:14 -08001080 const webrtc::ProcessingConfig processing_config = {
Alex Luebs3f11ef02016-01-15 15:51:58 -08001081 {{static_cast<int>(session->apmSamplingRate), session->inChannelCount},
1082 {static_cast<int>(session->apmSamplingRate), session->outChannelCount},
1083 {static_cast<int>(session->apmSamplingRate), inCnl},
1084 {static_cast<int>(session->apmSamplingRate), inCnl}}};
Alex Luebs9718b7d2015-11-24 14:33:14 -08001085 int status = session->apm->Initialize(processing_config);
Eric Laurenta9390d42011-06-17 20:17:17 -07001086 if (status < 0) {
1087 return -EINVAL;
1088 }
1089 session->revChannelCount = inCnl;
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001090 session->revFrame->num_channels_ = inCnl;
1091 session->revFrame->sample_rate_hz_ = session->apmSamplingRate;
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001092 // force process buffer reallocation
1093 session->revBufSize = 0;
1094 session->framesRev = 0;
1095
Eric Laurenta9390d42011-06-17 20:17:17 -07001096 return 0;
1097}
1098
Eric Laurent3d5188b2011-12-16 15:30:36 -08001099void Session_GetReverseConfig(preproc_session_t *session, effect_config_t *config)
1100{
1101 memset(config, 0, sizeof(effect_config_t));
1102 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
1103 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
1104 config->inputCfg.channels = config->outputCfg.channels =
Glenn Kastenab334fd2012-03-14 12:56:06 -07001105 audio_channel_in_mask_from_count(session->revChannelCount);
Eric Laurent3d5188b2011-12-16 15:30:36 -08001106 config->inputCfg.mask = config->outputCfg.mask =
1107 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
1108}
1109
Eric Laurenta9390d42011-06-17 20:17:17 -07001110void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
1111{
1112 if (enabled) {
1113 if(session->enabledMsk == 0) {
1114 session->framesIn = 0;
1115 if (session->inResampler != NULL) {
1116 speex_resampler_reset_mem(session->inResampler);
1117 }
1118 session->framesOut = 0;
1119 if (session->outResampler != NULL) {
1120 speex_resampler_reset_mem(session->outResampler);
1121 }
1122 }
1123 session->enabledMsk |= (1 << procId);
1124 if (HasReverseStream(procId)) {
1125 session->framesRev = 0;
1126 if (session->revResampler != NULL) {
1127 speex_resampler_reset_mem(session->revResampler);
1128 }
1129 session->revEnabledMsk |= (1 << procId);
1130 }
1131 } else {
1132 session->enabledMsk &= ~(1 << procId);
1133 if (HasReverseStream(procId)) {
1134 session->revEnabledMsk &= ~(1 << procId);
1135 }
1136 }
Steve Block3856b092011-10-20 11:56:00 +01001137 ALOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001138 procId, enabled, session->enabledMsk, session->revEnabledMsk);
1139 session->processedMsk = 0;
1140 if (HasReverseStream(procId)) {
1141 session->revProcessedMsk = 0;
1142 }
1143}
1144
1145//------------------------------------------------------------------------------
1146// Bundle functions
1147//------------------------------------------------------------------------------
1148
1149static int sInitStatus = 1;
1150static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
1151
1152preproc_session_t *PreProc_GetSession(int32_t procId, int32_t sessionId, int32_t ioId)
1153{
1154 size_t i;
Eric Laurenta9390d42011-06-17 20:17:17 -07001155 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1156 if (sSessions[i].io == ioId) {
1157 if (sSessions[i].createdMsk & (1 << procId)) {
1158 return NULL;
1159 }
1160 return &sSessions[i];
1161 }
1162 }
1163 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1164 if (sSessions[i].io == 0) {
1165 sSessions[i].id = sessionId;
1166 sSessions[i].io = ioId;
1167 return &sSessions[i];
1168 }
1169 }
1170 return NULL;
1171}
1172
1173
1174int PreProc_Init() {
1175 size_t i;
1176 int status = 0;
1177
1178 if (sInitStatus <= 0) {
1179 return sInitStatus;
1180 }
1181 for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
1182 status = Session_Init(&sSessions[i]);
1183 }
1184 sInitStatus = status;
1185 return sInitStatus;
1186}
1187
Glenn Kasten5e92a782012-01-30 07:40:52 -08001188const effect_descriptor_t *PreProc_GetDescriptor(const effect_uuid_t *uuid)
Eric Laurenta9390d42011-06-17 20:17:17 -07001189{
1190 size_t i;
1191 for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
1192 if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
1193 return sDescriptors[i];
1194 }
1195 }
1196 return NULL;
1197}
1198
1199
1200extern "C" {
1201
1202//------------------------------------------------------------------------------
1203// Effect Control Interface Implementation
1204//------------------------------------------------------------------------------
1205
1206int PreProcessingFx_Process(effect_handle_t self,
1207 audio_buffer_t *inBuffer,
1208 audio_buffer_t *outBuffer)
1209{
1210 preproc_effect_t * effect = (preproc_effect_t *)self;
Eric Laurenta9390d42011-06-17 20:17:17 -07001211
1212 if (effect == NULL){
Steve Block3856b092011-10-20 11:56:00 +01001213 ALOGV("PreProcessingFx_Process() ERROR effect == NULL");
Eric Laurenta9390d42011-06-17 20:17:17 -07001214 return -EINVAL;
1215 }
1216 preproc_session_t * session = (preproc_session_t *)effect->session;
1217
1218 if (inBuffer == NULL || inBuffer->raw == NULL ||
1219 outBuffer == NULL || outBuffer->raw == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001220 ALOGW("PreProcessingFx_Process() ERROR bad pointer");
Eric Laurenta9390d42011-06-17 20:17:17 -07001221 return -EINVAL;
1222 }
1223
1224 session->processedMsk |= (1<<effect->procId);
1225
Steve Block3856b092011-10-20 11:56:00 +01001226// ALOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001227// inBuffer->frameCount, session->enabledMsk, session->processedMsk);
1228
1229 if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
1230 effect->session->processedMsk = 0;
1231 size_t framesRq = outBuffer->frameCount;
1232 size_t framesWr = 0;
1233 if (session->framesOut) {
1234 size_t fr = session->framesOut;
1235 if (outBuffer->frameCount < fr) {
1236 fr = outBuffer->frameCount;
1237 }
1238 memcpy(outBuffer->s16,
1239 session->outBuf,
1240 fr * session->outChannelCount * sizeof(int16_t));
1241 memcpy(session->outBuf,
1242 session->outBuf + fr * session->outChannelCount,
1243 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1244 session->framesOut -= fr;
1245 framesWr += fr;
1246 }
1247 outBuffer->frameCount = framesWr;
1248 if (framesWr == framesRq) {
1249 inBuffer->frameCount = 0;
1250 return 0;
1251 }
1252
1253 if (session->inResampler != NULL) {
1254 size_t fr = session->frameCount - session->framesIn;
1255 if (inBuffer->frameCount < fr) {
1256 fr = inBuffer->frameCount;
1257 }
1258 if (session->inBufSize < session->framesIn + fr) {
Eric Laurent679650f2015-08-21 14:01:50 -07001259 int16_t *buf;
Eric Laurenta9390d42011-06-17 20:17:17 -07001260 session->inBufSize = session->framesIn + fr;
Eric Laurent679650f2015-08-21 14:01:50 -07001261 buf = (int16_t *)realloc(session->inBuf,
Eric Laurenta9390d42011-06-17 20:17:17 -07001262 session->inBufSize * session->inChannelCount * sizeof(int16_t));
Eric Laurent679650f2015-08-21 14:01:50 -07001263 if (buf == NULL) {
1264 session->framesIn = 0;
1265 free(session->inBuf);
1266 session->inBuf = NULL;
1267 return -ENOMEM;
1268 }
1269 session->inBuf = buf;
Eric Laurenta9390d42011-06-17 20:17:17 -07001270 }
1271 memcpy(session->inBuf + session->framesIn * session->inChannelCount,
1272 inBuffer->s16,
1273 fr * session->inChannelCount * sizeof(int16_t));
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001274#ifdef DUAL_MIC_TEST
1275 pthread_mutex_lock(&gPcmDumpLock);
1276 if (gPcmDumpFh != NULL) {
1277 fwrite(inBuffer->raw,
1278 fr * session->inChannelCount * sizeof(int16_t), 1, gPcmDumpFh);
1279 }
1280 pthread_mutex_unlock(&gPcmDumpLock);
1281#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001282
1283 session->framesIn += fr;
1284 inBuffer->frameCount = fr;
1285 if (session->framesIn < session->frameCount) {
1286 return 0;
1287 }
Kévin PETIT377b2ec2014-02-03 12:35:36 +00001288 spx_uint32_t frIn = session->framesIn;
1289 spx_uint32_t frOut = session->apmFrameCount;
Eric Laurenta9390d42011-06-17 20:17:17 -07001290 if (session->inChannelCount == 1) {
1291 speex_resampler_process_int(session->inResampler,
1292 0,
1293 session->inBuf,
1294 &frIn,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001295 session->procFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001296 &frOut);
1297 } else {
1298 speex_resampler_process_interleaved_int(session->inResampler,
1299 session->inBuf,
1300 &frIn,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001301 session->procFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001302 &frOut);
1303 }
1304 memcpy(session->inBuf,
1305 session->inBuf + frIn * session->inChannelCount,
1306 (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
1307 session->framesIn -= frIn;
1308 } else {
1309 size_t fr = session->frameCount - session->framesIn;
1310 if (inBuffer->frameCount < fr) {
1311 fr = inBuffer->frameCount;
1312 }
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001313 memcpy(session->procFrame->data_ + session->framesIn * session->inChannelCount,
Eric Laurenta9390d42011-06-17 20:17:17 -07001314 inBuffer->s16,
1315 fr * session->inChannelCount * sizeof(int16_t));
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001316
1317#ifdef DUAL_MIC_TEST
1318 pthread_mutex_lock(&gPcmDumpLock);
1319 if (gPcmDumpFh != NULL) {
1320 fwrite(inBuffer->raw,
1321 fr * session->inChannelCount * sizeof(int16_t), 1, gPcmDumpFh);
1322 }
1323 pthread_mutex_unlock(&gPcmDumpLock);
1324#endif
1325
Eric Laurenta9390d42011-06-17 20:17:17 -07001326 session->framesIn += fr;
1327 inBuffer->frameCount = fr;
1328 if (session->framesIn < session->frameCount) {
1329 return 0;
1330 }
1331 session->framesIn = 0;
1332 }
Alex Luebs766bf732015-12-14 21:32:13 -08001333 session->procFrame->samples_per_channel_ = session->apmFrameCount;
Eric Laurenta9390d42011-06-17 20:17:17 -07001334
1335 effect->session->apm->ProcessStream(session->procFrame);
1336
1337 if (session->outBufSize < session->framesOut + session->frameCount) {
Eric Laurent679650f2015-08-21 14:01:50 -07001338 int16_t *buf;
Eric Laurenta9390d42011-06-17 20:17:17 -07001339 session->outBufSize = session->framesOut + session->frameCount;
Eric Laurent679650f2015-08-21 14:01:50 -07001340 buf = (int16_t *)realloc(session->outBuf,
1341 session->outBufSize * session->outChannelCount * sizeof(int16_t));
1342 if (buf == NULL) {
1343 session->framesOut = 0;
1344 free(session->outBuf);
1345 session->outBuf = NULL;
1346 return -ENOMEM;
1347 }
1348 session->outBuf = buf;
Eric Laurenta9390d42011-06-17 20:17:17 -07001349 }
1350
1351 if (session->outResampler != NULL) {
Kévin PETIT377b2ec2014-02-03 12:35:36 +00001352 spx_uint32_t frIn = session->apmFrameCount;
1353 spx_uint32_t frOut = session->frameCount;
Eric Laurenta9390d42011-06-17 20:17:17 -07001354 if (session->inChannelCount == 1) {
1355 speex_resampler_process_int(session->outResampler,
1356 0,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001357 session->procFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001358 &frIn,
1359 session->outBuf + session->framesOut * session->outChannelCount,
1360 &frOut);
1361 } else {
1362 speex_resampler_process_interleaved_int(session->outResampler,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001363 session->procFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001364 &frIn,
1365 session->outBuf + session->framesOut * session->outChannelCount,
1366 &frOut);
1367 }
1368 session->framesOut += frOut;
1369 } else {
1370 memcpy(session->outBuf + session->framesOut * session->outChannelCount,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001371 session->procFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001372 session->frameCount * session->outChannelCount * sizeof(int16_t));
1373 session->framesOut += session->frameCount;
1374 }
1375 size_t fr = session->framesOut;
1376 if (framesRq - framesWr < fr) {
1377 fr = framesRq - framesWr;
1378 }
1379 memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
1380 session->outBuf,
1381 fr * session->outChannelCount * sizeof(int16_t));
1382 memcpy(session->outBuf,
1383 session->outBuf + fr * session->outChannelCount,
1384 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1385 session->framesOut -= fr;
1386 outBuffer->frameCount += fr;
1387
1388 return 0;
1389 } else {
1390 return -ENODATA;
1391 }
1392}
1393
1394int PreProcessingFx_Command(effect_handle_t self,
1395 uint32_t cmdCode,
1396 uint32_t cmdSize,
1397 void *pCmdData,
1398 uint32_t *replySize,
1399 void *pReplyData)
1400{
1401 preproc_effect_t * effect = (preproc_effect_t *) self;
Eric Laurenta9390d42011-06-17 20:17:17 -07001402
1403 if (effect == NULL){
1404 return -EINVAL;
1405 }
1406
Steve Block3856b092011-10-20 11:56:00 +01001407 //ALOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
Eric Laurenta9390d42011-06-17 20:17:17 -07001408
1409 switch (cmdCode){
1410 case EFFECT_CMD_INIT:
1411 if (pReplyData == NULL || *replySize != sizeof(int)){
1412 return -EINVAL;
1413 }
1414 if (effect->ops->init) {
1415 effect->ops->init(effect);
1416 }
1417 *(int *)pReplyData = 0;
1418 break;
1419
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001420 case EFFECT_CMD_SET_CONFIG: {
Eric Laurenta9390d42011-06-17 20:17:17 -07001421 if (pCmdData == NULL||
1422 cmdSize != sizeof(effect_config_t)||
1423 pReplyData == NULL||
1424 *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001425 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent3d5188b2011-12-16 15:30:36 -08001426 "EFFECT_CMD_SET_CONFIG: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001427 return -EINVAL;
1428 }
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001429#ifdef DUAL_MIC_TEST
1430 // make sure that the config command is accepted by making as if all effects were
1431 // disabled: this is OK for functional tests
1432 uint32_t enabledMsk = effect->session->enabledMsk;
1433 if (gDualMicEnabled) {
1434 effect->session->enabledMsk = 0;
1435 }
1436#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001437 *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001438#ifdef DUAL_MIC_TEST
1439 if (gDualMicEnabled) {
1440 effect->session->enabledMsk = enabledMsk;
1441 }
1442#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001443 if (*(int *)pReplyData != 0) {
1444 break;
1445 }
Eric Laurent76533e92012-02-17 17:52:04 -08001446 if (effect->state != PREPROC_EFFECT_STATE_ACTIVE) {
1447 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1448 }
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001449 } break;
Eric Laurenta9390d42011-06-17 20:17:17 -07001450
Eric Laurent3d5188b2011-12-16 15:30:36 -08001451 case EFFECT_CMD_GET_CONFIG:
1452 if (pReplyData == NULL ||
1453 *replySize != sizeof(effect_config_t)) {
1454 ALOGV("\tLVM_ERROR : PreProcessingFx_Command cmdCode Case: "
1455 "EFFECT_CMD_GET_CONFIG: ERROR");
1456 return -EINVAL;
1457 }
1458
Eric Laurent94fef382012-02-06 14:28:54 -08001459 Session_GetConfig(effect->session, (effect_config_t *)pReplyData);
Eric Laurent3d5188b2011-12-16 15:30:36 -08001460 break;
1461
1462 case EFFECT_CMD_SET_CONFIG_REVERSE:
1463 if (pCmdData == NULL ||
1464 cmdSize != sizeof(effect_config_t) ||
1465 pReplyData == NULL ||
1466 *replySize != sizeof(int)) {
Steve Block3856b092011-10-20 11:56:00 +01001467 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent3d5188b2011-12-16 15:30:36 -08001468 "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001469 return -EINVAL;
1470 }
1471 *(int *)pReplyData = Session_SetReverseConfig(effect->session,
1472 (effect_config_t *)pCmdData);
1473 if (*(int *)pReplyData != 0) {
1474 break;
1475 }
1476 break;
1477
Eric Laurent3d5188b2011-12-16 15:30:36 -08001478 case EFFECT_CMD_GET_CONFIG_REVERSE:
1479 if (pReplyData == NULL ||
1480 *replySize != sizeof(effect_config_t)){
1481 ALOGV("PreProcessingFx_Command cmdCode Case: "
1482 "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR");
1483 return -EINVAL;
1484 }
1485 Session_GetReverseConfig(effect->session, (effect_config_t *)pCmdData);
1486 break;
1487
Eric Laurenta9390d42011-06-17 20:17:17 -07001488 case EFFECT_CMD_RESET:
1489 if (effect->ops->reset) {
1490 effect->ops->reset(effect);
1491 }
1492 break;
1493
Eric Laurent0f714a42015-06-19 15:33:57 -07001494 case EFFECT_CMD_GET_PARAM: {
1495 effect_param_t *p = (effect_param_t *)pCmdData;
1496
1497 if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
1498 cmdSize < (sizeof(effect_param_t) + p->psize) ||
1499 pReplyData == NULL || replySize == NULL ||
1500 *replySize < (sizeof(effect_param_t) + p->psize)){
Steve Block3856b092011-10-20 11:56:00 +01001501 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001502 "EFFECT_CMD_GET_PARAM: ERROR");
1503 return -EINVAL;
1504 }
Eric Laurenta9390d42011-06-17 20:17:17 -07001505
1506 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
1507
1508 p = (effect_param_t *)pReplyData;
1509
1510 int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
1511
1512 if (effect->ops->get_parameter) {
1513 p->status = effect->ops->get_parameter(effect, p->data,
Ashok Bhatb302bd52014-02-18 11:40:00 +00001514 &p->vsize,
Eric Laurenta9390d42011-06-17 20:17:17 -07001515 p->data + voffset);
1516 *replySize = sizeof(effect_param_t) + voffset + p->vsize;
1517 }
1518 } break;
1519
1520 case EFFECT_CMD_SET_PARAM:{
1521 if (pCmdData == NULL||
Eric Laurent0f714a42015-06-19 15:33:57 -07001522 cmdSize < sizeof(effect_param_t) ||
1523 pReplyData == NULL || replySize == NULL ||
Eric Laurenta9390d42011-06-17 20:17:17 -07001524 *replySize != sizeof(int32_t)){
Steve Block3856b092011-10-20 11:56:00 +01001525 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001526 "EFFECT_CMD_SET_PARAM: ERROR");
1527 return -EINVAL;
1528 }
1529 effect_param_t *p = (effect_param_t *) pCmdData;
1530
1531 if (p->psize != sizeof(int32_t)){
Steve Block3856b092011-10-20 11:56:00 +01001532 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001533 "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
1534 return -EINVAL;
1535 }
1536 if (effect->ops->set_parameter) {
1537 *(int *)pReplyData = effect->ops->set_parameter(effect,
1538 (void *)p->data,
1539 p->data + p->psize);
1540 }
1541 } break;
1542
1543 case EFFECT_CMD_ENABLE:
Eric Laurent0f714a42015-06-19 15:33:57 -07001544 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001545 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001546 return -EINVAL;
1547 }
1548 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
1549 break;
1550
1551 case EFFECT_CMD_DISABLE:
Eric Laurent0f714a42015-06-19 15:33:57 -07001552 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001553 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001554 return -EINVAL;
1555 }
1556 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1557 break;
1558
1559 case EFFECT_CMD_SET_DEVICE:
1560 case EFFECT_CMD_SET_INPUT_DEVICE:
1561 if (pCmdData == NULL ||
1562 cmdSize != sizeof(uint32_t)) {
Steve Block3856b092011-10-20 11:56:00 +01001563 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001564 return -EINVAL;
1565 }
1566
1567 if (effect->ops->set_device) {
1568 effect->ops->set_device(effect, *(uint32_t *)pCmdData);
1569 }
1570 break;
1571
1572 case EFFECT_CMD_SET_VOLUME:
1573 case EFFECT_CMD_SET_AUDIO_MODE:
1574 break;
1575
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001576#ifdef DUAL_MIC_TEST
1577 ///// test commands start
1578 case PREPROC_CMD_DUAL_MIC_ENABLE: {
1579 if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
1580 pReplyData == NULL || replySize == NULL) {
1581 ALOGE("PreProcessingFx_Command cmdCode Case: "
1582 "PREPROC_CMD_DUAL_MIC_ENABLE: ERROR");
1583 *replySize = 0;
1584 return -EINVAL;
1585 }
1586 gDualMicEnabled = *(bool *)pCmdData;
1587 if (gDualMicEnabled) {
1588 effect->aux_channels_on = sHasAuxChannels[effect->procId];
1589 } else {
1590 effect->aux_channels_on = false;
1591 }
1592 effect->cur_channel_config = (effect->session->inChannelCount == 1) ?
1593 CHANNEL_CFG_MONO : CHANNEL_CFG_STEREO;
1594
1595 ALOGV("PREPROC_CMD_DUAL_MIC_ENABLE: %s", gDualMicEnabled ? "enabled" : "disabled");
1596 *replySize = sizeof(int);
1597 *(int *)pReplyData = 0;
1598 } break;
1599 case PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: {
1600 if (pCmdData == NULL|| pReplyData == NULL || replySize == NULL) {
1601 ALOGE("PreProcessingFx_Command cmdCode Case: "
1602 "PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: ERROR");
1603 *replySize = 0;
1604 return -EINVAL;
1605 }
1606 pthread_mutex_lock(&gPcmDumpLock);
1607 if (gPcmDumpFh != NULL) {
1608 fclose(gPcmDumpFh);
1609 gPcmDumpFh = NULL;
1610 }
1611 char *path = strndup((char *)pCmdData, cmdSize);
1612 gPcmDumpFh = fopen((char *)path, "wb");
1613 pthread_mutex_unlock(&gPcmDumpLock);
1614 ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: path %s gPcmDumpFh %p",
1615 path, gPcmDumpFh);
1616 ALOGE_IF(gPcmDumpFh <= 0, "gPcmDumpFh open error %d %s", errno, strerror(errno));
1617 free(path);
1618 *replySize = sizeof(int);
1619 *(int *)pReplyData = 0;
1620 } break;
1621 case PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: {
1622 if (pReplyData == NULL || replySize == NULL) {
1623 ALOGE("PreProcessingFx_Command cmdCode Case: "
1624 "PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: ERROR");
1625 *replySize = 0;
1626 return -EINVAL;
1627 }
1628 pthread_mutex_lock(&gPcmDumpLock);
1629 if (gPcmDumpFh != NULL) {
1630 fclose(gPcmDumpFh);
1631 gPcmDumpFh = NULL;
1632 }
1633 pthread_mutex_unlock(&gPcmDumpLock);
1634 ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP");
1635 *replySize = sizeof(int);
1636 *(int *)pReplyData = 0;
1637 } break;
1638 ///// test commands end
1639
1640 case EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: {
1641 if(!gDualMicEnabled) {
1642 return -EINVAL;
1643 }
1644 if (pCmdData == NULL|| cmdSize != 2 * sizeof(uint32_t) ||
1645 pReplyData == NULL || replySize == NULL) {
1646 ALOGE("PreProcessingFx_Command cmdCode Case: "
1647 "EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: ERROR");
1648 *replySize = 0;
1649 return -EINVAL;
1650 }
1651 if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS ||
1652 !effect->aux_channels_on) {
1653 ALOGV("PreProcessingFx_Command feature EFFECT_FEATURE_AUX_CHANNELS not supported by"
1654 " fx %d", effect->procId);
1655 *(uint32_t *)pReplyData = -ENOSYS;
1656 *replySize = sizeof(uint32_t);
1657 break;
1658 }
1659 size_t num_configs = *((uint32_t *)pCmdData + 1);
1660 if (*replySize < (2 * sizeof(uint32_t) +
1661 num_configs * sizeof(channel_config_t))) {
1662 *replySize = 0;
1663 return -EINVAL;
1664 }
1665
1666 *((uint32_t *)pReplyData + 1) = CHANNEL_CFG_CNT;
1667 if (num_configs < CHANNEL_CFG_CNT ||
1668 *replySize < (2 * sizeof(uint32_t) +
1669 CHANNEL_CFG_CNT * sizeof(channel_config_t))) {
1670 *(uint32_t *)pReplyData = -ENOMEM;
1671 } else {
1672 num_configs = CHANNEL_CFG_CNT;
1673 *(uint32_t *)pReplyData = 0;
1674 }
1675 ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS num config %d",
1676 num_configs);
1677
1678 *replySize = 2 * sizeof(uint32_t) + num_configs * sizeof(channel_config_t);
1679 *((uint32_t *)pReplyData + 1) = num_configs;
1680 memcpy((uint32_t *)pReplyData + 2, &sDualMicConfigs, num_configs * sizeof(channel_config_t));
1681 } break;
1682 case EFFECT_CMD_GET_FEATURE_CONFIG:
1683 if(!gDualMicEnabled) {
1684 return -EINVAL;
1685 }
1686 if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
1687 pReplyData == NULL || replySize == NULL ||
1688 *replySize < sizeof(uint32_t) + sizeof(channel_config_t)) {
1689 ALOGE("PreProcessingFx_Command cmdCode Case: "
1690 "EFFECT_CMD_GET_FEATURE_CONFIG: ERROR");
1691 return -EINVAL;
1692 }
1693 if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1694 *(uint32_t *)pReplyData = -ENOSYS;
1695 *replySize = sizeof(uint32_t);
1696 break;
1697 }
1698 ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_CONFIG");
1699 *(uint32_t *)pReplyData = 0;
1700 *replySize = sizeof(uint32_t) + sizeof(channel_config_t);
1701 memcpy((uint32_t *)pReplyData + 1,
1702 &sDualMicConfigs[effect->cur_channel_config],
1703 sizeof(channel_config_t));
1704 break;
1705 case EFFECT_CMD_SET_FEATURE_CONFIG: {
1706 ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG: "
1707 "gDualMicEnabled %d effect->aux_channels_on %d",
1708 gDualMicEnabled, effect->aux_channels_on);
1709 if(!gDualMicEnabled) {
1710 return -EINVAL;
1711 }
1712 if (pCmdData == NULL|| cmdSize != (sizeof(uint32_t) + sizeof(channel_config_t)) ||
1713 pReplyData == NULL || replySize == NULL ||
1714 *replySize < sizeof(uint32_t)) {
1715 ALOGE("PreProcessingFx_Command cmdCode Case: "
1716 "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1717 "pCmdData %p cmdSize %d pReplyData %p replySize %p *replySize %d",
1718 pCmdData, cmdSize, pReplyData, replySize, replySize ? *replySize : -1);
1719 return -EINVAL;
1720 }
1721 *replySize = sizeof(uint32_t);
1722 if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1723 *(uint32_t *)pReplyData = -ENOSYS;
1724 ALOGV("PreProcessingFx_Command cmdCode Case: "
1725 "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1726 "CmdData %d effect->aux_channels_on %d",
1727 *(uint32_t *)pCmdData, effect->aux_channels_on);
1728 break;
1729 }
1730 size_t i;
1731 for (i = 0; i < CHANNEL_CFG_CNT;i++) {
1732 if (memcmp((uint32_t *)pCmdData + 1,
1733 &sDualMicConfigs[i], sizeof(channel_config_t)) == 0) {
1734 break;
1735 }
1736 }
1737 if (i == CHANNEL_CFG_CNT) {
1738 *(uint32_t *)pReplyData = -EINVAL;
1739 ALOGW("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG invalid config"
1740 "[%08x].[%08x]", *((uint32_t *)pCmdData + 1), *((uint32_t *)pCmdData + 2));
1741 } else {
1742 effect->cur_channel_config = i;
1743 *(uint32_t *)pReplyData = 0;
1744 ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG New config"
1745 "[%08x].[%08x]", sDualMicConfigs[i].main_channels, sDualMicConfigs[i].aux_channels);
1746 }
1747 } break;
1748#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001749 default:
1750 return -EINVAL;
1751 }
1752 return 0;
1753}
1754
1755
1756int PreProcessingFx_GetDescriptor(effect_handle_t self,
1757 effect_descriptor_t *pDescriptor)
1758{
1759 preproc_effect_t * effect = (preproc_effect_t *) self;
1760
1761 if (effect == NULL || pDescriptor == NULL) {
1762 return -EINVAL;
1763 }
1764
Glenn Kastena189a682012-02-20 12:16:30 -08001765 *pDescriptor = *sDescriptors[effect->procId];
Eric Laurenta9390d42011-06-17 20:17:17 -07001766
1767 return 0;
1768}
1769
1770int PreProcessingFx_ProcessReverse(effect_handle_t self,
1771 audio_buffer_t *inBuffer,
Eric Laurent0f714a42015-06-19 15:33:57 -07001772 audio_buffer_t *outBuffer __unused)
Eric Laurenta9390d42011-06-17 20:17:17 -07001773{
1774 preproc_effect_t * effect = (preproc_effect_t *)self;
Eric Laurenta9390d42011-06-17 20:17:17 -07001775
1776 if (effect == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001777 ALOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
Eric Laurenta9390d42011-06-17 20:17:17 -07001778 return -EINVAL;
1779 }
1780 preproc_session_t * session = (preproc_session_t *)effect->session;
1781
1782 if (inBuffer == NULL || inBuffer->raw == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001783 ALOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
Eric Laurenta9390d42011-06-17 20:17:17 -07001784 return -EINVAL;
1785 }
1786
1787 session->revProcessedMsk |= (1<<effect->procId);
1788
Steve Block3856b092011-10-20 11:56:00 +01001789// ALOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001790// inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
1791
1792
1793 if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
1794 effect->session->revProcessedMsk = 0;
1795 if (session->revResampler != NULL) {
1796 size_t fr = session->frameCount - session->framesRev;
1797 if (inBuffer->frameCount < fr) {
1798 fr = inBuffer->frameCount;
1799 }
1800 if (session->revBufSize < session->framesRev + fr) {
Eric Laurent679650f2015-08-21 14:01:50 -07001801 int16_t *buf;
Eric Laurenta9390d42011-06-17 20:17:17 -07001802 session->revBufSize = session->framesRev + fr;
Eric Laurent679650f2015-08-21 14:01:50 -07001803 buf = (int16_t *)realloc(session->revBuf,
1804 session->revBufSize * session->inChannelCount * sizeof(int16_t));
1805 if (buf == NULL) {
1806 session->framesRev = 0;
1807 free(session->revBuf);
1808 session->revBuf = NULL;
1809 return -ENOMEM;
1810 }
1811 session->revBuf = buf;
Eric Laurenta9390d42011-06-17 20:17:17 -07001812 }
1813 memcpy(session->revBuf + session->framesRev * session->inChannelCount,
1814 inBuffer->s16,
1815 fr * session->inChannelCount * sizeof(int16_t));
1816
1817 session->framesRev += fr;
1818 inBuffer->frameCount = fr;
1819 if (session->framesRev < session->frameCount) {
1820 return 0;
1821 }
Kévin PETIT377b2ec2014-02-03 12:35:36 +00001822 spx_uint32_t frIn = session->framesRev;
1823 spx_uint32_t frOut = session->apmFrameCount;
Eric Laurenta9390d42011-06-17 20:17:17 -07001824 if (session->inChannelCount == 1) {
1825 speex_resampler_process_int(session->revResampler,
1826 0,
1827 session->revBuf,
1828 &frIn,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001829 session->revFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001830 &frOut);
1831 } else {
1832 speex_resampler_process_interleaved_int(session->revResampler,
1833 session->revBuf,
1834 &frIn,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001835 session->revFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001836 &frOut);
1837 }
1838 memcpy(session->revBuf,
1839 session->revBuf + frIn * session->inChannelCount,
1840 (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
1841 session->framesRev -= frIn;
1842 } else {
1843 size_t fr = session->frameCount - session->framesRev;
1844 if (inBuffer->frameCount < fr) {
1845 fr = inBuffer->frameCount;
1846 }
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001847 memcpy(session->revFrame->data_ + session->framesRev * session->inChannelCount,
Eric Laurenta9390d42011-06-17 20:17:17 -07001848 inBuffer->s16,
1849 fr * session->inChannelCount * sizeof(int16_t));
1850 session->framesRev += fr;
1851 inBuffer->frameCount = fr;
1852 if (session->framesRev < session->frameCount) {
1853 return 0;
1854 }
1855 session->framesRev = 0;
1856 }
Alex Luebs766bf732015-12-14 21:32:13 -08001857 session->revFrame->samples_per_channel_ = session->apmFrameCount;
Eric Laurenta9390d42011-06-17 20:17:17 -07001858 effect->session->apm->AnalyzeReverseStream(session->revFrame);
1859 return 0;
1860 } else {
1861 return -ENODATA;
1862 }
1863}
1864
1865
1866// effect_handle_t interface implementation for effect
1867const struct effect_interface_s sEffectInterface = {
1868 PreProcessingFx_Process,
1869 PreProcessingFx_Command,
1870 PreProcessingFx_GetDescriptor,
1871 NULL
1872};
1873
1874const struct effect_interface_s sEffectInterfaceReverse = {
1875 PreProcessingFx_Process,
1876 PreProcessingFx_Command,
1877 PreProcessingFx_GetDescriptor,
1878 PreProcessingFx_ProcessReverse
1879};
1880
1881//------------------------------------------------------------------------------
1882// Effect Library Interface Implementation
1883//------------------------------------------------------------------------------
1884
Glenn Kasten5e92a782012-01-30 07:40:52 -08001885int PreProcessingLib_Create(const effect_uuid_t *uuid,
Eric Laurenta9390d42011-06-17 20:17:17 -07001886 int32_t sessionId,
1887 int32_t ioId,
1888 effect_handle_t *pInterface)
1889{
Steve Block3856b092011-10-20 11:56:00 +01001890 ALOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
Eric Laurenta9390d42011-06-17 20:17:17 -07001891
1892 int status;
1893 const effect_descriptor_t *desc;
1894 preproc_session_t *session;
1895 uint32_t procId;
1896
1897 if (PreProc_Init() != 0) {
1898 return sInitStatus;
1899 }
1900 desc = PreProc_GetDescriptor(uuid);
1901 if (desc == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +00001902 ALOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
Eric Laurenta9390d42011-06-17 20:17:17 -07001903 return -EINVAL;
1904 }
1905 procId = UuidToProcId(&desc->type);
1906
1907 session = PreProc_GetSession(procId, sessionId, ioId);
1908 if (session == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +00001909 ALOGW("EffectCreate: no more session available");
Eric Laurenta9390d42011-06-17 20:17:17 -07001910 return -EINVAL;
1911 }
1912
1913 status = Session_CreateEffect(session, procId, pInterface);
1914
1915 if (status < 0 && session->createdMsk == 0) {
1916 session->io = 0;
1917 }
1918 return status;
1919}
1920
1921int PreProcessingLib_Release(effect_handle_t interface)
1922{
Steve Block3856b092011-10-20 11:56:00 +01001923 ALOGV("EffectRelease start %p", interface);
Eric Laurenta9390d42011-06-17 20:17:17 -07001924 if (PreProc_Init() != 0) {
1925 return sInitStatus;
1926 }
1927
1928 preproc_effect_t *fx = (preproc_effect_t *)interface;
1929
1930 if (fx->session->io == 0) {
1931 return -EINVAL;
1932 }
1933 return Session_ReleaseEffect(fx->session, fx);
1934}
1935
Glenn Kasten5e92a782012-01-30 07:40:52 -08001936int PreProcessingLib_GetDescriptor(const effect_uuid_t *uuid,
Eric Laurenta9390d42011-06-17 20:17:17 -07001937 effect_descriptor_t *pDescriptor) {
1938
1939 if (pDescriptor == NULL || uuid == NULL){
1940 return -EINVAL;
1941 }
1942
1943 const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
1944 if (desc == NULL) {
Steve Block3856b092011-10-20 11:56:00 +01001945 ALOGV("PreProcessingLib_GetDescriptor() not found");
Eric Laurenta9390d42011-06-17 20:17:17 -07001946 return -EINVAL;
1947 }
1948
Steve Block3856b092011-10-20 11:56:00 +01001949 ALOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
Eric Laurenta9390d42011-06-17 20:17:17 -07001950
Glenn Kastena189a682012-02-20 12:16:30 -08001951 *pDescriptor = *desc;
Eric Laurenta9390d42011-06-17 20:17:17 -07001952 return 0;
1953}
1954
Marco Nelissen7f16b192012-10-25 16:05:57 -07001955// This is the only symbol that needs to be exported
1956__attribute__ ((visibility ("default")))
Eric Laurenta9390d42011-06-17 20:17:17 -07001957audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
synergydevc9d8ea72013-10-19 22:51:33 -07001958 .tag = AUDIO_EFFECT_LIBRARY_TAG,
1959 .version = EFFECT_LIBRARY_API_VERSION,
1960 .name = "Audio Preprocessing Library",
1961 .implementor = "The Android Open Source Project",
1962 .create_effect = PreProcessingLib_Create,
1963 .release_effect = PreProcessingLib_Release,
1964 .get_descriptor = PreProcessingLib_GetDescriptor
Eric Laurenta9390d42011-06-17 20:17:17 -07001965};
1966
1967}; // extern "C"