1 /*
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 <audio_effects/effect_aec.h>
22 #include <audio_effects/effect_agc.h>
23 #include <hardware/audio_effect.h>
24 #include <utils/Log.h>
25 #include <utils/Timers.h>
26 #include <audio_effects/effect_agc2.h>
27 #include <audio_effects/effect_ns.h>
28 #include <audio_processing.h>
29 #include <module_common_types.h>
30
31 // undefine to perform multi channels API functional tests
32 //#define DUAL_MIC_TEST
33
34 //------------------------------------------------------------------------------
35 // local definitions
36 //------------------------------------------------------------------------------
37
38 // maximum number of sessions
39 #define PREPROC_NUM_SESSIONS 8
40
41 // types of pre processing modules
42 enum preproc_id {
43 PREPROC_AGC, // Automatic Gain Control
44 PREPROC_AGC2, // Automatic Gain Control 2
45 PREPROC_AEC, // Acoustic Echo Canceler
46 PREPROC_NS, // Noise Suppressor
47 PREPROC_NUM_EFFECTS
48 };
49
50 // Session state
51 enum preproc_session_state {
52 PREPROC_SESSION_STATE_INIT, // initialized
53 PREPROC_SESSION_STATE_CONFIG // configuration received
54 };
55
56 // Effect/Preprocessor state
57 enum 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
65 typedef void* preproc_fx_handle_t;
66
67 typedef struct preproc_session_s preproc_session_t;
68 typedef struct preproc_effect_s preproc_effect_t;
69 typedef 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.
73 struct 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, uint32_t* size, void* value);
81 int (*set_device)(preproc_effect_t* fx, uint32_t device);
82 };
83
84 // Effect context
85 struct 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
92 uint32_t type; // subtype of effect
93 #ifdef DUAL_MIC_TEST
94 bool aux_channels_on; // support auxiliary channels
95 size_t cur_channel_config; // current auciliary channel configuration
96 #endif
97 };
98
99 // Session context
100 struct preproc_session_s {
101 struct preproc_effect_s effects[PREPROC_NUM_EFFECTS]; // effects in this session
102 uint32_t state; // current state (enum preproc_session_state)
103 int id; // audio session ID
104 int io; // handle of input stream this session is on
105 rtc::scoped_refptr<webrtc::AudioProcessing>
106 apm; // handle on webRTC audio processing module (APM)
107 // Audio Processing module builder
108 webrtc::AudioProcessingBuilder ap_builder;
109 // frameCount represents the size of the buffers used for processing, and must represent 10ms.
110 size_t frameCount;
111 uint32_t samplingRate; // sampling rate at effect process interface
112 uint32_t inChannelCount; // input channel count
113 uint32_t outChannelCount; // output channel count
114 uint32_t createdMsk; // bit field containing IDs of crested pre processors
115 uint32_t enabledMsk; // bit field containing IDs of enabled pre processors
116 uint32_t processedMsk; // bit field containing IDs of pre processors already
117 // processed in current round
118 // audio config strucutre
119 webrtc::AudioProcessing::Config config;
120 webrtc::StreamConfig inputConfig; // input stream configuration
121 webrtc::StreamConfig outputConfig; // output stream configuration
122 uint32_t revChannelCount; // number of channels on reverse stream
123 uint32_t revEnabledMsk; // bit field containing IDs of enabled pre processors
124 // with reverse channel
125 uint32_t revProcessedMsk; // bit field containing IDs of pre processors with reverse
126 // channel already processed in current round
127 webrtc::StreamConfig revConfig; // reverse stream configuration.
128 };
129
130 #ifdef DUAL_MIC_TEST
131 enum {
132 PREPROC_CMD_DUAL_MIC_ENABLE = EFFECT_CMD_FIRST_PROPRIETARY, // enable dual mic mode
133 PREPROC_CMD_DUAL_MIC_PCM_DUMP_START, // start pcm capture
134 PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP // stop pcm capture
135 };
136
137 enum {
138 CHANNEL_CFG_MONO,
139 CHANNEL_CFG_STEREO,
140 CHANNEL_CFG_MONO_AUX,
141 CHANNEL_CFG_STEREO_AUX,
142 CHANNEL_CFG_CNT,
143 CHANNEL_CFG_FIRST_AUX = CHANNEL_CFG_MONO_AUX,
144 };
145
146 const channel_config_t sDualMicConfigs[CHANNEL_CFG_CNT] = {
147 {AUDIO_CHANNEL_IN_MONO, 0},
148 {AUDIO_CHANNEL_IN_STEREO, 0},
149 {AUDIO_CHANNEL_IN_FRONT, AUDIO_CHANNEL_IN_BACK},
150 {AUDIO_CHANNEL_IN_STEREO, AUDIO_CHANNEL_IN_RIGHT}};
151
152 bool sHasAuxChannels[PREPROC_NUM_EFFECTS] = {
153 false, // PREPROC_AGC
154 false, // PREPROC_AGC2
155 true, // PREPROC_AEC
156 true, // PREPROC_NS
157 };
158
159 bool gDualMicEnabled;
160 FILE* gPcmDumpFh;
161 static pthread_mutex_t gPcmDumpLock = PTHREAD_MUTEX_INITIALIZER;
162 #endif
163
164 //------------------------------------------------------------------------------
165 // Effect descriptors
166 //------------------------------------------------------------------------------
167
168 // UUIDs for effect types have been generated from http://www.itu.int/ITU-T/asn1/uuid.html
169 // as the pre processing effects are not defined by OpenSL ES
170
171 // Automatic Gain Control
172 static const effect_descriptor_t sAgcDescriptor = {
173 {0x0a8abfe0, 0x654c, 0x11e0, 0xba26, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
174 {0xaa8130e0, 0x66fc, 0x11e0, 0xbad0, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
175 EFFECT_CONTROL_API_VERSION,
176 (EFFECT_FLAG_TYPE_PRE_PROC | EFFECT_FLAG_DEVICE_IND),
177 0, // FIXME indicate CPU load
178 0, // FIXME indicate memory usage
179 "Automatic Gain Control",
180 "The Android Open Source Project"};
181
182 // Automatic Gain Control 2
183 static const effect_descriptor_t sAgc2Descriptor = {
184 {0xae3c653b, 0xbe18, 0x4ab8, 0x8938, {0x41, 0x8f, 0x0a, 0x7f, 0x06, 0xac}}, // type
185 {0x89f38e65, 0xd4d2, 0x4d64, 0xad0e, {0x2b, 0x3e, 0x79, 0x9e, 0xa8, 0x86}}, // uuid
186 EFFECT_CONTROL_API_VERSION,
187 (EFFECT_FLAG_TYPE_PRE_PROC | EFFECT_FLAG_DEVICE_IND),
188 0, // FIXME indicate CPU load
189 0, // FIXME indicate memory usage
190 "Automatic Gain Control 2",
191 "The Android Open Source Project"};
192
193 // Acoustic Echo Cancellation
194 static const effect_descriptor_t sAecDescriptor = {
195 {0x7b491460, 0x8d4d, 0x11e0, 0xbd61, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
196 {0xbb392ec0, 0x8d4d, 0x11e0, 0xa896, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
197 EFFECT_CONTROL_API_VERSION,
198 (EFFECT_FLAG_TYPE_PRE_PROC | EFFECT_FLAG_DEVICE_IND),
199 0, // FIXME indicate CPU load
200 0, // FIXME indicate memory usage
201 "Acoustic Echo Canceler",
202 "The Android Open Source Project"};
203
204 // Noise suppression
205 static const effect_descriptor_t sNsDescriptor = {
206 {0x58b4b260, 0x8e06, 0x11e0, 0xaa8e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
207 {0xc06c8400, 0x8e06, 0x11e0, 0x9cb6, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
208 EFFECT_CONTROL_API_VERSION,
209 (EFFECT_FLAG_TYPE_PRE_PROC | EFFECT_FLAG_DEVICE_IND),
210 0, // FIXME indicate CPU load
211 0, // FIXME indicate memory usage
212 "Noise Suppression",
213 "The Android Open Source Project"};
214
215 static const effect_descriptor_t* sDescriptors[PREPROC_NUM_EFFECTS] = {&sAgcDescriptor,
216 &sAgc2Descriptor,
217 &sAecDescriptor,
218 &sNsDescriptor};
219
220 //------------------------------------------------------------------------------
221 // Helper functions
222 //------------------------------------------------------------------------------
223
224 const effect_uuid_t* const sUuidToPreProcTable[PREPROC_NUM_EFFECTS] = {FX_IID_AGC,
225 FX_IID_AGC2,
226 FX_IID_AEC, FX_IID_NS};
227
ProcIdToUuid(int procId)228 const effect_uuid_t* ProcIdToUuid(int procId) {
229 if (procId >= PREPROC_NUM_EFFECTS) {
230 return EFFECT_UUID_NULL;
231 }
232 return sUuidToPreProcTable[procId];
233 }
234
UuidToProcId(const effect_uuid_t * uuid)235 uint32_t UuidToProcId(const effect_uuid_t* uuid) {
236 size_t i;
237 for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
238 if (memcmp(uuid, sUuidToPreProcTable[i], sizeof(*uuid)) == 0) {
239 break;
240 }
241 }
242 return i;
243 }
244
HasReverseStream(uint32_t procId)245 bool HasReverseStream(uint32_t procId) {
246 if (procId == PREPROC_AEC) {
247 return true;
248 }
249 return false;
250 }
251
252 //------------------------------------------------------------------------------
253 // Automatic Gain Control (AGC)
254 //------------------------------------------------------------------------------
255
256 static const int kAgcDefaultTargetLevel = 3;
257 static const int kAgcDefaultCompGain = 9;
258 static const bool kAgcDefaultLimiter = true;
259
Agc2Init(preproc_effect_t * effect)260 int Agc2Init(preproc_effect_t* effect) {
261 ALOGV("Agc2Init");
262 effect->session->config = effect->session->apm->GetConfig();
263 effect->session->config.gain_controller2.fixed_digital.gain_db = 0.f;
264 effect->session->apm->ApplyConfig(effect->session->config);
265 return 0;
266 }
267
AgcInit(preproc_effect_t * effect)268 int AgcInit(preproc_effect_t* effect) {
269 ALOGV("AgcInit");
270 effect->session->config = effect->session->apm->GetConfig();
271 effect->session->config.gain_controller1.target_level_dbfs = kAgcDefaultTargetLevel;
272 effect->session->config.gain_controller1.compression_gain_db = kAgcDefaultCompGain;
273 effect->session->config.gain_controller1.enable_limiter = kAgcDefaultLimiter;
274 effect->session->apm->ApplyConfig(effect->session->config);
275 return 0;
276 }
277
Agc2Create(preproc_effect_t * effect)278 int Agc2Create(preproc_effect_t* effect) {
279 Agc2Init(effect);
280 return 0;
281 }
282
AgcCreate(preproc_effect_t * effect)283 int AgcCreate(preproc_effect_t* effect) {
284 AgcInit(effect);
285 return 0;
286 }
287
Agc2GetParameter(preproc_effect_t * effect,void * pParam,uint32_t * pValueSize,void * pValue)288 int Agc2GetParameter(preproc_effect_t* effect, void* pParam, uint32_t* pValueSize, void* pValue) {
289 int status = 0;
290 uint32_t param = *(uint32_t*)pParam;
291 agc2_settings_t* pProperties = (agc2_settings_t*)pValue;
292
293 switch (param) {
294 case AGC2_PARAM_FIXED_DIGITAL_GAIN:
295 if (*pValueSize < sizeof(float)) {
296 *pValueSize = 0.f;
297 return -EINVAL;
298 }
299 break;
300 case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
301 if (*pValueSize < sizeof(int32_t)) {
302 *pValueSize = 0;
303 return -EINVAL;
304 }
305 break;
306 case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
307 if (*pValueSize < sizeof(float)) {
308 *pValueSize = 0.f;
309 return -EINVAL;
310 }
311 break;
312 case AGC2_PARAM_PROPERTIES:
313 if (*pValueSize < sizeof(agc2_settings_t)) {
314 *pValueSize = 0;
315 return -EINVAL;
316 }
317 break;
318
319 default:
320 ALOGW("Agc2GetParameter() unknown param %08x", param);
321 status = -EINVAL;
322 break;
323 }
324
325 effect->session->config = effect->session->apm->GetConfig();
326 switch (param) {
327 case AGC2_PARAM_FIXED_DIGITAL_GAIN:
328 *(float*)pValue =
329 (float)(effect->session->config.gain_controller2.fixed_digital.gain_db);
330 ALOGV("Agc2GetParameter() target level %f dB", *(float*)pValue);
331 break;
332 case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
333 // WebRTC only supports RMS level estimator now
334 *(uint32_t*)pValue = (uint32_t)(0);
335 ALOGV("Agc2GetParameter() level estimator RMS");
336 break;
337 case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
338 *(float*)pValue = (float)(2.0);
339 ALOGV("Agc2GetParameter() extra saturation margin %f dB", *(float*)pValue);
340 break;
341 case AGC2_PARAM_PROPERTIES:
342 pProperties->fixedDigitalGain =
343 (float)(effect->session->config.gain_controller2.fixed_digital.gain_db);
344 pProperties->level_estimator = 0;
345 pProperties->extraSaturationMargin = 2.0;
346 break;
347 default:
348 ALOGW("Agc2GetParameter() unknown param %d", param);
349 status = -EINVAL;
350 break;
351 }
352
353 return status;
354 }
355
AgcGetParameter(preproc_effect_t * effect,void * pParam,uint32_t * pValueSize,void * pValue)356 int AgcGetParameter(preproc_effect_t* effect, void* pParam, uint32_t* pValueSize, void* pValue) {
357 int status = 0;
358 uint32_t param = *(uint32_t*)pParam;
359 t_agc_settings* pProperties = (t_agc_settings*)pValue;
360
361 switch (param) {
362 case AGC_PARAM_TARGET_LEVEL:
363 case AGC_PARAM_COMP_GAIN:
364 if (*pValueSize < sizeof(int16_t)) {
365 *pValueSize = 0;
366 return -EINVAL;
367 }
368 break;
369 case AGC_PARAM_LIMITER_ENA:
370 if (*pValueSize < sizeof(bool)) {
371 *pValueSize = 0;
372 return -EINVAL;
373 }
374 break;
375 case AGC_PARAM_PROPERTIES:
376 if (*pValueSize < sizeof(t_agc_settings)) {
377 *pValueSize = 0;
378 return -EINVAL;
379 }
380 break;
381
382 default:
383 ALOGW("AgcGetParameter() unknown param %08x", param);
384 status = -EINVAL;
385 break;
386 }
387
388 effect->session->config = effect->session->apm->GetConfig();
389 switch (param) {
390 case AGC_PARAM_TARGET_LEVEL:
391 *(int16_t*)pValue =
392 (int16_t)(effect->session->config.gain_controller1.target_level_dbfs * -100);
393 ALOGV("AgcGetParameter() target level %d milliBels", *(int16_t*)pValue);
394 break;
395 case AGC_PARAM_COMP_GAIN:
396 *(int16_t*)pValue =
397 (int16_t)(effect->session->config.gain_controller1.compression_gain_db * -100);
398 ALOGV("AgcGetParameter() comp gain %d milliBels", *(int16_t*)pValue);
399 break;
400 case AGC_PARAM_LIMITER_ENA:
401 *(bool*)pValue = (bool)(effect->session->config.gain_controller1.enable_limiter);
402 ALOGV("AgcGetParameter() limiter enabled %s",
403 (*(int16_t*)pValue != 0) ? "true" : "false");
404 break;
405 case AGC_PARAM_PROPERTIES:
406 pProperties->targetLevel =
407 (int16_t)(effect->session->config.gain_controller1.target_level_dbfs * -100);
408 pProperties->compGain =
409 (int16_t)(effect->session->config.gain_controller1.compression_gain_db * -100);
410 pProperties->limiterEnabled =
411 (bool)(effect->session->config.gain_controller1.enable_limiter);
412 break;
413 default:
414 ALOGW("AgcGetParameter() unknown param %d", param);
415 status = -EINVAL;
416 break;
417 }
418 return status;
419 }
420
Agc2SetParameter(preproc_effect_t * effect,void * pParam,void * pValue)421 int Agc2SetParameter(preproc_effect_t* effect, void* pParam, void* pValue) {
422 int status = 0;
423 uint32_t param = *(uint32_t*)pParam;
424 float valueFloat = 0.f;
425 agc2_settings_t* pProperties = (agc2_settings_t*)pValue;
426 effect->session->config = effect->session->apm->GetConfig();
427 switch (param) {
428 case AGC2_PARAM_FIXED_DIGITAL_GAIN:
429 valueFloat = (float)(*(int32_t*)pValue);
430 ALOGV("Agc2SetParameter() fixed digital gain %f dB", valueFloat);
431 effect->session->config.gain_controller2.fixed_digital.gain_db = valueFloat;
432 break;
433 case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
434 ALOGV("Agc2SetParameter() level estimator %d", *(uint32_t*)pValue);
435 if (*(uint32_t*)pValue != 0) {
436 // only RMS is supported
437 status = -EINVAL;
438 }
439 break;
440 case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
441 valueFloat = (float)(*(int32_t*)pValue);
442 ALOGV("Agc2SetParameter() extra saturation margin %f dB", valueFloat);
443 if (valueFloat != 2.0) {
444 // extra_staturation_margin_db is no longer configurable in webrtc
445 status = -EINVAL;
446 }
447 break;
448 case AGC2_PARAM_PROPERTIES:
449 ALOGV("Agc2SetParameter() properties gain %f, level %d margin %f",
450 pProperties->fixedDigitalGain, pProperties->level_estimator,
451 pProperties->extraSaturationMargin);
452 effect->session->config.gain_controller2.fixed_digital.gain_db =
453 pProperties->fixedDigitalGain;
454 if (pProperties->level_estimator != 0 || pProperties->extraSaturationMargin != 2.0) {
455 status = -EINVAL;
456 }
457 break;
458 default:
459 ALOGW("Agc2SetParameter() unknown param %08x value %08x", param, *(uint32_t*)pValue);
460 status = -EINVAL;
461 break;
462 }
463 effect->session->apm->ApplyConfig(effect->session->config);
464
465 ALOGV("Agc2SetParameter() done status %d", status);
466
467 return status;
468 }
469
AgcSetParameter(preproc_effect_t * effect,void * pParam,void * pValue)470 int AgcSetParameter(preproc_effect_t* effect, void* pParam, void* pValue) {
471 int status = 0;
472 uint32_t param = *(uint32_t*)pParam;
473 t_agc_settings* pProperties = (t_agc_settings*)pValue;
474 effect->session->config = effect->session->apm->GetConfig();
475 switch (param) {
476 case AGC_PARAM_TARGET_LEVEL:
477 ALOGV("AgcSetParameter() target level %d milliBels", *(int16_t*)pValue);
478 effect->session->config.gain_controller1.target_level_dbfs =
479 (-(*(int16_t*)pValue / 100));
480 break;
481 case AGC_PARAM_COMP_GAIN:
482 ALOGV("AgcSetParameter() comp gain %d milliBels", *(int16_t*)pValue);
483 effect->session->config.gain_controller1.compression_gain_db =
484 (*(int16_t*)pValue / 100);
485 break;
486 case AGC_PARAM_LIMITER_ENA:
487 ALOGV("AgcSetParameter() limiter enabled %s", *(bool*)pValue ? "true" : "false");
488 effect->session->config.gain_controller1.enable_limiter = (*(bool*)pValue);
489 break;
490 case AGC_PARAM_PROPERTIES:
491 ALOGV("AgcSetParameter() properties level %d, gain %d limiter %d",
492 pProperties->targetLevel, pProperties->compGain, pProperties->limiterEnabled);
493 effect->session->config.gain_controller1.target_level_dbfs =
494 -(pProperties->targetLevel / 100);
495 effect->session->config.gain_controller1.compression_gain_db =
496 pProperties->compGain / 100;
497 effect->session->config.gain_controller1.enable_limiter = pProperties->limiterEnabled;
498 break;
499 default:
500 ALOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t*)pValue);
501 status = -EINVAL;
502 break;
503 }
504 effect->session->apm->ApplyConfig(effect->session->config);
505
506 ALOGV("AgcSetParameter() done status %d", status);
507
508 return status;
509 }
510
Agc2Enable(preproc_effect_t * effect)511 void Agc2Enable(preproc_effect_t* effect) {
512 effect->session->config = effect->session->apm->GetConfig();
513 effect->session->config.gain_controller2.enabled = true;
514 effect->session->apm->ApplyConfig(effect->session->config);
515 }
516
AgcEnable(preproc_effect_t * effect)517 void AgcEnable(preproc_effect_t* effect) {
518 effect->session->config = effect->session->apm->GetConfig();
519 effect->session->config.gain_controller1.enabled = true;
520 effect->session->apm->ApplyConfig(effect->session->config);
521 }
522
Agc2Disable(preproc_effect_t * effect)523 void Agc2Disable(preproc_effect_t* effect) {
524 effect->session->config = effect->session->apm->GetConfig();
525 effect->session->config.gain_controller2.enabled = false;
526 effect->session->apm->ApplyConfig(effect->session->config);
527 }
528
AgcDisable(preproc_effect_t * effect)529 void AgcDisable(preproc_effect_t* effect) {
530 effect->session->config = effect->session->apm->GetConfig();
531 effect->session->config.gain_controller1.enabled = false;
532 effect->session->apm->ApplyConfig(effect->session->config);
533 }
534
535 static const preproc_ops_t sAgcOps = {AgcCreate, AgcInit, NULL, AgcEnable, AgcDisable,
536 AgcSetParameter, AgcGetParameter, NULL};
537
538 static const preproc_ops_t sAgc2Ops = {Agc2Create, Agc2Init, NULL,
539 Agc2Enable, Agc2Disable, Agc2SetParameter,
540 Agc2GetParameter, NULL};
541
542 //------------------------------------------------------------------------------
543 // Acoustic Echo Canceler (AEC)
544 //------------------------------------------------------------------------------
545
546
AecInit(preproc_effect_t * effect)547 int AecInit(preproc_effect_t* effect) {
548 ALOGV("AecInit");
549 effect->session->config = effect->session->apm->GetConfig();
550 effect->session->config.echo_canceller.mobile_mode = true;
551 effect->session->apm->ApplyConfig(effect->session->config);
552 return 0;
553 }
554
AecCreate(preproc_effect_t * effect)555 int AecCreate(preproc_effect_t* effect) {
556 AecInit(effect);
557 return 0;
558 }
559
AecGetParameter(preproc_effect_t * effect,void * pParam,uint32_t * pValueSize,void * pValue)560 int AecGetParameter(preproc_effect_t* effect, void* pParam, uint32_t* pValueSize, void* pValue) {
561 int status = 0;
562 uint32_t param = *(uint32_t*)pParam;
563
564 if (*pValueSize < sizeof(uint32_t)) {
565 return -EINVAL;
566 }
567 switch (param) {
568 case AEC_PARAM_ECHO_DELAY:
569 case AEC_PARAM_PROPERTIES:
570 *(uint32_t*)pValue = 1000 * effect->session->apm->stream_delay_ms();
571 ALOGV("AecGetParameter() echo delay %d us", *(uint32_t*)pValue);
572 break;
573 case AEC_PARAM_MOBILE_MODE:
574 effect->session->config = effect->session->apm->GetConfig();
575 *(uint32_t*)pValue = effect->session->config.echo_canceller.mobile_mode;
576 ALOGV("AecGetParameter() mobile mode %d us", *(uint32_t*)pValue);
577 break;
578 default:
579 ALOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t*)pValue);
580 status = -EINVAL;
581 break;
582 }
583 return status;
584 }
585
AecSetParameter(preproc_effect_t * effect,void * pParam,void * pValue)586 int AecSetParameter(preproc_effect_t* effect, void* pParam, void* pValue) {
587 int status = 0;
588 uint32_t param = *(uint32_t*)pParam;
589 uint32_t value = *(uint32_t*)pValue;
590
591 switch (param) {
592 case AEC_PARAM_ECHO_DELAY:
593 case AEC_PARAM_PROPERTIES:
594 status = effect->session->apm->set_stream_delay_ms(value / 1000);
595 ALOGV("AecSetParameter() echo delay %d us, status %d", value, status);
596 break;
597 case AEC_PARAM_MOBILE_MODE:
598 effect->session->config = effect->session->apm->GetConfig();
599 effect->session->config.echo_canceller.mobile_mode = value;
600 ALOGV("AecSetParameter() mobile mode %d us", value);
601 effect->session->apm->ApplyConfig(effect->session->config);
602 break;
603 default:
604 ALOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t*)pValue);
605 status = -EINVAL;
606 break;
607 }
608 return status;
609 }
610
AecEnable(preproc_effect_t * effect)611 void AecEnable(preproc_effect_t* effect) {
612 effect->session->config = effect->session->apm->GetConfig();
613 effect->session->config.echo_canceller.enabled = true;
614 effect->session->apm->ApplyConfig(effect->session->config);
615 }
616
AecDisable(preproc_effect_t * effect)617 void AecDisable(preproc_effect_t* effect) {
618 effect->session->config = effect->session->apm->GetConfig();
619 effect->session->config.echo_canceller.enabled = false;
620 effect->session->apm->ApplyConfig(effect->session->config);
621 }
622
AecSetDevice(preproc_effect_t * effect,uint32_t device)623 int AecSetDevice(preproc_effect_t* effect, uint32_t device) {
624 ALOGV("AecSetDevice %08x", device);
625
626 if (audio_is_input_device(device)) {
627 return 0;
628 }
629
630 return 0;
631 }
632
633 static const preproc_ops_t sAecOps = {AecCreate, AecInit, NULL,
634 AecEnable, AecDisable, AecSetParameter,
635 AecGetParameter, AecSetDevice};
636
637 //------------------------------------------------------------------------------
638 // Noise Suppression (NS)
639 //------------------------------------------------------------------------------
640
641 static const webrtc::AudioProcessing::Config::NoiseSuppression::Level kNsDefaultLevel =
642 webrtc::AudioProcessing::Config::NoiseSuppression::kModerate;
643
NsInit(preproc_effect_t * effect)644 int NsInit(preproc_effect_t* effect) {
645 ALOGV("NsInit");
646 effect->session->config = effect->session->apm->GetConfig();
647 effect->session->config.noise_suppression.level = kNsDefaultLevel;
648 effect->session->apm->ApplyConfig(effect->session->config);
649 effect->type = NS_TYPE_SINGLE_CHANNEL;
650 return 0;
651 }
652
NsCreate(preproc_effect_t * effect)653 int NsCreate(preproc_effect_t* effect) {
654 NsInit(effect);
655 return 0;
656 }
657
NsGetParameter(preproc_effect_t *,void *,uint32_t *,void *)658 int NsGetParameter(preproc_effect_t* /*effect __unused*/, void* /*pParam __unused*/,
659 uint32_t* /*pValueSize __unused*/, void* /*pValue __unused*/) {
660 int status = 0;
661 return status;
662 }
663
NsSetParameter(preproc_effect_t * effect,void * pParam,void * pValue)664 int NsSetParameter(preproc_effect_t* effect, void* pParam, void* pValue) {
665 int status = 0;
666 uint32_t param = *(uint32_t*)pParam;
667 uint32_t value = *(uint32_t*)pValue;
668 effect->session->config = effect->session->apm->GetConfig();
669 switch (param) {
670 case NS_PARAM_LEVEL:
671 effect->session->config.noise_suppression.level =
672 (webrtc::AudioProcessing::Config::NoiseSuppression::Level)value;
673 ALOGV("NsSetParameter() level %d", value);
674 break;
675 default:
676 ALOGW("NsSetParameter() unknown param %08x value %08x", param, value);
677 status = -EINVAL;
678 }
679 effect->session->apm->ApplyConfig(effect->session->config);
680
681 return status;
682 }
683
NsEnable(preproc_effect_t * effect)684 void NsEnable(preproc_effect_t* effect) {
685 effect->session->config = effect->session->apm->GetConfig();
686 effect->session->config.noise_suppression.enabled = true;
687 effect->session->apm->ApplyConfig(effect->session->config);
688 }
689
NsDisable(preproc_effect_t * effect)690 void NsDisable(preproc_effect_t* effect) {
691 ALOGV("NsDisable");
692 effect->session->config = effect->session->apm->GetConfig();
693 effect->session->config.noise_suppression.enabled = false;
694 effect->session->apm->ApplyConfig(effect->session->config);
695 }
696
697 static const preproc_ops_t sNsOps = {NsCreate, NsInit, NULL, NsEnable,
698 NsDisable, NsSetParameter, NsGetParameter, NULL};
699
700 static const preproc_ops_t* sPreProcOps[PREPROC_NUM_EFFECTS] = {&sAgcOps,
701 &sAgc2Ops,
702 &sAecOps, &sNsOps};
703
704 //------------------------------------------------------------------------------
705 // Effect functions
706 //------------------------------------------------------------------------------
707
708 void Session_SetProcEnabled(preproc_session_t* session, uint32_t procId, bool enabled);
709
710 extern "C" const struct effect_interface_s sEffectInterface;
711 extern "C" const struct effect_interface_s sEffectInterfaceReverse;
712
713 #define BAD_STATE_ABORT(from, to) LOG_ALWAYS_FATAL("Bad state transition from %d to %d", from, to);
714
Effect_SetState(preproc_effect_t * effect,uint32_t state)715 int Effect_SetState(preproc_effect_t* effect, uint32_t state) {
716 int status = 0;
717 ALOGV("Effect_SetState proc %d, new %d old %d", effect->procId, state, effect->state);
718 switch (state) {
719 case PREPROC_EFFECT_STATE_INIT:
720 switch (effect->state) {
721 case PREPROC_EFFECT_STATE_ACTIVE:
722 effect->ops->disable(effect);
723 Session_SetProcEnabled(effect->session, effect->procId, false);
724 break;
725 case PREPROC_EFFECT_STATE_CONFIG:
726 case PREPROC_EFFECT_STATE_CREATED:
727 case PREPROC_EFFECT_STATE_INIT:
728 break;
729 default:
730 BAD_STATE_ABORT(effect->state, state);
731 }
732 break;
733 case PREPROC_EFFECT_STATE_CREATED:
734 switch (effect->state) {
735 case PREPROC_EFFECT_STATE_INIT:
736 status = effect->ops->create(effect);
737 break;
738 case PREPROC_EFFECT_STATE_CREATED:
739 case PREPROC_EFFECT_STATE_ACTIVE:
740 case PREPROC_EFFECT_STATE_CONFIG:
741 ALOGE("Effect_SetState invalid transition");
742 status = -ENOSYS;
743 break;
744 default:
745 BAD_STATE_ABORT(effect->state, state);
746 }
747 break;
748 case PREPROC_EFFECT_STATE_CONFIG:
749 switch (effect->state) {
750 case PREPROC_EFFECT_STATE_INIT:
751 ALOGE("Effect_SetState invalid transition");
752 status = -ENOSYS;
753 break;
754 case PREPROC_EFFECT_STATE_ACTIVE:
755 effect->ops->disable(effect);
756 Session_SetProcEnabled(effect->session, effect->procId, false);
757 break;
758 case PREPROC_EFFECT_STATE_CREATED:
759 case PREPROC_EFFECT_STATE_CONFIG:
760 break;
761 default:
762 BAD_STATE_ABORT(effect->state, state);
763 }
764 break;
765 case PREPROC_EFFECT_STATE_ACTIVE:
766 switch (effect->state) {
767 case PREPROC_EFFECT_STATE_INIT:
768 case PREPROC_EFFECT_STATE_CREATED:
769 ALOGE("Effect_SetState invalid transition");
770 status = -ENOSYS;
771 break;
772 case PREPROC_EFFECT_STATE_ACTIVE:
773 // enabling an already enabled effect is just ignored
774 break;
775 case PREPROC_EFFECT_STATE_CONFIG:
776 effect->ops->enable(effect);
777 Session_SetProcEnabled(effect->session, effect->procId, true);
778 break;
779 default:
780 BAD_STATE_ABORT(effect->state, state);
781 }
782 break;
783 default:
784 BAD_STATE_ABORT(effect->state, state);
785 }
786 if (status == 0) {
787 effect->state = state;
788 }
789 return status;
790 }
791
Effect_Init(preproc_effect_t * effect,uint32_t procId)792 int Effect_Init(preproc_effect_t* effect, uint32_t procId) {
793 if (HasReverseStream(procId)) {
794 effect->itfe = &sEffectInterfaceReverse;
795 } else {
796 effect->itfe = &sEffectInterface;
797 }
798 effect->ops = sPreProcOps[procId];
799 effect->procId = procId;
800 effect->state = PREPROC_EFFECT_STATE_INIT;
801 return 0;
802 }
803
Effect_Create(preproc_effect_t * effect,preproc_session_t * session,effect_handle_t * interface)804 int Effect_Create(preproc_effect_t* effect, preproc_session_t* session,
805 effect_handle_t* interface) {
806 effect->session = session;
807 *interface = (effect_handle_t)&effect->itfe;
808 return Effect_SetState(effect, PREPROC_EFFECT_STATE_CREATED);
809 }
810
Effect_Release(preproc_effect_t * effect)811 int Effect_Release(preproc_effect_t* effect) {
812 return Effect_SetState(effect, PREPROC_EFFECT_STATE_INIT);
813 }
814
815 //------------------------------------------------------------------------------
816 // Session functions
817 //------------------------------------------------------------------------------
818
819 #define RESAMPLER_QUALITY SPEEX_RESAMPLER_QUALITY_VOIP
820
821 static const int kPreprocDefaultSr = 16000;
822 static const int kPreProcDefaultCnl = 1;
823
Session_Init(preproc_session_t * session)824 int Session_Init(preproc_session_t* session) {
825 size_t i;
826 int status = 0;
827
828 session->state = PREPROC_SESSION_STATE_INIT;
829 session->id = 0;
830 session->io = 0;
831 session->createdMsk = 0;
832 for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
833 status = Effect_Init(&session->effects[i], i);
834 }
835 return status;
836 }
837
Session_CreateEffect(preproc_session_t * session,int32_t procId,effect_handle_t * interface)838 extern "C" int Session_CreateEffect(preproc_session_t* session, int32_t procId,
839 effect_handle_t* interface) {
840 int status = -ENOMEM;
841
842 ALOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
843
844 if (session->createdMsk == 0) {
845 session->apm = session->ap_builder.Create();
846 if (session->apm == NULL) {
847 ALOGW("Session_CreateEffect could not get apm engine");
848 goto error;
849 }
850 session->frameCount = kPreprocDefaultSr / 100;
851 session->samplingRate = kPreprocDefaultSr;
852 session->inChannelCount = kPreProcDefaultCnl;
853 session->outChannelCount = kPreProcDefaultCnl;
854 session->inputConfig.set_sample_rate_hz(kPreprocDefaultSr);
855 session->inputConfig.set_num_channels(kPreProcDefaultCnl);
856 session->outputConfig.set_sample_rate_hz(kPreprocDefaultSr);
857 session->outputConfig.set_num_channels(kPreProcDefaultCnl);
858 session->revChannelCount = kPreProcDefaultCnl;
859 session->revConfig.set_sample_rate_hz(kPreprocDefaultSr);
860 session->revConfig.set_num_channels(kPreProcDefaultCnl);
861 session->enabledMsk = 0;
862 session->processedMsk = 0;
863 session->revEnabledMsk = 0;
864 session->revProcessedMsk = 0;
865 }
866 status = Effect_Create(&session->effects[procId], session, interface);
867 if (status < 0) {
868 goto error;
869 }
870 ALOGV("Session_CreateEffect OK");
871 session->createdMsk |= (1 << procId);
872 return status;
873
874 error:
875 if (session->createdMsk == 0) {
876 // Scoped_refptr will handle reference counting here
877 session->apm = nullptr;
878 }
879 return status;
880 }
881
Session_ReleaseEffect(preproc_session_t * session,preproc_effect_t * fx)882 int Session_ReleaseEffect(preproc_session_t* session, preproc_effect_t* fx) {
883 ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
884 session->createdMsk &= ~(1 << fx->procId);
885 if (session->createdMsk == 0) {
886 // Scoped_refptr will handle reference counting here
887 session->apm = nullptr;
888 session->id = 0;
889 }
890
891 return 0;
892 }
893
Session_SetConfig(preproc_session_t * session,effect_config_t * config)894 int Session_SetConfig(preproc_session_t* session, effect_config_t* config) {
895 uint32_t inCnl = audio_channel_count_from_in_mask(config->inputCfg.channels);
896 uint32_t outCnl = audio_channel_count_from_in_mask(config->outputCfg.channels);
897
898 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
899 config->inputCfg.format != config->outputCfg.format ||
900 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
901 return -EINVAL;
902 }
903
904 ALOGV("Session_SetConfig sr %d cnl %08x", config->inputCfg.samplingRate,
905 config->inputCfg.channels);
906
907 session->samplingRate = config->inputCfg.samplingRate;
908 session->frameCount = session->samplingRate / 100;
909 session->inChannelCount = inCnl;
910 session->outChannelCount = outCnl;
911 session->inputConfig.set_sample_rate_hz(session->samplingRate);
912 session->inputConfig.set_num_channels(inCnl);
913 session->outputConfig.set_sample_rate_hz(session->samplingRate);
914 session->outputConfig.set_num_channels(inCnl);
915
916 session->revChannelCount = inCnl;
917 session->revConfig.set_sample_rate_hz(session->samplingRate);
918 session->revConfig.set_num_channels(inCnl);
919
920 session->state = PREPROC_SESSION_STATE_CONFIG;
921 return 0;
922 }
923
Session_GetConfig(preproc_session_t * session,effect_config_t * config)924 void Session_GetConfig(preproc_session_t* session, effect_config_t* config) {
925 memset(config, 0, sizeof(effect_config_t));
926 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
927 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
928 config->inputCfg.channels = audio_channel_in_mask_from_count(session->inChannelCount);
929 // "out" doesn't mean output device, so this is the correct API to convert channel count to mask
930 config->outputCfg.channels = audio_channel_in_mask_from_count(session->outChannelCount);
931 config->inputCfg.mask = config->outputCfg.mask =
932 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
933 }
934
Session_SetReverseConfig(preproc_session_t * session,effect_config_t * config)935 int Session_SetReverseConfig(preproc_session_t* session, effect_config_t* config) {
936 if (config->inputCfg.samplingRate != config->outputCfg.samplingRate ||
937 config->inputCfg.format != config->outputCfg.format ||
938 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
939 return -EINVAL;
940 }
941
942 ALOGV("Session_SetReverseConfig sr %d cnl %08x", config->inputCfg.samplingRate,
943 config->inputCfg.channels);
944
945 if (session->state < PREPROC_SESSION_STATE_CONFIG) {
946 return -ENOSYS;
947 }
948 if (config->inputCfg.samplingRate != session->samplingRate ||
949 config->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) {
950 return -EINVAL;
951 }
952 uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
953 session->revChannelCount = inCnl;
954
955 return 0;
956 }
957
Session_GetReverseConfig(preproc_session_t * session,effect_config_t * config)958 void Session_GetReverseConfig(preproc_session_t* session, effect_config_t* config) {
959 memset(config, 0, sizeof(effect_config_t));
960 config->inputCfg.samplingRate = config->outputCfg.samplingRate = session->samplingRate;
961 config->inputCfg.format = config->outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
962 config->inputCfg.channels = config->outputCfg.channels =
963 audio_channel_in_mask_from_count(session->revChannelCount);
964 config->inputCfg.mask = config->outputCfg.mask =
965 (EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT);
966 }
967
Session_SetProcEnabled(preproc_session_t * session,uint32_t procId,bool enabled)968 void Session_SetProcEnabled(preproc_session_t* session, uint32_t procId, bool enabled) {
969 if (enabled) {
970 session->enabledMsk |= (1 << procId);
971 if (HasReverseStream(procId)) {
972 session->revEnabledMsk |= (1 << procId);
973 }
974 } else {
975 session->enabledMsk &= ~(1 << procId);
976 if (HasReverseStream(procId)) {
977 session->revEnabledMsk &= ~(1 << procId);
978 }
979 }
980 ALOGV("Session_SetProcEnabled proc %d, enabled %d enabledMsk %08x revEnabledMsk %08x", procId,
981 enabled, session->enabledMsk, session->revEnabledMsk);
982 session->processedMsk = 0;
983 if (HasReverseStream(procId)) {
984 session->revProcessedMsk = 0;
985 }
986 }
987
988 //------------------------------------------------------------------------------
989 // Bundle functions
990 //------------------------------------------------------------------------------
991
992 static int sInitStatus = 1;
993 static preproc_session_t sSessions[PREPROC_NUM_SESSIONS];
994
PreProc_GetSession(int32_t procId,int32_t sessionId,int32_t ioId)995 preproc_session_t* PreProc_GetSession(int32_t procId, int32_t sessionId, int32_t ioId) {
996 size_t i;
997 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
998 if (sSessions[i].id == sessionId) {
999 if (sSessions[i].createdMsk & (1 << procId)) {
1000 return NULL;
1001 }
1002 return &sSessions[i];
1003 }
1004 }
1005 for (i = 0; i < PREPROC_NUM_SESSIONS; i++) {
1006 if (sSessions[i].id == 0) {
1007 sSessions[i].id = sessionId;
1008 sSessions[i].io = ioId;
1009 return &sSessions[i];
1010 }
1011 }
1012 return NULL;
1013 }
1014
PreProc_Init()1015 int PreProc_Init() {
1016 size_t i;
1017 int status = 0;
1018
1019 if (sInitStatus <= 0) {
1020 return sInitStatus;
1021 }
1022 for (i = 0; i < PREPROC_NUM_SESSIONS && status == 0; i++) {
1023 status = Session_Init(&sSessions[i]);
1024 }
1025 sInitStatus = status;
1026 return sInitStatus;
1027 }
1028
PreProc_GetDescriptor(const effect_uuid_t * uuid)1029 const effect_descriptor_t* PreProc_GetDescriptor(const effect_uuid_t* uuid) {
1030 size_t i;
1031 for (i = 0; i < PREPROC_NUM_EFFECTS; i++) {
1032 if (memcmp(&sDescriptors[i]->uuid, uuid, sizeof(effect_uuid_t)) == 0) {
1033 return sDescriptors[i];
1034 }
1035 }
1036 return NULL;
1037 }
1038
1039 extern "C" {
1040
1041 //------------------------------------------------------------------------------
1042 // Effect Control Interface Implementation
1043 //------------------------------------------------------------------------------
1044
PreProcessingFx_Process(effect_handle_t self,audio_buffer_t * inBuffer,audio_buffer_t * outBuffer)1045 int PreProcessingFx_Process(effect_handle_t self, audio_buffer_t* inBuffer,
1046 audio_buffer_t* outBuffer) {
1047 preproc_effect_t* effect = (preproc_effect_t*)self;
1048
1049 if (effect == NULL) {
1050 ALOGV("PreProcessingFx_Process() ERROR effect == NULL");
1051 return -EINVAL;
1052 }
1053 preproc_session_t* session = (preproc_session_t*)effect->session;
1054
1055 if (inBuffer == NULL || inBuffer->raw == NULL || outBuffer == NULL || outBuffer->raw == NULL) {
1056 ALOGW("PreProcessingFx_Process() ERROR bad pointer");
1057 return -EINVAL;
1058 }
1059
1060 if (inBuffer->frameCount != outBuffer->frameCount) {
1061 ALOGW("inBuffer->frameCount %zu is not equal to outBuffer->frameCount %zu",
1062 inBuffer->frameCount, outBuffer->frameCount);
1063 return -EINVAL;
1064 }
1065
1066 if (inBuffer->frameCount != session->frameCount) {
1067 ALOGW("inBuffer->frameCount %zu != %zu representing 10ms at sampling rate %d",
1068 inBuffer->frameCount, session->frameCount, session->samplingRate);
1069 return -EINVAL;
1070 }
1071
1072 session->processedMsk |= (1 << effect->procId);
1073
1074 // ALOGV("PreProcessingFx_Process In %d frames enabledMsk %08x processedMsk %08x",
1075 // inBuffer->frameCount, session->enabledMsk, session->processedMsk);
1076 if ((session->processedMsk & session->enabledMsk) == session->enabledMsk) {
1077 effect->session->processedMsk = 0;
1078 if (int status = effect->session->apm->ProcessStream(
1079 (const int16_t* const)inBuffer->s16,
1080 (const webrtc::StreamConfig)effect->session->inputConfig,
1081 (const webrtc::StreamConfig)effect->session->outputConfig,
1082 (int16_t* const)outBuffer->s16);
1083 status != 0) {
1084 ALOGE("Process Stream failed with error %d\n", status);
1085 return status;
1086 }
1087 return 0;
1088 } else {
1089 return -ENODATA;
1090 }
1091 }
1092
PreProcessingFx_Command(effect_handle_t self,uint32_t cmdCode,uint32_t cmdSize,void * pCmdData,uint32_t * replySize,void * pReplyData)1093 int PreProcessingFx_Command(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize,
1094 void* pCmdData, uint32_t* replySize, void* pReplyData) {
1095 preproc_effect_t* effect = (preproc_effect_t*)self;
1096
1097 if (effect == NULL) {
1098 return -EINVAL;
1099 }
1100
1101 // ALOGV("PreProcessingFx_Command: command %d cmdSize %d",cmdCode, cmdSize);
1102
1103 switch (cmdCode) {
1104 case EFFECT_CMD_INIT:
1105 if (pReplyData == NULL || *replySize != sizeof(int)) {
1106 return -EINVAL;
1107 }
1108 if (effect->ops->init) {
1109 effect->ops->init(effect);
1110 }
1111 *(int*)pReplyData = 0;
1112 break;
1113
1114 case EFFECT_CMD_SET_CONFIG: {
1115 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) || pReplyData == NULL ||
1116 *replySize != sizeof(int)) {
1117 ALOGV("PreProcessingFx_Command cmdCode Case: "
1118 "EFFECT_CMD_SET_CONFIG: ERROR");
1119 return -EINVAL;
1120 }
1121 #ifdef DUAL_MIC_TEST
1122 // make sure that the config command is accepted by making as if all effects were
1123 // disabled: this is OK for functional tests
1124 uint32_t enabledMsk = effect->session->enabledMsk;
1125 if (gDualMicEnabled) {
1126 effect->session->enabledMsk = 0;
1127 }
1128 #endif
1129 *(int*)pReplyData = Session_SetConfig(effect->session, (effect_config_t*)pCmdData);
1130 #ifdef DUAL_MIC_TEST
1131 if (gDualMicEnabled) {
1132 effect->session->enabledMsk = enabledMsk;
1133 }
1134 #endif
1135 if (*(int*)pReplyData != 0) {
1136 break;
1137 }
1138 if (effect->state != PREPROC_EFFECT_STATE_ACTIVE) {
1139 *(int*)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1140 }
1141 } break;
1142
1143 case EFFECT_CMD_GET_CONFIG:
1144 if (pReplyData == NULL || *replySize != sizeof(effect_config_t)) {
1145 ALOGV("\tLVM_ERROR : PreProcessingFx_Command cmdCode Case: "
1146 "EFFECT_CMD_GET_CONFIG: ERROR");
1147 return -EINVAL;
1148 }
1149
1150 Session_GetConfig(effect->session, (effect_config_t*)pReplyData);
1151 break;
1152
1153 case EFFECT_CMD_SET_CONFIG_REVERSE:
1154 if (pCmdData == NULL || cmdSize != sizeof(effect_config_t) || pReplyData == NULL ||
1155 *replySize != sizeof(int)) {
1156 ALOGV("PreProcessingFx_Command cmdCode Case: "
1157 "EFFECT_CMD_SET_CONFIG_REVERSE: ERROR");
1158 return -EINVAL;
1159 }
1160 *(int*)pReplyData =
1161 Session_SetReverseConfig(effect->session, (effect_config_t*)pCmdData);
1162 if (*(int*)pReplyData != 0) {
1163 break;
1164 }
1165 break;
1166
1167 case EFFECT_CMD_GET_CONFIG_REVERSE:
1168 if (pReplyData == NULL || *replySize != sizeof(effect_config_t)) {
1169 ALOGV("PreProcessingFx_Command cmdCode Case: "
1170 "EFFECT_CMD_GET_CONFIG_REVERSE: ERROR");
1171 return -EINVAL;
1172 }
1173 Session_GetReverseConfig(effect->session, (effect_config_t*)pCmdData);
1174 break;
1175
1176 case EFFECT_CMD_RESET:
1177 if (effect->ops->reset) {
1178 effect->ops->reset(effect);
1179 }
1180 break;
1181
1182 case EFFECT_CMD_GET_PARAM: {
1183 effect_param_t* p = (effect_param_t*)pCmdData;
1184
1185 if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) ||
1186 cmdSize < (sizeof(effect_param_t) + p->psize) || pReplyData == NULL ||
1187 replySize == NULL || *replySize < (sizeof(effect_param_t) + p->psize)) {
1188 ALOGV("PreProcessingFx_Command cmdCode Case: "
1189 "EFFECT_CMD_GET_PARAM: ERROR");
1190 return -EINVAL;
1191 }
1192
1193 memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + p->psize);
1194
1195 p = (effect_param_t*)pReplyData;
1196
1197 int voffset = ((p->psize - 1) / sizeof(int32_t) + 1) * sizeof(int32_t);
1198
1199 if (effect->ops->get_parameter) {
1200 p->status =
1201 effect->ops->get_parameter(effect, p->data, &p->vsize, p->data + voffset);
1202 *replySize = sizeof(effect_param_t) + voffset + p->vsize;
1203 }
1204 } break;
1205
1206 case EFFECT_CMD_SET_PARAM: {
1207 if (pCmdData == NULL || cmdSize < sizeof(effect_param_t) || pReplyData == NULL ||
1208 replySize == NULL || *replySize != sizeof(int32_t)) {
1209 ALOGV("PreProcessingFx_Command cmdCode Case: "
1210 "EFFECT_CMD_SET_PARAM: ERROR");
1211 return -EINVAL;
1212 }
1213 effect_param_t* p = (effect_param_t*)pCmdData;
1214
1215 if (p->psize != sizeof(int32_t)) {
1216 ALOGV("PreProcessingFx_Command cmdCode Case: "
1217 "EFFECT_CMD_SET_PARAM: ERROR, psize is not sizeof(int32_t)");
1218 return -EINVAL;
1219 }
1220 if (effect->ops->set_parameter) {
1221 *(int*)pReplyData =
1222 effect->ops->set_parameter(effect, (void*)p->data, p->data + p->psize);
1223 }
1224 } break;
1225
1226 case EFFECT_CMD_ENABLE:
1227 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
1228 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_ENABLE: ERROR");
1229 return -EINVAL;
1230 }
1231 *(int*)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_ACTIVE);
1232 break;
1233
1234 case EFFECT_CMD_DISABLE:
1235 if (pReplyData == NULL || replySize == NULL || *replySize != sizeof(int)) {
1236 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_DISABLE: ERROR");
1237 return -EINVAL;
1238 }
1239 *(int*)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
1240 break;
1241
1242 case EFFECT_CMD_SET_DEVICE:
1243 case EFFECT_CMD_SET_INPUT_DEVICE:
1244 if (pCmdData == NULL || cmdSize != sizeof(uint32_t)) {
1245 ALOGV("PreProcessingFx_Command cmdCode Case: EFFECT_CMD_SET_DEVICE: ERROR");
1246 return -EINVAL;
1247 }
1248
1249 if (effect->ops->set_device) {
1250 effect->ops->set_device(effect, *(uint32_t*)pCmdData);
1251 }
1252 break;
1253
1254 case EFFECT_CMD_SET_VOLUME:
1255 case EFFECT_CMD_SET_AUDIO_MODE:
1256 break;
1257
1258 #ifdef DUAL_MIC_TEST
1259 ///// test commands start
1260 case PREPROC_CMD_DUAL_MIC_ENABLE: {
1261 if (pCmdData == NULL || cmdSize != sizeof(uint32_t) || pReplyData == NULL ||
1262 replySize == NULL) {
1263 ALOGE("PreProcessingFx_Command cmdCode Case: "
1264 "PREPROC_CMD_DUAL_MIC_ENABLE: ERROR");
1265 *replySize = 0;
1266 return -EINVAL;
1267 }
1268 gDualMicEnabled = *(bool*)pCmdData;
1269 if (gDualMicEnabled) {
1270 effect->aux_channels_on = sHasAuxChannels[effect->procId];
1271 } else {
1272 effect->aux_channels_on = false;
1273 }
1274 effect->cur_channel_config =
1275 (effect->session->inChannelCount == 1) ? CHANNEL_CFG_MONO : CHANNEL_CFG_STEREO;
1276
1277 ALOGV("PREPROC_CMD_DUAL_MIC_ENABLE: %s", gDualMicEnabled ? "enabled" : "disabled");
1278 *replySize = sizeof(int);
1279 *(int*)pReplyData = 0;
1280 } break;
1281 case PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: {
1282 if (pCmdData == NULL || pReplyData == NULL || replySize == NULL) {
1283 ALOGE("PreProcessingFx_Command cmdCode Case: "
1284 "PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: ERROR");
1285 *replySize = 0;
1286 return -EINVAL;
1287 }
1288 pthread_mutex_lock(&gPcmDumpLock);
1289 if (gPcmDumpFh != NULL) {
1290 fclose(gPcmDumpFh);
1291 gPcmDumpFh = NULL;
1292 }
1293 char* path = strndup((char*)pCmdData, cmdSize);
1294 gPcmDumpFh = fopen((char*)path, "wb");
1295 pthread_mutex_unlock(&gPcmDumpLock);
1296 ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_START: path %s gPcmDumpFh %p", path, gPcmDumpFh);
1297 ALOGE_IF(gPcmDumpFh <= 0, "gPcmDumpFh open error %d %s", errno, strerror(errno));
1298 free(path);
1299 *replySize = sizeof(int);
1300 *(int*)pReplyData = 0;
1301 } break;
1302 case PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: {
1303 if (pReplyData == NULL || replySize == NULL) {
1304 ALOGE("PreProcessingFx_Command cmdCode Case: "
1305 "PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP: ERROR");
1306 *replySize = 0;
1307 return -EINVAL;
1308 }
1309 pthread_mutex_lock(&gPcmDumpLock);
1310 if (gPcmDumpFh != NULL) {
1311 fclose(gPcmDumpFh);
1312 gPcmDumpFh = NULL;
1313 }
1314 pthread_mutex_unlock(&gPcmDumpLock);
1315 ALOGV("PREPROC_CMD_DUAL_MIC_PCM_DUMP_STOP");
1316 *replySize = sizeof(int);
1317 *(int*)pReplyData = 0;
1318 } break;
1319 ///// test commands end
1320
1321 case EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: {
1322 if (!gDualMicEnabled) {
1323 return -EINVAL;
1324 }
1325 if (pCmdData == NULL || cmdSize != 2 * sizeof(uint32_t) || pReplyData == NULL ||
1326 replySize == NULL) {
1327 ALOGE("PreProcessingFx_Command cmdCode Case: "
1328 "EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS: ERROR");
1329 *replySize = 0;
1330 return -EINVAL;
1331 }
1332 if (*(uint32_t*)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1333 ALOGV("PreProcessingFx_Command feature EFFECT_FEATURE_AUX_CHANNELS not supported by"
1334 " fx %d",
1335 effect->procId);
1336 *(uint32_t*)pReplyData = -ENOSYS;
1337 *replySize = sizeof(uint32_t);
1338 break;
1339 }
1340 size_t num_configs = *((uint32_t*)pCmdData + 1);
1341 if (*replySize < (2 * sizeof(uint32_t) + num_configs * sizeof(channel_config_t))) {
1342 *replySize = 0;
1343 return -EINVAL;
1344 }
1345
1346 *((uint32_t*)pReplyData + 1) = CHANNEL_CFG_CNT;
1347 if (num_configs < CHANNEL_CFG_CNT ||
1348 *replySize < (2 * sizeof(uint32_t) + CHANNEL_CFG_CNT * sizeof(channel_config_t))) {
1349 *(uint32_t*)pReplyData = -ENOMEM;
1350 } else {
1351 num_configs = CHANNEL_CFG_CNT;
1352 *(uint32_t*)pReplyData = 0;
1353 }
1354 ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_SUPPORTED_CONFIGS num config %d",
1355 num_configs);
1356
1357 *replySize = 2 * sizeof(uint32_t) + num_configs * sizeof(channel_config_t);
1358 *((uint32_t*)pReplyData + 1) = num_configs;
1359 memcpy((uint32_t*)pReplyData + 2, &sDualMicConfigs,
1360 num_configs * sizeof(channel_config_t));
1361 } break;
1362 case EFFECT_CMD_GET_FEATURE_CONFIG:
1363 if (!gDualMicEnabled) {
1364 return -EINVAL;
1365 }
1366 if (pCmdData == NULL || cmdSize != sizeof(uint32_t) || pReplyData == NULL ||
1367 replySize == NULL || *replySize < sizeof(uint32_t) + sizeof(channel_config_t)) {
1368 ALOGE("PreProcessingFx_Command cmdCode Case: "
1369 "EFFECT_CMD_GET_FEATURE_CONFIG: ERROR");
1370 return -EINVAL;
1371 }
1372 if (*(uint32_t*)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1373 *(uint32_t*)pReplyData = -ENOSYS;
1374 *replySize = sizeof(uint32_t);
1375 break;
1376 }
1377 ALOGV("PreProcessingFx_Command EFFECT_CMD_GET_FEATURE_CONFIG");
1378 *(uint32_t*)pReplyData = 0;
1379 *replySize = sizeof(uint32_t) + sizeof(channel_config_t);
1380 memcpy((uint32_t*)pReplyData + 1, &sDualMicConfigs[effect->cur_channel_config],
1381 sizeof(channel_config_t));
1382 break;
1383 case EFFECT_CMD_SET_FEATURE_CONFIG: {
1384 ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG: "
1385 "gDualMicEnabled %d effect->aux_channels_on %d",
1386 gDualMicEnabled, effect->aux_channels_on);
1387 if (!gDualMicEnabled) {
1388 return -EINVAL;
1389 }
1390 if (pCmdData == NULL || cmdSize != (sizeof(uint32_t) + sizeof(channel_config_t)) ||
1391 pReplyData == NULL || replySize == NULL || *replySize < sizeof(uint32_t)) {
1392 ALOGE("PreProcessingFx_Command cmdCode Case: "
1393 "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1394 "pCmdData %p cmdSize %d pReplyData %p replySize %p *replySize %d",
1395 pCmdData, cmdSize, pReplyData, replySize, replySize ? *replySize : -1);
1396 return -EINVAL;
1397 }
1398 *replySize = sizeof(uint32_t);
1399 if (*(uint32_t*)pCmdData != EFFECT_FEATURE_AUX_CHANNELS || !effect->aux_channels_on) {
1400 *(uint32_t*)pReplyData = -ENOSYS;
1401 ALOGV("PreProcessingFx_Command cmdCode Case: "
1402 "EFFECT_CMD_SET_FEATURE_CONFIG: ERROR\n"
1403 "CmdData %d effect->aux_channels_on %d",
1404 *(uint32_t*)pCmdData, effect->aux_channels_on);
1405 break;
1406 }
1407 size_t i;
1408 for (i = 0; i < CHANNEL_CFG_CNT; i++) {
1409 if (memcmp((uint32_t*)pCmdData + 1, &sDualMicConfigs[i],
1410 sizeof(channel_config_t)) == 0) {
1411 break;
1412 }
1413 }
1414 if (i == CHANNEL_CFG_CNT) {
1415 *(uint32_t*)pReplyData = -EINVAL;
1416 ALOGW("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG invalid config"
1417 "[%08x].[%08x]",
1418 *((uint32_t*)pCmdData + 1), *((uint32_t*)pCmdData + 2));
1419 } else {
1420 effect->cur_channel_config = i;
1421 *(uint32_t*)pReplyData = 0;
1422 ALOGV("PreProcessingFx_Command EFFECT_CMD_SET_FEATURE_CONFIG New config"
1423 "[%08x].[%08x]",
1424 sDualMicConfigs[i].main_channels, sDualMicConfigs[i].aux_channels);
1425 }
1426 } break;
1427 #endif
1428 default:
1429 return -EINVAL;
1430 }
1431 return 0;
1432 }
1433
PreProcessingFx_GetDescriptor(effect_handle_t self,effect_descriptor_t * pDescriptor)1434 int PreProcessingFx_GetDescriptor(effect_handle_t self, effect_descriptor_t* pDescriptor) {
1435 preproc_effect_t* effect = (preproc_effect_t*)self;
1436
1437 if (effect == NULL || pDescriptor == NULL) {
1438 return -EINVAL;
1439 }
1440
1441 *pDescriptor = *sDescriptors[effect->procId];
1442
1443 return 0;
1444 }
1445
PreProcessingFx_ProcessReverse(effect_handle_t self,audio_buffer_t * inBuffer,audio_buffer_t * outBuffer)1446 int PreProcessingFx_ProcessReverse(effect_handle_t self, audio_buffer_t* inBuffer,
1447 audio_buffer_t* outBuffer) {
1448 preproc_effect_t* effect = (preproc_effect_t*)self;
1449
1450 if (effect == NULL) {
1451 ALOGW("PreProcessingFx_ProcessReverse() ERROR effect == NULL");
1452 return -EINVAL;
1453 }
1454 preproc_session_t* session = (preproc_session_t*)effect->session;
1455
1456 if (inBuffer == NULL || inBuffer->raw == NULL) {
1457 ALOGW("PreProcessingFx_ProcessReverse() ERROR bad pointer");
1458 return -EINVAL;
1459 }
1460
1461 if (inBuffer->frameCount != outBuffer->frameCount) {
1462 ALOGW("inBuffer->frameCount %zu is not equal to outBuffer->frameCount %zu",
1463 inBuffer->frameCount, outBuffer->frameCount);
1464 return -EINVAL;
1465 }
1466
1467 if (inBuffer->frameCount != session->frameCount) {
1468 ALOGW("inBuffer->frameCount %zu != %zu representing 10ms at sampling rate %d",
1469 inBuffer->frameCount, session->frameCount, session->samplingRate);
1470 return -EINVAL;
1471 }
1472
1473 session->revProcessedMsk |= (1 << effect->procId);
1474
1475 // ALOGV("PreProcessingFx_ProcessReverse In %d frames revEnabledMsk %08x revProcessedMsk
1476 // %08x",
1477 // inBuffer->frameCount, session->revEnabledMsk, session->revProcessedMsk);
1478
1479 if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
1480 effect->session->revProcessedMsk = 0;
1481 if (int status = effect->session->apm->ProcessReverseStream(
1482 (const int16_t* const)inBuffer->s16,
1483 (const webrtc::StreamConfig)effect->session->revConfig,
1484 (const webrtc::StreamConfig)effect->session->revConfig,
1485 (int16_t* const)outBuffer->s16);
1486 status != 0) {
1487 ALOGE("Process Reverse Stream failed with error %d\n", status);
1488 return status;
1489 }
1490 return 0;
1491 } else {
1492 return -ENODATA;
1493 }
1494 }
1495
1496 // effect_handle_t interface implementation for effect
1497 const struct effect_interface_s sEffectInterface = {
1498 PreProcessingFx_Process, PreProcessingFx_Command, PreProcessingFx_GetDescriptor, NULL};
1499
1500 const struct effect_interface_s sEffectInterfaceReverse = {
1501 PreProcessingFx_Process, PreProcessingFx_Command, PreProcessingFx_GetDescriptor,
1502 PreProcessingFx_ProcessReverse};
1503
1504 //------------------------------------------------------------------------------
1505 // Effect Library Interface Implementation
1506 //------------------------------------------------------------------------------
1507
PreProcessingLib_Create(const effect_uuid_t * uuid,int32_t sessionId,int32_t ioId,effect_handle_t * pInterface)1508 int PreProcessingLib_Create(const effect_uuid_t* uuid, int32_t sessionId, int32_t ioId,
1509 effect_handle_t* pInterface) {
1510 ALOGV("EffectCreate: uuid: %08x session %d IO: %d", uuid->timeLow, sessionId, ioId);
1511
1512 int status;
1513 const effect_descriptor_t* desc;
1514 preproc_session_t* session;
1515 uint32_t procId;
1516
1517 if (PreProc_Init() != 0) {
1518 return sInitStatus;
1519 }
1520 desc = PreProc_GetDescriptor(uuid);
1521 if (desc == NULL) {
1522 ALOGW("EffectCreate: fx not found uuid: %08x", uuid->timeLow);
1523 return -EINVAL;
1524 }
1525 procId = UuidToProcId(&desc->type);
1526
1527 session = PreProc_GetSession(procId, sessionId, ioId);
1528 if (session == NULL) {
1529 ALOGW("EffectCreate: no more session available");
1530 return -EINVAL;
1531 }
1532
1533 status = Session_CreateEffect(session, procId, pInterface);
1534
1535 if (status < 0 && session->createdMsk == 0) {
1536 session->id = 0;
1537 }
1538 return status;
1539 }
1540
PreProcessingLib_Release(effect_handle_t interface)1541 int PreProcessingLib_Release(effect_handle_t interface) {
1542 ALOGV("EffectRelease start %p", interface);
1543 if (PreProc_Init() != 0) {
1544 return sInitStatus;
1545 }
1546
1547 preproc_effect_t* fx = (preproc_effect_t*)interface;
1548
1549 if (fx->session->id == 0) {
1550 return -EINVAL;
1551 }
1552 return Session_ReleaseEffect(fx->session, fx);
1553 }
1554
PreProcessingLib_GetDescriptor(const effect_uuid_t * uuid,effect_descriptor_t * pDescriptor)1555 int PreProcessingLib_GetDescriptor(const effect_uuid_t* uuid, effect_descriptor_t* pDescriptor) {
1556 if (pDescriptor == NULL || uuid == NULL) {
1557 return -EINVAL;
1558 }
1559
1560 const effect_descriptor_t* desc = PreProc_GetDescriptor(uuid);
1561 if (desc == NULL) {
1562 ALOGV("PreProcessingLib_GetDescriptor() not found");
1563 return -EINVAL;
1564 }
1565
1566 ALOGV("PreProcessingLib_GetDescriptor() got fx %s", desc->name);
1567
1568 *pDescriptor = *desc;
1569 return 0;
1570 }
1571
1572 // This is the only symbol that needs to be exported
1573 __attribute__((visibility("default"))) audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
1574 .tag = AUDIO_EFFECT_LIBRARY_TAG,
1575 .version = EFFECT_LIBRARY_API_VERSION,
1576 .name = "Audio Preprocessing Library",
1577 .implementor = "The Android Open Source Project",
1578 .create_effect = PreProcessingLib_Create,
1579 .release_effect = PreProcessingLib_Release,
1580 .get_descriptor = PreProcessingLib_GetDescriptor};
1581
1582 }; // extern "C"
1583