blob: 5709837441b28585b8b1c6cc717f886f2f2c88d2 [file] [log] [blame]
Eric Laurenta9390d42011-06-17 20:17:17 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19#define LOG_TAG "PreProcessing"
20//#define LOG_NDEBUG 0
21#include <utils/Log.h>
22#include <utils/Timers.h>
23#include <hardware/audio_effect.h>
24#include <audio_effects/effect_aec.h>
25#include <audio_effects/effect_agc.h>
26#include <audio_effects/effect_ns.h>
Eric Laurent53876962012-01-31 12:35:20 -080027#include <module_common_types.h>
28#include <audio_processing.h>
Eric Laurenta9390d42011-06-17 20:17:17 -070029#include "speex/speex_resampler.h"
30
Eric Laurent3f9c84c2012-04-03 15:36:53 -070031// undefine to perform multi channels API functional tests
32//#define DUAL_MIC_TEST
Eric Laurenta9390d42011-06-17 20:17:17 -070033
34//------------------------------------------------------------------------------
35// local definitions
36//------------------------------------------------------------------------------
37
38// maximum number of sessions
39#define PREPROC_NUM_SESSIONS 8
40
41// types of pre processing modules
42enum preproc_id
43{
44 PREPROC_AGC, // Automatic Gain Control
45 PREPROC_AEC, // Acoustic Echo Canceler
46 PREPROC_NS, // Noise Suppressor
47 PREPROC_NUM_EFFECTS
48};
49
50// Session state
51enum preproc_session_state {
52 PREPROC_SESSION_STATE_INIT, // initialized
53 PREPROC_SESSION_STATE_CONFIG // configuration received
54};
55
56// Effect/Preprocessor state
57enum preproc_effect_state {
58 PREPROC_EFFECT_STATE_INIT, // initialized
59 PREPROC_EFFECT_STATE_CREATED, // webRTC engine created
60 PREPROC_EFFECT_STATE_CONFIG, // configuration received/disabled
61 PREPROC_EFFECT_STATE_ACTIVE // active/enabled
62};
63
64// handle on webRTC engine
65typedef void* preproc_fx_handle_t;
66
67typedef struct preproc_session_s preproc_session_t;
68typedef struct preproc_effect_s preproc_effect_t;
69typedef struct preproc_ops_s preproc_ops_t;
70
71// Effect operation table. Functions for all pre processors are declared in sPreProcOps[] table.
72// Function pointer can be null if no action required.
73struct preproc_ops_s {
74 int (* create)(preproc_effect_t *fx);
75 int (* init)(preproc_effect_t *fx);
76 int (* reset)(preproc_effect_t *fx);
77 void (* enable)(preproc_effect_t *fx);
78 void (* disable)(preproc_effect_t *fx);
79 int (* set_parameter)(preproc_effect_t *fx, void *param, void *value);
80 int (* get_parameter)(preproc_effect_t *fx, void *param, size_t *size, void *value);
81 int (* set_device)(preproc_effect_t *fx, uint32_t device);
82};
83
84// Effect context
85struct preproc_effect_s {
86 const struct effect_interface_s *itfe;
87 uint32_t procId; // type of pre processor (enum preproc_id)
88 uint32_t state; // current state (enum preproc_effect_state)
89 preproc_session_t *session; // session the effect is on
90 const preproc_ops_t *ops; // effect ops table
91 preproc_fx_handle_t engine; // handle on webRTC engine
Eric Laurent3f9c84c2012-04-03 15:36:53 -070092#ifdef DUAL_MIC_TEST
93 bool aux_channels_on; // support auxiliary channels
94 size_t cur_channel_config; // current auciliary channel configuration
95#endif
Eric Laurenta9390d42011-06-17 20:17:17 -070096};
97
98// Session context
99struct preproc_session_s {
100 struct preproc_effect_s effects[PREPROC_NUM_EFFECTS]; // effects in this session
101 uint32_t state; // current state (enum preproc_session_state)
102 int id; // audio session ID
103 int io; // handle of input stream this session is on
104 webrtc::AudioProcessing* apm; // handle on webRTC audio processing module (APM)
105 size_t apmFrameCount; // buffer size for webRTC process (10 ms)
106 uint32_t apmSamplingRate; // webRTC APM sampling rate (8/16 or 32 kHz)
107 size_t frameCount; // buffer size before input resampler ( <=> apmFrameCount)
108 uint32_t samplingRate; // sampling rate at effect process interface
109 uint32_t inChannelCount; // input channel count
110 uint32_t outChannelCount; // output channel count
111 uint32_t createdMsk; // bit field containing IDs of crested pre processors
112 uint32_t enabledMsk; // bit field containing IDs of enabled pre processors
113 uint32_t processedMsk; // bit field containing IDs of pre processors already
114 // processed in current round
115 webrtc::AudioFrame *procFrame; // audio frame passed to webRTC AMP ProcessStream()
116 int16_t *inBuf; // input buffer used when resampling
117 size_t inBufSize; // input buffer size in frames
118 size_t framesIn; // number of frames in input buffer
119 SpeexResamplerState *inResampler; // handle on input speex resampler
120 int16_t *outBuf; // output buffer used when resampling
121 size_t outBufSize; // output buffer size in frames
122 size_t framesOut; // number of frames in output buffer
123 SpeexResamplerState *outResampler; // handle on output speex resampler
124 uint32_t revChannelCount; // number of channels on reverse stream
125 uint32_t revEnabledMsk; // bit field containing IDs of enabled pre processors
126 // with reverse channel
127 uint32_t revProcessedMsk; // bit field containing IDs of pre processors with reverse
128 // channel already processed in current round
129 webrtc::AudioFrame *revFrame; // audio frame passed to webRTC AMP AnalyzeReverseStream()
130 int16_t *revBuf; // reverse channel input buffer
131 size_t revBufSize; // reverse channel input buffer size
132 size_t framesRev; // number of frames in reverse channel input buffer
133 SpeexResamplerState *revResampler; // handle on reverse channel input speex resampler
134};
135
Eric Laurent3f9c84c2012-04-03 15:36:53 -0700136#ifdef DUAL_MIC_TEST
137enum {
138 PREPROC_CMD_DUAL_MIC_ENABLE = EFFECT_CMD_FIRST_PROPRIETARY, // enable dual mic mode
139 PREPROC_CMD_DUAL_MIC_PCM_DUMP_START, // start pcm capture
140 PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP // stop pcm capture
141};
142
143enum {
144 CHANNEL_CFG_MONO,
145 CHANNEL_CFG_STEREO,
146 CHANNEL_CFG_MONO_AUX,
147 CHANNEL_CFG_STEREO_AUX,
148 CHANNEL_CFG_CNT,
149 CHANNEL_CFG_FIRST_AUX = CHANNEL_CFG_MONO_AUX,
150};
151
152const channel_config_t sDualMicConfigs[CHANNEL_CFG_CNT] = {
153 {AUDIO_CHANNEL_IN_MONO , 0},
154 {AUDIO_CHANNEL_IN_STEREO , 0},
155 {AUDIO_CHANNEL_IN_FRONT , AUDIO_CHANNEL_IN_BACK},
156 {AUDIO_CHANNEL_IN_STEREO , AUDIO_CHANNEL_IN_RIGHT}
157};
158
159bool sHasAuxChannels[PREPROC_NUM_EFFECTS] = {
160 false, // PREPROC_AGC
161 true, // PREPROC_AEC
162 true, // PREPROC_NS
163};
164
165bool gDualMicEnabled;
166FILE *gPcmDumpFh;
167static pthread_mutex_t gPcmDumpLock = PTHREAD_MUTEX_INITIALIZER;
168#endif
169
170
Eric Laurenta9390d42011-06-17 20:17:17 -0700171//------------------------------------------------------------------------------
172// Effect descriptors
173//------------------------------------------------------------------------------
174
175// UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html
176// as the pre processing effects are not defined by OpenSL ES
177
178// Automatic Gain Control
179static const effect_descriptor_t sAgcDescriptor = {
180 { 0x0a8abfe0, 0x654c, 0x11e0, 0xba26, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
181 { 0xaa8130e0, 0x66fc, 0x11e0, 0xbad0, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
182 EFFECT_CONTROL_API_VERSION,
183 (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
184 0, //FIXME indicate CPU load
185 0, //FIXME indicate memory usage
186 "Automatic Gain Control",
187 "The Android Open Source Project"
188};
189
190// Acoustic Echo Cancellation
191static const effect_descriptor_t sAecDescriptor = {
192 { 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
193 { 0xbb392ec0, 0x8d4d, 0x11e0, 0xa896, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
194 EFFECT_CONTROL_API_VERSION,
195 (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
196 0, //FIXME indicate CPU load
197 0, //FIXME indicate memory usage
198 "Acoustic Echo Canceler",
199 "The Android Open Source Project"
200};
201
202// Noise suppression
203static const effect_descriptor_t sNsDescriptor = {
204 { 0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
205 { 0xc06c8400, 0x8e06, 0x11e0, 0x9cb6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // uuid
206 EFFECT_CONTROL_API_VERSION,
207 (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
208 0, //FIXME indicate CPU load
209 0, //FIXME indicate memory usage
210 "Noise Suppression",
211 "The Android Open Source Project"
212};
213
214
215static const effect_descriptor_t *sDescriptors[PREPROC_NUM_EFFECTS] = {
216 &sAgcDescriptor,
217 &sAecDescriptor,
218 &sNsDescriptor
219};
220
221//------------------------------------------------------------------------------
222// Helper functions
223//------------------------------------------------------------------------------
224
225const effect_uuid_t * const sUuidToPreProcTable[PREPROC_NUM_EFFECTS] = {
226 FX_IID_AGC,
227 FX_IID_AEC,
228 FX_IID_NS
229};
230
231
232const effect_uuid_t * ProcIdToUuid(int procId)
233{
234 if (procId >= PREPROC_NUM_EFFECTS) {
235 return EFFECT_UUID_NULL;
236 }
237 return sUuidToPreProcTable[procId];
238}
239
240uint32_t UuidToProcId(const effect_uuid_t * uuid)
241{
242 size_t i;
243 for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
244 if (memcmp(uuid, sUuidToPreProcTable[i], sizeof(*uuid)) == 0) {
245 break;
246 }
247 }
248 return i;
249}
250
251bool HasReverseStream(uint32_t procId)
252{
253 if (procId == PREPROC_AEC) {
254 return true;
255 }
256 return false;
257}
258
259
260//------------------------------------------------------------------------------
261// Automatic Gain Control (AGC)
262//------------------------------------------------------------------------------
263
Eric Laurent53876962012-01-31 12:35:20 -0800264static const int kAgcDefaultTargetLevel = 3;
265static const int kAgcDefaultCompGain = 9;
Eric Laurenta9390d42011-06-17 20:17:17 -0700266static const bool kAgcDefaultLimiter = true;
267
268int AgcInit (preproc_effect_t *effect)
269{
Steve Block3856b092011-10-20 11:56:00 +0100270 ALOGV("AgcInit");
Eric Laurenta9390d42011-06-17 20:17:17 -0700271 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
272 agc->set_mode(webrtc::GainControl::kFixedDigital);
273 agc->set_target_level_dbfs(kAgcDefaultTargetLevel);
274 agc->set_compression_gain_db(kAgcDefaultCompGain);
275 agc->enable_limiter(kAgcDefaultLimiter);
276 return 0;
277}
278
279int AgcCreate(preproc_effect_t *effect)
280{
281 webrtc::GainControl *agc = effect->session->apm->gain_control();
Steve Block3856b092011-10-20 11:56:00 +0100282 ALOGV("AgcCreate got agc %p", agc);
Eric Laurenta9390d42011-06-17 20:17:17 -0700283 if (agc == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000284 ALOGW("AgcCreate Error");
Eric Laurenta9390d42011-06-17 20:17:17 -0700285 return -ENOMEM;
286 }
287 effect->engine = static_cast<preproc_fx_handle_t>(agc);
288 AgcInit(effect);
289 return 0;
290}
291
292int AgcGetParameter(preproc_effect_t *effect,
293 void *pParam,
294 size_t *pValueSize,
295 void *pValue)
296{
297 int status = 0;
298 uint32_t param = *(uint32_t *)pParam;
299 t_agc_settings *pProperties = (t_agc_settings *)pValue;
300 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
301
302 switch (param) {
303 case AGC_PARAM_TARGET_LEVEL:
304 case AGC_PARAM_COMP_GAIN:
305 if (*pValueSize < sizeof(int16_t)) {
306 *pValueSize = 0;
307 return -EINVAL;
308 }
309 break;
310 case AGC_PARAM_LIMITER_ENA:
311 if (*pValueSize < sizeof(bool)) {
312 *pValueSize = 0;
313 return -EINVAL;
314 }
315 break;
316 case AGC_PARAM_PROPERTIES:
317 if (*pValueSize < sizeof(t_agc_settings)) {
318 *pValueSize = 0;
319 return -EINVAL;
320 }
321 break;
322
323 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000324 ALOGW("AgcGetParameter() unknown param %08x", param);
Eric Laurenta9390d42011-06-17 20:17:17 -0700325 status = -EINVAL;
326 break;
327 }
328
329 switch (param) {
330 case AGC_PARAM_TARGET_LEVEL:
331 *(int16_t *) pValue = (int16_t)(agc->target_level_dbfs() * -100);
Steve Block3856b092011-10-20 11:56:00 +0100332 ALOGV("AgcGetParameter() target level %d milliBels", *(int16_t *) pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700333 break;
334 case AGC_PARAM_COMP_GAIN:
335 *(int16_t *) pValue = (int16_t)(agc->compression_gain_db() * 100);
Steve Block3856b092011-10-20 11:56:00 +0100336 ALOGV("AgcGetParameter() comp gain %d milliBels", *(int16_t *) pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700337 break;
338 case AGC_PARAM_LIMITER_ENA:
339 *(bool *) pValue = (bool)agc->is_limiter_enabled();
Steve Block3856b092011-10-20 11:56:00 +0100340 ALOGV("AgcGetParameter() limiter enabled %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700341 (*(int16_t *) pValue != 0) ? "true" : "false");
342 break;
343 case AGC_PARAM_PROPERTIES:
344 pProperties->targetLevel = (int16_t)(agc->target_level_dbfs() * -100);
345 pProperties->compGain = (int16_t)(agc->compression_gain_db() * 100);
346 pProperties->limiterEnabled = (bool)agc->is_limiter_enabled();
347 break;
348 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000349 ALOGW("AgcGetParameter() unknown param %d", param);
Eric Laurenta9390d42011-06-17 20:17:17 -0700350 status = -EINVAL;
351 break;
352 }
353 return status;
354}
355
356int AgcSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
357{
358 int status = 0;
359 uint32_t param = *(uint32_t *)pParam;
360 t_agc_settings *pProperties = (t_agc_settings *)pValue;
361 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
362
363 switch (param) {
364 case AGC_PARAM_TARGET_LEVEL:
Steve Block3856b092011-10-20 11:56:00 +0100365 ALOGV("AgcSetParameter() target level %d milliBels", *(int16_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700366 status = agc->set_target_level_dbfs(-(*(int16_t *)pValue / 100));
367 break;
368 case AGC_PARAM_COMP_GAIN:
Steve Block3856b092011-10-20 11:56:00 +0100369 ALOGV("AgcSetParameter() comp gain %d milliBels", *(int16_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700370 status = agc->set_compression_gain_db(*(int16_t *)pValue / 100);
371 break;
372 case AGC_PARAM_LIMITER_ENA:
Steve Block3856b092011-10-20 11:56:00 +0100373 ALOGV("AgcSetParameter() limiter enabled %s", *(bool *)pValue ? "true" : "false");
Eric Laurenta9390d42011-06-17 20:17:17 -0700374 status = agc->enable_limiter(*(bool *)pValue);
375 break;
376 case AGC_PARAM_PROPERTIES:
Steve Block3856b092011-10-20 11:56:00 +0100377 ALOGV("AgcSetParameter() properties level %d, gain %d limiter %d",
Eric Laurenta9390d42011-06-17 20:17:17 -0700378 pProperties->targetLevel,
379 pProperties->compGain,
380 pProperties->limiterEnabled);
381 status = agc->set_target_level_dbfs(-(pProperties->targetLevel / 100));
382 if (status != 0) break;
383 status = agc->set_compression_gain_db(pProperties->compGain / 100);
384 if (status != 0) break;
385 status = agc->enable_limiter(pProperties->limiterEnabled);
386 break;
387 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000388 ALOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700389 status = -EINVAL;
390 break;
391 }
392
Steve Block3856b092011-10-20 11:56:00 +0100393 ALOGV("AgcSetParameter() done status %d", status);
Eric Laurenta9390d42011-06-17 20:17:17 -0700394
395 return status;
396}
397
398void AgcEnable(preproc_effect_t *effect)
399{
400 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
Steve Block3856b092011-10-20 11:56:00 +0100401 ALOGV("AgcEnable agc %p", agc);
Eric Laurenta9390d42011-06-17 20:17:17 -0700402 agc->Enable(true);
403}
404
405void AgcDisable(preproc_effect_t *effect)
406{
Steve Block3856b092011-10-20 11:56:00 +0100407 ALOGV("AgcDisable");
Eric Laurenta9390d42011-06-17 20:17:17 -0700408 webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
409 agc->Enable(false);
410}
411
412
413static const preproc_ops_t sAgcOps = {
414 AgcCreate,
415 AgcInit,
416 NULL,
417 AgcEnable,
418 AgcDisable,
419 AgcSetParameter,
420 AgcGetParameter,
421 NULL
422};
423
424
425//------------------------------------------------------------------------------
426// Acoustic Echo Canceler (AEC)
427//------------------------------------------------------------------------------
428
429static const webrtc::EchoControlMobile::RoutingMode kAecDefaultMode =
430 webrtc::EchoControlMobile::kEarpiece;
431static const bool kAecDefaultComfortNoise = true;
432
433int AecInit (preproc_effect_t *effect)
434{
Steve Block3856b092011-10-20 11:56:00 +0100435 ALOGV("AecInit");
Eric Laurenta9390d42011-06-17 20:17:17 -0700436 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
437 aec->set_routing_mode(kAecDefaultMode);
438 aec->enable_comfort_noise(kAecDefaultComfortNoise);
439 return 0;
440}
441
442int AecCreate(preproc_effect_t *effect)
443{
444 webrtc::EchoControlMobile *aec = effect->session->apm->echo_control_mobile();
Steve Block3856b092011-10-20 11:56:00 +0100445 ALOGV("AecCreate got aec %p", aec);
Eric Laurenta9390d42011-06-17 20:17:17 -0700446 if (aec == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000447 ALOGW("AgcCreate Error");
Eric Laurenta9390d42011-06-17 20:17:17 -0700448 return -ENOMEM;
449 }
450 effect->engine = static_cast<preproc_fx_handle_t>(aec);
451 AecInit (effect);
452 return 0;
453}
454
455int AecGetParameter(preproc_effect_t *effect,
456 void *pParam,
457 size_t *pValueSize,
458 void *pValue)
459{
460 int status = 0;
461 uint32_t param = *(uint32_t *)pParam;
462
463 if (*pValueSize < sizeof(uint32_t)) {
464 return -EINVAL;
465 }
466 switch (param) {
467 case AEC_PARAM_ECHO_DELAY:
468 case AEC_PARAM_PROPERTIES:
469 *(uint32_t *)pValue = 1000 * effect->session->apm->stream_delay_ms();
Steve Block3856b092011-10-20 11:56:00 +0100470 ALOGV("AecGetParameter() echo delay %d us", *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700471 break;
472 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000473 ALOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700474 status = -EINVAL;
475 break;
476 }
477 return status;
478}
479
480int AecSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
481{
482 int status = 0;
483 uint32_t param = *(uint32_t *)pParam;
484 uint32_t value = *(uint32_t *)pValue;
485
486 switch (param) {
487 case AEC_PARAM_ECHO_DELAY:
488 case AEC_PARAM_PROPERTIES:
489 status = effect->session->apm->set_stream_delay_ms(value/1000);
Steve Block3856b092011-10-20 11:56:00 +0100490 ALOGV("AecSetParameter() echo delay %d us, status %d", value, status);
Eric Laurenta9390d42011-06-17 20:17:17 -0700491 break;
492 default:
Steve Block5ff1dd52012-01-05 23:22:43 +0000493 ALOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
Eric Laurenta9390d42011-06-17 20:17:17 -0700494 status = -EINVAL;
495 break;
496 }
497 return status;
498}
499
500void AecEnable(preproc_effect_t *effect)
501{
502 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
Steve Block3856b092011-10-20 11:56:00 +0100503 ALOGV("AecEnable aec %p", aec);
Eric Laurenta9390d42011-06-17 20:17:17 -0700504 aec->Enable(true);
505}
506
507void AecDisable(preproc_effect_t *effect)
508{
Steve Block3856b092011-10-20 11:56:00 +0100509 ALOGV("AecDisable");
Eric Laurenta9390d42011-06-17 20:17:17 -0700510 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
511 aec->Enable(false);
512}
513
514int AecSetDevice(preproc_effect_t *effect, uint32_t device)
515{
Steve Block3856b092011-10-20 11:56:00 +0100516 ALOGV("AecSetDevice %08x", device);
Eric Laurenta9390d42011-06-17 20:17:17 -0700517 webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
518 webrtc::EchoControlMobile::RoutingMode mode = webrtc::EchoControlMobile::kQuietEarpieceOrHeadset;
519
520 switch(device) {
521 case AUDIO_DEVICE_OUT_EARPIECE:
522 mode = webrtc::EchoControlMobile::kEarpiece;
523 break;
524 case AUDIO_DEVICE_OUT_SPEAKER:
525 mode = webrtc::EchoControlMobile::kSpeakerphone;
526 break;
527 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
528 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
529 default:
530 break;
531 }
532 aec->set_routing_mode(mode);
533 return 0;
534}
535
536static const preproc_ops_t sAecOps = {
537 AecCreate,
538 AecInit,
539 NULL,
540 AecEnable,
541 AecDisable,
542 AecSetParameter,
543 AecGetParameter,
544 AecSetDevice
545};
546
547//------------------------------------------------------------------------------
548// Noise Suppression (NS)
549//------------------------------------------------------------------------------
550
551static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
552
553int NsInit (preproc_effect_t *effect)
554{
Steve Block3856b092011-10-20 11:56:00 +0100555 ALOGV("NsInit");
Eric Laurenta9390d42011-06-17 20:17:17 -0700556 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
557 ns->set_level(kNsDefaultLevel);
558 return 0;
559}
560
561int NsCreate(preproc_effect_t *effect)
562{
563 webrtc::NoiseSuppression *ns = effect->session->apm->noise_suppression();
Steve Block3856b092011-10-20 11:56:00 +0100564 ALOGV("NsCreate got ns %p", ns);
Eric Laurenta9390d42011-06-17 20:17:17 -0700565 if (ns == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000566 ALOGW("AgcCreate Error");
Eric Laurenta9390d42011-06-17 20:17:17 -0700567 return -ENOMEM;
568 }
569 effect->engine = static_cast<preproc_fx_handle_t>(ns);
570 NsInit (effect);
571 return 0;
572}
573
574int NsGetParameter(preproc_effect_t *effect,
575 void *pParam,
576 size_t *pValueSize,
577 void *pValue)
578{
579 int status = 0;
580 return status;
581}
582
583int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
584{
585 int status = 0;
586 return status;
587}
588
589void NsEnable(preproc_effect_t *effect)
590{
591 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
Steve Block3856b092011-10-20 11:56:00 +0100592 ALOGV("NsEnable ns %p", ns);
Eric Laurenta9390d42011-06-17 20:17:17 -0700593 ns->Enable(true);
594}
595
596void NsDisable(preproc_effect_t *effect)
597{
Steve Block3856b092011-10-20 11:56:00 +0100598 ALOGV("NsDisable");
Eric Laurenta9390d42011-06-17 20:17:17 -0700599 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
600 ns->Enable(false);
601}
602
603static const preproc_ops_t sNsOps = {
604 NsCreate,
605 NsInit,
606 NULL,
607 NsEnable,
608 NsDisable,
609 NsSetParameter,
610 NsGetParameter,
611 NULL
612};
613
614
615static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
616 &sAgcOps,
617 &sAecOps,
618 &sNsOps
619};
620
621
622//------------------------------------------------------------------------------
623// Effect functions
624//------------------------------------------------------------------------------
625
626void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled);
627
628extern "C" const struct effect_interface_s sEffectInterface;
629extern "C" const struct effect_interface_s sEffectInterfaceReverse;
630
631#define BAD_STATE_ABORT(from, to) \
632 LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to);
633
634int Effect_SetState(preproc_effect_t *effect, uint32_t state)
635{
636 int status = 0;
Steve Block3856b092011-10-20 11:56:00 +0100637 ALOGV("Effect_SetState proc %d, new %d old %d", effect->procId, state, effect->state);
Eric Laurenta9390d42011-06-17 20:17:17 -0700638 switch(state) {
639 case PREPROC_EFFECT_STATE_INIT:
640 switch(effect->state) {
641 case PREPROC_EFFECT_STATE_ACTIVE:
642 effect->ops->disable(effect);
643 Session_SetProcEnabled(effect->session, effect->procId, false);
644 case PREPROC_EFFECT_STATE_CONFIG:
645 case PREPROC_EFFECT_STATE_CREATED:
646 case PREPROC_EFFECT_STATE_INIT:
647 break;
648 default:
649 BAD_STATE_ABORT(effect->state, state);
650 }
651 break;
652 case PREPROC_EFFECT_STATE_CREATED:
653 switch(effect->state) {
654 case PREPROC_EFFECT_STATE_INIT:
655 status = effect->ops->create(effect);
656 break;
657 case PREPROC_EFFECT_STATE_CREATED:
658 case PREPROC_EFFECT_STATE_ACTIVE:
659 case PREPROC_EFFECT_STATE_CONFIG:
Steve Block29357bc2012-01-06 19:20:56 +0000660 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700661 status = -ENOSYS;
662 break;
663 default:
664 BAD_STATE_ABORT(effect->state, state);
665 }
666 break;
667 case PREPROC_EFFECT_STATE_CONFIG:
668 switch(effect->state) {
669 case PREPROC_EFFECT_STATE_INIT:
Steve Block29357bc2012-01-06 19:20:56 +0000670 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700671 status = -ENOSYS;
672 break;
673 case PREPROC_EFFECT_STATE_ACTIVE:
674 effect->ops->disable(effect);
675 Session_SetProcEnabled(effect->session, effect->procId, false);
676 break;
677 case PREPROC_EFFECT_STATE_CREATED:
678 case PREPROC_EFFECT_STATE_CONFIG:
679 break;
680 default:
681 BAD_STATE_ABORT(effect->state, state);
682 }
683 break;
684 case PREPROC_EFFECT_STATE_ACTIVE:
685 switch(effect->state) {
686 case PREPROC_EFFECT_STATE_INIT:
687 case PREPROC_EFFECT_STATE_CREATED:
Steve Block29357bc2012-01-06 19:20:56 +0000688 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700689 status = -ENOSYS;
690 break;
Eric Laurent3f9c84c2012-04-03 15:36:53 -0700691 case PREPROC_EFFECT_STATE_ACTIVE:
692 // enabling an already enabled effect is just ignored
693 break;
Eric Laurenta9390d42011-06-17 20:17:17 -0700694 case PREPROC_EFFECT_STATE_CONFIG:
695 effect->ops->enable(effect);
696 Session_SetProcEnabled(effect->session, effect->procId, true);
697 break;
698 default:
699 BAD_STATE_ABORT(effect->state, state);
700 }
701 break;
702 default:
703 BAD_STATE_ABORT(effect->state, state);
704 }
705 if (status == 0) {
706 effect->state = state;
707 }
708 return status;
709}
710
711int Effect_Init(preproc_effect_t *effect, uint32_t procId)
712{
713 if (HasReverseStream(procId)) {
714 effect->itfe = &sEffectInterfaceReverse;
715 } else {
716 effect->itfe = &sEffectInterface;
717 }
718 effect->ops = sPreProcOps[procId];
719 effect->procId = procId;
720 effect->state = PREPROC_EFFECT_STATE_INIT;
721 return 0;
722}
723
724int Effect_Create(preproc_effect_t *effect,
725 preproc_session_t *session,
726 effect_handle_t *interface)
727{
728 effect->session = session;
729 *interface = (effect_handle_t)&effect->itfe;
730 return Effect_SetState(effect, PREPROC_EFFECT_STATE_CREATED);
731}
732
733int Effect_Release(preproc_effect_t *effect)
734{
735 return Effect_SetState(effect, PREPROC_EFFECT_STATE_INIT);
736}
737
738
739//------------------------------------------------------------------------------
740// Session functions
741//------------------------------------------------------------------------------
742
743#define RESAMPLER_QUALITY SPEEX_RESAMPLER_QUALITY_VOIP
744
745static const int kPreprocDefaultSr = 16000;
746static const int kPreProcDefaultCnl = 1;
747
748int Session_Init(preproc_session_t *session)
749{
750 size_t i;
751 int status = 0;
752
753 session->state = PREPROC_SESSION_STATE_INIT;
754 session->id = 0;
755 session->io = 0;
756 session->createdMsk = 0;
757 session->apm = NULL;
758 for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
759 status = Effect_Init(&session->effects[i], i);
760 }
761 return status;
762}
763
764
765extern "C" int Session_CreateEffect(preproc_session_t *session,
766 int32_t procId,
767 effect_handle_t *interface)
768{
769 int status = -ENOMEM;
770
Steve Block3856b092011-10-20 11:56:00 +0100771 ALOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
Eric Laurenta9390d42011-06-17 20:17:17 -0700772
773 if (session->createdMsk == 0) {
774 session->apm = webrtc::AudioProcessing::Create(session->io);
775 if (session->apm == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000776 ALOGW("Session_CreateEffect could not get apm engine");
Eric Laurenta9390d42011-06-17 20:17:17 -0700777 goto error;
778 }
779 session->apm->set_sample_rate_hz(kPreprocDefaultSr);
780 session->apm->set_num_channels(kPreProcDefaultCnl, kPreProcDefaultCnl);
781 session->apm->set_num_reverse_channels(kPreProcDefaultCnl);
782 session->procFrame = new webrtc::AudioFrame();
783 if (session->procFrame == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000784 ALOGW("Session_CreateEffect could not allocate audio frame");
Eric Laurenta9390d42011-06-17 20:17:17 -0700785 goto error;
786 }
787 session->revFrame = new webrtc::AudioFrame();
788 if (session->revFrame == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000789 ALOGW("Session_CreateEffect could not allocate reverse audio frame");
Eric Laurenta9390d42011-06-17 20:17:17 -0700790 goto error;
791 }
792 session->apmSamplingRate = kPreprocDefaultSr;
793 session->apmFrameCount = (kPreprocDefaultSr) / 100;
794 session->frameCount = session->apmFrameCount;
795 session->samplingRate = kPreprocDefaultSr;
796 session->inChannelCount = kPreProcDefaultCnl;
797 session->outChannelCount = kPreProcDefaultCnl;
798 session->procFrame->_frequencyInHz = kPreprocDefaultSr;
799 session->procFrame->_audioChannel = kPreProcDefaultCnl;
800 session->revChannelCount = kPreProcDefaultCnl;
801 session->revFrame->_frequencyInHz = kPreprocDefaultSr;
802 session->revFrame->_audioChannel = kPreProcDefaultCnl;
803 session->enabledMsk = 0;
804 session->processedMsk = 0;
805 session->revEnabledMsk = 0;
806 session->revProcessedMsk = 0;
807 session->inResampler = NULL;
808 session->inBuf = NULL;
809 session->inBufSize = 0;
810 session->outResampler = NULL;
811 session->outBuf = NULL;
812 session->outBufSize = 0;
813 session->revResampler = NULL;
814 session->revBuf = NULL;
815 session->revBufSize = 0;
816 }
817 status = Effect_Create(&session->effects[procId], session, interface);
818 if (status < 0) {
819 goto error;
820 }
Steve Block3856b092011-10-20 11:56:00 +0100821 ALOGV("Session_CreateEffect OK");
Eric Laurenta9390d42011-06-17 20:17:17 -0700822 session->createdMsk |= (1<<procId);
823 return status;
824
825error:
826 if (session->createdMsk == 0) {
827 delete session->revFrame;
828 session->revFrame = NULL;
829 delete session->procFrame;
830 session->procFrame = NULL;
831 webrtc::AudioProcessing::Destroy(session->apm);
832 session->apm = NULL;
833 }
834 return status;
835}
836
837int Session_ReleaseEffect(preproc_session_t *session,
838 preproc_effect_t *fx)
839{
Steve Block5ff1dd52012-01-05 23:22:43 +0000840 ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
Eric Laurenta9390d42011-06-17 20:17:17 -0700841 session->createdMsk &= ~(1<<fx->procId);
842 if (session->createdMsk == 0) {
843 webrtc::AudioProcessing::Destroy(session->apm);
844 session->apm = NULL;
845 delete session->procFrame;
846 session->procFrame = NULL;
847 delete session->revFrame;
848 session->revFrame = NULL;
849 if (session->inResampler != NULL) {
850 speex_resampler_destroy(session->inResampler);
851 session->inResampler = NULL;
852 }
853 if (session->outResampler != NULL) {
854 speex_resampler_destroy(session->outResampler);
855 session->outResampler = NULL;
856 }
857 if (session->revResampler != NULL) {
858 speex_resampler_destroy(session->revResampler);
859 session->revResampler = NULL;
860 }
861 delete session->inBuf;
862 session->inBuf = NULL;
863 delete session->outBuf;
864 session->outBuf = NULL;
865 delete session->revBuf;
866 session->revBuf = NULL;
867
868 session->io = 0;
869 }
870
871 return 0;
872}
873
874
875int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
876{
877 uint32_t sr;
878 uint32_t inCnl = popcount(config->inputCfg.channels);
879 uint32_t outCnl = popcount(config->outputCfg.channels);
880
881 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
882 config->inputCfg.format != config->outputCfg.format ||
883 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
884 return -EINVAL;
885 }
886
Steve Block3856b092011-10-20 11:56:00 +0100887 ALOGV("Session_SetConfig sr %d cnl %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -0700888 config->inputCfg.samplingRate, config->inputCfg.channels);
889 int status;
890
Eric Laurent76533e92012-02-17 17:52:04 -0800891 // if at least one process is enabled, do not accept configuration changes
892 if (session->enabledMsk) {
893 if (session->samplingRate != config->inputCfg.samplingRate ||
894 session->inChannelCount != inCnl ||
895 session->outChannelCount != outCnl) {
896 return -ENOSYS;
897 } else {
898 return 0;
899 }
900 }
901
Eric Laurenta9390d42011-06-17 20:17:17 -0700902 // AEC implementation is limited to 16kHz
903 if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
904 session->apmSamplingRate = 32000;
905 } else
906 if (config->inputCfg.samplingRate >= 16000) {
907 session->apmSamplingRate = 16000;
908 } else if (config->inputCfg.samplingRate >= 8000) {
909 session->apmSamplingRate = 8000;
910 }
911 status = session->apm->set_sample_rate_hz(session->apmSamplingRate);
912 if (status < 0) {
913 return -EINVAL;
914 }
915 status = session->apm->set_num_channels(inCnl, outCnl);
916 if (status < 0) {
917 return -EINVAL;
918 }
919 status = session->apm->set_num_reverse_channels(inCnl);
920 if (status < 0) {
921 return -EINVAL;
922 }
923
924 session->samplingRate = config->inputCfg.samplingRate;
925 session->apmFrameCount = session->apmSamplingRate / 100;
926 if (session->samplingRate == session->apmSamplingRate) {
927 session->frameCount = session->apmFrameCount;
928 } else {
929 session->frameCount = (session->apmFrameCount * session->samplingRate) /
930 session->apmSamplingRate + 1;
931 }
932 session->inChannelCount = inCnl;
933 session->outChannelCount = outCnl;
934 session->procFrame->_audioChannel = inCnl;
935 session->procFrame->_frequencyInHz = session->apmSamplingRate;
936
937 session->revChannelCount = inCnl;
938 session->revFrame->_audioChannel = inCnl;
939 session->revFrame->_frequencyInHz = session->apmSamplingRate;
940
Eric Laurent3f9c84c2012-04-03 15:36:53 -0700941 // force process buffer reallocation
942 session->inBufSize = 0;
943 session->outBufSize = 0;
944 session->framesIn = 0;
945 session->framesOut = 0;
946
947
Eric Laurenta9390d42011-06-17 20:17:17 -0700948 if (session->inResampler != NULL) {
949 speex_resampler_destroy(session->inResampler);
950 session->inResampler = NULL;
951 }
952 if (session->outResampler != NULL) {
953 speex_resampler_destroy(session->outResampler);
954 session->outResampler = NULL;
955 }
956 if (session->revResampler != NULL) {
957 speex_resampler_destroy(session->revResampler);
958 session->revResampler = NULL;
959 }
960 if (session->samplingRate != session->apmSamplingRate) {
961 int error;
962 session->inResampler = speex_resampler_init(session->inChannelCount,
963 session->samplingRate,
964 session->apmSamplingRate,
965 RESAMPLER_QUALITY,
966 &error);
967 if (session->inResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000968 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700969 speex_resampler_strerror(error));
970 return -EINVAL;
971 }
972 session->outResampler = speex_resampler_init(session->outChannelCount,
973 session->apmSamplingRate,
974 session->samplingRate,
975 RESAMPLER_QUALITY,
976 &error);
977 if (session->outResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000978 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700979 speex_resampler_strerror(error));
980 speex_resampler_destroy(session->inResampler);
981 session->inResampler = NULL;
982 return -EINVAL;
983 }
984 session->revResampler = speex_resampler_init(session->inChannelCount,
985 session->samplingRate,
986 session->apmSamplingRate,
987 RESAMPLER_QUALITY,
988 &error);
989 if (session->revResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000990 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700991 speex_resampler_strerror(error));
992 speex_resampler_destroy(session->inResampler);
993 session->inResampler = NULL;
994 speex_resampler_destroy(session->outResampler);
995 session->outResampler = NULL;
996 return -EINVAL;
997 }
998 }
999
1000 session->state = PREPROC_SESSION_STATE_CONFIG;
1001 return 0;
1002}
1003
Eric Laurent3d5188b2011-12-16 15:30:36 -08001004void Session_GetConfig(preproc_session_t *session, effect_config_t *config)
1005{
1006 memset(config, 0, sizeof(effect_config_t));
1007 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
1008 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Glenn Kastenab334fd2012-03-14 12:56:06 -07001009 config->inputCfg.channels = audio_channel_in_mask_from_count(session->inChannelCount);
1010 // "out" doesn't mean output device, so this is the correct API to convert channel count to mask
1011 config->outputCfg.channels = audio_channel_in_mask_from_count(session->outChannelCount);
Eric Laurent3d5188b2011-12-16 15:30:36 -08001012 config->inputCfg.mask = config->outputCfg.mask =
1013 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
1014}
1015
Eric Laurenta9390d42011-06-17 20:17:17 -07001016int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
1017{
1018 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
1019 config->inputCfg.format != config->outputCfg.format ||
1020 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
1021 return -EINVAL;
1022 }
1023
Steve Block3856b092011-10-20 11:56:00 +01001024 ALOGV("Session_SetReverseConfig sr %d cnl %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001025 config->inputCfg.samplingRate, config->inputCfg.channels);
1026
1027 if (session->state < PREPROC_SESSION_STATE_CONFIG) {
1028 return -ENOSYS;
1029 }
1030 if (config->inputCfg.samplingRate != session->samplingRate ||
1031 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
1032 return -EINVAL;
1033 }
1034 uint32_t inCnl = popcount(config->inputCfg.channels);
1035 int status = session->apm->set_num_reverse_channels(inCnl);
1036 if (status < 0) {
1037 return -EINVAL;
1038 }
1039 session->revChannelCount = inCnl;
1040 session->revFrame->_audioChannel = inCnl;
1041 session->revFrame->_frequencyInHz = session->apmSamplingRate;
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001042 // force process buffer reallocation
1043 session->revBufSize = 0;
1044 session->framesRev = 0;
1045
Eric Laurenta9390d42011-06-17 20:17:17 -07001046 return 0;
1047}
1048
Eric Laurent3d5188b2011-12-16 15:30:36 -08001049void Session_GetReverseConfig(preproc_session_t *session, effect_config_t *config)
1050{
1051 memset(config, 0, sizeof(effect_config_t));
1052 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
1053 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
1054 config->inputCfg.channels = config->outputCfg.channels =
Glenn Kastenab334fd2012-03-14 12:56:06 -07001055 audio_channel_in_mask_from_count(session->revChannelCount);
Eric Laurent3d5188b2011-12-16 15:30:36 -08001056 config->inputCfg.mask = config->outputCfg.mask =
1057 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
1058}
1059
Eric Laurenta9390d42011-06-17 20:17:17 -07001060void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
1061{
1062 if (enabled) {
1063 if(session->enabledMsk == 0) {
1064 session->framesIn = 0;
1065 if (session->inResampler != NULL) {
1066 speex_resampler_reset_mem(session->inResampler);
1067 }
1068 session->framesOut = 0;
1069 if (session->outResampler != NULL) {
1070 speex_resampler_reset_mem(session->outResampler);
1071 }
1072 }
1073 session->enabledMsk |= (1 << procId);
1074 if (HasReverseStream(procId)) {
1075 session->framesRev = 0;
1076 if (session->revResampler != NULL) {
1077 speex_resampler_reset_mem(session->revResampler);
1078 }
1079 session->revEnabledMsk |= (1 << procId);
1080 }
1081 } else {
1082 session->enabledMsk &= ~(1 << procId);
1083 if (HasReverseStream(procId)) {
1084 session->revEnabledMsk &= ~(1 << procId);
1085 }
1086 }
Steve Block3856b092011-10-20 11:56:00 +01001087 ALOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001088 procId, enabled, session->enabledMsk, session->revEnabledMsk);
1089 session->processedMsk = 0;
1090 if (HasReverseStream(procId)) {
1091 session->revProcessedMsk = 0;
1092 }
1093}
1094
1095//------------------------------------------------------------------------------
1096// Bundle functions
1097//------------------------------------------------------------------------------
1098
1099static int sInitStatus = 1;
1100static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
1101
1102preproc_session_t *PreProc_GetSession(int32_t procId, int32_t sessionId, int32_t ioId)
1103{
1104 size_t i;
1105 int free = -1;
1106 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1107 if (sSessions[i].io == ioId) {
1108 if (sSessions[i].createdMsk & (1 << procId)) {
1109 return NULL;
1110 }
1111 return &sSessions[i];
1112 }
1113 }
1114 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1115 if (sSessions[i].io == 0) {
1116 sSessions[i].id = sessionId;
1117 sSessions[i].io = ioId;
1118 return &sSessions[i];
1119 }
1120 }
1121 return NULL;
1122}
1123
1124
1125int PreProc_Init() {
1126 size_t i;
1127 int status = 0;
1128
1129 if (sInitStatus <= 0) {
1130 return sInitStatus;
1131 }
1132 for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
1133 status = Session_Init(&sSessions[i]);
1134 }
1135 sInitStatus = status;
1136 return sInitStatus;
1137}
1138
Glenn Kasten5e92a782012-01-30 07:40:52 -08001139const effect_descriptor_t *PreProc_GetDescriptor(const effect_uuid_t *uuid)
Eric Laurenta9390d42011-06-17 20:17:17 -07001140{
1141 size_t i;
1142 for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
1143 if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
1144 return sDescriptors[i];
1145 }
1146 }
1147 return NULL;
1148}
1149
1150
1151extern "C" {
1152
1153//------------------------------------------------------------------------------
1154// Effect Control Interface Implementation
1155//------------------------------------------------------------------------------
1156
1157int PreProcessingFx_Process(effect_handle_t self,
1158 audio_buffer_t *inBuffer,
1159 audio_buffer_t *outBuffer)
1160{
1161 preproc_effect_t * effect = (preproc_effect_t *)self;
1162 int status = 0;
1163
1164 if (effect == NULL){
Steve Block3856b092011-10-20 11:56:00 +01001165 ALOGV("PreProcessingFx_Process() ERROR effect == NULL");
Eric Laurenta9390d42011-06-17 20:17:17 -07001166 return -EINVAL;
1167 }
1168 preproc_session_t * session = (preproc_session_t *)effect->session;
1169
1170 if (inBuffer == NULL || inBuffer->raw == NULL ||
1171 outBuffer == NULL || outBuffer->raw == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001172 ALOGW("PreProcessingFx_Process() ERROR bad pointer");
Eric Laurenta9390d42011-06-17 20:17:17 -07001173 return -EINVAL;
1174 }
1175
1176 session->processedMsk |= (1<<effect->procId);
1177
Steve Block3856b092011-10-20 11:56:00 +01001178// ALOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001179// inBuffer->frameCount, session->enabledMsk, session->processedMsk);
1180
1181 if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
1182 effect->session->processedMsk = 0;
1183 size_t framesRq = outBuffer->frameCount;
1184 size_t framesWr = 0;
1185 if (session->framesOut) {
1186 size_t fr = session->framesOut;
1187 if (outBuffer->frameCount < fr) {
1188 fr = outBuffer->frameCount;
1189 }
1190 memcpy(outBuffer->s16,
1191 session->outBuf,
1192 fr * session->outChannelCount * sizeof(int16_t));
1193 memcpy(session->outBuf,
1194 session->outBuf + fr * session->outChannelCount,
1195 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1196 session->framesOut -= fr;
1197 framesWr += fr;
1198 }
1199 outBuffer->frameCount = framesWr;
1200 if (framesWr == framesRq) {
1201 inBuffer->frameCount = 0;
1202 return 0;
1203 }
1204
1205 if (session->inResampler != NULL) {
1206 size_t fr = session->frameCount - session->framesIn;
1207 if (inBuffer->frameCount < fr) {
1208 fr = inBuffer->frameCount;
1209 }
1210 if (session->inBufSize < session->framesIn + fr) {
1211 session->inBufSize = session->framesIn + fr;
1212 session->inBuf = (int16_t *)realloc(session->inBuf,
1213 session->inBufSize * session->inChannelCount * sizeof(int16_t));
1214 }
1215 memcpy(session->inBuf + session->framesIn * session->inChannelCount,
1216 inBuffer->s16,
1217 fr * session->inChannelCount * sizeof(int16_t));
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001218#ifdef DUAL_MIC_TEST
1219 pthread_mutex_lock(&gPcmDumpLock);
1220 if (gPcmDumpFh != NULL) {
1221 fwrite(inBuffer->raw,
1222 fr * session->inChannelCount * sizeof(int16_t), 1, gPcmDumpFh);
1223 }
1224 pthread_mutex_unlock(&gPcmDumpLock);
1225#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001226
1227 session->framesIn += fr;
1228 inBuffer->frameCount = fr;
1229 if (session->framesIn < session->frameCount) {
1230 return 0;
1231 }
1232 size_t frIn = session->framesIn;
1233 size_t frOut = session->apmFrameCount;
1234 if (session->inChannelCount == 1) {
1235 speex_resampler_process_int(session->inResampler,
1236 0,
1237 session->inBuf,
1238 &frIn,
1239 session->procFrame->_payloadData,
1240 &frOut);
1241 } else {
1242 speex_resampler_process_interleaved_int(session->inResampler,
1243 session->inBuf,
1244 &frIn,
1245 session->procFrame->_payloadData,
1246 &frOut);
1247 }
1248 memcpy(session->inBuf,
1249 session->inBuf + frIn * session->inChannelCount,
1250 (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
1251 session->framesIn -= frIn;
1252 } else {
1253 size_t fr = session->frameCount - session->framesIn;
1254 if (inBuffer->frameCount < fr) {
1255 fr = inBuffer->frameCount;
1256 }
1257 memcpy(session->procFrame->_payloadData + session->framesIn * session->inChannelCount,
1258 inBuffer->s16,
1259 fr * session->inChannelCount * sizeof(int16_t));
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001260
1261#ifdef DUAL_MIC_TEST
1262 pthread_mutex_lock(&gPcmDumpLock);
1263 if (gPcmDumpFh != NULL) {
1264 fwrite(inBuffer->raw,
1265 fr * session->inChannelCount * sizeof(int16_t), 1, gPcmDumpFh);
1266 }
1267 pthread_mutex_unlock(&gPcmDumpLock);
1268#endif
1269
Eric Laurenta9390d42011-06-17 20:17:17 -07001270 session->framesIn += fr;
1271 inBuffer->frameCount = fr;
1272 if (session->framesIn < session->frameCount) {
1273 return 0;
1274 }
1275 session->framesIn = 0;
1276 }
1277 session->procFrame->_payloadDataLengthInSamples =
1278 session->apmFrameCount * session->inChannelCount;
1279
1280 effect->session->apm->ProcessStream(session->procFrame);
1281
1282 if (session->outBufSize < session->framesOut + session->frameCount) {
1283 session->outBufSize = session->framesOut + session->frameCount;
1284 session->outBuf = (int16_t *)realloc(session->outBuf,
1285 session->outBufSize * session->outChannelCount * sizeof(int16_t));
1286 }
1287
1288 if (session->outResampler != NULL) {
1289 size_t frIn = session->apmFrameCount;
1290 size_t frOut = session->frameCount;
1291 if (session->inChannelCount == 1) {
1292 speex_resampler_process_int(session->outResampler,
1293 0,
1294 session->procFrame->_payloadData,
1295 &frIn,
1296 session->outBuf + session->framesOut * session->outChannelCount,
1297 &frOut);
1298 } else {
1299 speex_resampler_process_interleaved_int(session->outResampler,
1300 session->procFrame->_payloadData,
1301 &frIn,
1302 session->outBuf + session->framesOut * session->outChannelCount,
1303 &frOut);
1304 }
1305 session->framesOut += frOut;
1306 } else {
1307 memcpy(session->outBuf + session->framesOut * session->outChannelCount,
1308 session->procFrame->_payloadData,
1309 session->frameCount * session->outChannelCount * sizeof(int16_t));
1310 session->framesOut += session->frameCount;
1311 }
1312 size_t fr = session->framesOut;
1313 if (framesRq - framesWr < fr) {
1314 fr = framesRq - framesWr;
1315 }
1316 memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
1317 session->outBuf,
1318 fr * session->outChannelCount * sizeof(int16_t));
1319 memcpy(session->outBuf,
1320 session->outBuf + fr * session->outChannelCount,
1321 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1322 session->framesOut -= fr;
1323 outBuffer->frameCount += fr;
1324
1325 return 0;
1326 } else {
1327 return -ENODATA;
1328 }
1329}
1330
1331int PreProcessingFx_Command(effect_handle_t self,
1332 uint32_t cmdCode,
1333 uint32_t cmdSize,
1334 void *pCmdData,
1335 uint32_t *replySize,
1336 void *pReplyData)
1337{
1338 preproc_effect_t * effect = (preproc_effect_t *) self;
1339 int retsize;
1340 int status;
1341
1342 if (effect == NULL){
1343 return -EINVAL;
1344 }
1345
Steve Block3856b092011-10-20 11:56:00 +01001346 //ALOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
Eric Laurenta9390d42011-06-17 20:17:17 -07001347
1348 switch (cmdCode){
1349 case EFFECT_CMD_INIT:
1350 if (pReplyData == NULL || *replySize != sizeof(int)){
1351 return -EINVAL;
1352 }
1353 if (effect->ops->init) {
1354 effect->ops->init(effect);
1355 }
1356 *(int *)pReplyData = 0;
1357 break;
1358
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001359 case EFFECT_CMD_SET_CONFIG: {
Eric Laurenta9390d42011-06-17 20:17:17 -07001360 if (pCmdData == NULL||
1361 cmdSize != sizeof(effect_config_t)||
1362 pReplyData == NULL||
1363 *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001364 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent3d5188b2011-12-16 15:30:36 -08001365 "EFFECT_CMD_SET_CONFIG: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001366 return -EINVAL;
1367 }
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001368#ifdef DUAL_MIC_TEST
1369 // make sure that the config command is accepted by making as if all effects were
1370 // disabled: this is OK for functional tests
1371 uint32_t enabledMsk = effect->session->enabledMsk;
1372 if (gDualMicEnabled) {
1373 effect->session->enabledMsk = 0;
1374 }
1375#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001376 *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001377#ifdef DUAL_MIC_TEST
1378 if (gDualMicEnabled) {
1379 effect->session->enabledMsk = enabledMsk;
1380 }
1381#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001382 if (*(int *)pReplyData != 0) {
1383 break;
1384 }
Eric Laurent76533e92012-02-17 17:52:04 -08001385 if (effect->state != PREPROC_EFFECT_STATE_ACTIVE) {
1386 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1387 }
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001388 } break;
Eric Laurenta9390d42011-06-17 20:17:17 -07001389
Eric Laurent3d5188b2011-12-16 15:30:36 -08001390 case EFFECT_CMD_GET_CONFIG:
1391 if (pReplyData == NULL ||
1392 *replySize != sizeof(effect_config_t)) {
1393 ALOGV("\tLVM_ERROR : PreProcessingFx_Command cmdCode Case: "
1394 "EFFECT_CMD_GET_CONFIG: ERROR");
1395 return -EINVAL;
1396 }
1397
Eric Laurent94fef382012-02-06 14:28:54 -08001398 Session_GetConfig(effect->session, (effect_config_t *)pReplyData);
Eric Laurent3d5188b2011-12-16 15:30:36 -08001399 break;
1400
1401 case EFFECT_CMD_SET_CONFIG_REVERSE:
1402 if (pCmdData == NULL ||
1403 cmdSize != sizeof(effect_config_t) ||
1404 pReplyData == NULL ||
1405 *replySize != sizeof(int)) {
Steve Block3856b092011-10-20 11:56:00 +01001406 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent3d5188b2011-12-16 15:30:36 -08001407 "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001408 return -EINVAL;
1409 }
1410 *(int *)pReplyData = Session_SetReverseConfig(effect->session,
1411 (effect_config_t *)pCmdData);
1412 if (*(int *)pReplyData != 0) {
1413 break;
1414 }
1415 break;
1416
Eric Laurent3d5188b2011-12-16 15:30:36 -08001417 case EFFECT_CMD_GET_CONFIG_REVERSE:
1418 if (pReplyData == NULL ||
1419 *replySize != sizeof(effect_config_t)){
1420 ALOGV("PreProcessingFx_Command cmdCode Case: "
1421 "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR");
1422 return -EINVAL;
1423 }
1424 Session_GetReverseConfig(effect->session, (effect_config_t *)pCmdData);
1425 break;
1426
Eric Laurenta9390d42011-06-17 20:17:17 -07001427 case EFFECT_CMD_RESET:
1428 if (effect->ops->reset) {
1429 effect->ops->reset(effect);
1430 }
1431 break;
1432
1433 case EFFECT_CMD_GET_PARAM:{
1434 if (pCmdData == NULL ||
1435 cmdSize < (int)sizeof(effect_param_t) ||
1436 pReplyData == NULL ||
1437 *replySize < (int)sizeof(effect_param_t)){
Steve Block3856b092011-10-20 11:56:00 +01001438 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001439 "EFFECT_CMD_GET_PARAM: ERROR");
1440 return -EINVAL;
1441 }
1442 effect_param_t *p = (effect_param_t *)pCmdData;
1443
1444 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
1445
1446 p = (effect_param_t *)pReplyData;
1447
1448 int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
1449
1450 if (effect->ops->get_parameter) {
1451 p->status = effect->ops->get_parameter(effect, p->data,
1452 (size_t *)&p->vsize,
1453 p->data + voffset);
1454 *replySize = sizeof(effect_param_t) + voffset + p->vsize;
1455 }
1456 } break;
1457
1458 case EFFECT_CMD_SET_PARAM:{
1459 if (pCmdData == NULL||
1460 cmdSize < (int)sizeof(effect_param_t) ||
1461 pReplyData == NULL ||
1462 *replySize != sizeof(int32_t)){
Steve Block3856b092011-10-20 11:56:00 +01001463 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001464 "EFFECT_CMD_SET_PARAM: ERROR");
1465 return -EINVAL;
1466 }
1467 effect_param_t *p = (effect_param_t *) pCmdData;
1468
1469 if (p->psize != sizeof(int32_t)){
Steve Block3856b092011-10-20 11:56:00 +01001470 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001471 "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
1472 return -EINVAL;
1473 }
1474 if (effect->ops->set_parameter) {
1475 *(int *)pReplyData = effect->ops->set_parameter(effect,
1476 (void *)p->data,
1477 p->data + p->psize);
1478 }
1479 } break;
1480
1481 case EFFECT_CMD_ENABLE:
1482 if (pReplyData == NULL || *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001483 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001484 return -EINVAL;
1485 }
1486 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
1487 break;
1488
1489 case EFFECT_CMD_DISABLE:
1490 if (pReplyData == NULL || *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001491 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001492 return -EINVAL;
1493 }
1494 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1495 break;
1496
1497 case EFFECT_CMD_SET_DEVICE:
1498 case EFFECT_CMD_SET_INPUT_DEVICE:
1499 if (pCmdData == NULL ||
1500 cmdSize != sizeof(uint32_t)) {
Steve Block3856b092011-10-20 11:56:00 +01001501 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001502 return -EINVAL;
1503 }
1504
1505 if (effect->ops->set_device) {
1506 effect->ops->set_device(effect, *(uint32_t *)pCmdData);
1507 }
1508 break;
1509
1510 case EFFECT_CMD_SET_VOLUME:
1511 case EFFECT_CMD_SET_AUDIO_MODE:
1512 break;
1513
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001514#ifdef DUAL_MIC_TEST
1515 ///// test commands start
1516 case PREPROC_CMD_DUAL_MIC_ENABLE: {
1517 if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
1518 pReplyData == NULL || replySize == NULL) {
1519 ALOGE("PreProcessingFx_Command cmdCode Case: "
1520 "PREPROC_CMD_DUAL_MIC_ENABLE: ERROR");
1521 *replySize = 0;
1522 return -EINVAL;
1523 }
1524 gDualMicEnabled = *(bool *)pCmdData;
1525 if (gDualMicEnabled) {
1526 effect->aux_channels_on = sHasAuxChannels[effect->procId];
1527 } else {
1528 effect->aux_channels_on = false;
1529 }
1530 effect->cur_channel_config = (effect->session->inChannelCount == 1) ?
1531 CHANNEL_CFG_MONO : CHANNEL_CFG_STEREO;
1532
1533 ALOGV("PREPROC_CMD_DUAL_MIC_ENABLE: %s", gDualMicEnabled ? "enabled" : "disabled");
1534 *replySize = sizeof(int);
1535 *(int *)pReplyData = 0;
1536 } break;
1537 case PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: {
1538 if (pCmdData == NULL|| pReplyData == NULL || replySize == NULL) {
1539 ALOGE("PreProcessingFx_Command cmdCode Case: "
1540 "PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: ERROR");
1541 *replySize = 0;
1542 return -EINVAL;
1543 }
1544 pthread_mutex_lock(&gPcmDumpLock);
1545 if (gPcmDumpFh != NULL) {
1546 fclose(gPcmDumpFh);
1547 gPcmDumpFh = NULL;
1548 }
1549 char *path = strndup((char *)pCmdData, cmdSize);
1550 gPcmDumpFh = fopen((char *)path, "wb");
1551 pthread_mutex_unlock(&gPcmDumpLock);
1552 ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: path %s gPcmDumpFh %p",
1553 path, gPcmDumpFh);
1554 ALOGE_IF(gPcmDumpFh <= 0, "gPcmDumpFh open error %d %s", errno, strerror(errno));
1555 free(path);
1556 *replySize = sizeof(int);
1557 *(int *)pReplyData = 0;
1558 } break;
1559 case PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: {
1560 if (pReplyData == NULL || replySize == NULL) {
1561 ALOGE("PreProcessingFx_Command cmdCode Case: "
1562 "PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: ERROR");
1563 *replySize = 0;
1564 return -EINVAL;
1565 }
1566 pthread_mutex_lock(&gPcmDumpLock);
1567 if (gPcmDumpFh != NULL) {
1568 fclose(gPcmDumpFh);
1569 gPcmDumpFh = NULL;
1570 }
1571 pthread_mutex_unlock(&gPcmDumpLock);
1572 ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP");
1573 *replySize = sizeof(int);
1574 *(int *)pReplyData = 0;
1575 } break;
1576 ///// test commands end
1577
1578 case EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: {
1579 if(!gDualMicEnabled) {
1580 return -EINVAL;
1581 }
1582 if (pCmdData == NULL|| cmdSize != 2 * sizeof(uint32_t) ||
1583 pReplyData == NULL || replySize == NULL) {
1584 ALOGE("PreProcessingFx_Command cmdCode Case: "
1585 "EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: ERROR");
1586 *replySize = 0;
1587 return -EINVAL;
1588 }
1589 if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS ||
1590 !effect->aux_channels_on) {
1591 ALOGV("PreProcessingFx_Command feature EFFECT_FEATURE_AUX_CHANNELS not supported by"
1592 " fx %d", effect->procId);
1593 *(uint32_t *)pReplyData = -ENOSYS;
1594 *replySize = sizeof(uint32_t);
1595 break;
1596 }
1597 size_t num_configs = *((uint32_t *)pCmdData + 1);
1598 if (*replySize < (2 * sizeof(uint32_t) +
1599 num_configs * sizeof(channel_config_t))) {
1600 *replySize = 0;
1601 return -EINVAL;
1602 }
1603
1604 *((uint32_t *)pReplyData + 1) = CHANNEL_CFG_CNT;
1605 if (num_configs < CHANNEL_CFG_CNT ||
1606 *replySize < (2 * sizeof(uint32_t) +
1607 CHANNEL_CFG_CNT * sizeof(channel_config_t))) {
1608 *(uint32_t *)pReplyData = -ENOMEM;
1609 } else {
1610 num_configs = CHANNEL_CFG_CNT;
1611 *(uint32_t *)pReplyData = 0;
1612 }
1613 ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS num config %d",
1614 num_configs);
1615
1616 *replySize = 2 * sizeof(uint32_t) + num_configs * sizeof(channel_config_t);
1617 *((uint32_t *)pReplyData + 1) = num_configs;
1618 memcpy((uint32_t *)pReplyData + 2, &sDualMicConfigs, num_configs * sizeof(channel_config_t));
1619 } break;
1620 case EFFECT_CMD_GET_FEATURE_CONFIG:
1621 if(!gDualMicEnabled) {
1622 return -EINVAL;
1623 }
1624 if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
1625 pReplyData == NULL || replySize == NULL ||
1626 *replySize < sizeof(uint32_t) + sizeof(channel_config_t)) {
1627 ALOGE("PreProcessingFx_Command cmdCode Case: "
1628 "EFFECT_CMD_GET_FEATURE_CONFIG: ERROR");
1629 return -EINVAL;
1630 }
1631 if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1632 *(uint32_t *)pReplyData = -ENOSYS;
1633 *replySize = sizeof(uint32_t);
1634 break;
1635 }
1636 ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_CONFIG");
1637 *(uint32_t *)pReplyData = 0;
1638 *replySize = sizeof(uint32_t) + sizeof(channel_config_t);
1639 memcpy((uint32_t *)pReplyData + 1,
1640 &sDualMicConfigs[effect->cur_channel_config],
1641 sizeof(channel_config_t));
1642 break;
1643 case EFFECT_CMD_SET_FEATURE_CONFIG: {
1644 ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG: "
1645 "gDualMicEnabled %d effect->aux_channels_on %d",
1646 gDualMicEnabled, effect->aux_channels_on);
1647 if(!gDualMicEnabled) {
1648 return -EINVAL;
1649 }
1650 if (pCmdData == NULL|| cmdSize != (sizeof(uint32_t) + sizeof(channel_config_t)) ||
1651 pReplyData == NULL || replySize == NULL ||
1652 *replySize < sizeof(uint32_t)) {
1653 ALOGE("PreProcessingFx_Command cmdCode Case: "
1654 "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1655 "pCmdData %p cmdSize %d pReplyData %p replySize %p *replySize %d",
1656 pCmdData, cmdSize, pReplyData, replySize, replySize ? *replySize : -1);
1657 return -EINVAL;
1658 }
1659 *replySize = sizeof(uint32_t);
1660 if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1661 *(uint32_t *)pReplyData = -ENOSYS;
1662 ALOGV("PreProcessingFx_Command cmdCode Case: "
1663 "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1664 "CmdData %d effect->aux_channels_on %d",
1665 *(uint32_t *)pCmdData, effect->aux_channels_on);
1666 break;
1667 }
1668 size_t i;
1669 for (i = 0; i < CHANNEL_CFG_CNT;i++) {
1670 if (memcmp((uint32_t *)pCmdData + 1,
1671 &sDualMicConfigs[i], sizeof(channel_config_t)) == 0) {
1672 break;
1673 }
1674 }
1675 if (i == CHANNEL_CFG_CNT) {
1676 *(uint32_t *)pReplyData = -EINVAL;
1677 ALOGW("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG invalid config"
1678 "[%08x].[%08x]", *((uint32_t *)pCmdData + 1), *((uint32_t *)pCmdData + 2));
1679 } else {
1680 effect->cur_channel_config = i;
1681 *(uint32_t *)pReplyData = 0;
1682 ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG New config"
1683 "[%08x].[%08x]", sDualMicConfigs[i].main_channels, sDualMicConfigs[i].aux_channels);
1684 }
1685 } break;
1686#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001687 default:
1688 return -EINVAL;
1689 }
1690 return 0;
1691}
1692
1693
1694int PreProcessingFx_GetDescriptor(effect_handle_t self,
1695 effect_descriptor_t *pDescriptor)
1696{
1697 preproc_effect_t * effect = (preproc_effect_t *) self;
1698
1699 if (effect == NULL || pDescriptor == NULL) {
1700 return -EINVAL;
1701 }
1702
Glenn Kastena189a682012-02-20 12:16:30 -08001703 *pDescriptor = *sDescriptors[effect->procId];
Eric Laurenta9390d42011-06-17 20:17:17 -07001704
1705 return 0;
1706}
1707
1708int PreProcessingFx_ProcessReverse(effect_handle_t self,
1709 audio_buffer_t *inBuffer,
1710 audio_buffer_t *outBuffer)
1711{
1712 preproc_effect_t * effect = (preproc_effect_t *)self;
1713 int status = 0;
1714
1715 if (effect == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001716 ALOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
Eric Laurenta9390d42011-06-17 20:17:17 -07001717 return -EINVAL;
1718 }
1719 preproc_session_t * session = (preproc_session_t *)effect->session;
1720
1721 if (inBuffer == NULL || inBuffer->raw == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001722 ALOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
Eric Laurenta9390d42011-06-17 20:17:17 -07001723 return -EINVAL;
1724 }
1725
1726 session->revProcessedMsk |= (1<<effect->procId);
1727
Steve Block3856b092011-10-20 11:56:00 +01001728// ALOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001729// inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
1730
1731
1732 if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
1733 effect->session->revProcessedMsk = 0;
1734 if (session->revResampler != NULL) {
1735 size_t fr = session->frameCount - session->framesRev;
1736 if (inBuffer->frameCount < fr) {
1737 fr = inBuffer->frameCount;
1738 }
1739 if (session->revBufSize < session->framesRev + fr) {
1740 session->revBufSize = session->framesRev + fr;
1741 session->revBuf = (int16_t *)realloc(session->revBuf,
1742 session->revBufSize * session->inChannelCount * sizeof(int16_t));
1743 }
1744 memcpy(session->revBuf + session->framesRev * session->inChannelCount,
1745 inBuffer->s16,
1746 fr * session->inChannelCount * sizeof(int16_t));
1747
1748 session->framesRev += fr;
1749 inBuffer->frameCount = fr;
1750 if (session->framesRev < session->frameCount) {
1751 return 0;
1752 }
1753 size_t frIn = session->framesRev;
1754 size_t frOut = session->apmFrameCount;
1755 if (session->inChannelCount == 1) {
1756 speex_resampler_process_int(session->revResampler,
1757 0,
1758 session->revBuf,
1759 &frIn,
1760 session->revFrame->_payloadData,
1761 &frOut);
1762 } else {
1763 speex_resampler_process_interleaved_int(session->revResampler,
1764 session->revBuf,
1765 &frIn,
1766 session->revFrame->_payloadData,
1767 &frOut);
1768 }
1769 memcpy(session->revBuf,
1770 session->revBuf + frIn * session->inChannelCount,
1771 (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
1772 session->framesRev -= frIn;
1773 } else {
1774 size_t fr = session->frameCount - session->framesRev;
1775 if (inBuffer->frameCount < fr) {
1776 fr = inBuffer->frameCount;
1777 }
1778 memcpy(session->revFrame->_payloadData + session->framesRev * session->inChannelCount,
1779 inBuffer->s16,
1780 fr * session->inChannelCount * sizeof(int16_t));
1781 session->framesRev += fr;
1782 inBuffer->frameCount = fr;
1783 if (session->framesRev < session->frameCount) {
1784 return 0;
1785 }
1786 session->framesRev = 0;
1787 }
1788 session->revFrame->_payloadDataLengthInSamples =
1789 session->apmFrameCount * session->inChannelCount;
1790 effect->session->apm->AnalyzeReverseStream(session->revFrame);
1791 return 0;
1792 } else {
1793 return -ENODATA;
1794 }
1795}
1796
1797
1798// effect_handle_t interface implementation for effect
1799const struct effect_interface_s sEffectInterface = {
1800 PreProcessingFx_Process,
1801 PreProcessingFx_Command,
1802 PreProcessingFx_GetDescriptor,
1803 NULL
1804};
1805
1806const struct effect_interface_s sEffectInterfaceReverse = {
1807 PreProcessingFx_Process,
1808 PreProcessingFx_Command,
1809 PreProcessingFx_GetDescriptor,
1810 PreProcessingFx_ProcessReverse
1811};
1812
1813//------------------------------------------------------------------------------
1814// Effect Library Interface Implementation
1815//------------------------------------------------------------------------------
1816
1817int PreProcessingLib_QueryNumberEffects(uint32_t *pNumEffects)
1818{
1819 if (PreProc_Init() != 0) {
1820 return sInitStatus;
1821 }
1822 if (pNumEffects == NULL) {
1823 return -EINVAL;
1824 }
1825 *pNumEffects = PREPROC_NUM_EFFECTS;
1826 return sInitStatus;
1827}
1828
1829int PreProcessingLib_QueryEffect(uint32_t index, effect_descriptor_t *pDescriptor)
1830{
1831 if (PreProc_Init() != 0) {
1832 return sInitStatus;
1833 }
1834 if (index >= PREPROC_NUM_EFFECTS) {
1835 return -EINVAL;
1836 }
Glenn Kastena189a682012-02-20 12:16:30 -08001837 *pDescriptor = *sDescriptors[index];
Eric Laurenta9390d42011-06-17 20:17:17 -07001838 return 0;
1839}
1840
Glenn Kasten5e92a782012-01-30 07:40:52 -08001841int PreProcessingLib_Create(const effect_uuid_t *uuid,
Eric Laurenta9390d42011-06-17 20:17:17 -07001842 int32_t sessionId,
1843 int32_t ioId,
1844 effect_handle_t *pInterface)
1845{
Steve Block3856b092011-10-20 11:56:00 +01001846 ALOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
Eric Laurenta9390d42011-06-17 20:17:17 -07001847
1848 int status;
1849 const effect_descriptor_t *desc;
1850 preproc_session_t *session;
1851 uint32_t procId;
1852
1853 if (PreProc_Init() != 0) {
1854 return sInitStatus;
1855 }
1856 desc = PreProc_GetDescriptor(uuid);
1857 if (desc == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +00001858 ALOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
Eric Laurenta9390d42011-06-17 20:17:17 -07001859 return -EINVAL;
1860 }
1861 procId = UuidToProcId(&desc->type);
1862
1863 session = PreProc_GetSession(procId, sessionId, ioId);
1864 if (session == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +00001865 ALOGW("EffectCreate: no more session available");
Eric Laurenta9390d42011-06-17 20:17:17 -07001866 return -EINVAL;
1867 }
1868
1869 status = Session_CreateEffect(session, procId, pInterface);
1870
1871 if (status < 0 && session->createdMsk == 0) {
1872 session->io = 0;
1873 }
1874 return status;
1875}
1876
1877int PreProcessingLib_Release(effect_handle_t interface)
1878{
1879 int status;
Steve Block3856b092011-10-20 11:56:00 +01001880 ALOGV("EffectRelease start %p", interface);
Eric Laurenta9390d42011-06-17 20:17:17 -07001881 if (PreProc_Init() != 0) {
1882 return sInitStatus;
1883 }
1884
1885 preproc_effect_t *fx = (preproc_effect_t *)interface;
1886
1887 if (fx->session->io == 0) {
1888 return -EINVAL;
1889 }
1890 return Session_ReleaseEffect(fx->session, fx);
1891}
1892
Glenn Kasten5e92a782012-01-30 07:40:52 -08001893int PreProcessingLib_GetDescriptor(const effect_uuid_t *uuid,
Eric Laurenta9390d42011-06-17 20:17:17 -07001894 effect_descriptor_t *pDescriptor) {
1895
1896 if (pDescriptor == NULL || uuid == NULL){
1897 return -EINVAL;
1898 }
1899
1900 const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
1901 if (desc == NULL) {
Steve Block3856b092011-10-20 11:56:00 +01001902 ALOGV("PreProcessingLib_GetDescriptor() not found");
Eric Laurenta9390d42011-06-17 20:17:17 -07001903 return -EINVAL;
1904 }
1905
Steve Block3856b092011-10-20 11:56:00 +01001906 ALOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
Eric Laurenta9390d42011-06-17 20:17:17 -07001907
Glenn Kastena189a682012-02-20 12:16:30 -08001908 *pDescriptor = *desc;
Eric Laurenta9390d42011-06-17 20:17:17 -07001909 return 0;
1910}
1911
1912audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
1913 tag : AUDIO_EFFECT_LIBRARY_TAG,
1914 version : EFFECT_LIBRARY_API_VERSION,
1915 name : "Audio Preprocessing Library",
1916 implementor : "The Android Open Source Project",
1917 query_num_effects : PreProcessingLib_QueryNumberEffects,
1918 query_effect : PreProcessingLib_QueryEffect,
1919 create_effect : PreProcessingLib_Create,
1920 release_effect : PreProcessingLib_Release,
1921 get_descriptor : PreProcessingLib_GetDescriptor
1922};
1923
1924}; // extern "C"