• 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     }
404     if (effectEn[PREPROC_NS]) {
405         if (int status = preProcSetConfigParam(NS_PARAM_LEVEL, (uint32_t)preProcCfgParams.nsLevel,
406                                                effectHandle[PREPROC_NS]);
407             status != 0) {
408             ALOGE("Invalid Noise Suppression level Error %d\n", status);
409             return EXIT_FAILURE;
410         }
411     }
412 
413     // Process Call
414     const int frameLength = (int)(preProcCfgParams.samplingFreq * kTenMilliSecVal);
415     const int ioChannelCount = audio_channel_count_from_in_mask(preProcCfgParams.chMask);
416     const int fileChannelCount = preProcCfgParams.fileChannels;
417     const int ioFrameSize = ioChannelCount * sizeof(short);
418     const int inFrameSize = fileChannelCount * sizeof(short);
419     int frameCounter = 0;
420     while (true) {
421         std::vector<short> in(frameLength * ioChannelCount);
422         std::vector<short> out(frameLength * ioChannelCount);
423         std::vector<short> farIn(frameLength * ioChannelCount);
424         size_t samplesRead = fread(in.data(), inFrameSize, frameLength, inputFp.get());
425         if (samplesRead == 0) {
426             break;
427         }
428         if (fileChannelCount != ioChannelCount) {
429             adjust_channels(in.data(), fileChannelCount, in.data(), ioChannelCount, sizeof(short),
430                             frameLength * inFrameSize);
431             if (preProcCfgParams.monoMode == 1) {
432                 for (int i = 0; i < frameLength; ++i) {
433                     auto* fp = &in[i * ioChannelCount];
434                     std::fill(fp + 1, fp + ioChannelCount, *fp);  // replicate ch 0
435                 }
436             }
437         }
438         audio_buffer_t inputBuffer, outputBuffer;
439         audio_buffer_t farInBuffer{};
440         inputBuffer.frameCount = frameLength;
441         outputBuffer.frameCount = frameLength;
442         inputBuffer.s16 = in.data();
443         outputBuffer.s16 = out.data();
444 
445         if (farFp != nullptr) {
446             samplesRead = fread(farIn.data(), inFrameSize, frameLength, farFp.get());
447             if (samplesRead == 0) {
448                 break;
449             }
450             if (fileChannelCount != ioChannelCount) {
451                 adjust_channels(farIn.data(), fileChannelCount, farIn.data(), ioChannelCount,
452                                 sizeof(short), frameLength * inFrameSize);
453                 if (preProcCfgParams.monoMode == 1) {
454                     for (int i = 0; i < frameLength; ++i) {
455                         auto* fp = &farIn[i * ioChannelCount];
456                         std::fill(fp + 1, fp + ioChannelCount, *fp);  // replicate ch 0
457                     }
458                 }
459             }
460 
461             farInBuffer.frameCount = frameLength;
462             farInBuffer.s16 = farIn.data();
463         }
464 
465         for (int i = 0; i < PREPROC_NUM_EFFECTS; i++) {
466             if (effectEn[i] == 1) {
467                 if (i == PREPROC_AEC) {
468                     if (int status = preProcSetConfigParam(AEC_PARAM_ECHO_DELAY,
469                                                            (uint32_t)preProcCfgParams.aecDelay,
470                                                            effectHandle[PREPROC_AEC]);
471                         status != 0) {
472                         ALOGE("preProcSetConfigParam returned Error %d\n", status);
473                         return EXIT_FAILURE;
474                     }
475                 }
476                 if (int status = (*effectHandle[i])
477                                          ->process(effectHandle[i], &inputBuffer, &outputBuffer);
478                     status != 0) {
479                     ALOGE("\nError: Process i = %d returned with error %d\n", i, status);
480                     return EXIT_FAILURE;
481                 }
482                 if (i == PREPROC_AEC) {
483                     if (int status = (*effectHandle[i])
484                                              ->process_reverse(effectHandle[i], &farInBuffer,
485                                                                &outputBuffer);
486                         status != 0) {
487                         ALOGE("\nError: Process reverse i = %d returned with error %d\n", i,
488                               status);
489                         return EXIT_FAILURE;
490                     }
491                 }
492             }
493         }
494         if (outputFp != nullptr) {
495             if (fileChannelCount != ioChannelCount) {
496                 adjust_channels(out.data(), ioChannelCount, out.data(), fileChannelCount,
497                                 sizeof(short), frameLength * ioFrameSize);
498             }
499             size_t samplesWritten =
500                     fwrite(out.data(), inFrameSize, outputBuffer.frameCount, outputFp.get());
501             if (samplesWritten != outputBuffer.frameCount) {
502                 ALOGE("\nError: Output file writing failed");
503                 break;
504             }
505         }
506         frameCounter += frameLength;
507     }
508     printf("frameCounter: [%d]\n", frameCounter);
509     // Release all the effect handles created
510     for (int i = 0; i < PREPROC_NUM_EFFECTS; i++) {
511         if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle[i]);
512             status != 0) {
513             ALOGE("Audio Preprocessing release returned an error = %d\n", status);
514             return EXIT_FAILURE;
515         }
516     }
517     return EXIT_SUCCESS;
518 }
519