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