blob: 1d76f625578e5b7347192a2cf4a8e31088f048fb [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
31
32//------------------------------------------------------------------------------
33// local definitions
34//------------------------------------------------------------------------------
35
36// maximum number of sessions
37#define PREPROC_NUM_SESSIONS 8
38
39// types of pre processing modules
40enum preproc_id
41{
42 PREPROC_AGC, // Automatic Gain Control
43 PREPROC_AEC, // Acoustic Echo Canceler
44 PREPROC_NS, // Noise Suppressor
45 PREPROC_NUM_EFFECTS
46};
47
48// Session state
49enum preproc_session_state {
50 PREPROC_SESSION_STATE_INIT, // initialized
51 PREPROC_SESSION_STATE_CONFIG // configuration received
52};
53
54// Effect/Preprocessor state
55enum preproc_effect_state {
56 PREPROC_EFFECT_STATE_INIT, // initialized
57 PREPROC_EFFECT_STATE_CREATED, // webRTC engine created
58 PREPROC_EFFECT_STATE_CONFIG, // configuration received/disabled
59 PREPROC_EFFECT_STATE_ACTIVE // active/enabled
60};
61
62// handle on webRTC engine
63typedef void* preproc_fx_handle_t;
64
65typedef struct preproc_session_s preproc_session_t;
66typedef struct preproc_effect_s preproc_effect_t;
67typedef struct preproc_ops_s preproc_ops_t;
68
69// Effect operation table. Functions for all pre processors are declared in sPreProcOps[] table.
70// Function pointer can be null if no action required.
71struct preproc_ops_s {
72 int (* create)(preproc_effect_t *fx);
73 int (* init)(preproc_effect_t *fx);
74 int (* reset)(preproc_effect_t *fx);
75 void (* enable)(preproc_effect_t *fx);
76 void (* disable)(preproc_effect_t *fx);
77 int (* set_parameter)(preproc_effect_t *fx, void *param, void *value);
78 int (* get_parameter)(preproc_effect_t *fx, void *param, size_t *size, void *value);
79 int (* set_device)(preproc_effect_t *fx, uint32_t device);
80};
81
82// Effect context
83struct preproc_effect_s {
84 const struct effect_interface_s *itfe;
85 uint32_t procId; // type of pre processor (enum preproc_id)
86 uint32_t state; // current state (enum preproc_effect_state)
87 preproc_session_t *session; // session the effect is on
88 const preproc_ops_t *ops; // effect ops table
89 preproc_fx_handle_t engine; // handle on webRTC engine
90};
91
92// Session context
93struct preproc_session_s {
94 struct preproc_effect_s effects[PREPROC_NUM_EFFECTS]; // effects in this session
95 uint32_t state; // current state (enum preproc_session_state)
96 int id; // audio session ID
97 int io; // handle of input stream this session is on
98 webrtc::AudioProcessing* apm; // handle on webRTC audio processing module (APM)
99 size_t apmFrameCount; // buffer size for webRTC process (10 ms)
100 uint32_t apmSamplingRate; // webRTC APM sampling rate (8/16 or 32 kHz)
101 size_t frameCount; // buffer size before input resampler ( <=> apmFrameCount)
102 uint32_t samplingRate; // sampling rate at effect process interface
103 uint32_t inChannelCount; // input channel count
104 uint32_t outChannelCount; // output channel count
105 uint32_t createdMsk; // bit field containing IDs of crested pre processors
106 uint32_t enabledMsk; // bit field containing IDs of enabled pre processors
107 uint32_t processedMsk; // bit field containing IDs of pre processors already
108 // processed in current round
109 webrtc::AudioFrame *procFrame; // audio frame passed to webRTC AMP ProcessStream()
110 int16_t *inBuf; // input buffer used when resampling
111 size_t inBufSize; // input buffer size in frames
112 size_t framesIn; // number of frames in input buffer
113 SpeexResamplerState *inResampler; // handle on input speex resampler
114 int16_t *outBuf; // output buffer used when resampling
115 size_t outBufSize; // output buffer size in frames
116 size_t framesOut; // number of frames in output buffer
117 SpeexResamplerState *outResampler; // handle on output speex resampler
118 uint32_t revChannelCount; // number of channels on reverse stream
119 uint32_t revEnabledMsk; // bit field containing IDs of enabled pre processors
120 // with reverse channel
121 uint32_t revProcessedMsk; // bit field containing IDs of pre processors with reverse
122 // channel already processed in current round
123 webrtc::AudioFrame *revFrame; // audio frame passed to webRTC AMP AnalyzeReverseStream()
124 int16_t *revBuf; // reverse channel input buffer
125 size_t revBufSize; // reverse channel input buffer size
126 size_t framesRev; // number of frames in reverse channel input buffer
127 SpeexResamplerState *revResampler; // handle on reverse channel input speex resampler
128};
129
130//------------------------------------------------------------------------------
131// Effect descriptors
132//------------------------------------------------------------------------------
133
134// UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html
135// as the pre processing effects are not defined by OpenSL ES
136
137// Automatic Gain Control
138static const effect_descriptor_t sAgcDescriptor = {
139 { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
140 { 0xaa8130e0, 0x66fc, 0x11e0, 0xbad0, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
141 EFFECT_CONTROL_API_VERSION,
142 (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
143 0, //FIXME indicate CPU load
144 0, //FIXME indicate memory usage
145 "Automatic Gain Control",
146 "The Android Open Source Project"
147};
148
149// Acoustic Echo Cancellation
150static const effect_descriptor_t sAecDescriptor = {
151 { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
152 { 0xbb392ec0, 0x8d4d, 0x11e0, 0xa896, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
153 EFFECT_CONTROL_API_VERSION,
154 (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
155 0, //FIXME indicate CPU load
156 0, //FIXME indicate memory usage
157 "Acoustic Echo Canceler",
158 "The Android Open Source Project"
159};
160
161// Noise suppression
162static const effect_descriptor_t sNsDescriptor = {
163 { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
164 { 0xc06c8400, 0x8e06, 0x11e0, 0x9cb6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
165 EFFECT_CONTROL_API_VERSION,
166 (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
167 0, //FIXME indicate CPU load
168 0, //FIXME indicate memory usage
169 "Noise Suppression",
170 "The Android Open Source Project"
171};
172
173
174static const effect_descriptor_t *sDescriptors[PREPROC_NUM_EFFECTS] = {
175 &sAgcDescriptor,
176 &sAecDescriptor,
177 &sNsDescriptor
178};
179
180//------------------------------------------------------------------------------
181// Helper functions
182//------------------------------------------------------------------------------
183
184const effect_uuid_t * const sUuidToPreProcTable[PREPROC_NUM_EFFECTS] = {
185 FX_IID_AGC,
186 FX_IID_AEC,
187 FX_IID_NS
188};
189
190
191const effect_uuid_t * ProcIdToUuid(int procId)
192{
193 if (procId >= PREPROC_NUM_EFFECTS) {
194 return EFFECT_UUID_NULL;
195 }
196 return sUuidToPreProcTable[procId];
197}
198
199uint32_t UuidToProcId(const effect_uuid_t * uuid)
200{
201 size_t i;
202 for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
203 if (memcmp(uuid, sUuidToPreProcTable[i], sizeof(*uuid)) == 0) {
204 break;
205 }
206 }
207 return i;
208}
209
210bool HasReverseStream(uint32_t procId)
211{
212 if (procId == PREPROC_AEC) {
213 return true;
214 }
215 return false;
216}
217
218
219//------------------------------------------------------------------------------
220// Automatic Gain Control (AGC)
221//------------------------------------------------------------------------------
222
Eric Laurent53876962012-01-31 12:35:20 -0800223static const int kAgcDefaultTargetLevel = 3;
224static const int kAgcDefaultCompGain = 9;
Eric Laurenta9390d42011-06-17 20:17:17 -0700225static const bool kAgcDefaultLimiter = true;
226
227int AgcInit (preproc_effect_t *effect)
228{
Steve Block3856b092011-10-20 11:56:00 +0100229 ALOGV("AgcInit");
Eric Laurenta9390d42011-06-17 20:17:17 -0700230 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
231 agc->set_mode(webrtc::GainControl::kFixedDigital);
232 agc->set_target_level_dbfs(kAgcDefaultTargetLevel);
233 agc->set_compression_gain_db(kAgcDefaultCompGain);
234 agc->enable_limiter(kAgcDefaultLimiter);
235 return 0;
236}
237
238int AgcCreate(preproc_effect_t *effect)
239{
240 webrtc::GainControl *agc = effect->session->apm->gain_control();
Steve Block3856b092011-10-20 11:56:00 +0100241 ALOGV("AgcCreate got agc %p", agc);
Eric Laurenta9390d42011-06-17 20:17:17 -0700242 if (agc == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000243 ALOGW("AgcCreate Error");
Eric Laurenta9390d42011-06-17 20:17:17 -0700244 return -ENOMEM;
245 }
246 effect->engine = static_cast<preproc_fx_handle_t>(agc);
247 AgcInit(effect);
248 return 0;
249}
250
251int AgcGetParameter(preproc_effect_t *effect,
252 void *pParam,
253 size_t *pValueSize,
254 void *pValue)
255{
256 int status = 0;
257 uint32_t param = *(uint32_t *)pParam;
258 t_agc_settings *pProperties = (t_agc_settings *)pValue;
259 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
260
261 switch (param) {
262 case AGC_PARAM_TARGET_LEVEL:
263 case AGC_PARAM_COMP_GAIN:
264 if (*pValueSize < sizeof(int16_t)) {
265 *pValueSize = 0;
266 return -EINVAL;
267 }
268 break;
269 case AGC_PARAM_LIMITER_ENA:
270 if (*pValueSize < sizeof(bool)) {
271 *pValueSize = 0;
272 return -EINVAL;
273 }
274 break;
275 case AGC_PARAM_PROPERTIES:
276 if (*pValueSize < sizeof(t_agc_settings)) {
277 *pValueSize = 0;
278 return -EINVAL;
279 }
280 break;
281
282 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000283 ALOGW("AgcGetParameter() unknown param %08x", param);
Eric Laurenta9390d42011-06-17 20:17:17 -0700284 status = -EINVAL;
285 break;
286 }
287
288 switch (param) {
289 case AGC_PARAM_TARGET_LEVEL:
290 *(int16_t *) pValue = (int16_t)(agc->target_level_dbfs() * -100);
Steve Block3856b092011-10-20 11:56:00 +0100291 ALOGV("AgcGetParameter() target level %d milliBels", *(int16_t *) pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700292 break;
293 case AGC_PARAM_COMP_GAIN:
294 *(int16_t *) pValue = (int16_t)(agc->compression_gain_db() * 100);
Steve Block3856b092011-10-20 11:56:00 +0100295 ALOGV("AgcGetParameter() comp gain %d milliBels", *(int16_t *) pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700296 break;
297 case AGC_PARAM_LIMITER_ENA:
298 *(bool *) pValue = (bool)agc->is_limiter_enabled();
Steve Block3856b092011-10-20 11:56:00 +0100299 ALOGV("AgcGetParameter() limiter enabled %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700300 (*(int16_t *) pValue != 0) ? "true" : "false");
301 break;
302 case AGC_PARAM_PROPERTIES:
303 pProperties->targetLevel = (int16_t)(agc->target_level_dbfs() * -100);
304 pProperties->compGain = (int16_t)(agc->compression_gain_db() * 100);
305 pProperties->limiterEnabled = (bool)agc->is_limiter_enabled();
306 break;
307 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000308 ALOGW("AgcGetParameter() unknown param %d", param);
Eric Laurenta9390d42011-06-17 20:17:17 -0700309 status = -EINVAL;
310 break;
311 }
312 return status;
313}
314
315int AgcSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
316{
317 int status = 0;
318 uint32_t param = *(uint32_t *)pParam;
319 t_agc_settings *pProperties = (t_agc_settings *)pValue;
320 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
321
322 switch (param) {
323 case AGC_PARAM_TARGET_LEVEL:
Steve Block3856b092011-10-20 11:56:00 +0100324 ALOGV("AgcSetParameter() target level %d milliBels", *(int16_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700325 status = agc->set_target_level_dbfs(-(*(int16_t *)pValue / 100));
326 break;
327 case AGC_PARAM_COMP_GAIN:
Steve Block3856b092011-10-20 11:56:00 +0100328 ALOGV("AgcSetParameter() comp gain %d milliBels", *(int16_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700329 status = agc->set_compression_gain_db(*(int16_t *)pValue / 100);
330 break;
331 case AGC_PARAM_LIMITER_ENA:
Steve Block3856b092011-10-20 11:56:00 +0100332 ALOGV("AgcSetParameter() limiter enabled %s", *(bool *)pValue ? "true" : "false");
Eric Laurenta9390d42011-06-17 20:17:17 -0700333 status = agc->enable_limiter(*(bool *)pValue);
334 break;
335 case AGC_PARAM_PROPERTIES:
Steve Block3856b092011-10-20 11:56:00 +0100336 ALOGV("AgcSetParameter() properties level %d, gain %d limiter %d",
Eric Laurenta9390d42011-06-17 20:17:17 -0700337 pProperties->targetLevel,
338 pProperties->compGain,
339 pProperties->limiterEnabled);
340 status = agc->set_target_level_dbfs(-(pProperties->targetLevel / 100));
341 if (status != 0) break;
342 status = agc->set_compression_gain_db(pProperties->compGain / 100);
343 if (status != 0) break;
344 status = agc->enable_limiter(pProperties->limiterEnabled);
345 break;
346 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000347 ALOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700348 status = -EINVAL;
349 break;
350 }
351
Steve Block3856b092011-10-20 11:56:00 +0100352 ALOGV("AgcSetParameter() done status %d", status);
Eric Laurenta9390d42011-06-17 20:17:17 -0700353
354 return status;
355}
356
357void AgcEnable(preproc_effect_t *effect)
358{
359 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
Steve Block3856b092011-10-20 11:56:00 +0100360 ALOGV("AgcEnable agc %p", agc);
Eric Laurenta9390d42011-06-17 20:17:17 -0700361 agc->Enable(true);
362}
363
364void AgcDisable(preproc_effect_t *effect)
365{
Steve Block3856b092011-10-20 11:56:00 +0100366 ALOGV("AgcDisable");
Eric Laurenta9390d42011-06-17 20:17:17 -0700367 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
368 agc->Enable(false);
369}
370
371
372static const preproc_ops_t sAgcOps = {
373 AgcCreate,
374 AgcInit,
375 NULL,
376 AgcEnable,
377 AgcDisable,
378 AgcSetParameter,
379 AgcGetParameter,
380 NULL
381};
382
383
384//------------------------------------------------------------------------------
385// Acoustic Echo Canceler (AEC)
386//------------------------------------------------------------------------------
387
388static const webrtc::EchoControlMobile::RoutingMode kAecDefaultMode =
389 webrtc::EchoControlMobile::kEarpiece;
390static const bool kAecDefaultComfortNoise = true;
391
392int AecInit (preproc_effect_t *effect)
393{
Steve Block3856b092011-10-20 11:56:00 +0100394 ALOGV("AecInit");
Eric Laurenta9390d42011-06-17 20:17:17 -0700395 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
396 aec->set_routing_mode(kAecDefaultMode);
397 aec->enable_comfort_noise(kAecDefaultComfortNoise);
398 return 0;
399}
400
401int AecCreate(preproc_effect_t *effect)
402{
403 webrtc::EchoControlMobile *aec = effect->session->apm->echo_control_mobile();
Steve Block3856b092011-10-20 11:56:00 +0100404 ALOGV("AecCreate got aec %p", aec);
Eric Laurenta9390d42011-06-17 20:17:17 -0700405 if (aec == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000406 ALOGW("AgcCreate Error");
Eric Laurenta9390d42011-06-17 20:17:17 -0700407 return -ENOMEM;
408 }
409 effect->engine = static_cast<preproc_fx_handle_t>(aec);
410 AecInit (effect);
411 return 0;
412}
413
414int AecGetParameter(preproc_effect_t *effect,
415 void *pParam,
416 size_t *pValueSize,
417 void *pValue)
418{
419 int status = 0;
420 uint32_t param = *(uint32_t *)pParam;
421
422 if (*pValueSize < sizeof(uint32_t)) {
423 return -EINVAL;
424 }
425 switch (param) {
426 case AEC_PARAM_ECHO_DELAY:
427 case AEC_PARAM_PROPERTIES:
428 *(uint32_t *)pValue = 1000 * effect->session->apm->stream_delay_ms();
Steve Block3856b092011-10-20 11:56:00 +0100429 ALOGV("AecGetParameter() echo delay %d us", *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700430 break;
431 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000432 ALOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700433 status = -EINVAL;
434 break;
435 }
436 return status;
437}
438
439int AecSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
440{
441 int status = 0;
442 uint32_t param = *(uint32_t *)pParam;
443 uint32_t value = *(uint32_t *)pValue;
444
445 switch (param) {
446 case AEC_PARAM_ECHO_DELAY:
447 case AEC_PARAM_PROPERTIES:
448 status = effect->session->apm->set_stream_delay_ms(value/1000);
Steve Block3856b092011-10-20 11:56:00 +0100449 ALOGV("AecSetParameter() echo delay %d us, status %d", value, status);
Eric Laurenta9390d42011-06-17 20:17:17 -0700450 break;
451 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000452 ALOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700453 status = -EINVAL;
454 break;
455 }
456 return status;
457}
458
459void AecEnable(preproc_effect_t *effect)
460{
461 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
Steve Block3856b092011-10-20 11:56:00 +0100462 ALOGV("AecEnable aec %p", aec);
Eric Laurenta9390d42011-06-17 20:17:17 -0700463 aec->Enable(true);
464}
465
466void AecDisable(preproc_effect_t *effect)
467{
Steve Block3856b092011-10-20 11:56:00 +0100468 ALOGV("AecDisable");
Eric Laurenta9390d42011-06-17 20:17:17 -0700469 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
470 aec->Enable(false);
471}
472
473int AecSetDevice(preproc_effect_t *effect, uint32_t device)
474{
Steve Block3856b092011-10-20 11:56:00 +0100475 ALOGV("AecSetDevice %08x", device);
Eric Laurenta9390d42011-06-17 20:17:17 -0700476 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
477 webrtc::EchoControlMobile::RoutingMode mode = webrtc::EchoControlMobile::kQuietEarpieceOrHeadset;
478
479 switch(device) {
480 case AUDIO_DEVICE_OUT_EARPIECE:
481 mode = webrtc::EchoControlMobile::kEarpiece;
482 break;
483 case AUDIO_DEVICE_OUT_SPEAKER:
484 mode = webrtc::EchoControlMobile::kSpeakerphone;
485 break;
486 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
487 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
488 default:
489 break;
490 }
491 aec->set_routing_mode(mode);
492 return 0;
493}
494
495static const preproc_ops_t sAecOps = {
496 AecCreate,
497 AecInit,
498 NULL,
499 AecEnable,
500 AecDisable,
501 AecSetParameter,
502 AecGetParameter,
503 AecSetDevice
504};
505
506//------------------------------------------------------------------------------
507// Noise Suppression (NS)
508//------------------------------------------------------------------------------
509
510static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
511
512int NsInit (preproc_effect_t *effect)
513{
Steve Block3856b092011-10-20 11:56:00 +0100514 ALOGV("NsInit");
Eric Laurenta9390d42011-06-17 20:17:17 -0700515 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
516 ns->set_level(kNsDefaultLevel);
517 return 0;
518}
519
520int NsCreate(preproc_effect_t *effect)
521{
522 webrtc::NoiseSuppression *ns = effect->session->apm->noise_suppression();
Steve Block3856b092011-10-20 11:56:00 +0100523 ALOGV("NsCreate got ns %p", ns);
Eric Laurenta9390d42011-06-17 20:17:17 -0700524 if (ns == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000525 ALOGW("AgcCreate Error");
Eric Laurenta9390d42011-06-17 20:17:17 -0700526 return -ENOMEM;
527 }
528 effect->engine = static_cast<preproc_fx_handle_t>(ns);
529 NsInit (effect);
530 return 0;
531}
532
533int NsGetParameter(preproc_effect_t *effect,
534 void *pParam,
535 size_t *pValueSize,
536 void *pValue)
537{
538 int status = 0;
539 return status;
540}
541
542int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
543{
544 int status = 0;
545 return status;
546}
547
548void NsEnable(preproc_effect_t *effect)
549{
550 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
Steve Block3856b092011-10-20 11:56:00 +0100551 ALOGV("NsEnable ns %p", ns);
Eric Laurenta9390d42011-06-17 20:17:17 -0700552 ns->Enable(true);
553}
554
555void NsDisable(preproc_effect_t *effect)
556{
Steve Block3856b092011-10-20 11:56:00 +0100557 ALOGV("NsDisable");
Eric Laurenta9390d42011-06-17 20:17:17 -0700558 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
559 ns->Enable(false);
560}
561
562static const preproc_ops_t sNsOps = {
563 NsCreate,
564 NsInit,
565 NULL,
566 NsEnable,
567 NsDisable,
568 NsSetParameter,
569 NsGetParameter,
570 NULL
571};
572
573
574static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
575 &sAgcOps,
576 &sAecOps,
577 &sNsOps
578};
579
580
581//------------------------------------------------------------------------------
582// Effect functions
583//------------------------------------------------------------------------------
584
585void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled);
586
587extern "C" const struct effect_interface_s sEffectInterface;
588extern "C" const struct effect_interface_s sEffectInterfaceReverse;
589
590#define BAD_STATE_ABORT(from, to) \
591 LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to);
592
593int Effect_SetState(preproc_effect_t *effect, uint32_t state)
594{
595 int status = 0;
Steve Block3856b092011-10-20 11:56:00 +0100596 ALOGV("Effect_SetState proc %d, new %d old %d", effect->procId, state, effect->state);
Eric Laurenta9390d42011-06-17 20:17:17 -0700597 switch(state) {
598 case PREPROC_EFFECT_STATE_INIT:
599 switch(effect->state) {
600 case PREPROC_EFFECT_STATE_ACTIVE:
601 effect->ops->disable(effect);
602 Session_SetProcEnabled(effect->session, effect->procId, false);
603 case PREPROC_EFFECT_STATE_CONFIG:
604 case PREPROC_EFFECT_STATE_CREATED:
605 case PREPROC_EFFECT_STATE_INIT:
606 break;
607 default:
608 BAD_STATE_ABORT(effect->state, state);
609 }
610 break;
611 case PREPROC_EFFECT_STATE_CREATED:
612 switch(effect->state) {
613 case PREPROC_EFFECT_STATE_INIT:
614 status = effect->ops->create(effect);
615 break;
616 case PREPROC_EFFECT_STATE_CREATED:
617 case PREPROC_EFFECT_STATE_ACTIVE:
618 case PREPROC_EFFECT_STATE_CONFIG:
Steve Block29357bc2012-01-06 19:20:56 +0000619 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700620 status = -ENOSYS;
621 break;
622 default:
623 BAD_STATE_ABORT(effect->state, state);
624 }
625 break;
626 case PREPROC_EFFECT_STATE_CONFIG:
627 switch(effect->state) {
628 case PREPROC_EFFECT_STATE_INIT:
Steve Block29357bc2012-01-06 19:20:56 +0000629 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700630 status = -ENOSYS;
631 break;
632 case PREPROC_EFFECT_STATE_ACTIVE:
633 effect->ops->disable(effect);
634 Session_SetProcEnabled(effect->session, effect->procId, false);
635 break;
636 case PREPROC_EFFECT_STATE_CREATED:
637 case PREPROC_EFFECT_STATE_CONFIG:
638 break;
639 default:
640 BAD_STATE_ABORT(effect->state, state);
641 }
642 break;
643 case PREPROC_EFFECT_STATE_ACTIVE:
644 switch(effect->state) {
645 case PREPROC_EFFECT_STATE_INIT:
646 case PREPROC_EFFECT_STATE_CREATED:
647 case PREPROC_EFFECT_STATE_ACTIVE:
Steve Block29357bc2012-01-06 19:20:56 +0000648 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700649 status = -ENOSYS;
650 break;
651 case PREPROC_EFFECT_STATE_CONFIG:
652 effect->ops->enable(effect);
653 Session_SetProcEnabled(effect->session, effect->procId, true);
654 break;
655 default:
656 BAD_STATE_ABORT(effect->state, state);
657 }
658 break;
659 default:
660 BAD_STATE_ABORT(effect->state, state);
661 }
662 if (status == 0) {
663 effect->state = state;
664 }
665 return status;
666}
667
668int Effect_Init(preproc_effect_t *effect, uint32_t procId)
669{
670 if (HasReverseStream(procId)) {
671 effect->itfe = &sEffectInterfaceReverse;
672 } else {
673 effect->itfe = &sEffectInterface;
674 }
675 effect->ops = sPreProcOps[procId];
676 effect->procId = procId;
677 effect->state = PREPROC_EFFECT_STATE_INIT;
678 return 0;
679}
680
681int Effect_Create(preproc_effect_t *effect,
682 preproc_session_t *session,
683 effect_handle_t *interface)
684{
685 effect->session = session;
686 *interface = (effect_handle_t)&effect->itfe;
687 return Effect_SetState(effect, PREPROC_EFFECT_STATE_CREATED);
688}
689
690int Effect_Release(preproc_effect_t *effect)
691{
692 return Effect_SetState(effect, PREPROC_EFFECT_STATE_INIT);
693}
694
695
696//------------------------------------------------------------------------------
697// Session functions
698//------------------------------------------------------------------------------
699
700#define RESAMPLER_QUALITY SPEEX_RESAMPLER_QUALITY_VOIP
701
702static const int kPreprocDefaultSr = 16000;
703static const int kPreProcDefaultCnl = 1;
704
705int Session_Init(preproc_session_t *session)
706{
707 size_t i;
708 int status = 0;
709
710 session->state = PREPROC_SESSION_STATE_INIT;
711 session->id = 0;
712 session->io = 0;
713 session->createdMsk = 0;
714 session->apm = NULL;
715 for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
716 status = Effect_Init(&session->effects[i], i);
717 }
718 return status;
719}
720
721
722extern "C" int Session_CreateEffect(preproc_session_t *session,
723 int32_t procId,
724 effect_handle_t *interface)
725{
726 int status = -ENOMEM;
727
Steve Block3856b092011-10-20 11:56:00 +0100728 ALOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
Eric Laurenta9390d42011-06-17 20:17:17 -0700729
730 if (session->createdMsk == 0) {
731 session->apm = webrtc::AudioProcessing::Create(session->io);
732 if (session->apm == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000733 ALOGW("Session_CreateEffect could not get apm engine");
Eric Laurenta9390d42011-06-17 20:17:17 -0700734 goto error;
735 }
736 session->apm->set_sample_rate_hz(kPreprocDefaultSr);
737 session->apm->set_num_channels(kPreProcDefaultCnl, kPreProcDefaultCnl);
738 session->apm->set_num_reverse_channels(kPreProcDefaultCnl);
739 session->procFrame = new webrtc::AudioFrame();
740 if (session->procFrame == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000741 ALOGW("Session_CreateEffect could not allocate audio frame");
Eric Laurenta9390d42011-06-17 20:17:17 -0700742 goto error;
743 }
744 session->revFrame = new webrtc::AudioFrame();
745 if (session->revFrame == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000746 ALOGW("Session_CreateEffect could not allocate reverse audio frame");
Eric Laurenta9390d42011-06-17 20:17:17 -0700747 goto error;
748 }
749 session->apmSamplingRate = kPreprocDefaultSr;
750 session->apmFrameCount = (kPreprocDefaultSr) / 100;
751 session->frameCount = session->apmFrameCount;
752 session->samplingRate = kPreprocDefaultSr;
753 session->inChannelCount = kPreProcDefaultCnl;
754 session->outChannelCount = kPreProcDefaultCnl;
755 session->procFrame->_frequencyInHz = kPreprocDefaultSr;
756 session->procFrame->_audioChannel = kPreProcDefaultCnl;
757 session->revChannelCount = kPreProcDefaultCnl;
758 session->revFrame->_frequencyInHz = kPreprocDefaultSr;
759 session->revFrame->_audioChannel = kPreProcDefaultCnl;
760 session->enabledMsk = 0;
761 session->processedMsk = 0;
762 session->revEnabledMsk = 0;
763 session->revProcessedMsk = 0;
764 session->inResampler = NULL;
765 session->inBuf = NULL;
766 session->inBufSize = 0;
767 session->outResampler = NULL;
768 session->outBuf = NULL;
769 session->outBufSize = 0;
770 session->revResampler = NULL;
771 session->revBuf = NULL;
772 session->revBufSize = 0;
773 }
774 status = Effect_Create(&session->effects[procId], session, interface);
775 if (status < 0) {
776 goto error;
777 }
Steve Block3856b092011-10-20 11:56:00 +0100778 ALOGV("Session_CreateEffect OK");
Eric Laurenta9390d42011-06-17 20:17:17 -0700779 session->createdMsk |= (1<<procId);
780 return status;
781
782error:
783 if (session->createdMsk == 0) {
784 delete session->revFrame;
785 session->revFrame = NULL;
786 delete session->procFrame;
787 session->procFrame = NULL;
788 webrtc::AudioProcessing::Destroy(session->apm);
789 session->apm = NULL;
790 }
791 return status;
792}
793
794int Session_ReleaseEffect(preproc_session_t *session,
795 preproc_effect_t *fx)
796{
Steve Block5ff1dd52012-01-05 23:22:43 +0000797 ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
Eric Laurenta9390d42011-06-17 20:17:17 -0700798 session->createdMsk &= ~(1<<fx->procId);
799 if (session->createdMsk == 0) {
800 webrtc::AudioProcessing::Destroy(session->apm);
801 session->apm = NULL;
802 delete session->procFrame;
803 session->procFrame = NULL;
804 delete session->revFrame;
805 session->revFrame = NULL;
806 if (session->inResampler != NULL) {
807 speex_resampler_destroy(session->inResampler);
808 session->inResampler = NULL;
809 }
810 if (session->outResampler != NULL) {
811 speex_resampler_destroy(session->outResampler);
812 session->outResampler = NULL;
813 }
814 if (session->revResampler != NULL) {
815 speex_resampler_destroy(session->revResampler);
816 session->revResampler = NULL;
817 }
818 delete session->inBuf;
819 session->inBuf = NULL;
820 delete session->outBuf;
821 session->outBuf = NULL;
822 delete session->revBuf;
823 session->revBuf = NULL;
824
825 session->io = 0;
826 }
827
828 return 0;
829}
830
831
832int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
833{
834 uint32_t sr;
835 uint32_t inCnl = popcount(config->inputCfg.channels);
836 uint32_t outCnl = popcount(config->outputCfg.channels);
837
838 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
839 config->inputCfg.format != config->outputCfg.format ||
840 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
841 return -EINVAL;
842 }
843
Steve Block3856b092011-10-20 11:56:00 +0100844 ALOGV("Session_SetConfig sr %d cnl %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -0700845 config->inputCfg.samplingRate, config->inputCfg.channels);
846 int status;
847
Eric Laurent76533e92012-02-17 17:52:04 -0800848 // if at least one process is enabled, do not accept configuration changes
849 if (session->enabledMsk) {
850 if (session->samplingRate != config->inputCfg.samplingRate ||
851 session->inChannelCount != inCnl ||
852 session->outChannelCount != outCnl) {
853 return -ENOSYS;
854 } else {
855 return 0;
856 }
857 }
858
Eric Laurenta9390d42011-06-17 20:17:17 -0700859 // AEC implementation is limited to 16kHz
860 if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
861 session->apmSamplingRate = 32000;
862 } else
863 if (config->inputCfg.samplingRate >= 16000) {
864 session->apmSamplingRate = 16000;
865 } else if (config->inputCfg.samplingRate >= 8000) {
866 session->apmSamplingRate = 8000;
867 }
868 status = session->apm->set_sample_rate_hz(session->apmSamplingRate);
869 if (status < 0) {
870 return -EINVAL;
871 }
872 status = session->apm->set_num_channels(inCnl, outCnl);
873 if (status < 0) {
874 return -EINVAL;
875 }
876 status = session->apm->set_num_reverse_channels(inCnl);
877 if (status < 0) {
878 return -EINVAL;
879 }
880
881 session->samplingRate = config->inputCfg.samplingRate;
882 session->apmFrameCount = session->apmSamplingRate / 100;
883 if (session->samplingRate == session->apmSamplingRate) {
884 session->frameCount = session->apmFrameCount;
885 } else {
886 session->frameCount = (session->apmFrameCount * session->samplingRate) /
887 session->apmSamplingRate + 1;
888 }
889 session->inChannelCount = inCnl;
890 session->outChannelCount = outCnl;
891 session->procFrame->_audioChannel = inCnl;
892 session->procFrame->_frequencyInHz = session->apmSamplingRate;
893
894 session->revChannelCount = inCnl;
895 session->revFrame->_audioChannel = inCnl;
896 session->revFrame->_frequencyInHz = session->apmSamplingRate;
897
898 if (session->inResampler != NULL) {
899 speex_resampler_destroy(session->inResampler);
900 session->inResampler = NULL;
901 }
902 if (session->outResampler != NULL) {
903 speex_resampler_destroy(session->outResampler);
904 session->outResampler = NULL;
905 }
906 if (session->revResampler != NULL) {
907 speex_resampler_destroy(session->revResampler);
908 session->revResampler = NULL;
909 }
910 if (session->samplingRate != session->apmSamplingRate) {
911 int error;
912 session->inResampler = speex_resampler_init(session->inChannelCount,
913 session->samplingRate,
914 session->apmSamplingRate,
915 RESAMPLER_QUALITY,
916 &error);
917 if (session->inResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000918 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700919 speex_resampler_strerror(error));
920 return -EINVAL;
921 }
922 session->outResampler = speex_resampler_init(session->outChannelCount,
923 session->apmSamplingRate,
924 session->samplingRate,
925 RESAMPLER_QUALITY,
926 &error);
927 if (session->outResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000928 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700929 speex_resampler_strerror(error));
930 speex_resampler_destroy(session->inResampler);
931 session->inResampler = NULL;
932 return -EINVAL;
933 }
934 session->revResampler = speex_resampler_init(session->inChannelCount,
935 session->samplingRate,
936 session->apmSamplingRate,
937 RESAMPLER_QUALITY,
938 &error);
939 if (session->revResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000940 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700941 speex_resampler_strerror(error));
942 speex_resampler_destroy(session->inResampler);
943 session->inResampler = NULL;
944 speex_resampler_destroy(session->outResampler);
945 session->outResampler = NULL;
946 return -EINVAL;
947 }
948 }
949
950 session->state = PREPROC_SESSION_STATE_CONFIG;
951 return 0;
952}
953
Eric Laurent3d5188b2011-12-16 15:30:36 -0800954void Session_GetConfig(preproc_session_t *session, effect_config_t *config)
955{
956 memset(config, 0, sizeof(effect_config_t));
957 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
958 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Glenn Kastenab334fd2012-03-14 12:56:06 -0700959 config->inputCfg.channels = audio_channel_in_mask_from_count(session->inChannelCount);
960 // "out" doesn't mean output device, so this is the correct API to convert channel count to mask
961 config->outputCfg.channels = audio_channel_in_mask_from_count(session->outChannelCount);
Eric Laurent3d5188b2011-12-16 15:30:36 -0800962 config->inputCfg.mask = config->outputCfg.mask =
963 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
964}
965
Eric Laurenta9390d42011-06-17 20:17:17 -0700966int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
967{
968 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
969 config->inputCfg.format != config->outputCfg.format ||
970 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
971 return -EINVAL;
972 }
973
Steve Block3856b092011-10-20 11:56:00 +0100974 ALOGV("Session_SetReverseConfig sr %d cnl %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -0700975 config->inputCfg.samplingRate, config->inputCfg.channels);
976
977 if (session->state < PREPROC_SESSION_STATE_CONFIG) {
978 return -ENOSYS;
979 }
980 if (config->inputCfg.samplingRate != session->samplingRate ||
981 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
982 return -EINVAL;
983 }
984 uint32_t inCnl = popcount(config->inputCfg.channels);
985 int status = session->apm->set_num_reverse_channels(inCnl);
986 if (status < 0) {
987 return -EINVAL;
988 }
989 session->revChannelCount = inCnl;
990 session->revFrame->_audioChannel = inCnl;
991 session->revFrame->_frequencyInHz = session->apmSamplingRate;
992 return 0;
993}
994
Eric Laurent3d5188b2011-12-16 15:30:36 -0800995void Session_GetReverseConfig(preproc_session_t *session, effect_config_t *config)
996{
997 memset(config, 0, sizeof(effect_config_t));
998 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
999 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
1000 config->inputCfg.channels = config->outputCfg.channels =
Glenn Kastenab334fd2012-03-14 12:56:06 -07001001 audio_channel_in_mask_from_count(session->revChannelCount);
Eric Laurent3d5188b2011-12-16 15:30:36 -08001002 config->inputCfg.mask = config->outputCfg.mask =
1003 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
1004}
1005
Eric Laurenta9390d42011-06-17 20:17:17 -07001006void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
1007{
1008 if (enabled) {
1009 if(session->enabledMsk == 0) {
1010 session->framesIn = 0;
1011 if (session->inResampler != NULL) {
1012 speex_resampler_reset_mem(session->inResampler);
1013 }
1014 session->framesOut = 0;
1015 if (session->outResampler != NULL) {
1016 speex_resampler_reset_mem(session->outResampler);
1017 }
1018 }
1019 session->enabledMsk |= (1 << procId);
1020 if (HasReverseStream(procId)) {
1021 session->framesRev = 0;
1022 if (session->revResampler != NULL) {
1023 speex_resampler_reset_mem(session->revResampler);
1024 }
1025 session->revEnabledMsk |= (1 << procId);
1026 }
1027 } else {
1028 session->enabledMsk &= ~(1 << procId);
1029 if (HasReverseStream(procId)) {
1030 session->revEnabledMsk &= ~(1 << procId);
1031 }
1032 }
Steve Block3856b092011-10-20 11:56:00 +01001033 ALOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001034 procId, enabled, session->enabledMsk, session->revEnabledMsk);
1035 session->processedMsk = 0;
1036 if (HasReverseStream(procId)) {
1037 session->revProcessedMsk = 0;
1038 }
1039}
1040
1041//------------------------------------------------------------------------------
1042// Bundle functions
1043//------------------------------------------------------------------------------
1044
1045static int sInitStatus = 1;
1046static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
1047
1048preproc_session_t *PreProc_GetSession(int32_t procId, int32_t sessionId, int32_t ioId)
1049{
1050 size_t i;
1051 int free = -1;
1052 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1053 if (sSessions[i].io == ioId) {
1054 if (sSessions[i].createdMsk & (1 << procId)) {
1055 return NULL;
1056 }
1057 return &sSessions[i];
1058 }
1059 }
1060 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1061 if (sSessions[i].io == 0) {
1062 sSessions[i].id = sessionId;
1063 sSessions[i].io = ioId;
1064 return &sSessions[i];
1065 }
1066 }
1067 return NULL;
1068}
1069
1070
1071int PreProc_Init() {
1072 size_t i;
1073 int status = 0;
1074
1075 if (sInitStatus <= 0) {
1076 return sInitStatus;
1077 }
1078 for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
1079 status = Session_Init(&sSessions[i]);
1080 }
1081 sInitStatus = status;
1082 return sInitStatus;
1083}
1084
Glenn Kasten5e92a782012-01-30 07:40:52 -08001085const effect_descriptor_t *PreProc_GetDescriptor(const effect_uuid_t *uuid)
Eric Laurenta9390d42011-06-17 20:17:17 -07001086{
1087 size_t i;
1088 for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
1089 if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
1090 return sDescriptors[i];
1091 }
1092 }
1093 return NULL;
1094}
1095
1096
1097extern "C" {
1098
1099//------------------------------------------------------------------------------
1100// Effect Control Interface Implementation
1101//------------------------------------------------------------------------------
1102
1103int PreProcessingFx_Process(effect_handle_t self,
1104 audio_buffer_t *inBuffer,
1105 audio_buffer_t *outBuffer)
1106{
1107 preproc_effect_t * effect = (preproc_effect_t *)self;
1108 int status = 0;
1109
1110 if (effect == NULL){
Steve Block3856b092011-10-20 11:56:00 +01001111 ALOGV("PreProcessingFx_Process() ERROR effect == NULL");
Eric Laurenta9390d42011-06-17 20:17:17 -07001112 return -EINVAL;
1113 }
1114 preproc_session_t * session = (preproc_session_t *)effect->session;
1115
1116 if (inBuffer == NULL || inBuffer->raw == NULL ||
1117 outBuffer == NULL || outBuffer->raw == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001118 ALOGW("PreProcessingFx_Process() ERROR bad pointer");
Eric Laurenta9390d42011-06-17 20:17:17 -07001119 return -EINVAL;
1120 }
1121
1122 session->processedMsk |= (1<<effect->procId);
1123
Steve Block3856b092011-10-20 11:56:00 +01001124// ALOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001125// inBuffer->frameCount, session->enabledMsk, session->processedMsk);
1126
1127 if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
1128 effect->session->processedMsk = 0;
1129 size_t framesRq = outBuffer->frameCount;
1130 size_t framesWr = 0;
1131 if (session->framesOut) {
1132 size_t fr = session->framesOut;
1133 if (outBuffer->frameCount < fr) {
1134 fr = outBuffer->frameCount;
1135 }
1136 memcpy(outBuffer->s16,
1137 session->outBuf,
1138 fr * session->outChannelCount * sizeof(int16_t));
1139 memcpy(session->outBuf,
1140 session->outBuf + fr * session->outChannelCount,
1141 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1142 session->framesOut -= fr;
1143 framesWr += fr;
1144 }
1145 outBuffer->frameCount = framesWr;
1146 if (framesWr == framesRq) {
1147 inBuffer->frameCount = 0;
1148 return 0;
1149 }
1150
1151 if (session->inResampler != NULL) {
1152 size_t fr = session->frameCount - session->framesIn;
1153 if (inBuffer->frameCount < fr) {
1154 fr = inBuffer->frameCount;
1155 }
1156 if (session->inBufSize < session->framesIn + fr) {
1157 session->inBufSize = session->framesIn + fr;
1158 session->inBuf = (int16_t *)realloc(session->inBuf,
1159 session->inBufSize * session->inChannelCount * sizeof(int16_t));
1160 }
1161 memcpy(session->inBuf + session->framesIn * session->inChannelCount,
1162 inBuffer->s16,
1163 fr * session->inChannelCount * sizeof(int16_t));
1164
1165 session->framesIn += fr;
1166 inBuffer->frameCount = fr;
1167 if (session->framesIn < session->frameCount) {
1168 return 0;
1169 }
1170 size_t frIn = session->framesIn;
1171 size_t frOut = session->apmFrameCount;
1172 if (session->inChannelCount == 1) {
1173 speex_resampler_process_int(session->inResampler,
1174 0,
1175 session->inBuf,
1176 &frIn,
1177 session->procFrame->_payloadData,
1178 &frOut);
1179 } else {
1180 speex_resampler_process_interleaved_int(session->inResampler,
1181 session->inBuf,
1182 &frIn,
1183 session->procFrame->_payloadData,
1184 &frOut);
1185 }
1186 memcpy(session->inBuf,
1187 session->inBuf + frIn * session->inChannelCount,
1188 (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
1189 session->framesIn -= frIn;
1190 } else {
1191 size_t fr = session->frameCount - session->framesIn;
1192 if (inBuffer->frameCount < fr) {
1193 fr = inBuffer->frameCount;
1194 }
1195 memcpy(session->procFrame->_payloadData + session->framesIn * session->inChannelCount,
1196 inBuffer->s16,
1197 fr * session->inChannelCount * sizeof(int16_t));
1198 session->framesIn += fr;
1199 inBuffer->frameCount = fr;
1200 if (session->framesIn < session->frameCount) {
1201 return 0;
1202 }
1203 session->framesIn = 0;
1204 }
1205 session->procFrame->_payloadDataLengthInSamples =
1206 session->apmFrameCount * session->inChannelCount;
1207
1208 effect->session->apm->ProcessStream(session->procFrame);
1209
1210 if (session->outBufSize < session->framesOut + session->frameCount) {
1211 session->outBufSize = session->framesOut + session->frameCount;
1212 session->outBuf = (int16_t *)realloc(session->outBuf,
1213 session->outBufSize * session->outChannelCount * sizeof(int16_t));
1214 }
1215
1216 if (session->outResampler != NULL) {
1217 size_t frIn = session->apmFrameCount;
1218 size_t frOut = session->frameCount;
1219 if (session->inChannelCount == 1) {
1220 speex_resampler_process_int(session->outResampler,
1221 0,
1222 session->procFrame->_payloadData,
1223 &frIn,
1224 session->outBuf + session->framesOut * session->outChannelCount,
1225 &frOut);
1226 } else {
1227 speex_resampler_process_interleaved_int(session->outResampler,
1228 session->procFrame->_payloadData,
1229 &frIn,
1230 session->outBuf + session->framesOut * session->outChannelCount,
1231 &frOut);
1232 }
1233 session->framesOut += frOut;
1234 } else {
1235 memcpy(session->outBuf + session->framesOut * session->outChannelCount,
1236 session->procFrame->_payloadData,
1237 session->frameCount * session->outChannelCount * sizeof(int16_t));
1238 session->framesOut += session->frameCount;
1239 }
1240 size_t fr = session->framesOut;
1241 if (framesRq - framesWr < fr) {
1242 fr = framesRq - framesWr;
1243 }
1244 memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
1245 session->outBuf,
1246 fr * session->outChannelCount * sizeof(int16_t));
1247 memcpy(session->outBuf,
1248 session->outBuf + fr * session->outChannelCount,
1249 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1250 session->framesOut -= fr;
1251 outBuffer->frameCount += fr;
1252
1253 return 0;
1254 } else {
1255 return -ENODATA;
1256 }
1257}
1258
1259int PreProcessingFx_Command(effect_handle_t self,
1260 uint32_t cmdCode,
1261 uint32_t cmdSize,
1262 void *pCmdData,
1263 uint32_t *replySize,
1264 void *pReplyData)
1265{
1266 preproc_effect_t * effect = (preproc_effect_t *) self;
1267 int retsize;
1268 int status;
1269
1270 if (effect == NULL){
1271 return -EINVAL;
1272 }
1273
Steve Block3856b092011-10-20 11:56:00 +01001274 //ALOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
Eric Laurenta9390d42011-06-17 20:17:17 -07001275
1276 switch (cmdCode){
1277 case EFFECT_CMD_INIT:
1278 if (pReplyData == NULL || *replySize != sizeof(int)){
1279 return -EINVAL;
1280 }
1281 if (effect->ops->init) {
1282 effect->ops->init(effect);
1283 }
1284 *(int *)pReplyData = 0;
1285 break;
1286
Eric Laurent3d5188b2011-12-16 15:30:36 -08001287 case EFFECT_CMD_SET_CONFIG:
Eric Laurenta9390d42011-06-17 20:17:17 -07001288 if (pCmdData == NULL||
1289 cmdSize != sizeof(effect_config_t)||
1290 pReplyData == NULL||
1291 *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001292 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent3d5188b2011-12-16 15:30:36 -08001293 "EFFECT_CMD_SET_CONFIG: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001294 return -EINVAL;
1295 }
1296 *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
1297 if (*(int *)pReplyData != 0) {
1298 break;
1299 }
Eric Laurent76533e92012-02-17 17:52:04 -08001300 if (effect->state != PREPROC_EFFECT_STATE_ACTIVE) {
1301 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1302 }
Eric Laurenta9390d42011-06-17 20:17:17 -07001303 break;
1304
Eric Laurent3d5188b2011-12-16 15:30:36 -08001305 case EFFECT_CMD_GET_CONFIG:
1306 if (pReplyData == NULL ||
1307 *replySize != sizeof(effect_config_t)) {
1308 ALOGV("\tLVM_ERROR : PreProcessingFx_Command cmdCode Case: "
1309 "EFFECT_CMD_GET_CONFIG: ERROR");
1310 return -EINVAL;
1311 }
1312
Eric Laurent94fef382012-02-06 14:28:54 -08001313 Session_GetConfig(effect->session, (effect_config_t *)pReplyData);
Eric Laurent3d5188b2011-12-16 15:30:36 -08001314 break;
1315
1316 case EFFECT_CMD_SET_CONFIG_REVERSE:
1317 if (pCmdData == NULL ||
1318 cmdSize != sizeof(effect_config_t) ||
1319 pReplyData == NULL ||
1320 *replySize != sizeof(int)) {
Steve Block3856b092011-10-20 11:56:00 +01001321 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent3d5188b2011-12-16 15:30:36 -08001322 "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001323 return -EINVAL;
1324 }
1325 *(int *)pReplyData = Session_SetReverseConfig(effect->session,
1326 (effect_config_t *)pCmdData);
1327 if (*(int *)pReplyData != 0) {
1328 break;
1329 }
1330 break;
1331
Eric Laurent3d5188b2011-12-16 15:30:36 -08001332 case EFFECT_CMD_GET_CONFIG_REVERSE:
1333 if (pReplyData == NULL ||
1334 *replySize != sizeof(effect_config_t)){
1335 ALOGV("PreProcessingFx_Command cmdCode Case: "
1336 "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR");
1337 return -EINVAL;
1338 }
1339 Session_GetReverseConfig(effect->session, (effect_config_t *)pCmdData);
1340 break;
1341
Eric Laurenta9390d42011-06-17 20:17:17 -07001342 case EFFECT_CMD_RESET:
1343 if (effect->ops->reset) {
1344 effect->ops->reset(effect);
1345 }
1346 break;
1347
1348 case EFFECT_CMD_GET_PARAM:{
1349 if (pCmdData == NULL ||
1350 cmdSize < (int)sizeof(effect_param_t) ||
1351 pReplyData == NULL ||
1352 *replySize < (int)sizeof(effect_param_t)){
Steve Block3856b092011-10-20 11:56:00 +01001353 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001354 "EFFECT_CMD_GET_PARAM: ERROR");
1355 return -EINVAL;
1356 }
1357 effect_param_t *p = (effect_param_t *)pCmdData;
1358
1359 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
1360
1361 p = (effect_param_t *)pReplyData;
1362
1363 int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
1364
1365 if (effect->ops->get_parameter) {
1366 p->status = effect->ops->get_parameter(effect, p->data,
1367 (size_t *)&p->vsize,
1368 p->data + voffset);
1369 *replySize = sizeof(effect_param_t) + voffset + p->vsize;
1370 }
1371 } break;
1372
1373 case EFFECT_CMD_SET_PARAM:{
1374 if (pCmdData == NULL||
1375 cmdSize < (int)sizeof(effect_param_t) ||
1376 pReplyData == NULL ||
1377 *replySize != sizeof(int32_t)){
Steve Block3856b092011-10-20 11:56:00 +01001378 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001379 "EFFECT_CMD_SET_PARAM: ERROR");
1380 return -EINVAL;
1381 }
1382 effect_param_t *p = (effect_param_t *) pCmdData;
1383
1384 if (p->psize != sizeof(int32_t)){
Steve Block3856b092011-10-20 11:56:00 +01001385 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001386 "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
1387 return -EINVAL;
1388 }
1389 if (effect->ops->set_parameter) {
1390 *(int *)pReplyData = effect->ops->set_parameter(effect,
1391 (void *)p->data,
1392 p->data + p->psize);
1393 }
1394 } break;
1395
1396 case EFFECT_CMD_ENABLE:
1397 if (pReplyData == NULL || *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001398 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001399 return -EINVAL;
1400 }
1401 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
1402 break;
1403
1404 case EFFECT_CMD_DISABLE:
1405 if (pReplyData == NULL || *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001406 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001407 return -EINVAL;
1408 }
1409 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1410 break;
1411
1412 case EFFECT_CMD_SET_DEVICE:
1413 case EFFECT_CMD_SET_INPUT_DEVICE:
1414 if (pCmdData == NULL ||
1415 cmdSize != sizeof(uint32_t)) {
Steve Block3856b092011-10-20 11:56:00 +01001416 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001417 return -EINVAL;
1418 }
1419
1420 if (effect->ops->set_device) {
1421 effect->ops->set_device(effect, *(uint32_t *)pCmdData);
1422 }
1423 break;
1424
1425 case EFFECT_CMD_SET_VOLUME:
1426 case EFFECT_CMD_SET_AUDIO_MODE:
1427 break;
1428
1429 default:
1430 return -EINVAL;
1431 }
1432 return 0;
1433}
1434
1435
1436int PreProcessingFx_GetDescriptor(effect_handle_t self,
1437 effect_descriptor_t *pDescriptor)
1438{
1439 preproc_effect_t * effect = (preproc_effect_t *) self;
1440
1441 if (effect == NULL || pDescriptor == NULL) {
1442 return -EINVAL;
1443 }
1444
1445 memcpy(pDescriptor, sDescriptors[effect->procId], sizeof(effect_descriptor_t));
1446
1447 return 0;
1448}
1449
1450int PreProcessingFx_ProcessReverse(effect_handle_t self,
1451 audio_buffer_t *inBuffer,
1452 audio_buffer_t *outBuffer)
1453{
1454 preproc_effect_t * effect = (preproc_effect_t *)self;
1455 int status = 0;
1456
1457 if (effect == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001458 ALOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
Eric Laurenta9390d42011-06-17 20:17:17 -07001459 return -EINVAL;
1460 }
1461 preproc_session_t * session = (preproc_session_t *)effect->session;
1462
1463 if (inBuffer == NULL || inBuffer->raw == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001464 ALOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
Eric Laurenta9390d42011-06-17 20:17:17 -07001465 return -EINVAL;
1466 }
1467
1468 session->revProcessedMsk |= (1<<effect->procId);
1469
Steve Block3856b092011-10-20 11:56:00 +01001470// ALOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001471// inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
1472
1473
1474 if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
1475 effect->session->revProcessedMsk = 0;
1476 if (session->revResampler != NULL) {
1477 size_t fr = session->frameCount - session->framesRev;
1478 if (inBuffer->frameCount < fr) {
1479 fr = inBuffer->frameCount;
1480 }
1481 if (session->revBufSize < session->framesRev + fr) {
1482 session->revBufSize = session->framesRev + fr;
1483 session->revBuf = (int16_t *)realloc(session->revBuf,
1484 session->revBufSize * session->inChannelCount * sizeof(int16_t));
1485 }
1486 memcpy(session->revBuf + session->framesRev * session->inChannelCount,
1487 inBuffer->s16,
1488 fr * session->inChannelCount * sizeof(int16_t));
1489
1490 session->framesRev += fr;
1491 inBuffer->frameCount = fr;
1492 if (session->framesRev < session->frameCount) {
1493 return 0;
1494 }
1495 size_t frIn = session->framesRev;
1496 size_t frOut = session->apmFrameCount;
1497 if (session->inChannelCount == 1) {
1498 speex_resampler_process_int(session->revResampler,
1499 0,
1500 session->revBuf,
1501 &frIn,
1502 session->revFrame->_payloadData,
1503 &frOut);
1504 } else {
1505 speex_resampler_process_interleaved_int(session->revResampler,
1506 session->revBuf,
1507 &frIn,
1508 session->revFrame->_payloadData,
1509 &frOut);
1510 }
1511 memcpy(session->revBuf,
1512 session->revBuf + frIn * session->inChannelCount,
1513 (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
1514 session->framesRev -= frIn;
1515 } else {
1516 size_t fr = session->frameCount - session->framesRev;
1517 if (inBuffer->frameCount < fr) {
1518 fr = inBuffer->frameCount;
1519 }
1520 memcpy(session->revFrame->_payloadData + session->framesRev * session->inChannelCount,
1521 inBuffer->s16,
1522 fr * session->inChannelCount * sizeof(int16_t));
1523 session->framesRev += fr;
1524 inBuffer->frameCount = fr;
1525 if (session->framesRev < session->frameCount) {
1526 return 0;
1527 }
1528 session->framesRev = 0;
1529 }
1530 session->revFrame->_payloadDataLengthInSamples =
1531 session->apmFrameCount * session->inChannelCount;
1532 effect->session->apm->AnalyzeReverseStream(session->revFrame);
1533 return 0;
1534 } else {
1535 return -ENODATA;
1536 }
1537}
1538
1539
1540// effect_handle_t interface implementation for effect
1541const struct effect_interface_s sEffectInterface = {
1542 PreProcessingFx_Process,
1543 PreProcessingFx_Command,
1544 PreProcessingFx_GetDescriptor,
1545 NULL
1546};
1547
1548const struct effect_interface_s sEffectInterfaceReverse = {
1549 PreProcessingFx_Process,
1550 PreProcessingFx_Command,
1551 PreProcessingFx_GetDescriptor,
1552 PreProcessingFx_ProcessReverse
1553};
1554
1555//------------------------------------------------------------------------------
1556// Effect Library Interface Implementation
1557//------------------------------------------------------------------------------
1558
1559int PreProcessingLib_QueryNumberEffects(uint32_t *pNumEffects)
1560{
1561 if (PreProc_Init() != 0) {
1562 return sInitStatus;
1563 }
1564 if (pNumEffects == NULL) {
1565 return -EINVAL;
1566 }
1567 *pNumEffects = PREPROC_NUM_EFFECTS;
1568 return sInitStatus;
1569}
1570
1571int PreProcessingLib_QueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
1572{
1573 if (PreProc_Init() != 0) {
1574 return sInitStatus;
1575 }
1576 if (index >= PREPROC_NUM_EFFECTS) {
1577 return -EINVAL;
1578 }
1579 memcpy(pDescriptor, sDescriptors[index], sizeof(effect_descriptor_t));
1580 return 0;
1581}
1582
Glenn Kasten5e92a782012-01-30 07:40:52 -08001583int PreProcessingLib_Create(const effect_uuid_t *uuid,
Eric Laurenta9390d42011-06-17 20:17:17 -07001584 int32_t sessionId,
1585 int32_t ioId,
1586 effect_handle_t *pInterface)
1587{
Steve Block3856b092011-10-20 11:56:00 +01001588 ALOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
Eric Laurenta9390d42011-06-17 20:17:17 -07001589
1590 int status;
1591 const effect_descriptor_t *desc;
1592 preproc_session_t *session;
1593 uint32_t procId;
1594
1595 if (PreProc_Init() != 0) {
1596 return sInitStatus;
1597 }
1598 desc = PreProc_GetDescriptor(uuid);
1599 if (desc == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +00001600 ALOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
Eric Laurenta9390d42011-06-17 20:17:17 -07001601 return -EINVAL;
1602 }
1603 procId = UuidToProcId(&desc->type);
1604
1605 session = PreProc_GetSession(procId, sessionId, ioId);
1606 if (session == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +00001607 ALOGW("EffectCreate: no more session available");
Eric Laurenta9390d42011-06-17 20:17:17 -07001608 return -EINVAL;
1609 }
1610
1611 status = Session_CreateEffect(session, procId, pInterface);
1612
1613 if (status < 0 && session->createdMsk == 0) {
1614 session->io = 0;
1615 }
1616 return status;
1617}
1618
1619int PreProcessingLib_Release(effect_handle_t interface)
1620{
1621 int status;
Steve Block3856b092011-10-20 11:56:00 +01001622 ALOGV("EffectRelease start %p", interface);
Eric Laurenta9390d42011-06-17 20:17:17 -07001623 if (PreProc_Init() != 0) {
1624 return sInitStatus;
1625 }
1626
1627 preproc_effect_t *fx = (preproc_effect_t *)interface;
1628
1629 if (fx->session->io == 0) {
1630 return -EINVAL;
1631 }
1632 return Session_ReleaseEffect(fx->session, fx);
1633}
1634
Glenn Kasten5e92a782012-01-30 07:40:52 -08001635int PreProcessingLib_GetDescriptor(const effect_uuid_t *uuid,
Eric Laurenta9390d42011-06-17 20:17:17 -07001636 effect_descriptor_t *pDescriptor) {
1637
1638 if (pDescriptor == NULL || uuid == NULL){
1639 return -EINVAL;
1640 }
1641
1642 const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
1643 if (desc == NULL) {
Steve Block3856b092011-10-20 11:56:00 +01001644 ALOGV("PreProcessingLib_GetDescriptor() not found");
Eric Laurenta9390d42011-06-17 20:17:17 -07001645 return -EINVAL;
1646 }
1647
Steve Block3856b092011-10-20 11:56:00 +01001648 ALOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
Eric Laurenta9390d42011-06-17 20:17:17 -07001649
1650 memcpy(pDescriptor, desc, sizeof(effect_descriptor_t));
1651 return 0;
1652}
1653
1654audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
1655 tag : AUDIO_EFFECT_LIBRARY_TAG,
1656 version : EFFECT_LIBRARY_API_VERSION,
1657 name : "Audio Preprocessing Library",
1658 implementor : "The Android Open Source Project",
1659 query_num_effects : PreProcessingLib_QueryNumberEffects,
1660 query_effect : PreProcessingLib_QueryEffect,
1661 create_effect : PreProcessingLib_Create,
1662 release_effect : PreProcessingLib_Release,
1663 get_descriptor : PreProcessingLib_GetDescriptor
1664};
1665
1666}; // extern "C"