blob: c99552bb399ccd1db26e98155e356a612f855ffa [file] [log] [blame]
Eric Laurent484e3202011-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>
27#include "modules/interface/module_common_types.h"
28#include "modules/audio_processing/main/interface/audio_processing.h"
29#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
223static const int kAgcDefaultTargetLevel = 0;
224static const int kAgcDefaultCompGain = 90;
225static const bool kAgcDefaultLimiter = true;
226
227int AgcInit (preproc_effect_t *effect)
228{
Steve Block71f2cf12011-10-20 11:56:00 +0100229 ALOGV("AgcInit");
Eric Laurent484e3202011-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 Block71f2cf12011-10-20 11:56:00 +0100241 ALOGV("AgcCreate got agc %p", agc);
Eric Laurent484e3202011-06-17 20:17:17 -0700242 if (agc == NULL) {
243 LOGW("AgcCreate Error");
244 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:
283 LOGW("AgcGetParameter() unknown param %08x", param);
284 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 Block71f2cf12011-10-20 11:56:00 +0100291 ALOGV("AgcGetParameter() target level %d milliBels", *(int16_t *) pValue);
Eric Laurent484e3202011-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 Block71f2cf12011-10-20 11:56:00 +0100295 ALOGV("AgcGetParameter() comp gain %d milliBels", *(int16_t *) pValue);
Eric Laurent484e3202011-06-17 20:17:17 -0700296 break;
297 case AGC_PARAM_LIMITER_ENA:
298 *(bool *) pValue = (bool)agc->is_limiter_enabled();
Steve Block71f2cf12011-10-20 11:56:00 +0100299 ALOGV("AgcGetParameter() limiter enabled %s",
Eric Laurent484e3202011-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:
308 LOGW("AgcGetParameter() unknown param %d", param);
309 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 Block71f2cf12011-10-20 11:56:00 +0100324 ALOGV("AgcSetParameter() target level %d milliBels", *(int16_t *)pValue);
Eric Laurent484e3202011-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 Block71f2cf12011-10-20 11:56:00 +0100328 ALOGV("AgcSetParameter() comp gain %d milliBels", *(int16_t *)pValue);
Eric Laurent484e3202011-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 Block71f2cf12011-10-20 11:56:00 +0100332 ALOGV("AgcSetParameter() limiter enabled %s", *(bool *)pValue ? "true" : "false");
Eric Laurent484e3202011-06-17 20:17:17 -0700333 status = agc->enable_limiter(*(bool *)pValue);
334 break;
335 case AGC_PARAM_PROPERTIES:
Steve Block71f2cf12011-10-20 11:56:00 +0100336 ALOGV("AgcSetParameter() properties level %d, gain %d limiter %d",
Eric Laurent484e3202011-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:
347 LOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
348 status = -EINVAL;
349 break;
350 }
351
Steve Block71f2cf12011-10-20 11:56:00 +0100352 ALOGV("AgcSetParameter() done status %d", status);
Eric Laurent484e3202011-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 Block71f2cf12011-10-20 11:56:00 +0100360 ALOGV("AgcEnable agc %p", agc);
Eric Laurent484e3202011-06-17 20:17:17 -0700361 agc->Enable(true);
362}
363
364void AgcDisable(preproc_effect_t *effect)
365{
Steve Block71f2cf12011-10-20 11:56:00 +0100366 ALOGV("AgcDisable");
Eric Laurent484e3202011-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 Block71f2cf12011-10-20 11:56:00 +0100394 ALOGV("AecInit");
Eric Laurent484e3202011-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 Block71f2cf12011-10-20 11:56:00 +0100404 ALOGV("AecCreate got aec %p", aec);
Eric Laurent484e3202011-06-17 20:17:17 -0700405 if (aec == NULL) {
406 LOGW("AgcCreate Error");
407 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 Block71f2cf12011-10-20 11:56:00 +0100429 ALOGV("AecGetParameter() echo delay %d us", *(uint32_t *)pValue);
Eric Laurent484e3202011-06-17 20:17:17 -0700430 break;
431 default:
432 LOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
433 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 Block71f2cf12011-10-20 11:56:00 +0100449 ALOGV("AecSetParameter() echo delay %d us, status %d", value, status);
Eric Laurent484e3202011-06-17 20:17:17 -0700450 break;
451 default:
452 LOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
453 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 Block71f2cf12011-10-20 11:56:00 +0100462 ALOGV("AecEnable aec %p", aec);
Eric Laurent484e3202011-06-17 20:17:17 -0700463 aec->Enable(true);
464}
465
466void AecDisable(preproc_effect_t *effect)
467{
Steve Block71f2cf12011-10-20 11:56:00 +0100468 ALOGV("AecDisable");
Eric Laurent484e3202011-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 Block71f2cf12011-10-20 11:56:00 +0100475 ALOGV("AecSetDevice %08x", device);
Eric Laurent484e3202011-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 Block71f2cf12011-10-20 11:56:00 +0100514 ALOGV("NsInit");
Eric Laurent484e3202011-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 Block71f2cf12011-10-20 11:56:00 +0100523 ALOGV("NsCreate got ns %p", ns);
Eric Laurent484e3202011-06-17 20:17:17 -0700524 if (ns == NULL) {
525 LOGW("AgcCreate Error");
526 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 Block71f2cf12011-10-20 11:56:00 +0100551 ALOGV("NsEnable ns %p", ns);
Eric Laurent484e3202011-06-17 20:17:17 -0700552 ns->Enable(true);
553}
554
555void NsDisable(preproc_effect_t *effect)
556{
Steve Block71f2cf12011-10-20 11:56:00 +0100557 ALOGV("NsDisable");
Eric Laurent484e3202011-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 Block71f2cf12011-10-20 11:56:00 +0100596 ALOGV("Effect_SetState proc %d, new %d old %d", effect->procId, state, effect->state);
Eric Laurent484e3202011-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:
619 LOGE("Effect_SetState invalid transition");
620 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:
629 LOGE("Effect_SetState invalid transition");
630 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:
648 LOGE("Effect_SetState invalid transition");
649 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 Block71f2cf12011-10-20 11:56:00 +0100728 ALOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
Eric Laurent484e3202011-06-17 20:17:17 -0700729
730 if (session->createdMsk == 0) {
731 session->apm = webrtc::AudioProcessing::Create(session->io);
732 if (session->apm == NULL) {
733 LOGW("Session_CreateEffect could not get apm engine");
734 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) {
741 LOGW("Session_CreateEffect could not allocate audio frame");
742 goto error;
743 }
744 session->revFrame = new webrtc::AudioFrame();
745 if (session->revFrame == NULL) {
746 LOGW("Session_CreateEffect could not allocate reverse audio frame");
747 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 Block71f2cf12011-10-20 11:56:00 +0100778 ALOGV("Session_CreateEffect OK");
Eric Laurent484e3202011-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{
797 LOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
798 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 Block71f2cf12011-10-20 11:56:00 +0100844 ALOGV("Session_SetConfig sr %d cnl %08x",
Eric Laurent484e3202011-06-17 20:17:17 -0700845 config->inputCfg.samplingRate, config->inputCfg.channels);
846 int status;
847
848 // AEC implementation is limited to 16kHz
849 if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
850 session->apmSamplingRate = 32000;
851 } else
852 if (config->inputCfg.samplingRate >= 16000) {
853 session->apmSamplingRate = 16000;
854 } else if (config->inputCfg.samplingRate >= 8000) {
855 session->apmSamplingRate = 8000;
856 }
857 status = session->apm->set_sample_rate_hz(session->apmSamplingRate);
858 if (status < 0) {
859 return -EINVAL;
860 }
861 status = session->apm->set_num_channels(inCnl, outCnl);
862 if (status < 0) {
863 return -EINVAL;
864 }
865 status = session->apm->set_num_reverse_channels(inCnl);
866 if (status < 0) {
867 return -EINVAL;
868 }
869
870 session->samplingRate = config->inputCfg.samplingRate;
871 session->apmFrameCount = session->apmSamplingRate / 100;
872 if (session->samplingRate == session->apmSamplingRate) {
873 session->frameCount = session->apmFrameCount;
874 } else {
875 session->frameCount = (session->apmFrameCount * session->samplingRate) /
876 session->apmSamplingRate + 1;
877 }
878 session->inChannelCount = inCnl;
879 session->outChannelCount = outCnl;
880 session->procFrame->_audioChannel = inCnl;
881 session->procFrame->_frequencyInHz = session->apmSamplingRate;
882
883 session->revChannelCount = inCnl;
884 session->revFrame->_audioChannel = inCnl;
885 session->revFrame->_frequencyInHz = session->apmSamplingRate;
886
887 if (session->inResampler != NULL) {
888 speex_resampler_destroy(session->inResampler);
889 session->inResampler = NULL;
890 }
891 if (session->outResampler != NULL) {
892 speex_resampler_destroy(session->outResampler);
893 session->outResampler = NULL;
894 }
895 if (session->revResampler != NULL) {
896 speex_resampler_destroy(session->revResampler);
897 session->revResampler = NULL;
898 }
899 if (session->samplingRate != session->apmSamplingRate) {
900 int error;
901 session->inResampler = speex_resampler_init(session->inChannelCount,
902 session->samplingRate,
903 session->apmSamplingRate,
904 RESAMPLER_QUALITY,
905 &error);
906 if (session->inResampler == NULL) {
907 LOGW("Session_SetConfig Cannot create speex resampler: %s",
908 speex_resampler_strerror(error));
909 return -EINVAL;
910 }
911 session->outResampler = speex_resampler_init(session->outChannelCount,
912 session->apmSamplingRate,
913 session->samplingRate,
914 RESAMPLER_QUALITY,
915 &error);
916 if (session->outResampler == NULL) {
917 LOGW("Session_SetConfig Cannot create speex resampler: %s",
918 speex_resampler_strerror(error));
919 speex_resampler_destroy(session->inResampler);
920 session->inResampler = NULL;
921 return -EINVAL;
922 }
923 session->revResampler = speex_resampler_init(session->inChannelCount,
924 session->samplingRate,
925 session->apmSamplingRate,
926 RESAMPLER_QUALITY,
927 &error);
928 if (session->revResampler == NULL) {
929 LOGW("Session_SetConfig Cannot create speex resampler: %s",
930 speex_resampler_strerror(error));
931 speex_resampler_destroy(session->inResampler);
932 session->inResampler = NULL;
933 speex_resampler_destroy(session->outResampler);
934 session->outResampler = NULL;
935 return -EINVAL;
936 }
937 }
938
939 session->state = PREPROC_SESSION_STATE_CONFIG;
940 return 0;
941}
942
Eric Laurent4abf8822011-12-16 15:30:36 -0800943void Session_GetConfig(preproc_session_t *session, effect_config_t *config)
944{
945 memset(config, 0, sizeof(effect_config_t));
946 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
947 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
948 config->inputCfg.channels = session->inChannelCount == 1 ?
949 AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO;
950 config->outputCfg.channels = session->outChannelCount == 1 ?
951 AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO;
952 config->inputCfg.mask = config->outputCfg.mask =
953 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
954}
955
Eric Laurent484e3202011-06-17 20:17:17 -0700956int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
957{
958 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
959 config->inputCfg.format != config->outputCfg.format ||
960 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
961 return -EINVAL;
962 }
963
Steve Block71f2cf12011-10-20 11:56:00 +0100964 ALOGV("Session_SetReverseConfig sr %d cnl %08x",
Eric Laurent484e3202011-06-17 20:17:17 -0700965 config->inputCfg.samplingRate, config->inputCfg.channels);
966
967 if (session->state < PREPROC_SESSION_STATE_CONFIG) {
968 return -ENOSYS;
969 }
970 if (config->inputCfg.samplingRate != session->samplingRate ||
971 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
972 return -EINVAL;
973 }
974 uint32_t inCnl = popcount(config->inputCfg.channels);
975 int status = session->apm->set_num_reverse_channels(inCnl);
976 if (status < 0) {
977 return -EINVAL;
978 }
979 session->revChannelCount = inCnl;
980 session->revFrame->_audioChannel = inCnl;
981 session->revFrame->_frequencyInHz = session->apmSamplingRate;
982 return 0;
983}
984
Eric Laurent4abf8822011-12-16 15:30:36 -0800985void Session_GetReverseConfig(preproc_session_t *session, effect_config_t *config)
986{
987 memset(config, 0, sizeof(effect_config_t));
988 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
989 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
990 config->inputCfg.channels = config->outputCfg.channels =
991 session->revChannelCount == 1 ? AUDIO_CHANNEL_IN_MONO : AUDIO_CHANNEL_IN_STEREO;
992 config->inputCfg.mask = config->outputCfg.mask =
993 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
994}
995
Eric Laurent484e3202011-06-17 20:17:17 -0700996void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
997{
998 if (enabled) {
999 if(session->enabledMsk == 0) {
1000 session->framesIn = 0;
1001 if (session->inResampler != NULL) {
1002 speex_resampler_reset_mem(session->inResampler);
1003 }
1004 session->framesOut = 0;
1005 if (session->outResampler != NULL) {
1006 speex_resampler_reset_mem(session->outResampler);
1007 }
1008 }
1009 session->enabledMsk |= (1 << procId);
1010 if (HasReverseStream(procId)) {
1011 session->framesRev = 0;
1012 if (session->revResampler != NULL) {
1013 speex_resampler_reset_mem(session->revResampler);
1014 }
1015 session->revEnabledMsk |= (1 << procId);
1016 }
1017 } else {
1018 session->enabledMsk &= ~(1 << procId);
1019 if (HasReverseStream(procId)) {
1020 session->revEnabledMsk &= ~(1 << procId);
1021 }
1022 }
Steve Block71f2cf12011-10-20 11:56:00 +01001023 ALOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x",
Eric Laurent484e3202011-06-17 20:17:17 -07001024 procId, enabled, session->enabledMsk, session->revEnabledMsk);
1025 session->processedMsk = 0;
1026 if (HasReverseStream(procId)) {
1027 session->revProcessedMsk = 0;
1028 }
1029}
1030
1031//------------------------------------------------------------------------------
1032// Bundle functions
1033//------------------------------------------------------------------------------
1034
1035static int sInitStatus = 1;
1036static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
1037
1038preproc_session_t *PreProc_GetSession(int32_t procId, int32_t sessionId, int32_t ioId)
1039{
1040 size_t i;
1041 int free = -1;
1042 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1043 if (sSessions[i].io == ioId) {
1044 if (sSessions[i].createdMsk & (1 << procId)) {
1045 return NULL;
1046 }
1047 return &sSessions[i];
1048 }
1049 }
1050 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1051 if (sSessions[i].io == 0) {
1052 sSessions[i].id = sessionId;
1053 sSessions[i].io = ioId;
1054 return &sSessions[i];
1055 }
1056 }
1057 return NULL;
1058}
1059
1060
1061int PreProc_Init() {
1062 size_t i;
1063 int status = 0;
1064
1065 if (sInitStatus <= 0) {
1066 return sInitStatus;
1067 }
1068 for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
1069 status = Session_Init(&sSessions[i]);
1070 }
1071 sInitStatus = status;
1072 return sInitStatus;
1073}
1074
1075const effect_descriptor_t *PreProc_GetDescriptor(effect_uuid_t *uuid)
1076{
1077 size_t i;
1078 for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
1079 if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
1080 return sDescriptors[i];
1081 }
1082 }
1083 return NULL;
1084}
1085
1086
1087extern "C" {
1088
1089//------------------------------------------------------------------------------
1090// Effect Control Interface Implementation
1091//------------------------------------------------------------------------------
1092
1093int PreProcessingFx_Process(effect_handle_t self,
1094 audio_buffer_t *inBuffer,
1095 audio_buffer_t *outBuffer)
1096{
1097 preproc_effect_t * effect = (preproc_effect_t *)self;
1098 int status = 0;
1099
1100 if (effect == NULL){
Steve Block71f2cf12011-10-20 11:56:00 +01001101 ALOGV("PreProcessingFx_Process() ERROR effect == NULL");
Eric Laurent484e3202011-06-17 20:17:17 -07001102 return -EINVAL;
1103 }
1104 preproc_session_t * session = (preproc_session_t *)effect->session;
1105
1106 if (inBuffer == NULL || inBuffer->raw == NULL ||
1107 outBuffer == NULL || outBuffer->raw == NULL){
1108 LOGW("PreProcessingFx_Process() ERROR bad pointer");
1109 return -EINVAL;
1110 }
1111
1112 session->processedMsk |= (1<<effect->procId);
1113
Steve Block71f2cf12011-10-20 11:56:00 +01001114// ALOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
Eric Laurent484e3202011-06-17 20:17:17 -07001115// inBuffer->frameCount, session->enabledMsk, session->processedMsk);
1116
1117 if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
1118 effect->session->processedMsk = 0;
1119 size_t framesRq = outBuffer->frameCount;
1120 size_t framesWr = 0;
1121 if (session->framesOut) {
1122 size_t fr = session->framesOut;
1123 if (outBuffer->frameCount < fr) {
1124 fr = outBuffer->frameCount;
1125 }
1126 memcpy(outBuffer->s16,
1127 session->outBuf,
1128 fr * session->outChannelCount * sizeof(int16_t));
1129 memcpy(session->outBuf,
1130 session->outBuf + fr * session->outChannelCount,
1131 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1132 session->framesOut -= fr;
1133 framesWr += fr;
1134 }
1135 outBuffer->frameCount = framesWr;
1136 if (framesWr == framesRq) {
1137 inBuffer->frameCount = 0;
1138 return 0;
1139 }
1140
1141 if (session->inResampler != NULL) {
1142 size_t fr = session->frameCount - session->framesIn;
1143 if (inBuffer->frameCount < fr) {
1144 fr = inBuffer->frameCount;
1145 }
1146 if (session->inBufSize < session->framesIn + fr) {
1147 session->inBufSize = session->framesIn + fr;
1148 session->inBuf = (int16_t *)realloc(session->inBuf,
1149 session->inBufSize * session->inChannelCount * sizeof(int16_t));
1150 }
1151 memcpy(session->inBuf + session->framesIn * session->inChannelCount,
1152 inBuffer->s16,
1153 fr * session->inChannelCount * sizeof(int16_t));
1154
1155 session->framesIn += fr;
1156 inBuffer->frameCount = fr;
1157 if (session->framesIn < session->frameCount) {
1158 return 0;
1159 }
1160 size_t frIn = session->framesIn;
1161 size_t frOut = session->apmFrameCount;
1162 if (session->inChannelCount == 1) {
1163 speex_resampler_process_int(session->inResampler,
1164 0,
1165 session->inBuf,
1166 &frIn,
1167 session->procFrame->_payloadData,
1168 &frOut);
1169 } else {
1170 speex_resampler_process_interleaved_int(session->inResampler,
1171 session->inBuf,
1172 &frIn,
1173 session->procFrame->_payloadData,
1174 &frOut);
1175 }
1176 memcpy(session->inBuf,
1177 session->inBuf + frIn * session->inChannelCount,
1178 (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
1179 session->framesIn -= frIn;
1180 } else {
1181 size_t fr = session->frameCount - session->framesIn;
1182 if (inBuffer->frameCount < fr) {
1183 fr = inBuffer->frameCount;
1184 }
1185 memcpy(session->procFrame->_payloadData + session->framesIn * session->inChannelCount,
1186 inBuffer->s16,
1187 fr * session->inChannelCount * sizeof(int16_t));
1188 session->framesIn += fr;
1189 inBuffer->frameCount = fr;
1190 if (session->framesIn < session->frameCount) {
1191 return 0;
1192 }
1193 session->framesIn = 0;
1194 }
1195 session->procFrame->_payloadDataLengthInSamples =
1196 session->apmFrameCount * session->inChannelCount;
1197
1198 effect->session->apm->ProcessStream(session->procFrame);
1199
1200 if (session->outBufSize < session->framesOut + session->frameCount) {
1201 session->outBufSize = session->framesOut + session->frameCount;
1202 session->outBuf = (int16_t *)realloc(session->outBuf,
1203 session->outBufSize * session->outChannelCount * sizeof(int16_t));
1204 }
1205
1206 if (session->outResampler != NULL) {
1207 size_t frIn = session->apmFrameCount;
1208 size_t frOut = session->frameCount;
1209 if (session->inChannelCount == 1) {
1210 speex_resampler_process_int(session->outResampler,
1211 0,
1212 session->procFrame->_payloadData,
1213 &frIn,
1214 session->outBuf + session->framesOut * session->outChannelCount,
1215 &frOut);
1216 } else {
1217 speex_resampler_process_interleaved_int(session->outResampler,
1218 session->procFrame->_payloadData,
1219 &frIn,
1220 session->outBuf + session->framesOut * session->outChannelCount,
1221 &frOut);
1222 }
1223 session->framesOut += frOut;
1224 } else {
1225 memcpy(session->outBuf + session->framesOut * session->outChannelCount,
1226 session->procFrame->_payloadData,
1227 session->frameCount * session->outChannelCount * sizeof(int16_t));
1228 session->framesOut += session->frameCount;
1229 }
1230 size_t fr = session->framesOut;
1231 if (framesRq - framesWr < fr) {
1232 fr = framesRq - framesWr;
1233 }
1234 memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
1235 session->outBuf,
1236 fr * session->outChannelCount * sizeof(int16_t));
1237 memcpy(session->outBuf,
1238 session->outBuf + fr * session->outChannelCount,
1239 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1240 session->framesOut -= fr;
1241 outBuffer->frameCount += fr;
1242
1243 return 0;
1244 } else {
1245 return -ENODATA;
1246 }
1247}
1248
1249int PreProcessingFx_Command(effect_handle_t self,
1250 uint32_t cmdCode,
1251 uint32_t cmdSize,
1252 void *pCmdData,
1253 uint32_t *replySize,
1254 void *pReplyData)
1255{
1256 preproc_effect_t * effect = (preproc_effect_t *) self;
1257 int retsize;
1258 int status;
1259
1260 if (effect == NULL){
1261 return -EINVAL;
1262 }
1263
Steve Block71f2cf12011-10-20 11:56:00 +01001264 //ALOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
Eric Laurent484e3202011-06-17 20:17:17 -07001265
1266 switch (cmdCode){
1267 case EFFECT_CMD_INIT:
1268 if (pReplyData == NULL || *replySize != sizeof(int)){
1269 return -EINVAL;
1270 }
1271 if (effect->ops->init) {
1272 effect->ops->init(effect);
1273 }
1274 *(int *)pReplyData = 0;
1275 break;
1276
Eric Laurent4abf8822011-12-16 15:30:36 -08001277 case EFFECT_CMD_SET_CONFIG:
Eric Laurent484e3202011-06-17 20:17:17 -07001278 if (pCmdData == NULL||
1279 cmdSize != sizeof(effect_config_t)||
1280 pReplyData == NULL||
1281 *replySize != sizeof(int)){
Steve Block71f2cf12011-10-20 11:56:00 +01001282 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent4abf8822011-12-16 15:30:36 -08001283 "EFFECT_CMD_SET_CONFIG: ERROR");
Eric Laurent484e3202011-06-17 20:17:17 -07001284 return -EINVAL;
1285 }
1286 *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
1287 if (*(int *)pReplyData != 0) {
1288 break;
1289 }
1290 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1291 break;
1292
Eric Laurent4abf8822011-12-16 15:30:36 -08001293 case EFFECT_CMD_GET_CONFIG:
1294 if (pReplyData == NULL ||
1295 *replySize != sizeof(effect_config_t)) {
1296 ALOGV("\tLVM_ERROR : PreProcessingFx_Command cmdCode Case: "
1297 "EFFECT_CMD_GET_CONFIG: ERROR");
1298 return -EINVAL;
1299 }
1300
1301 Session_GetConfig(effect->session, (effect_config_t *)pCmdData);
1302 break;
1303
1304 case EFFECT_CMD_SET_CONFIG_REVERSE:
1305 if (pCmdData == NULL ||
1306 cmdSize != sizeof(effect_config_t) ||
1307 pReplyData == NULL ||
1308 *replySize != sizeof(int)) {
Steve Block71f2cf12011-10-20 11:56:00 +01001309 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent4abf8822011-12-16 15:30:36 -08001310 "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR");
Eric Laurent484e3202011-06-17 20:17:17 -07001311 return -EINVAL;
1312 }
1313 *(int *)pReplyData = Session_SetReverseConfig(effect->session,
1314 (effect_config_t *)pCmdData);
1315 if (*(int *)pReplyData != 0) {
1316 break;
1317 }
1318 break;
1319
Eric Laurent4abf8822011-12-16 15:30:36 -08001320 case EFFECT_CMD_GET_CONFIG_REVERSE:
1321 if (pReplyData == NULL ||
1322 *replySize != sizeof(effect_config_t)){
1323 ALOGV("PreProcessingFx_Command cmdCode Case: "
1324 "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR");
1325 return -EINVAL;
1326 }
1327 Session_GetReverseConfig(effect->session, (effect_config_t *)pCmdData);
1328 break;
1329
Eric Laurent484e3202011-06-17 20:17:17 -07001330 case EFFECT_CMD_RESET:
1331 if (effect->ops->reset) {
1332 effect->ops->reset(effect);
1333 }
1334 break;
1335
1336 case EFFECT_CMD_GET_PARAM:{
1337 if (pCmdData == NULL ||
1338 cmdSize < (int)sizeof(effect_param_t) ||
1339 pReplyData == NULL ||
1340 *replySize < (int)sizeof(effect_param_t)){
Steve Block71f2cf12011-10-20 11:56:00 +01001341 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent484e3202011-06-17 20:17:17 -07001342 "EFFECT_CMD_GET_PARAM: ERROR");
1343 return -EINVAL;
1344 }
1345 effect_param_t *p = (effect_param_t *)pCmdData;
1346
1347 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
1348
1349 p = (effect_param_t *)pReplyData;
1350
1351 int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
1352
1353 if (effect->ops->get_parameter) {
1354 p->status = effect->ops->get_parameter(effect, p->data,
1355 (size_t *)&p->vsize,
1356 p->data + voffset);
1357 *replySize = sizeof(effect_param_t) + voffset + p->vsize;
1358 }
1359 } break;
1360
1361 case EFFECT_CMD_SET_PARAM:{
1362 if (pCmdData == NULL||
1363 cmdSize < (int)sizeof(effect_param_t) ||
1364 pReplyData == NULL ||
1365 *replySize != sizeof(int32_t)){
Steve Block71f2cf12011-10-20 11:56:00 +01001366 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent484e3202011-06-17 20:17:17 -07001367 "EFFECT_CMD_SET_PARAM: ERROR");
1368 return -EINVAL;
1369 }
1370 effect_param_t *p = (effect_param_t *) pCmdData;
1371
1372 if (p->psize != sizeof(int32_t)){
Steve Block71f2cf12011-10-20 11:56:00 +01001373 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent484e3202011-06-17 20:17:17 -07001374 "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
1375 return -EINVAL;
1376 }
1377 if (effect->ops->set_parameter) {
1378 *(int *)pReplyData = effect->ops->set_parameter(effect,
1379 (void *)p->data,
1380 p->data + p->psize);
1381 }
1382 } break;
1383
1384 case EFFECT_CMD_ENABLE:
1385 if (pReplyData == NULL || *replySize != sizeof(int)){
Steve Block71f2cf12011-10-20 11:56:00 +01001386 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
Eric Laurent484e3202011-06-17 20:17:17 -07001387 return -EINVAL;
1388 }
1389 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
1390 break;
1391
1392 case EFFECT_CMD_DISABLE:
1393 if (pReplyData == NULL || *replySize != sizeof(int)){
Steve Block71f2cf12011-10-20 11:56:00 +01001394 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
Eric Laurent484e3202011-06-17 20:17:17 -07001395 return -EINVAL;
1396 }
1397 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1398 break;
1399
1400 case EFFECT_CMD_SET_DEVICE:
1401 case EFFECT_CMD_SET_INPUT_DEVICE:
1402 if (pCmdData == NULL ||
1403 cmdSize != sizeof(uint32_t)) {
Steve Block71f2cf12011-10-20 11:56:00 +01001404 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
Eric Laurent484e3202011-06-17 20:17:17 -07001405 return -EINVAL;
1406 }
1407
1408 if (effect->ops->set_device) {
1409 effect->ops->set_device(effect, *(uint32_t *)pCmdData);
1410 }
1411 break;
1412
1413 case EFFECT_CMD_SET_VOLUME:
1414 case EFFECT_CMD_SET_AUDIO_MODE:
1415 break;
1416
1417 default:
1418 return -EINVAL;
1419 }
1420 return 0;
1421}
1422
1423
1424int PreProcessingFx_GetDescriptor(effect_handle_t self,
1425 effect_descriptor_t *pDescriptor)
1426{
1427 preproc_effect_t * effect = (preproc_effect_t *) self;
1428
1429 if (effect == NULL || pDescriptor == NULL) {
1430 return -EINVAL;
1431 }
1432
1433 memcpy(pDescriptor, sDescriptors[effect->procId], sizeof(effect_descriptor_t));
1434
1435 return 0;
1436}
1437
1438int PreProcessingFx_ProcessReverse(effect_handle_t self,
1439 audio_buffer_t *inBuffer,
1440 audio_buffer_t *outBuffer)
1441{
1442 preproc_effect_t * effect = (preproc_effect_t *)self;
1443 int status = 0;
1444
1445 if (effect == NULL){
1446 LOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
1447 return -EINVAL;
1448 }
1449 preproc_session_t * session = (preproc_session_t *)effect->session;
1450
1451 if (inBuffer == NULL || inBuffer->raw == NULL){
1452 LOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
1453 return -EINVAL;
1454 }
1455
1456 session->revProcessedMsk |= (1<<effect->procId);
1457
Steve Block71f2cf12011-10-20 11:56:00 +01001458// ALOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
Eric Laurent484e3202011-06-17 20:17:17 -07001459// inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
1460
1461
1462 if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
1463 effect->session->revProcessedMsk = 0;
1464 if (session->revResampler != NULL) {
1465 size_t fr = session->frameCount - session->framesRev;
1466 if (inBuffer->frameCount < fr) {
1467 fr = inBuffer->frameCount;
1468 }
1469 if (session->revBufSize < session->framesRev + fr) {
1470 session->revBufSize = session->framesRev + fr;
1471 session->revBuf = (int16_t *)realloc(session->revBuf,
1472 session->revBufSize * session->inChannelCount * sizeof(int16_t));
1473 }
1474 memcpy(session->revBuf + session->framesRev * session->inChannelCount,
1475 inBuffer->s16,
1476 fr * session->inChannelCount * sizeof(int16_t));
1477
1478 session->framesRev += fr;
1479 inBuffer->frameCount = fr;
1480 if (session->framesRev < session->frameCount) {
1481 return 0;
1482 }
1483 size_t frIn = session->framesRev;
1484 size_t frOut = session->apmFrameCount;
1485 if (session->inChannelCount == 1) {
1486 speex_resampler_process_int(session->revResampler,
1487 0,
1488 session->revBuf,
1489 &frIn,
1490 session->revFrame->_payloadData,
1491 &frOut);
1492 } else {
1493 speex_resampler_process_interleaved_int(session->revResampler,
1494 session->revBuf,
1495 &frIn,
1496 session->revFrame->_payloadData,
1497 &frOut);
1498 }
1499 memcpy(session->revBuf,
1500 session->revBuf + frIn * session->inChannelCount,
1501 (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
1502 session->framesRev -= frIn;
1503 } else {
1504 size_t fr = session->frameCount - session->framesRev;
1505 if (inBuffer->frameCount < fr) {
1506 fr = inBuffer->frameCount;
1507 }
1508 memcpy(session->revFrame->_payloadData + session->framesRev * session->inChannelCount,
1509 inBuffer->s16,
1510 fr * session->inChannelCount * sizeof(int16_t));
1511 session->framesRev += fr;
1512 inBuffer->frameCount = fr;
1513 if (session->framesRev < session->frameCount) {
1514 return 0;
1515 }
1516 session->framesRev = 0;
1517 }
1518 session->revFrame->_payloadDataLengthInSamples =
1519 session->apmFrameCount * session->inChannelCount;
1520 effect->session->apm->AnalyzeReverseStream(session->revFrame);
1521 return 0;
1522 } else {
1523 return -ENODATA;
1524 }
1525}
1526
1527
1528// effect_handle_t interface implementation for effect
1529const struct effect_interface_s sEffectInterface = {
1530 PreProcessingFx_Process,
1531 PreProcessingFx_Command,
1532 PreProcessingFx_GetDescriptor,
1533 NULL
1534};
1535
1536const struct effect_interface_s sEffectInterfaceReverse = {
1537 PreProcessingFx_Process,
1538 PreProcessingFx_Command,
1539 PreProcessingFx_GetDescriptor,
1540 PreProcessingFx_ProcessReverse
1541};
1542
1543//------------------------------------------------------------------------------
1544// Effect Library Interface Implementation
1545//------------------------------------------------------------------------------
1546
1547int PreProcessingLib_QueryNumberEffects(uint32_t *pNumEffects)
1548{
1549 if (PreProc_Init() != 0) {
1550 return sInitStatus;
1551 }
1552 if (pNumEffects == NULL) {
1553 return -EINVAL;
1554 }
1555 *pNumEffects = PREPROC_NUM_EFFECTS;
1556 return sInitStatus;
1557}
1558
1559int PreProcessingLib_QueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
1560{
1561 if (PreProc_Init() != 0) {
1562 return sInitStatus;
1563 }
1564 if (index >= PREPROC_NUM_EFFECTS) {
1565 return -EINVAL;
1566 }
1567 memcpy(pDescriptor, sDescriptors[index], sizeof(effect_descriptor_t));
1568 return 0;
1569}
1570
1571int PreProcessingLib_Create(effect_uuid_t *uuid,
1572 int32_t sessionId,
1573 int32_t ioId,
1574 effect_handle_t *pInterface)
1575{
Steve Block71f2cf12011-10-20 11:56:00 +01001576 ALOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
Eric Laurent484e3202011-06-17 20:17:17 -07001577
1578 int status;
1579 const effect_descriptor_t *desc;
1580 preproc_session_t *session;
1581 uint32_t procId;
1582
1583 if (PreProc_Init() != 0) {
1584 return sInitStatus;
1585 }
1586 desc = PreProc_GetDescriptor(uuid);
1587 if (desc == NULL) {
1588 LOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
1589 return -EINVAL;
1590 }
1591 procId = UuidToProcId(&desc->type);
1592
1593 session = PreProc_GetSession(procId, sessionId, ioId);
1594 if (session == NULL) {
1595 LOGW("EffectCreate: no more session available");
1596 return -EINVAL;
1597 }
1598
1599 status = Session_CreateEffect(session, procId, pInterface);
1600
1601 if (status < 0 && session->createdMsk == 0) {
1602 session->io = 0;
1603 }
1604 return status;
1605}
1606
1607int PreProcessingLib_Release(effect_handle_t interface)
1608{
1609 int status;
Steve Block71f2cf12011-10-20 11:56:00 +01001610 ALOGV("EffectRelease start %p", interface);
Eric Laurent484e3202011-06-17 20:17:17 -07001611 if (PreProc_Init() != 0) {
1612 return sInitStatus;
1613 }
1614
1615 preproc_effect_t *fx = (preproc_effect_t *)interface;
1616
1617 if (fx->session->io == 0) {
1618 return -EINVAL;
1619 }
1620 return Session_ReleaseEffect(fx->session, fx);
1621}
1622
1623int PreProcessingLib_GetDescriptor(effect_uuid_t *uuid,
1624 effect_descriptor_t *pDescriptor) {
1625
1626 if (pDescriptor == NULL || uuid == NULL){
1627 return -EINVAL;
1628 }
1629
1630 const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
1631 if (desc == NULL) {
Steve Block71f2cf12011-10-20 11:56:00 +01001632 ALOGV("PreProcessingLib_GetDescriptor() not found");
Eric Laurent484e3202011-06-17 20:17:17 -07001633 return -EINVAL;
1634 }
1635
Steve Block71f2cf12011-10-20 11:56:00 +01001636 ALOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
Eric Laurent484e3202011-06-17 20:17:17 -07001637
1638 memcpy(pDescriptor, desc, sizeof(effect_descriptor_t));
1639 return 0;
1640}
1641
1642audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
1643 tag : AUDIO_EFFECT_LIBRARY_TAG,
1644 version : EFFECT_LIBRARY_API_VERSION,
1645 name : "Audio Preprocessing Library",
1646 implementor : "The Android Open Source Project",
1647 query_num_effects : PreProcessingLib_QueryNumberEffects,
1648 query_effect : PreProcessingLib_QueryEffect,
1649 create_effect : PreProcessingLib_Create,
1650 release_effect : PreProcessingLib_Release,
1651 get_descriptor : PreProcessingLib_GetDescriptor
1652};
1653
1654}; // extern "C"