blob: 3244c1f5513f1481237a362814dc1b684490b06f [file] [log] [blame]
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +05301/*
2 * Copyright (C) 2020 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
Saketh Sathuvalli08337032020-09-22 21:13:45 +053017#include <getopt.h>
18#include <stddef.h>
19#include <stdint.h>
20#include <sys/stat.h>
21#include <vector>
22
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +053023#include <audio_effects/effect_aec.h>
24#include <audio_effects/effect_agc.h>
Saketh Sathuvalli08337032020-09-22 21:13:45 +053025#ifndef WEBRTC_LEGACY
26#include <audio_effects/effect_agc2.h>
27#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +053028#include <audio_effects/effect_ns.h>
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +053029#include <log/log.h>
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +053030
31// This is the only symbol that needs to be imported
32extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
33
34//------------------------------------------------------------------------------
35// local definitions
36//------------------------------------------------------------------------------
37
38// types of pre processing modules
39enum PreProcId {
40 PREPROC_AGC, // Automatic Gain Control
Saketh Sathuvalli08337032020-09-22 21:13:45 +053041#ifndef WEBRTC_LEGACY
42 PREPROC_AGC2, // Automatic Gain Control 2
43#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +053044 PREPROC_AEC, // Acoustic Echo Canceler
45 PREPROC_NS, // Noise Suppressor
46 PREPROC_NUM_EFFECTS
47};
48
49enum PreProcParams {
50 ARG_HELP = 1,
51 ARG_INPUT,
52 ARG_OUTPUT,
53 ARG_FAR,
54 ARG_FS,
55 ARG_CH_MASK,
56 ARG_AGC_TGT_LVL,
57 ARG_AGC_COMP_LVL,
58 ARG_AEC_DELAY,
59 ARG_NS_LVL,
Saketh Sathuvalli08337032020-09-22 21:13:45 +053060#ifndef WEBRTC_LEGACY
61 ARG_AEC_MOBILE,
62 ARG_AGC2_GAIN,
63 ARG_AGC2_LVL,
64 ARG_AGC2_SAT_MGN
65#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +053066};
67
68struct preProcConfigParams_t {
69 int samplingFreq = 16000;
70 audio_channel_mask_t chMask = AUDIO_CHANNEL_IN_MONO;
71 int nsLevel = 0; // a value between 0-3
72 int agcTargetLevel = 3; // in dB
73 int agcCompLevel = 9; // in dB
Saketh Sathuvalli08337032020-09-22 21:13:45 +053074#ifndef WEBRTC_LEGACY
75 float agc2Gain = 0.f; // in dB
76 float agc2SaturationMargin = 2.f; // in dB
77 int agc2Level = 0; // either kRms(0) or kPeak(1)
78#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +053079 int aecDelay = 0; // in ms
80};
81
82const effect_uuid_t kPreProcUuids[PREPROC_NUM_EFFECTS] = {
83 {0xaa8130e0, 0x66fc, 0x11e0, 0xbad0, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // agc uuid
Saketh Sathuvalli08337032020-09-22 21:13:45 +053084#ifndef WEBRTC_LEGACY
85 {0x89f38e65, 0xd4d2, 0x4d64, 0xad0e, {0x2b, 0x3e, 0x79, 0x9e, 0xa8, 0x86}}, // agc2 uuid
86#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +053087 {0xbb392ec0, 0x8d4d, 0x11e0, 0xa896, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // aec uuid
88 {0xc06c8400, 0x8e06, 0x11e0, 0x9cb6, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // ns uuid
89};
90
91constexpr audio_channel_mask_t kPreProcConfigChMask[] = {
92 AUDIO_CHANNEL_IN_MONO,
93 AUDIO_CHANNEL_IN_STEREO,
94 AUDIO_CHANNEL_IN_FRONT_BACK,
95 AUDIO_CHANNEL_IN_6,
96 AUDIO_CHANNEL_IN_2POINT0POINT2,
97 AUDIO_CHANNEL_IN_2POINT1POINT2,
98 AUDIO_CHANNEL_IN_3POINT0POINT2,
99 AUDIO_CHANNEL_IN_3POINT1POINT2,
100 AUDIO_CHANNEL_IN_5POINT1,
101 AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO,
102 AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO,
103 AUDIO_CHANNEL_IN_VOICE_CALL_MONO,
104};
105
106constexpr int kPreProcConfigChMaskCount = std::size(kPreProcConfigChMask);
107
108void printUsage() {
109 printf("\nUsage: ");
110 printf("\n <executable> [options]\n");
111 printf("\nwhere options are, ");
112 printf("\n --input <inputfile>");
113 printf("\n path to the input file");
114 printf("\n --output <outputfile>");
115 printf("\n path to the output file");
116 printf("\n --help");
117 printf("\n Prints this usage information");
118 printf("\n --fs <sampling_freq>");
119 printf("\n Sampling frequency in Hz, default 16000.");
120 printf("\n -ch_mask <channel_mask>\n");
121 printf("\n 0 - AUDIO_CHANNEL_IN_MONO");
122 printf("\n 1 - AUDIO_CHANNEL_IN_STEREO");
123 printf("\n 2 - AUDIO_CHANNEL_IN_FRONT_BACK");
124 printf("\n 3 - AUDIO_CHANNEL_IN_6");
125 printf("\n 4 - AUDIO_CHANNEL_IN_2POINT0POINT2");
126 printf("\n 5 - AUDIO_CHANNEL_IN_2POINT1POINT2");
127 printf("\n 6 - AUDIO_CHANNEL_IN_3POINT0POINT2");
128 printf("\n 7 - AUDIO_CHANNEL_IN_3POINT1POINT2");
129 printf("\n 8 - AUDIO_CHANNEL_IN_5POINT1");
130 printf("\n 9 - AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO");
131 printf("\n 10 - AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO ");
132 printf("\n 11 - AUDIO_CHANNEL_IN_VOICE_CALL_MONO ");
133 printf("\n default 0");
134 printf("\n --far <farend_file>");
135 printf("\n Path to far-end file needed for echo cancellation");
136 printf("\n --aec");
137 printf("\n Enable Echo Cancellation, default disabled");
138 printf("\n --ns");
139 printf("\n Enable Noise Suppression, default disabled");
140 printf("\n --agc");
141 printf("\n Enable Gain Control, default disabled");
Saketh Sathuvalli08337032020-09-22 21:13:45 +0530142#ifndef WEBRTC_LEGACY
143 printf("\n --agc2");
144 printf("\n Enable Gain Controller 2, default disabled");
145#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +0530146 printf("\n --ns_lvl <ns_level>");
147 printf("\n Noise Suppression level in dB, default value 0dB");
148 printf("\n --agc_tgt_lvl <target_level>");
149 printf("\n AGC Target Level in dB, default value 3dB");
150 printf("\n --agc_comp_lvl <comp_level>");
151 printf("\n AGC Comp Level in dB, default value 9dB");
Saketh Sathuvalli08337032020-09-22 21:13:45 +0530152#ifndef WEBRTC_LEGACY
153 printf("\n --agc2_gain <fixed_digital_gain>");
154 printf("\n AGC Fixed Digital Gain in dB, default value 0dB");
155 printf("\n --agc2_lvl <level_estimator>");
156 printf("\n AGC Adaptive Digital Level Estimator, default value kRms");
157 printf("\n --agc2_sat_mgn <saturation_margin>");
158 printf("\n AGC Adaptive Digital Saturation Margin in dB, default value 2dB");
159#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +0530160 printf("\n --aec_delay <delay>");
161 printf("\n AEC delay value in ms, default value 0ms");
Saketh Sathuvalli08337032020-09-22 21:13:45 +0530162#ifndef WEBRTC_LEGACY
163 printf("\n --aec_mobile");
164 printf("\n Enable mobile mode of echo canceller, default disabled");
165#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +0530166 printf("\n");
167}
168
169constexpr float kTenMilliSecVal = 0.01;
170
171int preProcCreateEffect(effect_handle_t *pEffectHandle, uint32_t effectType,
172 effect_config_t *pConfig, int sessionId, int ioId) {
173 if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(&kPreProcUuids[effectType],
174 sessionId, ioId, pEffectHandle);
175 status != 0) {
176 ALOGE("Audio Preprocessing create returned an error = %d\n", status);
177 return EXIT_FAILURE;
178 }
179 int reply = 0;
180 uint32_t replySize = sizeof(reply);
181 if (effectType == PREPROC_AEC) {
182 (**pEffectHandle)
183 ->command(*pEffectHandle, EFFECT_CMD_SET_CONFIG_REVERSE, sizeof(effect_config_t), pConfig,
184 &replySize, &reply);
185 }
186 (**pEffectHandle)
187 ->command(*pEffectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t), pConfig,
188 &replySize, &reply);
189 return reply;
190}
191
192int preProcSetConfigParam(uint32_t paramType, uint32_t paramValue, effect_handle_t effectHandle) {
193 int reply = 0;
194 uint32_t replySize = sizeof(reply);
195 uint32_t paramData[2] = {paramType, paramValue};
196 effect_param_t *effectParam =
197 (effect_param_t *)malloc(sizeof(*effectParam) + sizeof(paramData));
198 memcpy(&effectParam->data[0], &paramData[0], sizeof(paramData));
199 effectParam->psize = sizeof(paramData[0]);
200 (*effectHandle)
201 ->command(effectHandle, EFFECT_CMD_SET_PARAM, sizeof(effect_param_t), effectParam,
202 &replySize, &reply);
203 free(effectParam);
204 return reply;
205}
206
207int main(int argc, const char *argv[]) {
208 if (argc == 1) {
209 printUsage();
210 return EXIT_FAILURE;
211 }
212 const char *inputFile = nullptr;
213 const char *outputFile = nullptr;
214 const char *farFile = nullptr;
215 int effectEn[PREPROC_NUM_EFFECTS] = {0};
Saketh Sathuvalli08337032020-09-22 21:13:45 +0530216#ifndef WEBRTC_LEGACY
217 int aecMobileMode = 0;
218#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +0530219
220 const option long_opts[] = {
221 {"help", no_argument, nullptr, ARG_HELP},
222 {"input", required_argument, nullptr, ARG_INPUT},
223 {"output", required_argument, nullptr, ARG_OUTPUT},
224 {"far", required_argument, nullptr, ARG_FAR},
225 {"fs", required_argument, nullptr, ARG_FS},
226 {"ch_mask", required_argument, nullptr, ARG_CH_MASK},
227 {"agc_tgt_lvl", required_argument, nullptr, ARG_AGC_TGT_LVL},
228 {"agc_comp_lvl", required_argument, nullptr, ARG_AGC_COMP_LVL},
Saketh Sathuvalli08337032020-09-22 21:13:45 +0530229#ifndef WEBRTC_LEGACY
230 {"agc2_gain", required_argument, nullptr, ARG_AGC2_GAIN},
231 {"agc2_lvl", required_argument, nullptr, ARG_AGC2_LVL},
232 {"agc2_sat_mgn", required_argument, nullptr, ARG_AGC2_SAT_MGN},
233#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +0530234 {"aec_delay", required_argument, nullptr, ARG_AEC_DELAY},
235 {"ns_lvl", required_argument, nullptr, ARG_NS_LVL},
236 {"aec", no_argument, &effectEn[PREPROC_AEC], 1},
237 {"agc", no_argument, &effectEn[PREPROC_AGC], 1},
Saketh Sathuvalli08337032020-09-22 21:13:45 +0530238#ifndef WEBRTC_LEGACY
239 {"agc2", no_argument, &effectEn[PREPROC_AGC2], 1},
240#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +0530241 {"ns", no_argument, &effectEn[PREPROC_NS], 1},
Saketh Sathuvalli08337032020-09-22 21:13:45 +0530242#ifndef WEBRTC_LEGACY
243 {"aec_mobile", no_argument, &aecMobileMode, 1},
244#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +0530245 {nullptr, 0, nullptr, 0},
246 };
247 struct preProcConfigParams_t preProcCfgParams {};
248
249 while (true) {
250 const int opt = getopt_long(argc, (char *const *)argv, "i:o:", long_opts, nullptr);
251 if (opt == -1) {
252 break;
253 }
254 switch (opt) {
255 case ARG_HELP:
256 printUsage();
257 return 0;
258 case ARG_INPUT: {
259 inputFile = (char *)optarg;
260 break;
261 }
262 case ARG_OUTPUT: {
263 outputFile = (char *)optarg;
264 break;
265 }
266 case ARG_FAR: {
267 farFile = (char *)optarg;
268 break;
269 }
270 case ARG_FS: {
271 preProcCfgParams.samplingFreq = atoi(optarg);
272 break;
273 }
274 case ARG_CH_MASK: {
275 int chMaskIdx = atoi(optarg);
276 if (chMaskIdx < 0 or chMaskIdx > kPreProcConfigChMaskCount) {
277 ALOGE("Channel Mask index not in correct range\n");
278 printUsage();
279 return EXIT_FAILURE;
280 }
281 preProcCfgParams.chMask = kPreProcConfigChMask[chMaskIdx];
282 break;
283 }
284 case ARG_AGC_TGT_LVL: {
285 preProcCfgParams.agcTargetLevel = atoi(optarg);
286 break;
287 }
288 case ARG_AGC_COMP_LVL: {
289 preProcCfgParams.agcCompLevel = atoi(optarg);
290 break;
291 }
Saketh Sathuvalli08337032020-09-22 21:13:45 +0530292#ifndef WEBRTC_LEGACY
293 case ARG_AGC2_GAIN: {
294 preProcCfgParams.agc2Gain = atof(optarg);
295 break;
296 }
297 case ARG_AGC2_LVL: {
298 preProcCfgParams.agc2Level = atoi(optarg);
299 break;
300 }
301 case ARG_AGC2_SAT_MGN: {
302 preProcCfgParams.agc2SaturationMargin = atof(optarg);
303 break;
304 }
305#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +0530306 case ARG_AEC_DELAY: {
307 preProcCfgParams.aecDelay = atoi(optarg);
308 break;
309 }
310 case ARG_NS_LVL: {
311 preProcCfgParams.nsLevel = atoi(optarg);
312 break;
313 }
314 default:
315 break;
316 }
317 }
318
319 if (inputFile == nullptr) {
320 ALOGE("Error: missing input file\n");
321 printUsage();
322 return EXIT_FAILURE;
323 }
324
325 std::unique_ptr<FILE, decltype(&fclose)> inputFp(fopen(inputFile, "rb"), &fclose);
326 if (inputFp == nullptr) {
327 ALOGE("Cannot open input file %s\n", inputFile);
328 return EXIT_FAILURE;
329 }
330
331 std::unique_ptr<FILE, decltype(&fclose)> farFp(fopen(farFile, "rb"), &fclose);
332 std::unique_ptr<FILE, decltype(&fclose)> outputFp(fopen(outputFile, "wb"), &fclose);
333 if (effectEn[PREPROC_AEC]) {
334 if (farFile == nullptr) {
335 ALOGE("Far end signal file required for echo cancellation \n");
336 return EXIT_FAILURE;
337 }
338 if (farFp == nullptr) {
339 ALOGE("Cannot open far end stream file %s\n", farFile);
340 return EXIT_FAILURE;
341 }
342 struct stat statInput, statFar;
343 (void)fstat(fileno(inputFp.get()), &statInput);
344 (void)fstat(fileno(farFp.get()), &statFar);
345 if (statInput.st_size != statFar.st_size) {
346 ALOGE("Near and far end signals are of different sizes");
347 return EXIT_FAILURE;
348 }
349 }
350 if (outputFile != nullptr && outputFp == nullptr) {
351 ALOGE("Cannot open output file %s\n", outputFile);
352 return EXIT_FAILURE;
353 }
354
355 int32_t sessionId = 1;
356 int32_t ioId = 1;
357 effect_handle_t effectHandle[PREPROC_NUM_EFFECTS] = {nullptr};
358 effect_config_t config;
359 config.inputCfg.samplingRate = config.outputCfg.samplingRate = preProcCfgParams.samplingFreq;
360 config.inputCfg.channels = config.outputCfg.channels = preProcCfgParams.chMask;
361 config.inputCfg.format = config.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
362
363 // Create all the effect handles
364 for (int i = 0; i < PREPROC_NUM_EFFECTS; i++) {
365 if (int status = preProcCreateEffect(&effectHandle[i], i, &config, sessionId, ioId);
366 status != 0) {
367 ALOGE("Create effect call returned error %i", status);
368 return EXIT_FAILURE;
369 }
370 }
371
372 for (int i = 0; i < PREPROC_NUM_EFFECTS; i++) {
373 if (effectEn[i] == 1) {
374 int reply = 0;
375 uint32_t replySize = sizeof(reply);
376 (*effectHandle[i])
377 ->command(effectHandle[i], EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply);
378 if (reply != 0) {
379 ALOGE("Command enable call returned error %d\n", reply);
380 return EXIT_FAILURE;
381 }
382 }
383 }
384
385 // Set Config Params of the effects
386 if (effectEn[PREPROC_AGC]) {
387 if (int status = preProcSetConfigParam(AGC_PARAM_TARGET_LEVEL,
388 (uint32_t)preProcCfgParams.agcTargetLevel,
389 effectHandle[PREPROC_AGC]);
390 status != 0) {
391 ALOGE("Invalid AGC Target Level. Error %d\n", status);
392 return EXIT_FAILURE;
393 }
394 if (int status =
395 preProcSetConfigParam(AGC_PARAM_COMP_GAIN, (uint32_t)preProcCfgParams.agcCompLevel,
396 effectHandle[PREPROC_AGC]);
397 status != 0) {
398 ALOGE("Invalid AGC Comp Gain. Error %d\n", status);
399 return EXIT_FAILURE;
400 }
401 }
Saketh Sathuvalli08337032020-09-22 21:13:45 +0530402#ifndef WEBRTC_LEGACY
403 if (effectEn[PREPROC_AGC2]) {
404 if (int status = preProcSetConfigParam(AGC2_PARAM_FIXED_DIGITAL_GAIN,
405 (float)preProcCfgParams.agc2Gain,
406 effectHandle[PREPROC_AGC2]);
407 status != 0) {
408 ALOGE("Invalid AGC2 Fixed Digital Gain. Error %d\n", status);
409 return EXIT_FAILURE;
410 }
411 if (int status = preProcSetConfigParam(AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR,
412 (uint32_t)preProcCfgParams.agc2Level,
413 effectHandle[PREPROC_AGC2]);
414 status != 0) {
415 ALOGE("Invalid AGC2 Level Estimator. Error %d\n", status);
416 return EXIT_FAILURE;
417 }
418 if (int status = preProcSetConfigParam(AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN,
419 (float)preProcCfgParams.agc2SaturationMargin,
420 effectHandle[PREPROC_AGC2]);
421 status != 0) {
422 ALOGE("Invalid AGC2 Saturation Margin. Error %d\n", status);
423 return EXIT_FAILURE;
424 }
425 }
426#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +0530427 if (effectEn[PREPROC_NS]) {
428 if (int status = preProcSetConfigParam(NS_PARAM_LEVEL, (uint32_t)preProcCfgParams.nsLevel,
429 effectHandle[PREPROC_NS]);
430 status != 0) {
431 ALOGE("Invalid Noise Suppression level Error %d\n", status);
432 return EXIT_FAILURE;
433 }
434 }
Saketh Sathuvalli08337032020-09-22 21:13:45 +0530435#ifndef WEBRTC_LEGACY
436 if (effectEn[PREPROC_AEC]) {
437 if (int status = preProcSetConfigParam(AEC_PARAM_MOBILE_MODE, (uint32_t)aecMobileMode,
438 effectHandle[PREPROC_AEC]);
439 status != 0) {
440 ALOGE("Invalid AEC mobile mode value %d\n", status);
441 return EXIT_FAILURE;
442 }
443 }
444#endif
Saketh Sathuvalli4ece3e02020-07-19 21:19:39 +0530445
446 // Process Call
447 const int frameLength = (int)(preProcCfgParams.samplingFreq * kTenMilliSecVal);
448 const int ioChannelCount = audio_channel_count_from_in_mask(preProcCfgParams.chMask);
449 const int ioFrameSize = ioChannelCount * sizeof(short);
450 int frameCounter = 0;
451 while (true) {
452 std::vector<short> in(frameLength * ioChannelCount);
453 std::vector<short> out(frameLength * ioChannelCount);
454 std::vector<short> farIn(frameLength * ioChannelCount);
455 size_t samplesRead = fread(in.data(), ioFrameSize, frameLength, inputFp.get());
456 if (samplesRead == 0) {
457 break;
458 }
459 audio_buffer_t inputBuffer, outputBuffer;
460 audio_buffer_t farInBuffer{};
461 inputBuffer.frameCount = samplesRead;
462 outputBuffer.frameCount = samplesRead;
463 inputBuffer.s16 = in.data();
464 outputBuffer.s16 = out.data();
465
466 if (farFp != nullptr) {
467 samplesRead = fread(farIn.data(), ioFrameSize, frameLength, farFp.get());
468 if (samplesRead == 0) {
469 break;
470 }
471 farInBuffer.frameCount = samplesRead;
472 farInBuffer.s16 = farIn.data();
473 }
474
475 for (int i = 0; i < PREPROC_NUM_EFFECTS; i++) {
476 if (effectEn[i] == 1) {
477 if (i == PREPROC_AEC) {
478 if (int status =
479 preProcSetConfigParam(AEC_PARAM_ECHO_DELAY, (uint32_t)preProcCfgParams.aecDelay,
480 effectHandle[PREPROC_AEC]);
481 status != 0) {
482 ALOGE("preProcSetConfigParam returned Error %d\n", status);
483 return EXIT_FAILURE;
484 }
485 }
486 if (int status =
487 (*effectHandle[i])->process(effectHandle[i], &inputBuffer, &outputBuffer);
488 status != 0) {
489 ALOGE("\nError: Process i = %d returned with error %d\n", i, status);
490 return EXIT_FAILURE;
491 }
492 if (i == PREPROC_AEC) {
493 if (int status = (*effectHandle[i])
494 ->process_reverse(effectHandle[i], &farInBuffer, &outputBuffer);
495 status != 0) {
496 ALOGE("\nError: Process reverse i = %d returned with error %d\n", i, status);
497 return EXIT_FAILURE;
498 }
499 }
500 }
501 }
502 if (outputFp != nullptr) {
503 size_t samplesWritten =
504 fwrite(out.data(), ioFrameSize, outputBuffer.frameCount, outputFp.get());
505 if (samplesWritten != outputBuffer.frameCount) {
506 ALOGE("\nError: Output file writing failed");
507 break;
508 }
509 }
510 frameCounter += frameLength;
511 }
512 // Release all the effect handles created
513 for (int i = 0; i < PREPROC_NUM_EFFECTS; i++) {
514 if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle[i]);
515 status != 0) {
516 ALOGE("Audio Preprocessing release returned an error = %d\n", status);
517 return EXIT_FAILURE;
518 }
519 }
520 return EXIT_SUCCESS;
521}