blob: 032c5aabacb4f74b607a37f6a6aeea81890f858f [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 Block06ade6a2011-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 Block06ade6a2011-10-20 11:56:00 +0100241 ALOGV("AgcCreate got agc %p", agc);
Eric Laurent484e3202011-06-17 20:17:17 -0700242 if (agc == NULL) {
Steve Blocka51f0e72012-01-05 23:22:43 +0000243 ALOGW("AgcCreate Error");
Eric Laurent484e3202011-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 Blocka51f0e72012-01-05 23:22:43 +0000283 ALOGW("AgcGetParameter() unknown param %08x", param);
Eric Laurent484e3202011-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 Block06ade6a2011-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 Block06ade6a2011-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 Block06ade6a2011-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:
Steve Blocka51f0e72012-01-05 23:22:43 +0000308 ALOGW("AgcGetParameter() unknown param %d", param);
Eric Laurent484e3202011-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 Block06ade6a2011-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 Block06ade6a2011-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 Block06ade6a2011-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 Block06ade6a2011-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:
Steve Blocka51f0e72012-01-05 23:22:43 +0000347 ALOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurent484e3202011-06-17 20:17:17 -0700348 status = -EINVAL;
349 break;
350 }
351
Steve Block06ade6a2011-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 Block06ade6a2011-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 Block06ade6a2011-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 Block06ade6a2011-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 Block06ade6a2011-10-20 11:56:00 +0100404 ALOGV("AecCreate got aec %p", aec);
Eric Laurent484e3202011-06-17 20:17:17 -0700405 if (aec == NULL) {
Steve Blocka51f0e72012-01-05 23:22:43 +0000406 ALOGW("AgcCreate Error");
Eric Laurent484e3202011-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 Block06ade6a2011-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:
Steve Blocka51f0e72012-01-05 23:22:43 +0000432 ALOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurent484e3202011-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 Block06ade6a2011-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:
Steve Blocka51f0e72012-01-05 23:22:43 +0000452 ALOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurent484e3202011-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 Block06ade6a2011-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 Block06ade6a2011-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 Block06ade6a2011-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 Block06ade6a2011-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 Block06ade6a2011-10-20 11:56:00 +0100523 ALOGV("NsCreate got ns %p", ns);
Eric Laurent484e3202011-06-17 20:17:17 -0700524 if (ns == NULL) {
Steve Blocka51f0e72012-01-05 23:22:43 +0000525 ALOGW("AgcCreate Error");
Eric Laurent484e3202011-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 Block06ade6a2011-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 Block06ade6a2011-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 Block06ade6a2011-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 Block06ade6a2011-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) {
Steve Blocka51f0e72012-01-05 23:22:43 +0000733 ALOGW("Session_CreateEffect could not get apm engine");
Eric Laurent484e3202011-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 Blocka51f0e72012-01-05 23:22:43 +0000741 ALOGW("Session_CreateEffect could not allocate audio frame");
Eric Laurent484e3202011-06-17 20:17:17 -0700742 goto error;
743 }
744 session->revFrame = new webrtc::AudioFrame();
745 if (session->revFrame == NULL) {
Steve Blocka51f0e72012-01-05 23:22:43 +0000746 ALOGW("Session_CreateEffect could not allocate reverse audio frame");
Eric Laurent484e3202011-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 Block06ade6a2011-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{
Steve Blocka51f0e72012-01-05 23:22:43 +0000797 ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
Eric Laurent484e3202011-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 Block06ade6a2011-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) {
Steve Blocka51f0e72012-01-05 23:22:43 +0000907 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurent484e3202011-06-17 20:17:17 -0700908 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) {
Steve Blocka51f0e72012-01-05 23:22:43 +0000917 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurent484e3202011-06-17 20:17:17 -0700918 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) {
Steve Blocka51f0e72012-01-05 23:22:43 +0000929 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurent484e3202011-06-17 20:17:17 -0700930 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
943int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
944{
945 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
946 config->inputCfg.format != config->outputCfg.format ||
947 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
948 return -EINVAL;
949 }
950
Steve Block06ade6a2011-10-20 11:56:00 +0100951 ALOGV("Session_SetReverseConfig sr %d cnl %08x",
Eric Laurent484e3202011-06-17 20:17:17 -0700952 config->inputCfg.samplingRate, config->inputCfg.channels);
953
954 if (session->state < PREPROC_SESSION_STATE_CONFIG) {
955 return -ENOSYS;
956 }
957 if (config->inputCfg.samplingRate != session->samplingRate ||
958 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
959 return -EINVAL;
960 }
961 uint32_t inCnl = popcount(config->inputCfg.channels);
962 int status = session->apm->set_num_reverse_channels(inCnl);
963 if (status < 0) {
964 return -EINVAL;
965 }
966 session->revChannelCount = inCnl;
967 session->revFrame->_audioChannel = inCnl;
968 session->revFrame->_frequencyInHz = session->apmSamplingRate;
969 return 0;
970}
971
972void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
973{
974 if (enabled) {
975 if(session->enabledMsk == 0) {
976 session->framesIn = 0;
977 if (session->inResampler != NULL) {
978 speex_resampler_reset_mem(session->inResampler);
979 }
980 session->framesOut = 0;
981 if (session->outResampler != NULL) {
982 speex_resampler_reset_mem(session->outResampler);
983 }
984 }
985 session->enabledMsk |= (1 << procId);
986 if (HasReverseStream(procId)) {
987 session->framesRev = 0;
988 if (session->revResampler != NULL) {
989 speex_resampler_reset_mem(session->revResampler);
990 }
991 session->revEnabledMsk |= (1 << procId);
992 }
993 } else {
994 session->enabledMsk &= ~(1 << procId);
995 if (HasReverseStream(procId)) {
996 session->revEnabledMsk &= ~(1 << procId);
997 }
998 }
Steve Block06ade6a2011-10-20 11:56:00 +0100999 ALOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x",
Eric Laurent484e3202011-06-17 20:17:17 -07001000 procId, enabled, session->enabledMsk, session->revEnabledMsk);
1001 session->processedMsk = 0;
1002 if (HasReverseStream(procId)) {
1003 session->revProcessedMsk = 0;
1004 }
1005}
1006
1007//------------------------------------------------------------------------------
1008// Bundle functions
1009//------------------------------------------------------------------------------
1010
1011static int sInitStatus = 1;
1012static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
1013
1014preproc_session_t *PreProc_GetSession(int32_t procId, int32_t sessionId, int32_t ioId)
1015{
1016 size_t i;
1017 int free = -1;
1018 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1019 if (sSessions[i].io == ioId) {
1020 if (sSessions[i].createdMsk & (1 << procId)) {
1021 return NULL;
1022 }
1023 return &sSessions[i];
1024 }
1025 }
1026 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1027 if (sSessions[i].io == 0) {
1028 sSessions[i].id = sessionId;
1029 sSessions[i].io = ioId;
1030 return &sSessions[i];
1031 }
1032 }
1033 return NULL;
1034}
1035
1036
1037int PreProc_Init() {
1038 size_t i;
1039 int status = 0;
1040
1041 if (sInitStatus <= 0) {
1042 return sInitStatus;
1043 }
1044 for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
1045 status = Session_Init(&sSessions[i]);
1046 }
1047 sInitStatus = status;
1048 return sInitStatus;
1049}
1050
1051const effect_descriptor_t *PreProc_GetDescriptor(effect_uuid_t *uuid)
1052{
1053 size_t i;
1054 for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
1055 if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
1056 return sDescriptors[i];
1057 }
1058 }
1059 return NULL;
1060}
1061
1062
1063extern "C" {
1064
1065//------------------------------------------------------------------------------
1066// Effect Control Interface Implementation
1067//------------------------------------------------------------------------------
1068
1069int PreProcessingFx_Process(effect_handle_t self,
1070 audio_buffer_t *inBuffer,
1071 audio_buffer_t *outBuffer)
1072{
1073 preproc_effect_t * effect = (preproc_effect_t *)self;
1074 int status = 0;
1075
1076 if (effect == NULL){
Steve Block06ade6a2011-10-20 11:56:00 +01001077 ALOGV("PreProcessingFx_Process() ERROR effect == NULL");
Eric Laurent484e3202011-06-17 20:17:17 -07001078 return -EINVAL;
1079 }
1080 preproc_session_t * session = (preproc_session_t *)effect->session;
1081
1082 if (inBuffer == NULL || inBuffer->raw == NULL ||
1083 outBuffer == NULL || outBuffer->raw == NULL){
Steve Blocka51f0e72012-01-05 23:22:43 +00001084 ALOGW("PreProcessingFx_Process() ERROR bad pointer");
Eric Laurent484e3202011-06-17 20:17:17 -07001085 return -EINVAL;
1086 }
1087
1088 session->processedMsk |= (1<<effect->procId);
1089
Steve Block06ade6a2011-10-20 11:56:00 +01001090// ALOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
Eric Laurent484e3202011-06-17 20:17:17 -07001091// inBuffer->frameCount, session->enabledMsk, session->processedMsk);
1092
1093 if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
1094 effect->session->processedMsk = 0;
1095 size_t framesRq = outBuffer->frameCount;
1096 size_t framesWr = 0;
1097 if (session->framesOut) {
1098 size_t fr = session->framesOut;
1099 if (outBuffer->frameCount < fr) {
1100 fr = outBuffer->frameCount;
1101 }
1102 memcpy(outBuffer->s16,
1103 session->outBuf,
1104 fr * session->outChannelCount * sizeof(int16_t));
1105 memcpy(session->outBuf,
1106 session->outBuf + fr * session->outChannelCount,
1107 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1108 session->framesOut -= fr;
1109 framesWr += fr;
1110 }
1111 outBuffer->frameCount = framesWr;
1112 if (framesWr == framesRq) {
1113 inBuffer->frameCount = 0;
1114 return 0;
1115 }
1116
1117 if (session->inResampler != NULL) {
1118 size_t fr = session->frameCount - session->framesIn;
1119 if (inBuffer->frameCount < fr) {
1120 fr = inBuffer->frameCount;
1121 }
1122 if (session->inBufSize < session->framesIn + fr) {
1123 session->inBufSize = session->framesIn + fr;
1124 session->inBuf = (int16_t *)realloc(session->inBuf,
1125 session->inBufSize * session->inChannelCount * sizeof(int16_t));
1126 }
1127 memcpy(session->inBuf + session->framesIn * session->inChannelCount,
1128 inBuffer->s16,
1129 fr * session->inChannelCount * sizeof(int16_t));
1130
1131 session->framesIn += fr;
1132 inBuffer->frameCount = fr;
1133 if (session->framesIn < session->frameCount) {
1134 return 0;
1135 }
1136 size_t frIn = session->framesIn;
1137 size_t frOut = session->apmFrameCount;
1138 if (session->inChannelCount == 1) {
1139 speex_resampler_process_int(session->inResampler,
1140 0,
1141 session->inBuf,
1142 &frIn,
1143 session->procFrame->_payloadData,
1144 &frOut);
1145 } else {
1146 speex_resampler_process_interleaved_int(session->inResampler,
1147 session->inBuf,
1148 &frIn,
1149 session->procFrame->_payloadData,
1150 &frOut);
1151 }
1152 memcpy(session->inBuf,
1153 session->inBuf + frIn * session->inChannelCount,
1154 (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
1155 session->framesIn -= frIn;
1156 } else {
1157 size_t fr = session->frameCount - session->framesIn;
1158 if (inBuffer->frameCount < fr) {
1159 fr = inBuffer->frameCount;
1160 }
1161 memcpy(session->procFrame->_payloadData + session->framesIn * session->inChannelCount,
1162 inBuffer->s16,
1163 fr * session->inChannelCount * sizeof(int16_t));
1164 session->framesIn += fr;
1165 inBuffer->frameCount = fr;
1166 if (session->framesIn < session->frameCount) {
1167 return 0;
1168 }
1169 session->framesIn = 0;
1170 }
1171 session->procFrame->_payloadDataLengthInSamples =
1172 session->apmFrameCount * session->inChannelCount;
1173
1174 effect->session->apm->ProcessStream(session->procFrame);
1175
1176 if (session->outBufSize < session->framesOut + session->frameCount) {
1177 session->outBufSize = session->framesOut + session->frameCount;
1178 session->outBuf = (int16_t *)realloc(session->outBuf,
1179 session->outBufSize * session->outChannelCount * sizeof(int16_t));
1180 }
1181
1182 if (session->outResampler != NULL) {
1183 size_t frIn = session->apmFrameCount;
1184 size_t frOut = session->frameCount;
1185 if (session->inChannelCount == 1) {
1186 speex_resampler_process_int(session->outResampler,
1187 0,
1188 session->procFrame->_payloadData,
1189 &frIn,
1190 session->outBuf + session->framesOut * session->outChannelCount,
1191 &frOut);
1192 } else {
1193 speex_resampler_process_interleaved_int(session->outResampler,
1194 session->procFrame->_payloadData,
1195 &frIn,
1196 session->outBuf + session->framesOut * session->outChannelCount,
1197 &frOut);
1198 }
1199 session->framesOut += frOut;
1200 } else {
1201 memcpy(session->outBuf + session->framesOut * session->outChannelCount,
1202 session->procFrame->_payloadData,
1203 session->frameCount * session->outChannelCount * sizeof(int16_t));
1204 session->framesOut += session->frameCount;
1205 }
1206 size_t fr = session->framesOut;
1207 if (framesRq - framesWr < fr) {
1208 fr = framesRq - framesWr;
1209 }
1210 memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
1211 session->outBuf,
1212 fr * session->outChannelCount * sizeof(int16_t));
1213 memcpy(session->outBuf,
1214 session->outBuf + fr * session->outChannelCount,
1215 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1216 session->framesOut -= fr;
1217 outBuffer->frameCount += fr;
1218
1219 return 0;
1220 } else {
1221 return -ENODATA;
1222 }
1223}
1224
1225int PreProcessingFx_Command(effect_handle_t self,
1226 uint32_t cmdCode,
1227 uint32_t cmdSize,
1228 void *pCmdData,
1229 uint32_t *replySize,
1230 void *pReplyData)
1231{
1232 preproc_effect_t * effect = (preproc_effect_t *) self;
1233 int retsize;
1234 int status;
1235
1236 if (effect == NULL){
1237 return -EINVAL;
1238 }
1239
Steve Block06ade6a2011-10-20 11:56:00 +01001240 //ALOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
Eric Laurent484e3202011-06-17 20:17:17 -07001241
1242 switch (cmdCode){
1243 case EFFECT_CMD_INIT:
1244 if (pReplyData == NULL || *replySize != sizeof(int)){
1245 return -EINVAL;
1246 }
1247 if (effect->ops->init) {
1248 effect->ops->init(effect);
1249 }
1250 *(int *)pReplyData = 0;
1251 break;
1252
1253 case EFFECT_CMD_CONFIGURE:
1254 if (pCmdData == NULL||
1255 cmdSize != sizeof(effect_config_t)||
1256 pReplyData == NULL||
1257 *replySize != sizeof(int)){
Steve Block06ade6a2011-10-20 11:56:00 +01001258 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent484e3202011-06-17 20:17:17 -07001259 "EFFECT_CMD_CONFIGURE: ERROR");
1260 return -EINVAL;
1261 }
1262 *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
1263 if (*(int *)pReplyData != 0) {
1264 break;
1265 }
1266 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1267 break;
1268
1269 case EFFECT_CMD_CONFIGURE_REVERSE:
1270 if (pCmdData == NULL||
1271 cmdSize != sizeof(effect_config_t)||
1272 pReplyData == NULL||
1273 *replySize != sizeof(int)){
Steve Block06ade6a2011-10-20 11:56:00 +01001274 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent484e3202011-06-17 20:17:17 -07001275 "EFFECT_CMD_CONFIGURE_REVERSE: ERROR");
1276 return -EINVAL;
1277 }
1278 *(int *)pReplyData = Session_SetReverseConfig(effect->session,
1279 (effect_config_t *)pCmdData);
1280 if (*(int *)pReplyData != 0) {
1281 break;
1282 }
1283 break;
1284
1285 case EFFECT_CMD_RESET:
1286 if (effect->ops->reset) {
1287 effect->ops->reset(effect);
1288 }
1289 break;
1290
1291 case EFFECT_CMD_GET_PARAM:{
1292 if (pCmdData == NULL ||
1293 cmdSize < (int)sizeof(effect_param_t) ||
1294 pReplyData == NULL ||
1295 *replySize < (int)sizeof(effect_param_t)){
Steve Block06ade6a2011-10-20 11:56:00 +01001296 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent484e3202011-06-17 20:17:17 -07001297 "EFFECT_CMD_GET_PARAM: ERROR");
1298 return -EINVAL;
1299 }
1300 effect_param_t *p = (effect_param_t *)pCmdData;
1301
1302 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
1303
1304 p = (effect_param_t *)pReplyData;
1305
1306 int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
1307
1308 if (effect->ops->get_parameter) {
1309 p->status = effect->ops->get_parameter(effect, p->data,
1310 (size_t *)&p->vsize,
1311 p->data + voffset);
1312 *replySize = sizeof(effect_param_t) + voffset + p->vsize;
1313 }
1314 } break;
1315
1316 case EFFECT_CMD_SET_PARAM:{
1317 if (pCmdData == NULL||
1318 cmdSize < (int)sizeof(effect_param_t) ||
1319 pReplyData == NULL ||
1320 *replySize != sizeof(int32_t)){
Steve Block06ade6a2011-10-20 11:56:00 +01001321 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent484e3202011-06-17 20:17:17 -07001322 "EFFECT_CMD_SET_PARAM: ERROR");
1323 return -EINVAL;
1324 }
1325 effect_param_t *p = (effect_param_t *) pCmdData;
1326
1327 if (p->psize != sizeof(int32_t)){
Steve Block06ade6a2011-10-20 11:56:00 +01001328 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent484e3202011-06-17 20:17:17 -07001329 "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
1330 return -EINVAL;
1331 }
1332 if (effect->ops->set_parameter) {
1333 *(int *)pReplyData = effect->ops->set_parameter(effect,
1334 (void *)p->data,
1335 p->data + p->psize);
1336 }
1337 } break;
1338
1339 case EFFECT_CMD_ENABLE:
1340 if (pReplyData == NULL || *replySize != sizeof(int)){
Steve Block06ade6a2011-10-20 11:56:00 +01001341 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
Eric Laurent484e3202011-06-17 20:17:17 -07001342 return -EINVAL;
1343 }
1344 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
1345 break;
1346
1347 case EFFECT_CMD_DISABLE:
1348 if (pReplyData == NULL || *replySize != sizeof(int)){
Steve Block06ade6a2011-10-20 11:56:00 +01001349 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
Eric Laurent484e3202011-06-17 20:17:17 -07001350 return -EINVAL;
1351 }
1352 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1353 break;
1354
1355 case EFFECT_CMD_SET_DEVICE:
1356 case EFFECT_CMD_SET_INPUT_DEVICE:
1357 if (pCmdData == NULL ||
1358 cmdSize != sizeof(uint32_t)) {
Steve Block06ade6a2011-10-20 11:56:00 +01001359 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
Eric Laurent484e3202011-06-17 20:17:17 -07001360 return -EINVAL;
1361 }
1362
1363 if (effect->ops->set_device) {
1364 effect->ops->set_device(effect, *(uint32_t *)pCmdData);
1365 }
1366 break;
1367
1368 case EFFECT_CMD_SET_VOLUME:
1369 case EFFECT_CMD_SET_AUDIO_MODE:
1370 break;
1371
1372 default:
1373 return -EINVAL;
1374 }
1375 return 0;
1376}
1377
1378
1379int PreProcessingFx_GetDescriptor(effect_handle_t self,
1380 effect_descriptor_t *pDescriptor)
1381{
1382 preproc_effect_t * effect = (preproc_effect_t *) self;
1383
1384 if (effect == NULL || pDescriptor == NULL) {
1385 return -EINVAL;
1386 }
1387
1388 memcpy(pDescriptor, sDescriptors[effect->procId], sizeof(effect_descriptor_t));
1389
1390 return 0;
1391}
1392
1393int PreProcessingFx_ProcessReverse(effect_handle_t self,
1394 audio_buffer_t *inBuffer,
1395 audio_buffer_t *outBuffer)
1396{
1397 preproc_effect_t * effect = (preproc_effect_t *)self;
1398 int status = 0;
1399
1400 if (effect == NULL){
Steve Blocka51f0e72012-01-05 23:22:43 +00001401 ALOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
Eric Laurent484e3202011-06-17 20:17:17 -07001402 return -EINVAL;
1403 }
1404 preproc_session_t * session = (preproc_session_t *)effect->session;
1405
1406 if (inBuffer == NULL || inBuffer->raw == NULL){
Steve Blocka51f0e72012-01-05 23:22:43 +00001407 ALOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
Eric Laurent484e3202011-06-17 20:17:17 -07001408 return -EINVAL;
1409 }
1410
1411 session->revProcessedMsk |= (1<<effect->procId);
1412
Steve Block06ade6a2011-10-20 11:56:00 +01001413// ALOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
Eric Laurent484e3202011-06-17 20:17:17 -07001414// inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
1415
1416
1417 if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
1418 effect->session->revProcessedMsk = 0;
1419 if (session->revResampler != NULL) {
1420 size_t fr = session->frameCount - session->framesRev;
1421 if (inBuffer->frameCount < fr) {
1422 fr = inBuffer->frameCount;
1423 }
1424 if (session->revBufSize < session->framesRev + fr) {
1425 session->revBufSize = session->framesRev + fr;
1426 session->revBuf = (int16_t *)realloc(session->revBuf,
1427 session->revBufSize * session->inChannelCount * sizeof(int16_t));
1428 }
1429 memcpy(session->revBuf + session->framesRev * session->inChannelCount,
1430 inBuffer->s16,
1431 fr * session->inChannelCount * sizeof(int16_t));
1432
1433 session->framesRev += fr;
1434 inBuffer->frameCount = fr;
1435 if (session->framesRev < session->frameCount) {
1436 return 0;
1437 }
1438 size_t frIn = session->framesRev;
1439 size_t frOut = session->apmFrameCount;
1440 if (session->inChannelCount == 1) {
1441 speex_resampler_process_int(session->revResampler,
1442 0,
1443 session->revBuf,
1444 &frIn,
1445 session->revFrame->_payloadData,
1446 &frOut);
1447 } else {
1448 speex_resampler_process_interleaved_int(session->revResampler,
1449 session->revBuf,
1450 &frIn,
1451 session->revFrame->_payloadData,
1452 &frOut);
1453 }
1454 memcpy(session->revBuf,
1455 session->revBuf + frIn * session->inChannelCount,
1456 (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
1457 session->framesRev -= frIn;
1458 } else {
1459 size_t fr = session->frameCount - session->framesRev;
1460 if (inBuffer->frameCount < fr) {
1461 fr = inBuffer->frameCount;
1462 }
1463 memcpy(session->revFrame->_payloadData + session->framesRev * session->inChannelCount,
1464 inBuffer->s16,
1465 fr * session->inChannelCount * sizeof(int16_t));
1466 session->framesRev += fr;
1467 inBuffer->frameCount = fr;
1468 if (session->framesRev < session->frameCount) {
1469 return 0;
1470 }
1471 session->framesRev = 0;
1472 }
1473 session->revFrame->_payloadDataLengthInSamples =
1474 session->apmFrameCount * session->inChannelCount;
1475 effect->session->apm->AnalyzeReverseStream(session->revFrame);
1476 return 0;
1477 } else {
1478 return -ENODATA;
1479 }
1480}
1481
1482
1483// effect_handle_t interface implementation for effect
1484const struct effect_interface_s sEffectInterface = {
1485 PreProcessingFx_Process,
1486 PreProcessingFx_Command,
1487 PreProcessingFx_GetDescriptor,
1488 NULL
1489};
1490
1491const struct effect_interface_s sEffectInterfaceReverse = {
1492 PreProcessingFx_Process,
1493 PreProcessingFx_Command,
1494 PreProcessingFx_GetDescriptor,
1495 PreProcessingFx_ProcessReverse
1496};
1497
1498//------------------------------------------------------------------------------
1499// Effect Library Interface Implementation
1500//------------------------------------------------------------------------------
1501
1502int PreProcessingLib_QueryNumberEffects(uint32_t *pNumEffects)
1503{
1504 if (PreProc_Init() != 0) {
1505 return sInitStatus;
1506 }
1507 if (pNumEffects == NULL) {
1508 return -EINVAL;
1509 }
1510 *pNumEffects = PREPROC_NUM_EFFECTS;
1511 return sInitStatus;
1512}
1513
1514int PreProcessingLib_QueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
1515{
1516 if (PreProc_Init() != 0) {
1517 return sInitStatus;
1518 }
1519 if (index >= PREPROC_NUM_EFFECTS) {
1520 return -EINVAL;
1521 }
1522 memcpy(pDescriptor, sDescriptors[index], sizeof(effect_descriptor_t));
1523 return 0;
1524}
1525
1526int PreProcessingLib_Create(effect_uuid_t *uuid,
1527 int32_t sessionId,
1528 int32_t ioId,
1529 effect_handle_t *pInterface)
1530{
Steve Block06ade6a2011-10-20 11:56:00 +01001531 ALOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
Eric Laurent484e3202011-06-17 20:17:17 -07001532
1533 int status;
1534 const effect_descriptor_t *desc;
1535 preproc_session_t *session;
1536 uint32_t procId;
1537
1538 if (PreProc_Init() != 0) {
1539 return sInitStatus;
1540 }
1541 desc = PreProc_GetDescriptor(uuid);
1542 if (desc == NULL) {
Steve Blocka51f0e72012-01-05 23:22:43 +00001543 ALOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
Eric Laurent484e3202011-06-17 20:17:17 -07001544 return -EINVAL;
1545 }
1546 procId = UuidToProcId(&desc->type);
1547
1548 session = PreProc_GetSession(procId, sessionId, ioId);
1549 if (session == NULL) {
Steve Blocka51f0e72012-01-05 23:22:43 +00001550 ALOGW("EffectCreate: no more session available");
Eric Laurent484e3202011-06-17 20:17:17 -07001551 return -EINVAL;
1552 }
1553
1554 status = Session_CreateEffect(session, procId, pInterface);
1555
1556 if (status < 0 && session->createdMsk == 0) {
1557 session->io = 0;
1558 }
1559 return status;
1560}
1561
1562int PreProcessingLib_Release(effect_handle_t interface)
1563{
1564 int status;
Steve Block06ade6a2011-10-20 11:56:00 +01001565 ALOGV("EffectRelease start %p", interface);
Eric Laurent484e3202011-06-17 20:17:17 -07001566 if (PreProc_Init() != 0) {
1567 return sInitStatus;
1568 }
1569
1570 preproc_effect_t *fx = (preproc_effect_t *)interface;
1571
1572 if (fx->session->io == 0) {
1573 return -EINVAL;
1574 }
1575 return Session_ReleaseEffect(fx->session, fx);
1576}
1577
1578int PreProcessingLib_GetDescriptor(effect_uuid_t *uuid,
1579 effect_descriptor_t *pDescriptor) {
1580
1581 if (pDescriptor == NULL || uuid == NULL){
1582 return -EINVAL;
1583 }
1584
1585 const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
1586 if (desc == NULL) {
Steve Block06ade6a2011-10-20 11:56:00 +01001587 ALOGV("PreProcessingLib_GetDescriptor() not found");
Eric Laurent484e3202011-06-17 20:17:17 -07001588 return -EINVAL;
1589 }
1590
Steve Block06ade6a2011-10-20 11:56:00 +01001591 ALOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
Eric Laurent484e3202011-06-17 20:17:17 -07001592
1593 memcpy(pDescriptor, desc, sizeof(effect_descriptor_t));
1594 return 0;
1595}
1596
1597audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
1598 tag : AUDIO_EFFECT_LIBRARY_TAG,
1599 version : EFFECT_LIBRARY_API_VERSION,
1600 name : "Audio Preprocessing Library",
1601 implementor : "The Android Open Source Project",
1602 query_num_effects : PreProcessingLib_QueryNumberEffects,
1603 query_effect : PreProcessingLib_QueryEffect,
1604 create_effect : PreProcessingLib_Create,
1605 release_effect : PreProcessingLib_Release,
1606 get_descriptor : PreProcessingLib_GetDescriptor
1607};
1608
1609}; // extern "C"