blob: f3c038b3ddb318802d9c47d154f0c43f63d2bc6c [file] [log] [blame]
Eric Laurenta9390d42011-06-17 20:17:17 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <string.h>
19#define LOG_TAG "PreProcessing"
20//#define LOG_NDEBUG 0
21#include <utils/Log.h>
22#include <utils/Timers.h>
23#include <hardware/audio_effect.h>
24#include <audio_effects/effect_aec.h>
25#include <audio_effects/effect_agc.h>
26#include <audio_effects/effect_ns.h>
Eric Laurent53876962012-01-31 12:35:20 -080027#include <module_common_types.h>
28#include <audio_processing.h>
Eric Laurenta9390d42011-06-17 20:17:17 -070029#include "speex/speex_resampler.h"
30
Eric Laurent3f9c84c2012-04-03 15:36:53 -070031// undefine to perform multi channels API functional tests
32//#define DUAL_MIC_TEST
Eric Laurenta9390d42011-06-17 20:17:17 -070033
34//------------------------------------------------------------------------------
35// local definitions
36//------------------------------------------------------------------------------
37
38// maximum number of sessions
39#define PREPROC_NUM_SESSIONS 8
40
41// types of pre processing modules
42enum preproc_id
43{
44 PREPROC_AGC, // Automatic Gain Control
45 PREPROC_AEC, // Acoustic Echo Canceler
46 PREPROC_NS, // Noise Suppressor
47 PREPROC_NUM_EFFECTS
48};
49
50// Session state
51enum preproc_session_state {
52 PREPROC_SESSION_STATE_INIT, // initialized
53 PREPROC_SESSION_STATE_CONFIG // configuration received
54};
55
56// Effect/Preprocessor state
57enum preproc_effect_state {
58 PREPROC_EFFECT_STATE_INIT, // initialized
59 PREPROC_EFFECT_STATE_CREATED, // webRTC engine created
60 PREPROC_EFFECT_STATE_CONFIG, // configuration received/disabled
61 PREPROC_EFFECT_STATE_ACTIVE // active/enabled
62};
63
64// handle on webRTC engine
65typedef void* preproc_fx_handle_t;
66
67typedef struct preproc_session_s preproc_session_t;
68typedef struct preproc_effect_s preproc_effect_t;
69typedef struct preproc_ops_s preproc_ops_t;
70
71// Effect operation table. Functions for all pre processors are declared in sPreProcOps[] table.
72// Function pointer can be null if no action required.
73struct preproc_ops_s {
74 int (* create)(preproc_effect_t *fx);
75 int (* init)(preproc_effect_t *fx);
76 int (* reset)(preproc_effect_t *fx);
77 void (* enable)(preproc_effect_t *fx);
78 void (* disable)(preproc_effect_t *fx);
79 int (* set_parameter)(preproc_effect_t *fx, void *param, void *value);
Ashok Bhatb302bd52014-02-18 11:40:00 +000080 int (* get_parameter)(preproc_effect_t *fx, void *param, uint32_t *size, void *value);
Eric Laurenta9390d42011-06-17 20:17:17 -070081 int (* set_device)(preproc_effect_t *fx, uint32_t device);
82};
83
84// Effect context
85struct preproc_effect_s {
86 const struct effect_interface_s *itfe;
87 uint32_t procId; // type of pre processor (enum preproc_id)
88 uint32_t state; // current state (enum preproc_effect_state)
89 preproc_session_t *session; // session the effect is on
90 const preproc_ops_t *ops; // effect ops table
91 preproc_fx_handle_t engine; // handle on webRTC engine
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,
Ashok Bhatb302bd52014-02-18 11:40:00 +0000294 uint32_t *pValueSize,
Eric Laurenta9390d42011-06-17 20:17:17 -0700295 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
Ashok Bhatb302bd52014-02-18 11:40:00 +0000455int AecGetParameter(preproc_effect_t *effect,
Eric Laurenta9390d42011-06-17 20:17:17 -0700456 void *pParam,
Ashok Bhatb302bd52014-02-18 11:40:00 +0000457 uint32_t *pValueSize,
Eric Laurenta9390d42011-06-17 20:17:17 -0700458 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
Eric Laurent88959252012-08-28 14:26:53 -0700520 if (audio_is_input_device(device)) {
521 return 0;
522 }
523
Eric Laurenta9390d42011-06-17 20:17:17 -0700524 switch(device) {
525 case AUDIO_DEVICE_OUT_EARPIECE:
526 mode = webrtc::EchoControlMobile::kEarpiece;
527 break;
528 case AUDIO_DEVICE_OUT_SPEAKER:
529 mode = webrtc::EchoControlMobile::kSpeakerphone;
530 break;
531 case AUDIO_DEVICE_OUT_WIRED_HEADSET:
532 case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
533 default:
534 break;
535 }
536 aec->set_routing_mode(mode);
537 return 0;
538}
539
540static const preproc_ops_t sAecOps = {
541 AecCreate,
542 AecInit,
543 NULL,
544 AecEnable,
545 AecDisable,
546 AecSetParameter,
547 AecGetParameter,
548 AecSetDevice
549};
550
551//------------------------------------------------------------------------------
552// Noise Suppression (NS)
553//------------------------------------------------------------------------------
554
555static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
556
557int NsInit (preproc_effect_t *effect)
558{
Steve Block3856b092011-10-20 11:56:00 +0100559 ALOGV("NsInit");
Eric Laurenta9390d42011-06-17 20:17:17 -0700560 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
561 ns->set_level(kNsDefaultLevel);
562 return 0;
563}
564
565int NsCreate(preproc_effect_t *effect)
566{
567 webrtc::NoiseSuppression *ns = effect->session->apm->noise_suppression();
Steve Block3856b092011-10-20 11:56:00 +0100568 ALOGV("NsCreate got ns %p", ns);
Eric Laurenta9390d42011-06-17 20:17:17 -0700569 if (ns == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000570 ALOGW("AgcCreate Error");
Eric Laurenta9390d42011-06-17 20:17:17 -0700571 return -ENOMEM;
572 }
573 effect->engine = static_cast<preproc_fx_handle_t>(ns);
574 NsInit (effect);
575 return 0;
576}
577
Eric Laurent0f714a42015-06-19 15:33:57 -0700578int NsGetParameter(preproc_effect_t *effect __unused,
579 void *pParam __unused,
580 uint32_t *pValueSize __unused,
581 void *pValue __unused)
Eric Laurenta9390d42011-06-17 20:17:17 -0700582{
583 int status = 0;
584 return status;
585}
586
Eric Laurent0f714a42015-06-19 15:33:57 -0700587int NsSetParameter (preproc_effect_t *effect __unused,
588 void *pParam __unused,
589 void *pValue __unused)
Eric Laurenta9390d42011-06-17 20:17:17 -0700590{
591 int status = 0;
592 return status;
593}
594
595void NsEnable(preproc_effect_t *effect)
596{
597 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
Steve Block3856b092011-10-20 11:56:00 +0100598 ALOGV("NsEnable ns %p", ns);
Eric Laurenta9390d42011-06-17 20:17:17 -0700599 ns->Enable(true);
600}
601
602void NsDisable(preproc_effect_t *effect)
603{
Steve Block3856b092011-10-20 11:56:00 +0100604 ALOGV("NsDisable");
Eric Laurenta9390d42011-06-17 20:17:17 -0700605 webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
606 ns->Enable(false);
607}
608
609static const preproc_ops_t sNsOps = {
610 NsCreate,
611 NsInit,
612 NULL,
613 NsEnable,
614 NsDisable,
615 NsSetParameter,
616 NsGetParameter,
617 NULL
618};
619
620
621static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
622 &sAgcOps,
623 &sAecOps,
624 &sNsOps
625};
626
627
628//------------------------------------------------------------------------------
629// Effect functions
630//------------------------------------------------------------------------------
631
632void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled);
633
634extern "C" const struct effect_interface_s sEffectInterface;
635extern "C" const struct effect_interface_s sEffectInterfaceReverse;
636
637#define BAD_STATE_ABORT(from, to) \
638 LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to);
639
640int Effect_SetState(preproc_effect_t *effect, uint32_t state)
641{
642 int status = 0;
Steve Block3856b092011-10-20 11:56:00 +0100643 ALOGV("Effect_SetState proc %d, new %d old %d", effect->procId, state, effect->state);
Eric Laurenta9390d42011-06-17 20:17:17 -0700644 switch(state) {
645 case PREPROC_EFFECT_STATE_INIT:
646 switch(effect->state) {
647 case PREPROC_EFFECT_STATE_ACTIVE:
648 effect->ops->disable(effect);
649 Session_SetProcEnabled(effect->session, effect->procId, false);
650 case PREPROC_EFFECT_STATE_CONFIG:
651 case PREPROC_EFFECT_STATE_CREATED:
652 case PREPROC_EFFECT_STATE_INIT:
653 break;
654 default:
655 BAD_STATE_ABORT(effect->state, state);
656 }
657 break;
658 case PREPROC_EFFECT_STATE_CREATED:
659 switch(effect->state) {
660 case PREPROC_EFFECT_STATE_INIT:
661 status = effect->ops->create(effect);
662 break;
663 case PREPROC_EFFECT_STATE_CREATED:
664 case PREPROC_EFFECT_STATE_ACTIVE:
665 case PREPROC_EFFECT_STATE_CONFIG:
Steve Block29357bc2012-01-06 19:20:56 +0000666 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700667 status = -ENOSYS;
668 break;
669 default:
670 BAD_STATE_ABORT(effect->state, state);
671 }
672 break;
673 case PREPROC_EFFECT_STATE_CONFIG:
674 switch(effect->state) {
675 case PREPROC_EFFECT_STATE_INIT:
Steve Block29357bc2012-01-06 19:20:56 +0000676 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700677 status = -ENOSYS;
678 break;
679 case PREPROC_EFFECT_STATE_ACTIVE:
680 effect->ops->disable(effect);
681 Session_SetProcEnabled(effect->session, effect->procId, false);
682 break;
683 case PREPROC_EFFECT_STATE_CREATED:
684 case PREPROC_EFFECT_STATE_CONFIG:
685 break;
686 default:
687 BAD_STATE_ABORT(effect->state, state);
688 }
689 break;
690 case PREPROC_EFFECT_STATE_ACTIVE:
691 switch(effect->state) {
692 case PREPROC_EFFECT_STATE_INIT:
693 case PREPROC_EFFECT_STATE_CREATED:
Steve Block29357bc2012-01-06 19:20:56 +0000694 ALOGE("Effect_SetState invalid transition");
Eric Laurenta9390d42011-06-17 20:17:17 -0700695 status = -ENOSYS;
696 break;
Eric Laurent3f9c84c2012-04-03 15:36:53 -0700697 case PREPROC_EFFECT_STATE_ACTIVE:
698 // enabling an already enabled effect is just ignored
699 break;
Eric Laurenta9390d42011-06-17 20:17:17 -0700700 case PREPROC_EFFECT_STATE_CONFIG:
701 effect->ops->enable(effect);
702 Session_SetProcEnabled(effect->session, effect->procId, true);
703 break;
704 default:
705 BAD_STATE_ABORT(effect->state, state);
706 }
707 break;
708 default:
709 BAD_STATE_ABORT(effect->state, state);
710 }
711 if (status == 0) {
712 effect->state = state;
713 }
714 return status;
715}
716
717int Effect_Init(preproc_effect_t *effect, uint32_t procId)
718{
719 if (HasReverseStream(procId)) {
720 effect->itfe = &sEffectInterfaceReverse;
721 } else {
722 effect->itfe = &sEffectInterface;
723 }
724 effect->ops = sPreProcOps[procId];
725 effect->procId = procId;
726 effect->state = PREPROC_EFFECT_STATE_INIT;
727 return 0;
728}
729
730int Effect_Create(preproc_effect_t *effect,
731 preproc_session_t *session,
732 effect_handle_t *interface)
733{
734 effect->session = session;
735 *interface = (effect_handle_t)&effect->itfe;
736 return Effect_SetState(effect, PREPROC_EFFECT_STATE_CREATED);
737}
738
739int Effect_Release(preproc_effect_t *effect)
740{
741 return Effect_SetState(effect, PREPROC_EFFECT_STATE_INIT);
742}
743
744
745//------------------------------------------------------------------------------
746// Session functions
747//------------------------------------------------------------------------------
748
749#define RESAMPLER_QUALITY SPEEX_RESAMPLER_QUALITY_VOIP
750
751static const int kPreprocDefaultSr = 16000;
752static const int kPreProcDefaultCnl = 1;
753
754int Session_Init(preproc_session_t *session)
755{
756 size_t i;
757 int status = 0;
758
759 session->state = PREPROC_SESSION_STATE_INIT;
760 session->id = 0;
761 session->io = 0;
762 session->createdMsk = 0;
763 session->apm = NULL;
764 for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
765 status = Effect_Init(&session->effects[i], i);
766 }
767 return status;
768}
769
770
771extern "C" int Session_CreateEffect(preproc_session_t *session,
772 int32_t procId,
773 effect_handle_t *interface)
774{
775 int status = -ENOMEM;
776
Steve Block3856b092011-10-20 11:56:00 +0100777 ALOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
Eric Laurenta9390d42011-06-17 20:17:17 -0700778
779 if (session->createdMsk == 0) {
Alex Luebs9718b7d2015-11-24 14:33:14 -0800780 session->apm = webrtc::AudioProcessing::Create();
Eric Laurenta9390d42011-06-17 20:17:17 -0700781 if (session->apm == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000782 ALOGW("Session_CreateEffect could not get apm engine");
Eric Laurenta9390d42011-06-17 20:17:17 -0700783 goto error;
784 }
Alex Luebs9718b7d2015-11-24 14:33:14 -0800785 const webrtc::ProcessingConfig processing_config = {
786 {{kPreprocDefaultSr, kPreProcDefaultCnl},
787 {kPreprocDefaultSr, kPreProcDefaultCnl},
788 {kPreprocDefaultSr, kPreProcDefaultCnl},
789 {kPreprocDefaultSr, kPreProcDefaultCnl}}};
790 session->apm->Initialize(processing_config);
Eric Laurenta9390d42011-06-17 20:17:17 -0700791 session->procFrame = new webrtc::AudioFrame();
792 if (session->procFrame == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000793 ALOGW("Session_CreateEffect could not allocate audio frame");
Eric Laurenta9390d42011-06-17 20:17:17 -0700794 goto error;
795 }
796 session->revFrame = new webrtc::AudioFrame();
797 if (session->revFrame == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000798 ALOGW("Session_CreateEffect could not allocate reverse audio frame");
Eric Laurenta9390d42011-06-17 20:17:17 -0700799 goto error;
800 }
801 session->apmSamplingRate = kPreprocDefaultSr;
802 session->apmFrameCount = (kPreprocDefaultSr) / 100;
803 session->frameCount = session->apmFrameCount;
804 session->samplingRate = kPreprocDefaultSr;
805 session->inChannelCount = kPreProcDefaultCnl;
806 session->outChannelCount = kPreProcDefaultCnl;
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -0700807 session->procFrame->sample_rate_hz_ = kPreprocDefaultSr;
808 session->procFrame->num_channels_ = kPreProcDefaultCnl;
Eric Laurenta9390d42011-06-17 20:17:17 -0700809 session->revChannelCount = kPreProcDefaultCnl;
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -0700810 session->revFrame->sample_rate_hz_ = kPreprocDefaultSr;
811 session->revFrame->num_channels_ = kPreProcDefaultCnl;
Eric Laurenta9390d42011-06-17 20:17:17 -0700812 session->enabledMsk = 0;
813 session->processedMsk = 0;
814 session->revEnabledMsk = 0;
815 session->revProcessedMsk = 0;
816 session->inResampler = NULL;
817 session->inBuf = NULL;
818 session->inBufSize = 0;
819 session->outResampler = NULL;
820 session->outBuf = NULL;
821 session->outBufSize = 0;
822 session->revResampler = NULL;
823 session->revBuf = NULL;
824 session->revBufSize = 0;
825 }
826 status = Effect_Create(&session->effects[procId], session, interface);
827 if (status < 0) {
828 goto error;
829 }
Steve Block3856b092011-10-20 11:56:00 +0100830 ALOGV("Session_CreateEffect OK");
Eric Laurenta9390d42011-06-17 20:17:17 -0700831 session->createdMsk |= (1<<procId);
832 return status;
833
834error:
835 if (session->createdMsk == 0) {
836 delete session->revFrame;
837 session->revFrame = NULL;
838 delete session->procFrame;
839 session->procFrame = NULL;
Alex Luebs9718b7d2015-11-24 14:33:14 -0800840 delete session->apm;
Eric Laurenta9390d42011-06-17 20:17:17 -0700841 session->apm = NULL;
842 }
843 return status;
844}
845
846int Session_ReleaseEffect(preproc_session_t *session,
847 preproc_effect_t *fx)
848{
Steve Block5ff1dd52012-01-05 23:22:43 +0000849 ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
Eric Laurenta9390d42011-06-17 20:17:17 -0700850 session->createdMsk &= ~(1<<fx->procId);
851 if (session->createdMsk == 0) {
Alex Luebs9718b7d2015-11-24 14:33:14 -0800852 delete session->apm;
Eric Laurenta9390d42011-06-17 20:17:17 -0700853 session->apm = NULL;
854 delete session->procFrame;
855 session->procFrame = NULL;
856 delete session->revFrame;
857 session->revFrame = NULL;
858 if (session->inResampler != NULL) {
859 speex_resampler_destroy(session->inResampler);
860 session->inResampler = NULL;
861 }
862 if (session->outResampler != NULL) {
863 speex_resampler_destroy(session->outResampler);
864 session->outResampler = NULL;
865 }
866 if (session->revResampler != NULL) {
867 speex_resampler_destroy(session->revResampler);
868 session->revResampler = NULL;
869 }
870 delete session->inBuf;
871 session->inBuf = NULL;
872 delete session->outBuf;
873 session->outBuf = NULL;
874 delete session->revBuf;
875 session->revBuf = NULL;
876
877 session->io = 0;
878 }
879
880 return 0;
881}
882
883
884int Session_SetConfig(preproc_session_t *session, effect_config_t *config)
885{
886 uint32_t sr;
Andy Hunge5412692014-05-16 11:25:07 -0700887 uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
888 uint32_t outCnl = audio_channel_count_from_out_mask(config->outputCfg.channels);
Eric Laurenta9390d42011-06-17 20:17:17 -0700889
890 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
891 config->inputCfg.format != config->outputCfg.format ||
892 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
893 return -EINVAL;
894 }
895
Steve Block3856b092011-10-20 11:56:00 +0100896 ALOGV("Session_SetConfig sr %d cnl %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -0700897 config->inputCfg.samplingRate, config->inputCfg.channels);
898 int status;
899
Eric Laurent76533e92012-02-17 17:52:04 -0800900 // if at least one process is enabled, do not accept configuration changes
901 if (session->enabledMsk) {
902 if (session->samplingRate != config->inputCfg.samplingRate ||
903 session->inChannelCount != inCnl ||
904 session->outChannelCount != outCnl) {
905 return -ENOSYS;
906 } else {
907 return 0;
908 }
909 }
910
Eric Laurenta9390d42011-06-17 20:17:17 -0700911 // AEC implementation is limited to 16kHz
912 if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
913 session->apmSamplingRate = 32000;
914 } else
915 if (config->inputCfg.samplingRate >= 16000) {
916 session->apmSamplingRate = 16000;
917 } else if (config->inputCfg.samplingRate >= 8000) {
918 session->apmSamplingRate = 8000;
919 }
Alex Luebs9718b7d2015-11-24 14:33:14 -0800920
921 const webrtc::ProcessingConfig processing_config = {
922 {{static_cast<int>(session->apmSamplingRate), static_cast<int>(inCnl)},
923 {static_cast<int>(session->apmSamplingRate), static_cast<int>(outCnl)},
924 {static_cast<int>(session->apmSamplingRate), static_cast<int>(inCnl)},
925 {static_cast<int>(session->apmSamplingRate), static_cast<int>(inCnl)}}};
926 status = session->apm->Initialize(processing_config);
Eric Laurenta9390d42011-06-17 20:17:17 -0700927 if (status < 0) {
928 return -EINVAL;
929 }
930
931 session->samplingRate = config->inputCfg.samplingRate;
932 session->apmFrameCount = session->apmSamplingRate / 100;
933 if (session->samplingRate == session->apmSamplingRate) {
934 session->frameCount = session->apmFrameCount;
935 } else {
936 session->frameCount = (session->apmFrameCount * session->samplingRate) /
937 session->apmSamplingRate + 1;
938 }
939 session->inChannelCount = inCnl;
940 session->outChannelCount = outCnl;
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -0700941 session->procFrame->num_channels_ = inCnl;
942 session->procFrame->sample_rate_hz_ = session->apmSamplingRate;
Eric Laurenta9390d42011-06-17 20:17:17 -0700943
944 session->revChannelCount = inCnl;
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -0700945 session->revFrame->num_channels_ = inCnl;
946 session->revFrame->sample_rate_hz_ = session->apmSamplingRate;
Eric Laurenta9390d42011-06-17 20:17:17 -0700947
Eric Laurent3f9c84c2012-04-03 15:36:53 -0700948 // force process buffer reallocation
949 session->inBufSize = 0;
950 session->outBufSize = 0;
951 session->framesIn = 0;
952 session->framesOut = 0;
953
954
Eric Laurenta9390d42011-06-17 20:17:17 -0700955 if (session->inResampler != NULL) {
956 speex_resampler_destroy(session->inResampler);
957 session->inResampler = NULL;
958 }
959 if (session->outResampler != NULL) {
960 speex_resampler_destroy(session->outResampler);
961 session->outResampler = NULL;
962 }
963 if (session->revResampler != NULL) {
964 speex_resampler_destroy(session->revResampler);
965 session->revResampler = NULL;
966 }
967 if (session->samplingRate != session->apmSamplingRate) {
968 int error;
969 session->inResampler = speex_resampler_init(session->inChannelCount,
970 session->samplingRate,
971 session->apmSamplingRate,
972 RESAMPLER_QUALITY,
973 &error);
974 if (session->inResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000975 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700976 speex_resampler_strerror(error));
977 return -EINVAL;
978 }
979 session->outResampler = speex_resampler_init(session->outChannelCount,
980 session->apmSamplingRate,
981 session->samplingRate,
982 RESAMPLER_QUALITY,
983 &error);
984 if (session->outResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000985 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700986 speex_resampler_strerror(error));
987 speex_resampler_destroy(session->inResampler);
988 session->inResampler = NULL;
989 return -EINVAL;
990 }
991 session->revResampler = speex_resampler_init(session->inChannelCount,
992 session->samplingRate,
993 session->apmSamplingRate,
994 RESAMPLER_QUALITY,
995 &error);
996 if (session->revResampler == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000997 ALOGW("Session_SetConfig Cannot create speex resampler: %s",
Eric Laurenta9390d42011-06-17 20:17:17 -0700998 speex_resampler_strerror(error));
999 speex_resampler_destroy(session->inResampler);
1000 session->inResampler = NULL;
1001 speex_resampler_destroy(session->outResampler);
1002 session->outResampler = NULL;
1003 return -EINVAL;
1004 }
1005 }
1006
1007 session->state = PREPROC_SESSION_STATE_CONFIG;
1008 return 0;
1009}
1010
Eric Laurent3d5188b2011-12-16 15:30:36 -08001011void Session_GetConfig(preproc_session_t *session, effect_config_t *config)
1012{
1013 memset(config, 0, sizeof(effect_config_t));
1014 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
1015 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
Glenn Kastenab334fd2012-03-14 12:56:06 -07001016 config->inputCfg.channels = audio_channel_in_mask_from_count(session->inChannelCount);
1017 // "out" doesn't mean output device, so this is the correct API to convert channel count to mask
1018 config->outputCfg.channels = audio_channel_in_mask_from_count(session->outChannelCount);
Eric Laurent3d5188b2011-12-16 15:30:36 -08001019 config->inputCfg.mask = config->outputCfg.mask =
1020 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
1021}
1022
Eric Laurenta9390d42011-06-17 20:17:17 -07001023int Session_SetReverseConfig(preproc_session_t *session, effect_config_t *config)
1024{
1025 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
1026 config->inputCfg.format != config->outputCfg.format ||
1027 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
1028 return -EINVAL;
1029 }
1030
Steve Block3856b092011-10-20 11:56:00 +01001031 ALOGV("Session_SetReverseConfig sr %d cnl %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001032 config->inputCfg.samplingRate, config->inputCfg.channels);
1033
1034 if (session->state < PREPROC_SESSION_STATE_CONFIG) {
1035 return -ENOSYS;
1036 }
1037 if (config->inputCfg.samplingRate != session->samplingRate ||
1038 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
1039 return -EINVAL;
1040 }
Andy Hunge5412692014-05-16 11:25:07 -07001041 uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
Alex Luebs9718b7d2015-11-24 14:33:14 -08001042 const webrtc::ProcessingConfig processing_config = {
1043 {{static_cast<int>(session->apmSamplingRate),
1044 static_cast<int>(session->inChannelCount)},
1045 {static_cast<int>(session->apmSamplingRate),
1046 static_cast<int>(session->outChannelCount)},
1047 {static_cast<int>(session->apmSamplingRate),
1048 static_cast<int>(inCnl)},
1049 {static_cast<int>(session->apmSamplingRate),
1050 static_cast<int>(inCnl)}}};
1051 int status = session->apm->Initialize(processing_config);
Eric Laurenta9390d42011-06-17 20:17:17 -07001052 if (status < 0) {
1053 return -EINVAL;
1054 }
1055 session->revChannelCount = inCnl;
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001056 session->revFrame->num_channels_ = inCnl;
1057 session->revFrame->sample_rate_hz_ = session->apmSamplingRate;
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001058 // force process buffer reallocation
1059 session->revBufSize = 0;
1060 session->framesRev = 0;
1061
Eric Laurenta9390d42011-06-17 20:17:17 -07001062 return 0;
1063}
1064
Eric Laurent3d5188b2011-12-16 15:30:36 -08001065void Session_GetReverseConfig(preproc_session_t *session, effect_config_t *config)
1066{
1067 memset(config, 0, sizeof(effect_config_t));
1068 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
1069 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
1070 config->inputCfg.channels = config->outputCfg.channels =
Glenn Kastenab334fd2012-03-14 12:56:06 -07001071 audio_channel_in_mask_from_count(session->revChannelCount);
Eric Laurent3d5188b2011-12-16 15:30:36 -08001072 config->inputCfg.mask = config->outputCfg.mask =
1073 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
1074}
1075
Eric Laurenta9390d42011-06-17 20:17:17 -07001076void Session_SetProcEnabled(preproc_session_t *session, uint32_t procId, bool enabled)
1077{
1078 if (enabled) {
1079 if(session->enabledMsk == 0) {
1080 session->framesIn = 0;
1081 if (session->inResampler != NULL) {
1082 speex_resampler_reset_mem(session->inResampler);
1083 }
1084 session->framesOut = 0;
1085 if (session->outResampler != NULL) {
1086 speex_resampler_reset_mem(session->outResampler);
1087 }
1088 }
1089 session->enabledMsk |= (1 << procId);
1090 if (HasReverseStream(procId)) {
1091 session->framesRev = 0;
1092 if (session->revResampler != NULL) {
1093 speex_resampler_reset_mem(session->revResampler);
1094 }
1095 session->revEnabledMsk |= (1 << procId);
1096 }
1097 } else {
1098 session->enabledMsk &= ~(1 << procId);
1099 if (HasReverseStream(procId)) {
1100 session->revEnabledMsk &= ~(1 << procId);
1101 }
1102 }
Steve Block3856b092011-10-20 11:56:00 +01001103 ALOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001104 procId, enabled, session->enabledMsk, session->revEnabledMsk);
1105 session->processedMsk = 0;
1106 if (HasReverseStream(procId)) {
1107 session->revProcessedMsk = 0;
1108 }
1109}
1110
1111//------------------------------------------------------------------------------
1112// Bundle functions
1113//------------------------------------------------------------------------------
1114
1115static int sInitStatus = 1;
1116static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
1117
1118preproc_session_t *PreProc_GetSession(int32_t procId, int32_t sessionId, int32_t ioId)
1119{
1120 size_t i;
1121 int free = -1;
1122 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1123 if (sSessions[i].io == ioId) {
1124 if (sSessions[i].createdMsk & (1 << procId)) {
1125 return NULL;
1126 }
1127 return &sSessions[i];
1128 }
1129 }
1130 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1131 if (sSessions[i].io == 0) {
1132 sSessions[i].id = sessionId;
1133 sSessions[i].io = ioId;
1134 return &sSessions[i];
1135 }
1136 }
1137 return NULL;
1138}
1139
1140
1141int PreProc_Init() {
1142 size_t i;
1143 int status = 0;
1144
1145 if (sInitStatus <= 0) {
1146 return sInitStatus;
1147 }
1148 for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
1149 status = Session_Init(&sSessions[i]);
1150 }
1151 sInitStatus = status;
1152 return sInitStatus;
1153}
1154
Glenn Kasten5e92a782012-01-30 07:40:52 -08001155const effect_descriptor_t *PreProc_GetDescriptor(const effect_uuid_t *uuid)
Eric Laurenta9390d42011-06-17 20:17:17 -07001156{
1157 size_t i;
1158 for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
1159 if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
1160 return sDescriptors[i];
1161 }
1162 }
1163 return NULL;
1164}
1165
1166
1167extern "C" {
1168
1169//------------------------------------------------------------------------------
1170// Effect Control Interface Implementation
1171//------------------------------------------------------------------------------
1172
1173int PreProcessingFx_Process(effect_handle_t self,
1174 audio_buffer_t *inBuffer,
1175 audio_buffer_t *outBuffer)
1176{
1177 preproc_effect_t * effect = (preproc_effect_t *)self;
1178 int status = 0;
1179
1180 if (effect == NULL){
Steve Block3856b092011-10-20 11:56:00 +01001181 ALOGV("PreProcessingFx_Process() ERROR effect == NULL");
Eric Laurenta9390d42011-06-17 20:17:17 -07001182 return -EINVAL;
1183 }
1184 preproc_session_t * session = (preproc_session_t *)effect->session;
1185
1186 if (inBuffer == NULL || inBuffer->raw == NULL ||
1187 outBuffer == NULL || outBuffer->raw == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001188 ALOGW("PreProcessingFx_Process() ERROR bad pointer");
Eric Laurenta9390d42011-06-17 20:17:17 -07001189 return -EINVAL;
1190 }
1191
1192 session->processedMsk |= (1<<effect->procId);
1193
Steve Block3856b092011-10-20 11:56:00 +01001194// ALOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001195// inBuffer->frameCount, session->enabledMsk, session->processedMsk);
1196
1197 if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
1198 effect->session->processedMsk = 0;
1199 size_t framesRq = outBuffer->frameCount;
1200 size_t framesWr = 0;
1201 if (session->framesOut) {
1202 size_t fr = session->framesOut;
1203 if (outBuffer->frameCount < fr) {
1204 fr = outBuffer->frameCount;
1205 }
1206 memcpy(outBuffer->s16,
1207 session->outBuf,
1208 fr * session->outChannelCount * sizeof(int16_t));
1209 memcpy(session->outBuf,
1210 session->outBuf + fr * session->outChannelCount,
1211 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1212 session->framesOut -= fr;
1213 framesWr += fr;
1214 }
1215 outBuffer->frameCount = framesWr;
1216 if (framesWr == framesRq) {
1217 inBuffer->frameCount = 0;
1218 return 0;
1219 }
1220
1221 if (session->inResampler != NULL) {
1222 size_t fr = session->frameCount - session->framesIn;
1223 if (inBuffer->frameCount < fr) {
1224 fr = inBuffer->frameCount;
1225 }
1226 if (session->inBufSize < session->framesIn + fr) {
1227 session->inBufSize = session->framesIn + fr;
1228 session->inBuf = (int16_t *)realloc(session->inBuf,
1229 session->inBufSize * session->inChannelCount * sizeof(int16_t));
1230 }
1231 memcpy(session->inBuf + session->framesIn * session->inChannelCount,
1232 inBuffer->s16,
1233 fr * session->inChannelCount * sizeof(int16_t));
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001234#ifdef DUAL_MIC_TEST
1235 pthread_mutex_lock(&gPcmDumpLock);
1236 if (gPcmDumpFh != NULL) {
1237 fwrite(inBuffer->raw,
1238 fr * session->inChannelCount * sizeof(int16_t), 1, gPcmDumpFh);
1239 }
1240 pthread_mutex_unlock(&gPcmDumpLock);
1241#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001242
1243 session->framesIn += fr;
1244 inBuffer->frameCount = fr;
1245 if (session->framesIn < session->frameCount) {
1246 return 0;
1247 }
Kévin PETIT377b2ec2014-02-03 12:35:36 +00001248 spx_uint32_t frIn = session->framesIn;
1249 spx_uint32_t frOut = session->apmFrameCount;
Eric Laurenta9390d42011-06-17 20:17:17 -07001250 if (session->inChannelCount == 1) {
1251 speex_resampler_process_int(session->inResampler,
1252 0,
1253 session->inBuf,
1254 &frIn,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001255 session->procFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001256 &frOut);
1257 } else {
1258 speex_resampler_process_interleaved_int(session->inResampler,
1259 session->inBuf,
1260 &frIn,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001261 session->procFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001262 &frOut);
1263 }
1264 memcpy(session->inBuf,
1265 session->inBuf + frIn * session->inChannelCount,
1266 (session->framesIn - frIn) * session->inChannelCount * sizeof(int16_t));
1267 session->framesIn -= frIn;
1268 } else {
1269 size_t fr = session->frameCount - session->framesIn;
1270 if (inBuffer->frameCount < fr) {
1271 fr = inBuffer->frameCount;
1272 }
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001273 memcpy(session->procFrame->data_ + session->framesIn * session->inChannelCount,
Eric Laurenta9390d42011-06-17 20:17:17 -07001274 inBuffer->s16,
1275 fr * session->inChannelCount * sizeof(int16_t));
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001276
1277#ifdef DUAL_MIC_TEST
1278 pthread_mutex_lock(&gPcmDumpLock);
1279 if (gPcmDumpFh != NULL) {
1280 fwrite(inBuffer->raw,
1281 fr * session->inChannelCount * sizeof(int16_t), 1, gPcmDumpFh);
1282 }
1283 pthread_mutex_unlock(&gPcmDumpLock);
1284#endif
1285
Eric Laurenta9390d42011-06-17 20:17:17 -07001286 session->framesIn += fr;
1287 inBuffer->frameCount = fr;
1288 if (session->framesIn < session->frameCount) {
1289 return 0;
1290 }
1291 session->framesIn = 0;
1292 }
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001293 session->procFrame->samples_per_channel_ =
Eric Laurenta9390d42011-06-17 20:17:17 -07001294 session->apmFrameCount * session->inChannelCount;
1295
1296 effect->session->apm->ProcessStream(session->procFrame);
1297
1298 if (session->outBufSize < session->framesOut + session->frameCount) {
1299 session->outBufSize = session->framesOut + session->frameCount;
1300 session->outBuf = (int16_t *)realloc(session->outBuf,
1301 session->outBufSize * session->outChannelCount * sizeof(int16_t));
1302 }
1303
1304 if (session->outResampler != NULL) {
Kévin PETIT377b2ec2014-02-03 12:35:36 +00001305 spx_uint32_t frIn = session->apmFrameCount;
1306 spx_uint32_t frOut = session->frameCount;
Eric Laurenta9390d42011-06-17 20:17:17 -07001307 if (session->inChannelCount == 1) {
1308 speex_resampler_process_int(session->outResampler,
1309 0,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001310 session->procFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001311 &frIn,
1312 session->outBuf + session->framesOut * session->outChannelCount,
1313 &frOut);
1314 } else {
1315 speex_resampler_process_interleaved_int(session->outResampler,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001316 session->procFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001317 &frIn,
1318 session->outBuf + session->framesOut * session->outChannelCount,
1319 &frOut);
1320 }
1321 session->framesOut += frOut;
1322 } else {
1323 memcpy(session->outBuf + session->framesOut * session->outChannelCount,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001324 session->procFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001325 session->frameCount * session->outChannelCount * sizeof(int16_t));
1326 session->framesOut += session->frameCount;
1327 }
1328 size_t fr = session->framesOut;
1329 if (framesRq - framesWr < fr) {
1330 fr = framesRq - framesWr;
1331 }
1332 memcpy(outBuffer->s16 + framesWr * session->outChannelCount,
1333 session->outBuf,
1334 fr * session->outChannelCount * sizeof(int16_t));
1335 memcpy(session->outBuf,
1336 session->outBuf + fr * session->outChannelCount,
1337 (session->framesOut - fr) * session->outChannelCount * sizeof(int16_t));
1338 session->framesOut -= fr;
1339 outBuffer->frameCount += fr;
1340
1341 return 0;
1342 } else {
1343 return -ENODATA;
1344 }
1345}
1346
1347int PreProcessingFx_Command(effect_handle_t self,
1348 uint32_t cmdCode,
1349 uint32_t cmdSize,
1350 void *pCmdData,
1351 uint32_t *replySize,
1352 void *pReplyData)
1353{
1354 preproc_effect_t * effect = (preproc_effect_t *) self;
1355 int retsize;
1356 int status;
1357
1358 if (effect == NULL){
1359 return -EINVAL;
1360 }
1361
Steve Block3856b092011-10-20 11:56:00 +01001362 //ALOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
Eric Laurenta9390d42011-06-17 20:17:17 -07001363
1364 switch (cmdCode){
1365 case EFFECT_CMD_INIT:
1366 if (pReplyData == NULL || *replySize != sizeof(int)){
1367 return -EINVAL;
1368 }
1369 if (effect->ops->init) {
1370 effect->ops->init(effect);
1371 }
1372 *(int *)pReplyData = 0;
1373 break;
1374
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001375 case EFFECT_CMD_SET_CONFIG: {
Eric Laurenta9390d42011-06-17 20:17:17 -07001376 if (pCmdData == NULL||
1377 cmdSize != sizeof(effect_config_t)||
1378 pReplyData == NULL||
1379 *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001380 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent3d5188b2011-12-16 15:30:36 -08001381 "EFFECT_CMD_SET_CONFIG: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001382 return -EINVAL;
1383 }
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001384#ifdef DUAL_MIC_TEST
1385 // make sure that the config command is accepted by making as if all effects were
1386 // disabled: this is OK for functional tests
1387 uint32_t enabledMsk = effect->session->enabledMsk;
1388 if (gDualMicEnabled) {
1389 effect->session->enabledMsk = 0;
1390 }
1391#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001392 *(int *)pReplyData = Session_SetConfig(effect->session, (effect_config_t *)pCmdData);
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001393#ifdef DUAL_MIC_TEST
1394 if (gDualMicEnabled) {
1395 effect->session->enabledMsk = enabledMsk;
1396 }
1397#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001398 if (*(int *)pReplyData != 0) {
1399 break;
1400 }
Eric Laurent76533e92012-02-17 17:52:04 -08001401 if (effect->state != PREPROC_EFFECT_STATE_ACTIVE) {
1402 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1403 }
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001404 } break;
Eric Laurenta9390d42011-06-17 20:17:17 -07001405
Eric Laurent3d5188b2011-12-16 15:30:36 -08001406 case EFFECT_CMD_GET_CONFIG:
1407 if (pReplyData == NULL ||
1408 *replySize != sizeof(effect_config_t)) {
1409 ALOGV("\tLVM_ERROR : PreProcessingFx_Command cmdCode Case: "
1410 "EFFECT_CMD_GET_CONFIG: ERROR");
1411 return -EINVAL;
1412 }
1413
Eric Laurent94fef382012-02-06 14:28:54 -08001414 Session_GetConfig(effect->session, (effect_config_t *)pReplyData);
Eric Laurent3d5188b2011-12-16 15:30:36 -08001415 break;
1416
1417 case EFFECT_CMD_SET_CONFIG_REVERSE:
1418 if (pCmdData == NULL ||
1419 cmdSize != sizeof(effect_config_t) ||
1420 pReplyData == NULL ||
1421 *replySize != sizeof(int)) {
Steve Block3856b092011-10-20 11:56:00 +01001422 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurent3d5188b2011-12-16 15:30:36 -08001423 "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001424 return -EINVAL;
1425 }
1426 *(int *)pReplyData = Session_SetReverseConfig(effect->session,
1427 (effect_config_t *)pCmdData);
1428 if (*(int *)pReplyData != 0) {
1429 break;
1430 }
1431 break;
1432
Eric Laurent3d5188b2011-12-16 15:30:36 -08001433 case EFFECT_CMD_GET_CONFIG_REVERSE:
1434 if (pReplyData == NULL ||
1435 *replySize != sizeof(effect_config_t)){
1436 ALOGV("PreProcessingFx_Command cmdCode Case: "
1437 "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR");
1438 return -EINVAL;
1439 }
1440 Session_GetReverseConfig(effect->session, (effect_config_t *)pCmdData);
1441 break;
1442
Eric Laurenta9390d42011-06-17 20:17:17 -07001443 case EFFECT_CMD_RESET:
1444 if (effect->ops->reset) {
1445 effect->ops->reset(effect);
1446 }
1447 break;
1448
Eric Laurent0f714a42015-06-19 15:33:57 -07001449 case EFFECT_CMD_GET_PARAM: {
1450 effect_param_t *p = (effect_param_t *)pCmdData;
1451
1452 if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
1453 cmdSize < (sizeof(effect_param_t) + p->psize) ||
1454 pReplyData == NULL || replySize == NULL ||
1455 *replySize < (sizeof(effect_param_t) + p->psize)){
Steve Block3856b092011-10-20 11:56:00 +01001456 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001457 "EFFECT_CMD_GET_PARAM: ERROR");
1458 return -EINVAL;
1459 }
Eric Laurenta9390d42011-06-17 20:17:17 -07001460
1461 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
1462
1463 p = (effect_param_t *)pReplyData;
1464
1465 int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
1466
1467 if (effect->ops->get_parameter) {
1468 p->status = effect->ops->get_parameter(effect, p->data,
Ashok Bhatb302bd52014-02-18 11:40:00 +00001469 &p->vsize,
Eric Laurenta9390d42011-06-17 20:17:17 -07001470 p->data + voffset);
1471 *replySize = sizeof(effect_param_t) + voffset + p->vsize;
1472 }
1473 } break;
1474
1475 case EFFECT_CMD_SET_PARAM:{
1476 if (pCmdData == NULL||
Eric Laurent0f714a42015-06-19 15:33:57 -07001477 cmdSize < sizeof(effect_param_t) ||
1478 pReplyData == NULL || replySize == NULL ||
Eric Laurenta9390d42011-06-17 20:17:17 -07001479 *replySize != sizeof(int32_t)){
Steve Block3856b092011-10-20 11:56:00 +01001480 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001481 "EFFECT_CMD_SET_PARAM: ERROR");
1482 return -EINVAL;
1483 }
1484 effect_param_t *p = (effect_param_t *) pCmdData;
1485
1486 if (p->psize != sizeof(int32_t)){
Steve Block3856b092011-10-20 11:56:00 +01001487 ALOGV("PreProcessingFx_Command cmdCode Case: "
Eric Laurenta9390d42011-06-17 20:17:17 -07001488 "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
1489 return -EINVAL;
1490 }
1491 if (effect->ops->set_parameter) {
1492 *(int *)pReplyData = effect->ops->set_parameter(effect,
1493 (void *)p->data,
1494 p->data + p->psize);
1495 }
1496 } break;
1497
1498 case EFFECT_CMD_ENABLE:
Eric Laurent0f714a42015-06-19 15:33:57 -07001499 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001500 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001501 return -EINVAL;
1502 }
1503 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
1504 break;
1505
1506 case EFFECT_CMD_DISABLE:
Eric Laurent0f714a42015-06-19 15:33:57 -07001507 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)){
Steve Block3856b092011-10-20 11:56:00 +01001508 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001509 return -EINVAL;
1510 }
1511 *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1512 break;
1513
1514 case EFFECT_CMD_SET_DEVICE:
1515 case EFFECT_CMD_SET_INPUT_DEVICE:
1516 if (pCmdData == NULL ||
1517 cmdSize != sizeof(uint32_t)) {
Steve Block3856b092011-10-20 11:56:00 +01001518 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
Eric Laurenta9390d42011-06-17 20:17:17 -07001519 return -EINVAL;
1520 }
1521
1522 if (effect->ops->set_device) {
1523 effect->ops->set_device(effect, *(uint32_t *)pCmdData);
1524 }
1525 break;
1526
1527 case EFFECT_CMD_SET_VOLUME:
1528 case EFFECT_CMD_SET_AUDIO_MODE:
1529 break;
1530
Eric Laurent3f9c84c2012-04-03 15:36:53 -07001531#ifdef DUAL_MIC_TEST
1532 ///// test commands start
1533 case PREPROC_CMD_DUAL_MIC_ENABLE: {
1534 if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
1535 pReplyData == NULL || replySize == NULL) {
1536 ALOGE("PreProcessingFx_Command cmdCode Case: "
1537 "PREPROC_CMD_DUAL_MIC_ENABLE: ERROR");
1538 *replySize = 0;
1539 return -EINVAL;
1540 }
1541 gDualMicEnabled = *(bool *)pCmdData;
1542 if (gDualMicEnabled) {
1543 effect->aux_channels_on = sHasAuxChannels[effect->procId];
1544 } else {
1545 effect->aux_channels_on = false;
1546 }
1547 effect->cur_channel_config = (effect->session->inChannelCount == 1) ?
1548 CHANNEL_CFG_MONO : CHANNEL_CFG_STEREO;
1549
1550 ALOGV("PREPROC_CMD_DUAL_MIC_ENABLE: %s", gDualMicEnabled ? "enabled" : "disabled");
1551 *replySize = sizeof(int);
1552 *(int *)pReplyData = 0;
1553 } break;
1554 case PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: {
1555 if (pCmdData == NULL|| pReplyData == NULL || replySize == NULL) {
1556 ALOGE("PreProcessingFx_Command cmdCode Case: "
1557 "PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: ERROR");
1558 *replySize = 0;
1559 return -EINVAL;
1560 }
1561 pthread_mutex_lock(&gPcmDumpLock);
1562 if (gPcmDumpFh != NULL) {
1563 fclose(gPcmDumpFh);
1564 gPcmDumpFh = NULL;
1565 }
1566 char *path = strndup((char *)pCmdData, cmdSize);
1567 gPcmDumpFh = fopen((char *)path, "wb");
1568 pthread_mutex_unlock(&gPcmDumpLock);
1569 ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: path %s gPcmDumpFh %p",
1570 path, gPcmDumpFh);
1571 ALOGE_IF(gPcmDumpFh <= 0, "gPcmDumpFh open error %d %s", errno, strerror(errno));
1572 free(path);
1573 *replySize = sizeof(int);
1574 *(int *)pReplyData = 0;
1575 } break;
1576 case PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: {
1577 if (pReplyData == NULL || replySize == NULL) {
1578 ALOGE("PreProcessingFx_Command cmdCode Case: "
1579 "PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: ERROR");
1580 *replySize = 0;
1581 return -EINVAL;
1582 }
1583 pthread_mutex_lock(&gPcmDumpLock);
1584 if (gPcmDumpFh != NULL) {
1585 fclose(gPcmDumpFh);
1586 gPcmDumpFh = NULL;
1587 }
1588 pthread_mutex_unlock(&gPcmDumpLock);
1589 ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP");
1590 *replySize = sizeof(int);
1591 *(int *)pReplyData = 0;
1592 } break;
1593 ///// test commands end
1594
1595 case EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: {
1596 if(!gDualMicEnabled) {
1597 return -EINVAL;
1598 }
1599 if (pCmdData == NULL|| cmdSize != 2 * sizeof(uint32_t) ||
1600 pReplyData == NULL || replySize == NULL) {
1601 ALOGE("PreProcessingFx_Command cmdCode Case: "
1602 "EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: ERROR");
1603 *replySize = 0;
1604 return -EINVAL;
1605 }
1606 if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS ||
1607 !effect->aux_channels_on) {
1608 ALOGV("PreProcessingFx_Command feature EFFECT_FEATURE_AUX_CHANNELS not supported by"
1609 " fx %d", effect->procId);
1610 *(uint32_t *)pReplyData = -ENOSYS;
1611 *replySize = sizeof(uint32_t);
1612 break;
1613 }
1614 size_t num_configs = *((uint32_t *)pCmdData + 1);
1615 if (*replySize < (2 * sizeof(uint32_t) +
1616 num_configs * sizeof(channel_config_t))) {
1617 *replySize = 0;
1618 return -EINVAL;
1619 }
1620
1621 *((uint32_t *)pReplyData + 1) = CHANNEL_CFG_CNT;
1622 if (num_configs < CHANNEL_CFG_CNT ||
1623 *replySize < (2 * sizeof(uint32_t) +
1624 CHANNEL_CFG_CNT * sizeof(channel_config_t))) {
1625 *(uint32_t *)pReplyData = -ENOMEM;
1626 } else {
1627 num_configs = CHANNEL_CFG_CNT;
1628 *(uint32_t *)pReplyData = 0;
1629 }
1630 ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS num config %d",
1631 num_configs);
1632
1633 *replySize = 2 * sizeof(uint32_t) + num_configs * sizeof(channel_config_t);
1634 *((uint32_t *)pReplyData + 1) = num_configs;
1635 memcpy((uint32_t *)pReplyData + 2, &sDualMicConfigs, num_configs * sizeof(channel_config_t));
1636 } break;
1637 case EFFECT_CMD_GET_FEATURE_CONFIG:
1638 if(!gDualMicEnabled) {
1639 return -EINVAL;
1640 }
1641 if (pCmdData == NULL|| cmdSize != sizeof(uint32_t) ||
1642 pReplyData == NULL || replySize == NULL ||
1643 *replySize < sizeof(uint32_t) + sizeof(channel_config_t)) {
1644 ALOGE("PreProcessingFx_Command cmdCode Case: "
1645 "EFFECT_CMD_GET_FEATURE_CONFIG: ERROR");
1646 return -EINVAL;
1647 }
1648 if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1649 *(uint32_t *)pReplyData = -ENOSYS;
1650 *replySize = sizeof(uint32_t);
1651 break;
1652 }
1653 ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_CONFIG");
1654 *(uint32_t *)pReplyData = 0;
1655 *replySize = sizeof(uint32_t) + sizeof(channel_config_t);
1656 memcpy((uint32_t *)pReplyData + 1,
1657 &sDualMicConfigs[effect->cur_channel_config],
1658 sizeof(channel_config_t));
1659 break;
1660 case EFFECT_CMD_SET_FEATURE_CONFIG: {
1661 ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG: "
1662 "gDualMicEnabled %d effect->aux_channels_on %d",
1663 gDualMicEnabled, effect->aux_channels_on);
1664 if(!gDualMicEnabled) {
1665 return -EINVAL;
1666 }
1667 if (pCmdData == NULL|| cmdSize != (sizeof(uint32_t) + sizeof(channel_config_t)) ||
1668 pReplyData == NULL || replySize == NULL ||
1669 *replySize < sizeof(uint32_t)) {
1670 ALOGE("PreProcessingFx_Command cmdCode Case: "
1671 "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1672 "pCmdData %p cmdSize %d pReplyData %p replySize %p *replySize %d",
1673 pCmdData, cmdSize, pReplyData, replySize, replySize ? *replySize : -1);
1674 return -EINVAL;
1675 }
1676 *replySize = sizeof(uint32_t);
1677 if (*(uint32_t *)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1678 *(uint32_t *)pReplyData = -ENOSYS;
1679 ALOGV("PreProcessingFx_Command cmdCode Case: "
1680 "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1681 "CmdData %d effect->aux_channels_on %d",
1682 *(uint32_t *)pCmdData, effect->aux_channels_on);
1683 break;
1684 }
1685 size_t i;
1686 for (i = 0; i < CHANNEL_CFG_CNT;i++) {
1687 if (memcmp((uint32_t *)pCmdData + 1,
1688 &sDualMicConfigs[i], sizeof(channel_config_t)) == 0) {
1689 break;
1690 }
1691 }
1692 if (i == CHANNEL_CFG_CNT) {
1693 *(uint32_t *)pReplyData = -EINVAL;
1694 ALOGW("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG invalid config"
1695 "[%08x].[%08x]", *((uint32_t *)pCmdData + 1), *((uint32_t *)pCmdData + 2));
1696 } else {
1697 effect->cur_channel_config = i;
1698 *(uint32_t *)pReplyData = 0;
1699 ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG New config"
1700 "[%08x].[%08x]", sDualMicConfigs[i].main_channels, sDualMicConfigs[i].aux_channels);
1701 }
1702 } break;
1703#endif
Eric Laurenta9390d42011-06-17 20:17:17 -07001704 default:
1705 return -EINVAL;
1706 }
1707 return 0;
1708}
1709
1710
1711int PreProcessingFx_GetDescriptor(effect_handle_t self,
1712 effect_descriptor_t *pDescriptor)
1713{
1714 preproc_effect_t * effect = (preproc_effect_t *) self;
1715
1716 if (effect == NULL || pDescriptor == NULL) {
1717 return -EINVAL;
1718 }
1719
Glenn Kastena189a682012-02-20 12:16:30 -08001720 *pDescriptor = *sDescriptors[effect->procId];
Eric Laurenta9390d42011-06-17 20:17:17 -07001721
1722 return 0;
1723}
1724
1725int PreProcessingFx_ProcessReverse(effect_handle_t self,
1726 audio_buffer_t *inBuffer,
Eric Laurent0f714a42015-06-19 15:33:57 -07001727 audio_buffer_t *outBuffer __unused)
Eric Laurenta9390d42011-06-17 20:17:17 -07001728{
1729 preproc_effect_t * effect = (preproc_effect_t *)self;
1730 int status = 0;
1731
1732 if (effect == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001733 ALOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
Eric Laurenta9390d42011-06-17 20:17:17 -07001734 return -EINVAL;
1735 }
1736 preproc_session_t * session = (preproc_session_t *)effect->session;
1737
1738 if (inBuffer == NULL || inBuffer->raw == NULL){
Steve Block5ff1dd52012-01-05 23:22:43 +00001739 ALOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
Eric Laurenta9390d42011-06-17 20:17:17 -07001740 return -EINVAL;
1741 }
1742
1743 session->revProcessedMsk |= (1<<effect->procId);
1744
Steve Block3856b092011-10-20 11:56:00 +01001745// ALOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk %08x",
Eric Laurenta9390d42011-06-17 20:17:17 -07001746// inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
1747
1748
1749 if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
1750 effect->session->revProcessedMsk = 0;
1751 if (session->revResampler != NULL) {
1752 size_t fr = session->frameCount - session->framesRev;
1753 if (inBuffer->frameCount < fr) {
1754 fr = inBuffer->frameCount;
1755 }
1756 if (session->revBufSize < session->framesRev + fr) {
1757 session->revBufSize = session->framesRev + fr;
1758 session->revBuf = (int16_t *)realloc(session->revBuf,
1759 session->revBufSize * session->inChannelCount * sizeof(int16_t));
1760 }
1761 memcpy(session->revBuf + session->framesRev * session->inChannelCount,
1762 inBuffer->s16,
1763 fr * session->inChannelCount * sizeof(int16_t));
1764
1765 session->framesRev += fr;
1766 inBuffer->frameCount = fr;
1767 if (session->framesRev < session->frameCount) {
1768 return 0;
1769 }
Kévin PETIT377b2ec2014-02-03 12:35:36 +00001770 spx_uint32_t frIn = session->framesRev;
1771 spx_uint32_t frOut = session->apmFrameCount;
Eric Laurenta9390d42011-06-17 20:17:17 -07001772 if (session->inChannelCount == 1) {
1773 speex_resampler_process_int(session->revResampler,
1774 0,
1775 session->revBuf,
1776 &frIn,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001777 session->revFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001778 &frOut);
1779 } else {
1780 speex_resampler_process_interleaved_int(session->revResampler,
1781 session->revBuf,
1782 &frIn,
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001783 session->revFrame->data_,
Eric Laurenta9390d42011-06-17 20:17:17 -07001784 &frOut);
1785 }
1786 memcpy(session->revBuf,
1787 session->revBuf + frIn * session->inChannelCount,
1788 (session->framesRev - frIn) * session->inChannelCount * sizeof(int16_t));
1789 session->framesRev -= frIn;
1790 } else {
1791 size_t fr = session->frameCount - session->framesRev;
1792 if (inBuffer->frameCount < fr) {
1793 fr = inBuffer->frameCount;
1794 }
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001795 memcpy(session->revFrame->data_ + session->framesRev * session->inChannelCount,
Eric Laurenta9390d42011-06-17 20:17:17 -07001796 inBuffer->s16,
1797 fr * session->inChannelCount * sizeof(int16_t));
1798 session->framesRev += fr;
1799 inBuffer->frameCount = fr;
1800 if (session->framesRev < session->frameCount) {
1801 return 0;
1802 }
1803 session->framesRev = 0;
1804 }
Chih-Hung Hsiehde7fa312015-10-13 10:58:08 -07001805 session->revFrame->samples_per_channel_ =
Eric Laurenta9390d42011-06-17 20:17:17 -07001806 session->apmFrameCount * session->inChannelCount;
1807 effect->session->apm->AnalyzeReverseStream(session->revFrame);
1808 return 0;
1809 } else {
1810 return -ENODATA;
1811 }
1812}
1813
1814
1815// effect_handle_t interface implementation for effect
1816const struct effect_interface_s sEffectInterface = {
1817 PreProcessingFx_Process,
1818 PreProcessingFx_Command,
1819 PreProcessingFx_GetDescriptor,
1820 NULL
1821};
1822
1823const struct effect_interface_s sEffectInterfaceReverse = {
1824 PreProcessingFx_Process,
1825 PreProcessingFx_Command,
1826 PreProcessingFx_GetDescriptor,
1827 PreProcessingFx_ProcessReverse
1828};
1829
1830//------------------------------------------------------------------------------
1831// Effect Library Interface Implementation
1832//------------------------------------------------------------------------------
1833
Glenn Kasten5e92a782012-01-30 07:40:52 -08001834int PreProcessingLib_Create(const effect_uuid_t *uuid,
Eric Laurenta9390d42011-06-17 20:17:17 -07001835 int32_t sessionId,
1836 int32_t ioId,
1837 effect_handle_t *pInterface)
1838{
Steve Block3856b092011-10-20 11:56:00 +01001839 ALOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
Eric Laurenta9390d42011-06-17 20:17:17 -07001840
1841 int status;
1842 const effect_descriptor_t *desc;
1843 preproc_session_t *session;
1844 uint32_t procId;
1845
1846 if (PreProc_Init() != 0) {
1847 return sInitStatus;
1848 }
1849 desc = PreProc_GetDescriptor(uuid);
1850 if (desc == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +00001851 ALOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
Eric Laurenta9390d42011-06-17 20:17:17 -07001852 return -EINVAL;
1853 }
1854 procId = UuidToProcId(&desc->type);
1855
1856 session = PreProc_GetSession(procId, sessionId, ioId);
1857 if (session == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +00001858 ALOGW("EffectCreate: no more session available");
Eric Laurenta9390d42011-06-17 20:17:17 -07001859 return -EINVAL;
1860 }
1861
1862 status = Session_CreateEffect(session, procId, pInterface);
1863
1864 if (status < 0 && session->createdMsk == 0) {
1865 session->io = 0;
1866 }
1867 return status;
1868}
1869
1870int PreProcessingLib_Release(effect_handle_t interface)
1871{
1872 int status;
Steve Block3856b092011-10-20 11:56:00 +01001873 ALOGV("EffectRelease start %p", interface);
Eric Laurenta9390d42011-06-17 20:17:17 -07001874 if (PreProc_Init() != 0) {
1875 return sInitStatus;
1876 }
1877
1878 preproc_effect_t *fx = (preproc_effect_t *)interface;
1879
1880 if (fx->session->io == 0) {
1881 return -EINVAL;
1882 }
1883 return Session_ReleaseEffect(fx->session, fx);
1884}
1885
Glenn Kasten5e92a782012-01-30 07:40:52 -08001886int PreProcessingLib_GetDescriptor(const effect_uuid_t *uuid,
Eric Laurenta9390d42011-06-17 20:17:17 -07001887 effect_descriptor_t *pDescriptor) {
1888
1889 if (pDescriptor == NULL || uuid == NULL){
1890 return -EINVAL;
1891 }
1892
1893 const effect_descriptor_t *desc = PreProc_GetDescriptor(uuid);
1894 if (desc == NULL) {
Steve Block3856b092011-10-20 11:56:00 +01001895 ALOGV("PreProcessingLib_GetDescriptor() not found");
Eric Laurenta9390d42011-06-17 20:17:17 -07001896 return -EINVAL;
1897 }
1898
Steve Block3856b092011-10-20 11:56:00 +01001899 ALOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
Eric Laurenta9390d42011-06-17 20:17:17 -07001900
Glenn Kastena189a682012-02-20 12:16:30 -08001901 *pDescriptor = *desc;
Eric Laurenta9390d42011-06-17 20:17:17 -07001902 return 0;
1903}
1904
Marco Nelissen7f16b192012-10-25 16:05:57 -07001905// This is the only symbol that needs to be exported
1906__attribute__ ((visibility ("default")))
Eric Laurenta9390d42011-06-17 20:17:17 -07001907audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
synergydevc9d8ea72013-10-19 22:51:33 -07001908 .tag = AUDIO_EFFECT_LIBRARY_TAG,
1909 .version = EFFECT_LIBRARY_API_VERSION,
1910 .name = "Audio Preprocessing Library",
1911 .implementor = "The Android Open Source Project",
1912 .create_effect = PreProcessingLib_Create,
1913 .release_effect = PreProcessingLib_Release,
1914 .get_descriptor = PreProcessingLib_GetDescriptor
Eric Laurenta9390d42011-06-17 20:17:17 -07001915};
1916
1917}; // extern "C"