1 /*
2  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/audio_processing/test/audioproc_float_impl.h"
12 
13 #include <string.h>
14 
15 #include <iostream>
16 #include <memory>
17 #include <string>
18 #include <utility>
19 #include <vector>
20 
21 #include "absl/flags/flag.h"
22 #include "absl/flags/parse.h"
23 #include "absl/strings/string_view.h"
24 #include "modules/audio_processing/include/audio_processing.h"
25 #include "modules/audio_processing/test/aec_dump_based_simulator.h"
26 #include "modules/audio_processing/test/audio_processing_simulator.h"
27 #include "modules/audio_processing/test/wav_based_simulator.h"
28 #include "rtc_base/checks.h"
29 #include "rtc_base/strings/string_builder.h"
30 #include "system_wrappers/include/field_trial.h"
31 
32 constexpr int kParameterNotSpecifiedValue = -10000;
33 
34 ABSL_FLAG(std::string, dump_input, "", "Aec dump input filename");
35 ABSL_FLAG(std::string, dump_output, "", "Aec dump output filename");
36 ABSL_FLAG(std::string, i, "", "Forward stream input wav filename");
37 ABSL_FLAG(std::string, o, "", "Forward stream output wav filename");
38 ABSL_FLAG(std::string, ri, "", "Reverse stream input wav filename");
39 ABSL_FLAG(std::string, ro, "", "Reverse stream output wav filename");
40 ABSL_FLAG(std::string,
41           artificial_nearend,
42           "",
43           "Artificial nearend wav filename");
44 ABSL_FLAG(std::string, linear_aec_output, "", "Linear AEC output wav filename");
45 ABSL_FLAG(int,
46           output_num_channels,
47           kParameterNotSpecifiedValue,
48           "Number of forward stream output channels");
49 ABSL_FLAG(int,
50           reverse_output_num_channels,
51           kParameterNotSpecifiedValue,
52           "Number of Reverse stream output channels");
53 ABSL_FLAG(int,
54           output_sample_rate_hz,
55           kParameterNotSpecifiedValue,
56           "Forward stream output sample rate in Hz");
57 ABSL_FLAG(int,
58           reverse_output_sample_rate_hz,
59           kParameterNotSpecifiedValue,
60           "Reverse stream output sample rate in Hz");
61 ABSL_FLAG(bool,
62           fixed_interface,
63           false,
64           "Use the fixed interface when operating on wav files");
65 ABSL_FLAG(int,
66           aec,
67           kParameterNotSpecifiedValue,
68           "Activate (1) or deactivate(0) the echo canceller");
69 ABSL_FLAG(int,
70           aecm,
71           kParameterNotSpecifiedValue,
72           "Activate (1) or deactivate(0) the mobile echo controller");
73 ABSL_FLAG(int,
74           ed,
75           kParameterNotSpecifiedValue,
76           "Activate (1) or deactivate (0) the residual echo detector");
77 ABSL_FLAG(std::string,
78           ed_graph,
79           "",
80           "Output filename for graph of echo likelihood");
81 ABSL_FLAG(int,
82           agc,
83           kParameterNotSpecifiedValue,
84           "Activate (1) or deactivate(0) the AGC");
85 ABSL_FLAG(int,
86           agc2,
87           kParameterNotSpecifiedValue,
88           "Activate (1) or deactivate(0) the AGC2");
89 ABSL_FLAG(int,
90           pre_amplifier,
91           kParameterNotSpecifiedValue,
92           "Activate (1) or deactivate(0) the pre amplifier");
93 ABSL_FLAG(int,
94           hpf,
95           kParameterNotSpecifiedValue,
96           "Activate (1) or deactivate(0) the high-pass filter");
97 ABSL_FLAG(int,
98           ns,
99           kParameterNotSpecifiedValue,
100           "Activate (1) or deactivate(0) the noise suppressor");
101 ABSL_FLAG(int,
102           ts,
103           kParameterNotSpecifiedValue,
104           "Activate (1) or deactivate(0) the transient suppressor");
105 ABSL_FLAG(int,
106           analog_agc,
107           kParameterNotSpecifiedValue,
108           "Activate (1) or deactivate(0) the transient suppressor");
109 ABSL_FLAG(int,
110           vad,
111           kParameterNotSpecifiedValue,
112           "Activate (1) or deactivate(0) the voice activity detector");
113 ABSL_FLAG(int,
114           le,
115           kParameterNotSpecifiedValue,
116           "Activate (1) or deactivate(0) the level estimator");
117 ABSL_FLAG(bool,
118           all_default,
119           false,
120           "Activate all of the default components (will be overridden by any "
121           "other settings)");
122 ABSL_FLAG(int,
123           analog_agc_disable_digital_adaptive,
124           kParameterNotSpecifiedValue,
125           "Force-deactivate (1) digital adaptation in "
126           "experimental AGC. Digital adaptation is active by default (0).");
127 ABSL_FLAG(int,
128           analog_agc_agc2_level_estimator,
129           kParameterNotSpecifiedValue,
130           "AGC2 level estimation"
131           " in the experimental AGC. AGC1 level estimation is the default (0)");
132 ABSL_FLAG(int,
133           agc_mode,
134           kParameterNotSpecifiedValue,
135           "Specify the AGC mode (0-2)");
136 ABSL_FLAG(int,
137           agc_target_level,
138           kParameterNotSpecifiedValue,
139           "Specify the AGC target level (0-31)");
140 ABSL_FLAG(int,
141           agc_limiter,
142           kParameterNotSpecifiedValue,
143           "Activate (1) or deactivate(0) the level estimator");
144 ABSL_FLAG(int,
145           agc_compression_gain,
146           kParameterNotSpecifiedValue,
147           "Specify the AGC compression gain (0-90)");
148 ABSL_FLAG(int,
149           agc2_enable_adaptive_gain,
150           kParameterNotSpecifiedValue,
151           "Activate (1) or deactivate(0) the AGC2 adaptive gain");
152 ABSL_FLAG(float,
153           agc2_fixed_gain_db,
154           kParameterNotSpecifiedValue,
155           "AGC2 fixed gain (dB) to apply");
156 ABSL_FLAG(std::string,
157           agc2_adaptive_level_estimator,
158           "RMS",
159           "AGC2 adaptive digital level estimator to use [RMS, peak]");
160 ABSL_FLAG(float,
161           pre_amplifier_gain_factor,
162           kParameterNotSpecifiedValue,
163           "Pre-amplifier gain factor (linear) to apply");
164 ABSL_FLAG(int,
165           ns_level,
166           kParameterNotSpecifiedValue,
167           "Specify the NS level (0-3)");
168 ABSL_FLAG(int,
169           ns_analysis_on_linear_aec_output,
170           kParameterNotSpecifiedValue,
171           "Specifies whether the noise suppression analysis is done on the "
172           "linear AEC output");
173 ABSL_FLAG(int,
174           maximum_internal_processing_rate,
175           kParameterNotSpecifiedValue,
176           "Set a maximum internal processing rate (32000 or 48000) to override "
177           "the default rate");
178 ABSL_FLAG(int,
179           stream_delay,
180           kParameterNotSpecifiedValue,
181           "Specify the stream delay in ms to use");
182 ABSL_FLAG(int,
183           use_stream_delay,
184           kParameterNotSpecifiedValue,
185           "Activate (1) or deactivate(0) reporting the stream delay");
186 ABSL_FLAG(int,
187           stream_drift_samples,
188           kParameterNotSpecifiedValue,
189           "Specify the number of stream drift samples to use");
190 ABSL_FLAG(int, initial_mic_level, 100, "Initial mic level (0-255)");
191 ABSL_FLAG(int,
192           simulate_mic_gain,
193           0,
194           "Activate (1) or deactivate(0) the analog mic gain simulation");
195 ABSL_FLAG(int,
196           multi_channel_render,
197           kParameterNotSpecifiedValue,
198           "Activate (1) or deactivate(0) multi-channel render processing in "
199           "APM pipeline");
200 ABSL_FLAG(int,
201           multi_channel_capture,
202           kParameterNotSpecifiedValue,
203           "Activate (1) or deactivate(0) multi-channel capture processing in "
204           "APM pipeline");
205 ABSL_FLAG(int,
206           simulated_mic_kind,
207           kParameterNotSpecifiedValue,
208           "Specify which microphone kind to use for microphone simulation");
209 ABSL_FLAG(bool, performance_report, false, "Report the APM performance ");
210 ABSL_FLAG(std::string,
211           performance_report_output_file,
212           "",
213           "Generate a CSV file with the API call durations");
214 ABSL_FLAG(bool, verbose, false, "Produce verbose output");
215 ABSL_FLAG(bool,
216           quiet,
217           false,
218           "Avoid producing information about the progress.");
219 ABSL_FLAG(bool,
220           bitexactness_report,
221           false,
222           "Report bitexactness for aec dump result reproduction");
223 ABSL_FLAG(bool,
224           discard_settings_in_aecdump,
225           false,
226           "Discard any config settings specified in the aec dump");
227 ABSL_FLAG(bool,
228           store_intermediate_output,
229           false,
230           "Creates new output files after each init");
231 ABSL_FLAG(std::string,
232           custom_call_order_file,
233           "",
234           "Custom process API call order file");
235 ABSL_FLAG(std::string,
236           output_custom_call_order_file,
237           "",
238           "Generate custom process API call order file from AEC dump");
239 ABSL_FLAG(bool,
240           print_aec_parameter_values,
241           false,
242           "Print parameter values used in AEC in JSON-format");
243 ABSL_FLAG(std::string,
244           aec_settings,
245           "",
246           "File in JSON-format with custom AEC settings");
247 ABSL_FLAG(bool,
248           dump_data,
249           false,
250           "Dump internal data during the call (requires build flag)");
251 ABSL_FLAG(std::string,
252           dump_data_output_dir,
253           "",
254           "Internal data dump output directory");
255 ABSL_FLAG(bool,
256           float_wav_output,
257           false,
258           "Produce floating point wav output files.");
259 
260 ABSL_FLAG(std::string,
261           force_fieldtrials,
262           "",
263           "Field trials control experimental feature code which can be forced. "
264           "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/"
265           " will assign the group Enable to field trial WebRTC-FooFeature.");
266 
267 namespace webrtc {
268 namespace test {
269 namespace {
270 
271 const char kUsageDescription[] =
272     "Usage: audioproc_f [options] -i <input.wav>\n"
273     "                   or\n"
274     "       audioproc_f [options] -dump_input <aec_dump>\n"
275     "\n\n"
276     "Command-line tool to simulate a call using the audio "
277     "processing module, either based on wav files or "
278     "protobuf debug dump recordings.\n";
279 
GetAgc2AdaptiveLevelEstimatorNames()280 std::vector<std::string> GetAgc2AdaptiveLevelEstimatorNames() {
281   return {"RMS", "peak"};
282 }
283 
SetSettingIfSpecified(const std::string & value,absl::optional<std::string> * parameter)284 void SetSettingIfSpecified(const std::string& value,
285                            absl::optional<std::string>* parameter) {
286   if (value.compare("") != 0) {
287     *parameter = value;
288   }
289 }
290 
SetSettingIfSpecified(int value,absl::optional<int> * parameter)291 void SetSettingIfSpecified(int value, absl::optional<int>* parameter) {
292   if (value != kParameterNotSpecifiedValue) {
293     *parameter = value;
294   }
295 }
296 
SetSettingIfSpecified(float value,absl::optional<float> * parameter)297 void SetSettingIfSpecified(float value, absl::optional<float>* parameter) {
298   constexpr float kFloatParameterNotSpecifiedValue =
299       kParameterNotSpecifiedValue;
300   if (value != kFloatParameterNotSpecifiedValue) {
301     *parameter = value;
302   }
303 }
304 
SetSettingIfFlagSet(int32_t flag,absl::optional<bool> * parameter)305 void SetSettingIfFlagSet(int32_t flag, absl::optional<bool>* parameter) {
306   if (flag == 0) {
307     *parameter = false;
308   } else if (flag == 1) {
309     *parameter = true;
310   }
311 }
312 
313 AudioProcessing::Config::GainController2::LevelEstimator
MapAgc2AdaptiveLevelEstimator(absl::string_view name)314 MapAgc2AdaptiveLevelEstimator(absl::string_view name) {
315   if (name.compare("RMS") == 0) {
316     return AudioProcessing::Config::GainController2::LevelEstimator::kRms;
317   }
318   if (name.compare("peak") == 0) {
319     return AudioProcessing::Config::GainController2::LevelEstimator::kPeak;
320   }
321   auto concat_strings =
322       [](const std::vector<std::string>& strings) -> std::string {
323     rtc::StringBuilder ss;
324     for (const auto& s : strings) {
325       ss << " " << s;
326     }
327     return ss.Release();
328   };
329   RTC_CHECK(false)
330       << "Invalid value for agc2_adaptive_level_estimator, valid options:"
331       << concat_strings(GetAgc2AdaptiveLevelEstimatorNames()) << ".";
332 }
333 
CreateSettings()334 SimulationSettings CreateSettings() {
335   SimulationSettings settings;
336   if (absl::GetFlag(FLAGS_all_default)) {
337     settings.use_le = true;
338     settings.use_vad = true;
339     settings.use_ts = true;
340     settings.use_analog_agc = true;
341     settings.use_ns = true;
342     settings.use_hpf = true;
343     settings.use_agc = true;
344     settings.use_agc2 = false;
345     settings.use_pre_amplifier = false;
346     settings.use_aec = true;
347     settings.use_aecm = false;
348     settings.use_ed = false;
349   }
350   SetSettingIfSpecified(absl::GetFlag(FLAGS_dump_input),
351                         &settings.aec_dump_input_filename);
352   SetSettingIfSpecified(absl::GetFlag(FLAGS_dump_output),
353                         &settings.aec_dump_output_filename);
354   SetSettingIfSpecified(absl::GetFlag(FLAGS_i), &settings.input_filename);
355   SetSettingIfSpecified(absl::GetFlag(FLAGS_o), &settings.output_filename);
356   SetSettingIfSpecified(absl::GetFlag(FLAGS_ri),
357                         &settings.reverse_input_filename);
358   SetSettingIfSpecified(absl::GetFlag(FLAGS_ro),
359                         &settings.reverse_output_filename);
360   SetSettingIfSpecified(absl::GetFlag(FLAGS_artificial_nearend),
361                         &settings.artificial_nearend_filename);
362   SetSettingIfSpecified(absl::GetFlag(FLAGS_linear_aec_output),
363                         &settings.linear_aec_output_filename);
364   SetSettingIfSpecified(absl::GetFlag(FLAGS_output_num_channels),
365                         &settings.output_num_channels);
366   SetSettingIfSpecified(absl::GetFlag(FLAGS_reverse_output_num_channels),
367                         &settings.reverse_output_num_channels);
368   SetSettingIfSpecified(absl::GetFlag(FLAGS_output_sample_rate_hz),
369                         &settings.output_sample_rate_hz);
370   SetSettingIfSpecified(absl::GetFlag(FLAGS_reverse_output_sample_rate_hz),
371                         &settings.reverse_output_sample_rate_hz);
372   SetSettingIfFlagSet(absl::GetFlag(FLAGS_aec), &settings.use_aec);
373   SetSettingIfFlagSet(absl::GetFlag(FLAGS_aecm), &settings.use_aecm);
374   SetSettingIfFlagSet(absl::GetFlag(FLAGS_ed), &settings.use_ed);
375   SetSettingIfSpecified(absl::GetFlag(FLAGS_ed_graph),
376                         &settings.ed_graph_output_filename);
377   SetSettingIfFlagSet(absl::GetFlag(FLAGS_agc), &settings.use_agc);
378   SetSettingIfFlagSet(absl::GetFlag(FLAGS_agc2), &settings.use_agc2);
379   SetSettingIfFlagSet(absl::GetFlag(FLAGS_pre_amplifier),
380                       &settings.use_pre_amplifier);
381   SetSettingIfFlagSet(absl::GetFlag(FLAGS_hpf), &settings.use_hpf);
382   SetSettingIfFlagSet(absl::GetFlag(FLAGS_ns), &settings.use_ns);
383   SetSettingIfFlagSet(absl::GetFlag(FLAGS_ts), &settings.use_ts);
384   SetSettingIfFlagSet(absl::GetFlag(FLAGS_analog_agc),
385                       &settings.use_analog_agc);
386   SetSettingIfFlagSet(absl::GetFlag(FLAGS_vad), &settings.use_vad);
387   SetSettingIfFlagSet(absl::GetFlag(FLAGS_le), &settings.use_le);
388   SetSettingIfFlagSet(absl::GetFlag(FLAGS_analog_agc_disable_digital_adaptive),
389                       &settings.analog_agc_disable_digital_adaptive);
390   SetSettingIfFlagSet(absl::GetFlag(FLAGS_analog_agc_agc2_level_estimator),
391                       &settings.use_analog_agc_agc2_level_estimator);
392   SetSettingIfSpecified(absl::GetFlag(FLAGS_agc_mode), &settings.agc_mode);
393   SetSettingIfSpecified(absl::GetFlag(FLAGS_agc_target_level),
394                         &settings.agc_target_level);
395   SetSettingIfFlagSet(absl::GetFlag(FLAGS_agc_limiter),
396                       &settings.use_agc_limiter);
397   SetSettingIfSpecified(absl::GetFlag(FLAGS_agc_compression_gain),
398                         &settings.agc_compression_gain);
399   SetSettingIfFlagSet(absl::GetFlag(FLAGS_agc2_enable_adaptive_gain),
400                       &settings.agc2_use_adaptive_gain);
401   SetSettingIfSpecified(absl::GetFlag(FLAGS_agc2_fixed_gain_db),
402                         &settings.agc2_fixed_gain_db);
403   settings.agc2_adaptive_level_estimator = MapAgc2AdaptiveLevelEstimator(
404       absl::GetFlag(FLAGS_agc2_adaptive_level_estimator));
405   SetSettingIfSpecified(absl::GetFlag(FLAGS_pre_amplifier_gain_factor),
406                         &settings.pre_amplifier_gain_factor);
407   SetSettingIfSpecified(absl::GetFlag(FLAGS_ns_level), &settings.ns_level);
408   SetSettingIfFlagSet(absl::GetFlag(FLAGS_ns_analysis_on_linear_aec_output),
409                       &settings.ns_analysis_on_linear_aec_output);
410   SetSettingIfSpecified(absl::GetFlag(FLAGS_maximum_internal_processing_rate),
411                         &settings.maximum_internal_processing_rate);
412   SetSettingIfSpecified(absl::GetFlag(FLAGS_stream_delay),
413                         &settings.stream_delay);
414   SetSettingIfFlagSet(absl::GetFlag(FLAGS_use_stream_delay),
415                       &settings.use_stream_delay);
416   SetSettingIfSpecified(absl::GetFlag(FLAGS_custom_call_order_file),
417                         &settings.call_order_input_filename);
418   SetSettingIfSpecified(absl::GetFlag(FLAGS_output_custom_call_order_file),
419                         &settings.call_order_output_filename);
420   SetSettingIfSpecified(absl::GetFlag(FLAGS_aec_settings),
421                         &settings.aec_settings_filename);
422   settings.initial_mic_level = absl::GetFlag(FLAGS_initial_mic_level);
423   SetSettingIfFlagSet(absl::GetFlag(FLAGS_multi_channel_render),
424                       &settings.multi_channel_render);
425   SetSettingIfFlagSet(absl::GetFlag(FLAGS_multi_channel_capture),
426                       &settings.multi_channel_capture);
427   settings.simulate_mic_gain = absl::GetFlag(FLAGS_simulate_mic_gain);
428   SetSettingIfSpecified(absl::GetFlag(FLAGS_simulated_mic_kind),
429                         &settings.simulated_mic_kind);
430   settings.report_performance = absl::GetFlag(FLAGS_performance_report);
431   SetSettingIfSpecified(absl::GetFlag(FLAGS_performance_report_output_file),
432                         &settings.performance_report_output_filename);
433   settings.use_verbose_logging = absl::GetFlag(FLAGS_verbose);
434   settings.use_quiet_output = absl::GetFlag(FLAGS_quiet);
435   settings.report_bitexactness = absl::GetFlag(FLAGS_bitexactness_report);
436   settings.discard_all_settings_in_aecdump =
437       absl::GetFlag(FLAGS_discard_settings_in_aecdump);
438   settings.fixed_interface = absl::GetFlag(FLAGS_fixed_interface);
439   settings.store_intermediate_output =
440       absl::GetFlag(FLAGS_store_intermediate_output);
441   settings.print_aec_parameter_values =
442       absl::GetFlag(FLAGS_print_aec_parameter_values);
443   settings.dump_internal_data = absl::GetFlag(FLAGS_dump_data);
444   SetSettingIfSpecified(absl::GetFlag(FLAGS_dump_data_output_dir),
445                         &settings.dump_internal_data_output_dir);
446   settings.wav_output_format = absl::GetFlag(FLAGS_float_wav_output)
447                                    ? WavFile::SampleFormat::kFloat
448                                    : WavFile::SampleFormat::kInt16;
449 
450   return settings;
451 }
452 
ReportConditionalErrorAndExit(bool condition,const std::string & message)453 void ReportConditionalErrorAndExit(bool condition, const std::string& message) {
454   if (condition) {
455     std::cerr << message << std::endl;
456     exit(1);
457   }
458 }
459 
PerformBasicParameterSanityChecks(const SimulationSettings & settings,bool pre_constructed_ap_provided,bool pre_constructed_ap_builder_provided)460 void PerformBasicParameterSanityChecks(
461     const SimulationSettings& settings,
462     bool pre_constructed_ap_provided,
463     bool pre_constructed_ap_builder_provided) {
464   if (settings.input_filename || settings.reverse_input_filename) {
465     ReportConditionalErrorAndExit(
466         !!settings.aec_dump_input_filename,
467         "Error: The aec dump file cannot be specified "
468         "together with input wav files!\n");
469 
470     ReportConditionalErrorAndExit(
471         !!settings.aec_dump_input_string,
472         "Error: The aec dump input string cannot be specified "
473         "together with input wav files!\n");
474 
475     ReportConditionalErrorAndExit(!!settings.artificial_nearend_filename,
476                                   "Error: The artificial nearend cannot be "
477                                   "specified together with input wav files!\n");
478 
479     ReportConditionalErrorAndExit(!settings.input_filename,
480                                   "Error: When operating at wav files, the "
481                                   "input wav filename must be "
482                                   "specified!\n");
483 
484     ReportConditionalErrorAndExit(
485         settings.reverse_output_filename && !settings.reverse_input_filename,
486         "Error: When operating at wav files, the reverse input wav filename "
487         "must be specified if the reverse output wav filename is specified!\n");
488   } else {
489     ReportConditionalErrorAndExit(
490         !settings.aec_dump_input_filename && !settings.aec_dump_input_string,
491         "Error: Either the aec dump input file, the wav "
492         "input file or the aec dump input string must be specified!\n");
493     ReportConditionalErrorAndExit(
494         settings.aec_dump_input_filename && settings.aec_dump_input_string,
495         "Error: The aec dump input file cannot be specified together with the "
496         "aec dump input string!\n");
497   }
498 
499   ReportConditionalErrorAndExit(settings.use_aec && !(*settings.use_aec) &&
500                                     settings.linear_aec_output_filename,
501                                 "Error: The linear AEC ouput filename cannot "
502                                 "be specified without the AEC being active");
503 
504   ReportConditionalErrorAndExit(
505       settings.use_aec && *settings.use_aec && settings.use_aecm &&
506           *settings.use_aecm,
507       "Error: The AEC and the AECM cannot be activated at the same time!\n");
508 
509   ReportConditionalErrorAndExit(
510       settings.output_sample_rate_hz && *settings.output_sample_rate_hz <= 0,
511       "Error: --output_sample_rate_hz must be positive!\n");
512 
513   ReportConditionalErrorAndExit(
514       settings.reverse_output_sample_rate_hz &&
515           settings.output_sample_rate_hz &&
516           *settings.output_sample_rate_hz <= 0,
517       "Error: --reverse_output_sample_rate_hz must be positive!\n");
518 
519   ReportConditionalErrorAndExit(
520       settings.output_num_channels && *settings.output_num_channels <= 0,
521       "Error: --output_num_channels must be positive!\n");
522 
523   ReportConditionalErrorAndExit(
524       settings.reverse_output_num_channels &&
525           *settings.reverse_output_num_channels <= 0,
526       "Error: --reverse_output_num_channels must be positive!\n");
527 
528   ReportConditionalErrorAndExit(
529       settings.agc_target_level && ((*settings.agc_target_level) < 0 ||
530                                     (*settings.agc_target_level) > 31),
531       "Error: --agc_target_level must be specified between 0 and 31.\n");
532 
533   ReportConditionalErrorAndExit(
534       settings.agc_compression_gain && ((*settings.agc_compression_gain) < 0 ||
535                                         (*settings.agc_compression_gain) > 90),
536       "Error: --agc_compression_gain must be specified between 0 and 90.\n");
537 
538   ReportConditionalErrorAndExit(
539       settings.agc2_fixed_gain_db && ((*settings.agc2_fixed_gain_db) < 0 ||
540                                       (*settings.agc2_fixed_gain_db) > 90),
541       "Error: --agc2_fixed_gain_db must be specified between 0 and 90.\n");
542 
543   ReportConditionalErrorAndExit(
544       settings.ns_level &&
545           ((*settings.ns_level) < 0 || (*settings.ns_level) > 3),
546       "Error: --ns_level must be specified between 0 and 3.\n");
547 
548   ReportConditionalErrorAndExit(
549       settings.report_bitexactness && !settings.aec_dump_input_filename,
550       "Error: --bitexactness_report can only be used when operating on an "
551       "aecdump\n");
552 
553   ReportConditionalErrorAndExit(
554       settings.call_order_input_filename && settings.aec_dump_input_filename,
555       "Error: --custom_call_order_file cannot be used when operating on an "
556       "aecdump\n");
557 
558   ReportConditionalErrorAndExit(
559       (settings.initial_mic_level < 0 || settings.initial_mic_level > 255),
560       "Error: --initial_mic_level must be specified between 0 and 255.\n");
561 
562   ReportConditionalErrorAndExit(
563       settings.simulated_mic_kind && !settings.simulate_mic_gain,
564       "Error: --simulated_mic_kind cannot be specified when mic simulation is "
565       "disabled\n");
566 
567   ReportConditionalErrorAndExit(
568       !settings.simulated_mic_kind && settings.simulate_mic_gain,
569       "Error: --simulated_mic_kind must be specified when mic simulation is "
570       "enabled\n");
571 
572   auto valid_wav_name = [](const std::string& wav_file_name) {
573     if (wav_file_name.size() < 5) {
574       return false;
575     }
576     if ((wav_file_name.compare(wav_file_name.size() - 4, 4, ".wav") == 0) ||
577         (wav_file_name.compare(wav_file_name.size() - 4, 4, ".WAV") == 0)) {
578       return true;
579     }
580     return false;
581   };
582 
583   ReportConditionalErrorAndExit(
584       settings.input_filename && (!valid_wav_name(*settings.input_filename)),
585       "Error: --i must be a valid .wav file name.\n");
586 
587   ReportConditionalErrorAndExit(
588       settings.output_filename && (!valid_wav_name(*settings.output_filename)),
589       "Error: --o must be a valid .wav file name.\n");
590 
591   ReportConditionalErrorAndExit(
592       settings.reverse_input_filename &&
593           (!valid_wav_name(*settings.reverse_input_filename)),
594       "Error: --ri must be a valid .wav file name.\n");
595 
596   ReportConditionalErrorAndExit(
597       settings.reverse_output_filename &&
598           (!valid_wav_name(*settings.reverse_output_filename)),
599       "Error: --ro must be a valid .wav file name.\n");
600 
601   ReportConditionalErrorAndExit(
602       settings.artificial_nearend_filename &&
603           !valid_wav_name(*settings.artificial_nearend_filename),
604       "Error: --artifical_nearend must be a valid .wav file name.\n");
605 
606   ReportConditionalErrorAndExit(
607       settings.linear_aec_output_filename &&
608           (!valid_wav_name(*settings.linear_aec_output_filename)),
609       "Error: --linear_aec_output must be a valid .wav file name.\n");
610 
611   ReportConditionalErrorAndExit(
612       WEBRTC_APM_DEBUG_DUMP == 0 && settings.dump_internal_data,
613       "Error: --dump_data cannot be set without proper build support.\n");
614 
615   ReportConditionalErrorAndExit(
616       !settings.dump_internal_data &&
617           settings.dump_internal_data_output_dir.has_value(),
618       "Error: --dump_data_output_dir cannot be set without --dump_data.\n");
619 
620   ReportConditionalErrorAndExit(
621       !settings.aec_dump_input_filename &&
622           settings.call_order_output_filename.has_value(),
623       "Error: --output_custom_call_order_file needs an AEC dump input file.\n");
624 
625   ReportConditionalErrorAndExit(
626       (!settings.use_pre_amplifier || !(*settings.use_pre_amplifier)) &&
627           settings.pre_amplifier_gain_factor.has_value(),
628       "Error: --pre_amplifier_gain_factor needs --pre_amplifier to be "
629       "specified and set.\n");
630 
631   ReportConditionalErrorAndExit(
632       pre_constructed_ap_provided && pre_constructed_ap_builder_provided,
633       "Error: The AudioProcessing and the AudioProcessingBuilder cannot both "
634       "be specified at the same time.\n");
635 
636   ReportConditionalErrorAndExit(
637       settings.aec_settings_filename && pre_constructed_ap_provided,
638       "Error: The aec_settings_filename cannot be specified when a "
639       "pre-constructed audio processing object is provided.\n");
640 
641   ReportConditionalErrorAndExit(
642       settings.aec_settings_filename && pre_constructed_ap_provided,
643       "Error: The print_aec_parameter_values cannot be set when a "
644       "pre-constructed audio processing object is provided.\n");
645 
646   if (settings.linear_aec_output_filename && pre_constructed_ap_provided) {
647     std::cout << "Warning: For the linear AEC output to be stored, this must "
648                  "be configured in the AEC that is part of the provided "
649                  "AudioProcessing object."
650               << std::endl;
651   }
652 }
653 
RunSimulation(rtc::scoped_refptr<AudioProcessing> audio_processing,std::unique_ptr<AudioProcessingBuilder> ap_builder,int argc,char * argv[],absl::string_view input_aecdump,std::vector<float> * processed_capture_samples)654 int RunSimulation(rtc::scoped_refptr<AudioProcessing> audio_processing,
655                   std::unique_ptr<AudioProcessingBuilder> ap_builder,
656                   int argc,
657                   char* argv[],
658                   absl::string_view input_aecdump,
659                   std::vector<float>* processed_capture_samples) {
660   std::vector<char*> args = absl::ParseCommandLine(argc, argv);
661   if (args.size() != 1) {
662     printf("%s", kUsageDescription);
663     return 1;
664   }
665   // InitFieldTrialsFromString stores the char*, so the char array must
666   // outlive the application.
667   const std::string field_trials = absl::GetFlag(FLAGS_force_fieldtrials);
668   webrtc::field_trial::InitFieldTrialsFromString(field_trials.c_str());
669 
670   SimulationSettings settings = CreateSettings();
671   if (!input_aecdump.empty()) {
672     settings.aec_dump_input_string = input_aecdump;
673     settings.processed_capture_samples = processed_capture_samples;
674     RTC_CHECK(settings.processed_capture_samples);
675   }
676   PerformBasicParameterSanityChecks(settings, !!audio_processing, !!ap_builder);
677   std::unique_ptr<AudioProcessingSimulator> processor;
678 
679   if (settings.aec_dump_input_filename || settings.aec_dump_input_string) {
680     processor.reset(new AecDumpBasedSimulator(
681         settings, std::move(audio_processing), std::move(ap_builder)));
682   } else {
683     processor.reset(new WavBasedSimulator(settings, std::move(audio_processing),
684                                           std::move(ap_builder)));
685   }
686 
687   processor->Process();
688 
689   if (settings.report_performance) {
690     processor->GetApiCallStatistics().PrintReport();
691   }
692   if (settings.performance_report_output_filename) {
693     processor->GetApiCallStatistics().WriteReportToFile(
694         *settings.performance_report_output_filename);
695   }
696 
697   if (settings.report_bitexactness && settings.aec_dump_input_filename) {
698     if (processor->OutputWasBitexact()) {
699       std::cout << "The processing was bitexact.";
700     } else {
701       std::cout << "The processing was not bitexact.";
702     }
703   }
704 
705   return 0;
706 }
707 
708 }  // namespace
709 
AudioprocFloatImpl(rtc::scoped_refptr<AudioProcessing> audio_processing,int argc,char * argv[])710 int AudioprocFloatImpl(rtc::scoped_refptr<AudioProcessing> audio_processing,
711                        int argc,
712                        char* argv[]) {
713   return RunSimulation(
714       std::move(audio_processing), /*ap_builder=*/nullptr, argc, argv,
715       /*input_aecdump=*/"", /*processed_capture_samples=*/nullptr);
716 }
717 
AudioprocFloatImpl(std::unique_ptr<AudioProcessingBuilder> ap_builder,int argc,char * argv[],absl::string_view input_aecdump,std::vector<float> * processed_capture_samples)718 int AudioprocFloatImpl(std::unique_ptr<AudioProcessingBuilder> ap_builder,
719                        int argc,
720                        char* argv[],
721                        absl::string_view input_aecdump,
722                        std::vector<float>* processed_capture_samples) {
723   return RunSimulation(/*audio_processing=*/nullptr, std::move(ap_builder),
724                        argc, argv, input_aecdump, processed_capture_samples);
725 }
726 
727 }  // namespace test
728 }  // namespace webrtc
729