xref: /aosp_15_r20/external/webrtc/modules/audio_processing/test/audioproc_float_impl.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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(
94     int,
95     capture_level_adjustment,
96     kParameterNotSpecifiedValue,
97     "Activate (1) or deactivate(0) the capture level adjustment functionality");
98 ABSL_FLAG(int,
99           analog_mic_gain_emulation,
100           kParameterNotSpecifiedValue,
101           "Activate (1) or deactivate(0) the analog mic gain emulation in the "
102           "production (non-test) code.");
103 ABSL_FLAG(int,
104           hpf,
105           kParameterNotSpecifiedValue,
106           "Activate (1) or deactivate (0) the high-pass filter");
107 ABSL_FLAG(int,
108           ns,
109           kParameterNotSpecifiedValue,
110           "Activate (1) or deactivate (0) the noise suppressor");
111 ABSL_FLAG(int,
112           ts,
113           kParameterNotSpecifiedValue,
114           "Activate (1) or deactivate (0) the transient suppressor");
115 ABSL_FLAG(int,
116           analog_agc,
117           kParameterNotSpecifiedValue,
118           "Activate (1) or deactivate (0) the analog AGC");
119 ABSL_FLAG(bool,
120           all_default,
121           false,
122           "Activate all of the default components (will be overridden by any "
123           "other settings)");
124 ABSL_FLAG(int,
125           analog_agc_use_digital_adaptive_controller,
126           kParameterNotSpecifiedValue,
127           "Activate (1) or deactivate (0) digital adaptation in AGC1. "
128           "Digital adaptation is active by default.");
129 ABSL_FLAG(int,
130           agc_mode,
131           kParameterNotSpecifiedValue,
132           "Specify the AGC mode (0-2)");
133 ABSL_FLAG(int,
134           agc_target_level,
135           kParameterNotSpecifiedValue,
136           "Specify the AGC target level (0-31)");
137 ABSL_FLAG(int,
138           agc_limiter,
139           kParameterNotSpecifiedValue,
140           "Activate (1) or deactivate (0) the level estimator");
141 ABSL_FLAG(int,
142           agc_compression_gain,
143           kParameterNotSpecifiedValue,
144           "Specify the AGC compression gain (0-90)");
145 ABSL_FLAG(int,
146           agc2_enable_adaptive_gain,
147           kParameterNotSpecifiedValue,
148           "Activate (1) or deactivate (0) the AGC2 adaptive gain");
149 ABSL_FLAG(float,
150           agc2_fixed_gain_db,
151           kParameterNotSpecifiedValue,
152           "AGC2 fixed gain (dB) to apply");
153 ABSL_FLAG(float,
154           pre_amplifier_gain_factor,
155           kParameterNotSpecifiedValue,
156           "Pre-amplifier gain factor (linear) to apply");
157 ABSL_FLAG(float,
158           pre_gain_factor,
159           kParameterNotSpecifiedValue,
160           "Pre-gain factor (linear) to apply in the capture level adjustment");
161 ABSL_FLAG(float,
162           post_gain_factor,
163           kParameterNotSpecifiedValue,
164           "Post-gain factor (linear) to apply in the capture level adjustment");
165 ABSL_FLAG(float,
166           analog_mic_gain_emulation_initial_level,
167           kParameterNotSpecifiedValue,
168           "Emulated analog mic level to apply initially in the production "
169           "(non-test) code.");
170 ABSL_FLAG(int,
171           ns_level,
172           kParameterNotSpecifiedValue,
173           "Specify the NS level (0-3)");
174 ABSL_FLAG(int,
175           ns_analysis_on_linear_aec_output,
176           kParameterNotSpecifiedValue,
177           "Specifies whether the noise suppression analysis is done on the "
178           "linear AEC output");
179 ABSL_FLAG(int,
180           maximum_internal_processing_rate,
181           kParameterNotSpecifiedValue,
182           "Set a maximum internal processing rate (32000 or 48000) to override "
183           "the default rate");
184 ABSL_FLAG(int,
185           stream_delay,
186           kParameterNotSpecifiedValue,
187           "Specify the stream delay in ms to use");
188 ABSL_FLAG(int,
189           use_stream_delay,
190           kParameterNotSpecifiedValue,
191           "Activate (1) or deactivate (0) reporting the stream delay");
192 ABSL_FLAG(int,
193           stream_drift_samples,
194           kParameterNotSpecifiedValue,
195           "Specify the number of stream drift samples to use");
196 ABSL_FLAG(int,
197           initial_mic_level,
198           100,
199           "Initial mic level (0-255) for the analog mic gain simulation in the "
200           "test code");
201 ABSL_FLAG(int,
202           simulate_mic_gain,
203           0,
204           "Activate (1) or deactivate(0) the analog mic gain simulation in the "
205           "test code");
206 ABSL_FLAG(int,
207           multi_channel_render,
208           kParameterNotSpecifiedValue,
209           "Activate (1) or deactivate (0) multi-channel render processing in "
210           "APM pipeline");
211 ABSL_FLAG(int,
212           multi_channel_capture,
213           kParameterNotSpecifiedValue,
214           "Activate (1) or deactivate (0) multi-channel capture processing in "
215           "APM pipeline");
216 ABSL_FLAG(int,
217           simulated_mic_kind,
218           kParameterNotSpecifiedValue,
219           "Specify which microphone kind to use for microphone simulation");
220 ABSL_FLAG(int,
221           override_key_pressed,
222           kParameterNotSpecifiedValue,
223           "Always set to true (1) or to false (0) the key press state. If "
224           "unspecified, false is set with Wav files or, with AEC dumps, the "
225           "recorded event is used.");
226 ABSL_FLAG(int,
227           frame_for_sending_capture_output_used_false,
228           kParameterNotSpecifiedValue,
229           "Capture frame index for sending a runtime setting for that the "
230           "capture output is not used.");
231 ABSL_FLAG(int,
232           frame_for_sending_capture_output_used_true,
233           kParameterNotSpecifiedValue,
234           "Capture frame index for sending a runtime setting for that the "
235           "capture output is used.");
236 ABSL_FLAG(bool, performance_report, false, "Report the APM performance ");
237 ABSL_FLAG(std::string,
238           performance_report_output_file,
239           "",
240           "Generate a CSV file with the API call durations");
241 ABSL_FLAG(bool, verbose, false, "Produce verbose output");
242 ABSL_FLAG(bool,
243           quiet,
244           false,
245           "Avoid producing information about the progress.");
246 ABSL_FLAG(bool,
247           bitexactness_report,
248           false,
249           "Report bitexactness for aec dump result reproduction");
250 ABSL_FLAG(bool,
251           discard_settings_in_aecdump,
252           false,
253           "Discard any config settings specified in the aec dump");
254 ABSL_FLAG(bool,
255           store_intermediate_output,
256           false,
257           "Creates new output files after each init");
258 ABSL_FLAG(std::string,
259           custom_call_order_file,
260           "",
261           "Custom process API call order file");
262 ABSL_FLAG(std::string,
263           output_custom_call_order_file,
264           "",
265           "Generate custom process API call order file from AEC dump");
266 ABSL_FLAG(bool,
267           print_aec_parameter_values,
268           false,
269           "Print parameter values used in AEC in JSON-format");
270 ABSL_FLAG(std::string,
271           aec_settings,
272           "",
273           "File in JSON-format with custom AEC settings");
274 ABSL_FLAG(bool,
275           dump_data,
276           false,
277           "Dump internal data during the call (requires build flag)");
278 ABSL_FLAG(std::string,
279           dump_data_output_dir,
280           "",
281           "Internal data dump output directory");
282 ABSL_FLAG(int,
283           dump_set_to_use,
284           kParameterNotSpecifiedValue,
285           "Specifies the dump set to use (if not all the dump sets will "
286           "be used");
287 ABSL_FLAG(bool,
288           analyze,
289           false,
290           "Only analyze the call setup behavior (no processing)");
291 ABSL_FLAG(float,
292           dump_start_seconds,
293           kParameterNotSpecifiedValue,
294           "Start of when to dump data (seconds).");
295 ABSL_FLAG(float,
296           dump_end_seconds,
297           kParameterNotSpecifiedValue,
298           "End of when to dump data (seconds).");
299 ABSL_FLAG(int,
300           dump_start_frame,
301           kParameterNotSpecifiedValue,
302           "Start of when to dump data (frames).");
303 ABSL_FLAG(int,
304           dump_end_frame,
305           kParameterNotSpecifiedValue,
306           "End of when to dump data (frames).");
307 ABSL_FLAG(int,
308           init_to_process,
309           kParameterNotSpecifiedValue,
310           "Init index to process.");
311 
312 ABSL_FLAG(bool,
313           float_wav_output,
314           false,
315           "Produce floating point wav output files.");
316 
317 ABSL_FLAG(std::string,
318           force_fieldtrials,
319           "",
320           "Field trials control experimental feature code which can be forced. "
321           "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enable/"
322           " will assign the group Enable to field trial WebRTC-FooFeature.");
323 
324 namespace webrtc {
325 namespace test {
326 namespace {
327 
328 const char kUsageDescription[] =
329     "Usage: audioproc_f [options] -i <input.wav>\n"
330     "                   or\n"
331     "       audioproc_f [options] -dump_input <aec_dump>\n"
332     "\n\n"
333     "Command-line tool to simulate a call using the audio "
334     "processing module, either based on wav files or "
335     "protobuf debug dump recordings.\n";
336 
SetSettingIfSpecified(absl::string_view value,absl::optional<std::string> * parameter)337 void SetSettingIfSpecified(absl::string_view value,
338                            absl::optional<std::string>* parameter) {
339   if (value.compare("") != 0) {
340     *parameter = std::string(value);
341   }
342 }
343 
SetSettingIfSpecified(int value,absl::optional<int> * parameter)344 void SetSettingIfSpecified(int value, absl::optional<int>* parameter) {
345   if (value != kParameterNotSpecifiedValue) {
346     *parameter = value;
347   }
348 }
349 
SetSettingIfSpecified(float value,absl::optional<float> * parameter)350 void SetSettingIfSpecified(float value, absl::optional<float>* parameter) {
351   constexpr float kFloatParameterNotSpecifiedValue =
352       kParameterNotSpecifiedValue;
353   if (value != kFloatParameterNotSpecifiedValue) {
354     *parameter = value;
355   }
356 }
357 
SetSettingIfFlagSet(int32_t flag,absl::optional<bool> * parameter)358 void SetSettingIfFlagSet(int32_t flag, absl::optional<bool>* parameter) {
359   if (flag == 0) {
360     *parameter = false;
361   } else if (flag == 1) {
362     *parameter = true;
363   }
364 }
365 
CreateSettings()366 SimulationSettings CreateSettings() {
367   SimulationSettings settings;
368   if (absl::GetFlag(FLAGS_all_default)) {
369     settings.use_ts = true;
370     settings.use_analog_agc = true;
371     settings.use_ns = true;
372     settings.use_hpf = true;
373     settings.use_agc = true;
374     settings.use_agc2 = false;
375     settings.use_pre_amplifier = false;
376     settings.use_aec = true;
377     settings.use_aecm = false;
378     settings.use_ed = false;
379   }
380   SetSettingIfSpecified(absl::GetFlag(FLAGS_dump_input),
381                         &settings.aec_dump_input_filename);
382   SetSettingIfSpecified(absl::GetFlag(FLAGS_dump_output),
383                         &settings.aec_dump_output_filename);
384   SetSettingIfSpecified(absl::GetFlag(FLAGS_i), &settings.input_filename);
385   SetSettingIfSpecified(absl::GetFlag(FLAGS_o), &settings.output_filename);
386   SetSettingIfSpecified(absl::GetFlag(FLAGS_ri),
387                         &settings.reverse_input_filename);
388   SetSettingIfSpecified(absl::GetFlag(FLAGS_ro),
389                         &settings.reverse_output_filename);
390   SetSettingIfSpecified(absl::GetFlag(FLAGS_artificial_nearend),
391                         &settings.artificial_nearend_filename);
392   SetSettingIfSpecified(absl::GetFlag(FLAGS_linear_aec_output),
393                         &settings.linear_aec_output_filename);
394   SetSettingIfSpecified(absl::GetFlag(FLAGS_output_num_channels),
395                         &settings.output_num_channels);
396   SetSettingIfSpecified(absl::GetFlag(FLAGS_reverse_output_num_channels),
397                         &settings.reverse_output_num_channels);
398   SetSettingIfSpecified(absl::GetFlag(FLAGS_output_sample_rate_hz),
399                         &settings.output_sample_rate_hz);
400   SetSettingIfSpecified(absl::GetFlag(FLAGS_reverse_output_sample_rate_hz),
401                         &settings.reverse_output_sample_rate_hz);
402   SetSettingIfFlagSet(absl::GetFlag(FLAGS_aec), &settings.use_aec);
403   SetSettingIfFlagSet(absl::GetFlag(FLAGS_aecm), &settings.use_aecm);
404   SetSettingIfFlagSet(absl::GetFlag(FLAGS_ed), &settings.use_ed);
405   SetSettingIfSpecified(absl::GetFlag(FLAGS_ed_graph),
406                         &settings.ed_graph_output_filename);
407   SetSettingIfFlagSet(absl::GetFlag(FLAGS_agc), &settings.use_agc);
408   SetSettingIfFlagSet(absl::GetFlag(FLAGS_agc2), &settings.use_agc2);
409   SetSettingIfFlagSet(absl::GetFlag(FLAGS_pre_amplifier),
410                       &settings.use_pre_amplifier);
411   SetSettingIfFlagSet(absl::GetFlag(FLAGS_capture_level_adjustment),
412                       &settings.use_capture_level_adjustment);
413   SetSettingIfFlagSet(absl::GetFlag(FLAGS_analog_mic_gain_emulation),
414                       &settings.use_analog_mic_gain_emulation);
415   SetSettingIfFlagSet(absl::GetFlag(FLAGS_hpf), &settings.use_hpf);
416   SetSettingIfFlagSet(absl::GetFlag(FLAGS_ns), &settings.use_ns);
417   SetSettingIfSpecified(absl::GetFlag(FLAGS_ts), &settings.use_ts);
418   SetSettingIfFlagSet(absl::GetFlag(FLAGS_analog_agc),
419                       &settings.use_analog_agc);
420   SetSettingIfFlagSet(
421       absl::GetFlag(FLAGS_analog_agc_use_digital_adaptive_controller),
422       &settings.analog_agc_use_digital_adaptive_controller);
423   SetSettingIfSpecified(absl::GetFlag(FLAGS_agc_mode), &settings.agc_mode);
424   SetSettingIfSpecified(absl::GetFlag(FLAGS_agc_target_level),
425                         &settings.agc_target_level);
426   SetSettingIfFlagSet(absl::GetFlag(FLAGS_agc_limiter),
427                       &settings.use_agc_limiter);
428   SetSettingIfSpecified(absl::GetFlag(FLAGS_agc_compression_gain),
429                         &settings.agc_compression_gain);
430   SetSettingIfFlagSet(absl::GetFlag(FLAGS_agc2_enable_adaptive_gain),
431                       &settings.agc2_use_adaptive_gain);
432 
433   SetSettingIfSpecified(absl::GetFlag(FLAGS_agc2_fixed_gain_db),
434                         &settings.agc2_fixed_gain_db);
435   SetSettingIfSpecified(absl::GetFlag(FLAGS_pre_amplifier_gain_factor),
436                         &settings.pre_amplifier_gain_factor);
437   SetSettingIfSpecified(absl::GetFlag(FLAGS_pre_gain_factor),
438                         &settings.pre_gain_factor);
439   SetSettingIfSpecified(absl::GetFlag(FLAGS_post_gain_factor),
440                         &settings.post_gain_factor);
441   SetSettingIfSpecified(
442       absl::GetFlag(FLAGS_analog_mic_gain_emulation_initial_level),
443       &settings.analog_mic_gain_emulation_initial_level);
444   SetSettingIfSpecified(absl::GetFlag(FLAGS_ns_level), &settings.ns_level);
445   SetSettingIfFlagSet(absl::GetFlag(FLAGS_ns_analysis_on_linear_aec_output),
446                       &settings.ns_analysis_on_linear_aec_output);
447   SetSettingIfSpecified(absl::GetFlag(FLAGS_maximum_internal_processing_rate),
448                         &settings.maximum_internal_processing_rate);
449   SetSettingIfSpecified(absl::GetFlag(FLAGS_stream_delay),
450                         &settings.stream_delay);
451   SetSettingIfFlagSet(absl::GetFlag(FLAGS_use_stream_delay),
452                       &settings.use_stream_delay);
453   SetSettingIfSpecified(absl::GetFlag(FLAGS_custom_call_order_file),
454                         &settings.call_order_input_filename);
455   SetSettingIfSpecified(absl::GetFlag(FLAGS_output_custom_call_order_file),
456                         &settings.call_order_output_filename);
457   SetSettingIfSpecified(absl::GetFlag(FLAGS_aec_settings),
458                         &settings.aec_settings_filename);
459   settings.initial_mic_level = absl::GetFlag(FLAGS_initial_mic_level);
460   SetSettingIfFlagSet(absl::GetFlag(FLAGS_multi_channel_render),
461                       &settings.multi_channel_render);
462   SetSettingIfFlagSet(absl::GetFlag(FLAGS_multi_channel_capture),
463                       &settings.multi_channel_capture);
464   settings.simulate_mic_gain = absl::GetFlag(FLAGS_simulate_mic_gain);
465   SetSettingIfSpecified(absl::GetFlag(FLAGS_simulated_mic_kind),
466                         &settings.simulated_mic_kind);
467   SetSettingIfFlagSet(absl::GetFlag(FLAGS_override_key_pressed),
468                       &settings.override_key_pressed);
469   SetSettingIfSpecified(
470       absl::GetFlag(FLAGS_frame_for_sending_capture_output_used_false),
471       &settings.frame_for_sending_capture_output_used_false);
472   SetSettingIfSpecified(
473       absl::GetFlag(FLAGS_frame_for_sending_capture_output_used_true),
474       &settings.frame_for_sending_capture_output_used_true);
475   settings.report_performance = absl::GetFlag(FLAGS_performance_report);
476   SetSettingIfSpecified(absl::GetFlag(FLAGS_performance_report_output_file),
477                         &settings.performance_report_output_filename);
478   settings.use_verbose_logging = absl::GetFlag(FLAGS_verbose);
479   settings.use_quiet_output = absl::GetFlag(FLAGS_quiet);
480   settings.report_bitexactness = absl::GetFlag(FLAGS_bitexactness_report);
481   settings.discard_all_settings_in_aecdump =
482       absl::GetFlag(FLAGS_discard_settings_in_aecdump);
483   settings.fixed_interface = absl::GetFlag(FLAGS_fixed_interface);
484   settings.store_intermediate_output =
485       absl::GetFlag(FLAGS_store_intermediate_output);
486   settings.print_aec_parameter_values =
487       absl::GetFlag(FLAGS_print_aec_parameter_values);
488   settings.dump_internal_data = absl::GetFlag(FLAGS_dump_data);
489   SetSettingIfSpecified(absl::GetFlag(FLAGS_dump_data_output_dir),
490                         &settings.dump_internal_data_output_dir);
491   SetSettingIfSpecified(absl::GetFlag(FLAGS_dump_set_to_use),
492                         &settings.dump_set_to_use);
493   settings.wav_output_format = absl::GetFlag(FLAGS_float_wav_output)
494                                    ? WavFile::SampleFormat::kFloat
495                                    : WavFile::SampleFormat::kInt16;
496 
497   settings.analysis_only = absl::GetFlag(FLAGS_analyze);
498 
499   SetSettingIfSpecified(absl::GetFlag(FLAGS_dump_start_frame),
500                         &settings.dump_start_frame);
501   SetSettingIfSpecified(absl::GetFlag(FLAGS_dump_end_frame),
502                         &settings.dump_end_frame);
503 
504   constexpr int kFramesPerSecond = 100;
505   absl::optional<float> start_seconds;
506   SetSettingIfSpecified(absl::GetFlag(FLAGS_dump_start_seconds),
507                         &start_seconds);
508   if (start_seconds) {
509     settings.dump_start_frame = *start_seconds * kFramesPerSecond;
510   }
511 
512   absl::optional<float> end_seconds;
513   SetSettingIfSpecified(absl::GetFlag(FLAGS_dump_end_seconds), &end_seconds);
514   if (end_seconds) {
515     settings.dump_end_frame = *end_seconds * kFramesPerSecond;
516   }
517 
518   SetSettingIfSpecified(absl::GetFlag(FLAGS_init_to_process),
519                         &settings.init_to_process);
520 
521   return settings;
522 }
523 
ReportConditionalErrorAndExit(bool condition,absl::string_view message)524 void ReportConditionalErrorAndExit(bool condition, absl::string_view message) {
525   if (condition) {
526     std::cerr << message << std::endl;
527     exit(1);
528   }
529 }
530 
PerformBasicParameterSanityChecks(const SimulationSettings & settings,bool pre_constructed_ap_provided,bool pre_constructed_ap_builder_provided)531 void PerformBasicParameterSanityChecks(
532     const SimulationSettings& settings,
533     bool pre_constructed_ap_provided,
534     bool pre_constructed_ap_builder_provided) {
535   if (settings.input_filename || settings.reverse_input_filename) {
536     ReportConditionalErrorAndExit(
537         !!settings.aec_dump_input_filename,
538         "Error: The aec dump file cannot be specified "
539         "together with input wav files!\n");
540 
541     ReportConditionalErrorAndExit(
542         !!settings.aec_dump_input_string,
543         "Error: The aec dump input string cannot be specified "
544         "together with input wav files!\n");
545 
546     ReportConditionalErrorAndExit(!!settings.artificial_nearend_filename,
547                                   "Error: The artificial nearend cannot be "
548                                   "specified together with input wav files!\n");
549 
550     ReportConditionalErrorAndExit(!settings.input_filename,
551                                   "Error: When operating at wav files, the "
552                                   "input wav filename must be "
553                                   "specified!\n");
554 
555     ReportConditionalErrorAndExit(
556         settings.reverse_output_filename && !settings.reverse_input_filename,
557         "Error: When operating at wav files, the reverse input wav filename "
558         "must be specified if the reverse output wav filename is specified!\n");
559   } else {
560     ReportConditionalErrorAndExit(
561         !settings.aec_dump_input_filename && !settings.aec_dump_input_string,
562         "Error: Either the aec dump input file, the wav "
563         "input file or the aec dump input string must be specified!\n");
564     ReportConditionalErrorAndExit(
565         settings.aec_dump_input_filename && settings.aec_dump_input_string,
566         "Error: The aec dump input file cannot be specified together with the "
567         "aec dump input string!\n");
568   }
569 
570   ReportConditionalErrorAndExit(settings.use_aec && !(*settings.use_aec) &&
571                                     settings.linear_aec_output_filename,
572                                 "Error: The linear AEC ouput filename cannot "
573                                 "be specified without the AEC being active");
574 
575   ReportConditionalErrorAndExit(
576       settings.use_aec && *settings.use_aec && settings.use_aecm &&
577           *settings.use_aecm,
578       "Error: The AEC and the AECM cannot be activated at the same time!\n");
579 
580   ReportConditionalErrorAndExit(
581       settings.output_sample_rate_hz && *settings.output_sample_rate_hz <= 0,
582       "Error: --output_sample_rate_hz must be positive!\n");
583 
584   ReportConditionalErrorAndExit(
585       settings.reverse_output_sample_rate_hz &&
586           settings.output_sample_rate_hz &&
587           *settings.output_sample_rate_hz <= 0,
588       "Error: --reverse_output_sample_rate_hz must be positive!\n");
589 
590   ReportConditionalErrorAndExit(
591       settings.output_num_channels && *settings.output_num_channels <= 0,
592       "Error: --output_num_channels must be positive!\n");
593 
594   ReportConditionalErrorAndExit(
595       settings.reverse_output_num_channels &&
596           *settings.reverse_output_num_channels <= 0,
597       "Error: --reverse_output_num_channels must be positive!\n");
598 
599   ReportConditionalErrorAndExit(
600       settings.agc_target_level && ((*settings.agc_target_level) < 0 ||
601                                     (*settings.agc_target_level) > 31),
602       "Error: --agc_target_level must be specified between 0 and 31.\n");
603 
604   ReportConditionalErrorAndExit(
605       settings.agc_compression_gain && ((*settings.agc_compression_gain) < 0 ||
606                                         (*settings.agc_compression_gain) > 90),
607       "Error: --agc_compression_gain must be specified between 0 and 90.\n");
608 
609   ReportConditionalErrorAndExit(
610       settings.agc2_fixed_gain_db && ((*settings.agc2_fixed_gain_db) < 0 ||
611                                       (*settings.agc2_fixed_gain_db) > 90),
612       "Error: --agc2_fixed_gain_db must be specified between 0 and 90.\n");
613 
614   ReportConditionalErrorAndExit(
615       settings.ns_level &&
616           ((*settings.ns_level) < 0 || (*settings.ns_level) > 3),
617       "Error: --ns_level must be specified between 0 and 3.\n");
618 
619   ReportConditionalErrorAndExit(
620       settings.report_bitexactness && !settings.aec_dump_input_filename,
621       "Error: --bitexactness_report can only be used when operating on an "
622       "aecdump\n");
623 
624   ReportConditionalErrorAndExit(
625       settings.call_order_input_filename && settings.aec_dump_input_filename,
626       "Error: --custom_call_order_file cannot be used when operating on an "
627       "aecdump\n");
628 
629   ReportConditionalErrorAndExit(
630       (settings.initial_mic_level < 0 || settings.initial_mic_level > 255),
631       "Error: --initial_mic_level must be specified between 0 and 255.\n");
632 
633   ReportConditionalErrorAndExit(
634       settings.simulated_mic_kind && !settings.simulate_mic_gain,
635       "Error: --simulated_mic_kind cannot be specified when mic simulation is "
636       "disabled\n");
637 
638   ReportConditionalErrorAndExit(
639       !settings.simulated_mic_kind && settings.simulate_mic_gain,
640       "Error: --simulated_mic_kind must be specified when mic simulation is "
641       "enabled\n");
642 
643   // TODO(bugs.webrtc.org/7494): Document how the two settings below differ.
644   ReportConditionalErrorAndExit(
645       settings.simulate_mic_gain && settings.use_analog_mic_gain_emulation,
646       "Error: --simulate_mic_gain and --use_analog_mic_gain_emulation cannot "
647       "be enabled at the same time\n");
648 
649   auto valid_wav_name = [](absl::string_view wav_file_name) {
650     if (wav_file_name.size() < 5) {
651       return false;
652     }
653     if ((wav_file_name.compare(wav_file_name.size() - 4, 4, ".wav") == 0) ||
654         (wav_file_name.compare(wav_file_name.size() - 4, 4, ".WAV") == 0)) {
655       return true;
656     }
657     return false;
658   };
659 
660   ReportConditionalErrorAndExit(
661       settings.input_filename && (!valid_wav_name(*settings.input_filename)),
662       "Error: --i must be a valid .wav file name.\n");
663 
664   ReportConditionalErrorAndExit(
665       settings.output_filename && (!valid_wav_name(*settings.output_filename)),
666       "Error: --o must be a valid .wav file name.\n");
667 
668   ReportConditionalErrorAndExit(
669       settings.reverse_input_filename &&
670           (!valid_wav_name(*settings.reverse_input_filename)),
671       "Error: --ri must be a valid .wav file name.\n");
672 
673   ReportConditionalErrorAndExit(
674       settings.reverse_output_filename &&
675           (!valid_wav_name(*settings.reverse_output_filename)),
676       "Error: --ro must be a valid .wav file name.\n");
677 
678   ReportConditionalErrorAndExit(
679       settings.artificial_nearend_filename &&
680           !valid_wav_name(*settings.artificial_nearend_filename),
681       "Error: --artifical_nearend must be a valid .wav file name.\n");
682 
683   ReportConditionalErrorAndExit(
684       settings.linear_aec_output_filename &&
685           (!valid_wav_name(*settings.linear_aec_output_filename)),
686       "Error: --linear_aec_output must be a valid .wav file name.\n");
687 
688   ReportConditionalErrorAndExit(
689       WEBRTC_APM_DEBUG_DUMP == 0 && settings.dump_internal_data,
690       "Error: --dump_data cannot be set without proper build support.\n");
691 
692   ReportConditionalErrorAndExit(settings.init_to_process &&
693                                     *settings.init_to_process != 1 &&
694                                     !settings.aec_dump_input_filename,
695                                 "Error: --init_to_process must be set to 1 for "
696                                 "wav-file based simulations.\n");
697 
698   ReportConditionalErrorAndExit(
699       !settings.init_to_process &&
700           (settings.dump_start_frame || settings.dump_end_frame),
701       "Error: --init_to_process must be set when specifying a start and/or end "
702       "frame for when to dump internal data.\n");
703 
704   ReportConditionalErrorAndExit(
705       !settings.dump_internal_data &&
706           settings.dump_internal_data_output_dir.has_value(),
707       "Error: --dump_data_output_dir cannot be set without --dump_data.\n");
708 
709   ReportConditionalErrorAndExit(
710       !settings.aec_dump_input_filename &&
711           settings.call_order_output_filename.has_value(),
712       "Error: --output_custom_call_order_file needs an AEC dump input file.\n");
713 
714   ReportConditionalErrorAndExit(
715       (!settings.use_pre_amplifier || !(*settings.use_pre_amplifier)) &&
716           settings.pre_amplifier_gain_factor.has_value(),
717       "Error: --pre_amplifier_gain_factor needs --pre_amplifier to be "
718       "specified and set.\n");
719 
720   ReportConditionalErrorAndExit(
721       pre_constructed_ap_provided && pre_constructed_ap_builder_provided,
722       "Error: The AudioProcessing and the AudioProcessingBuilder cannot both "
723       "be specified at the same time.\n");
724 
725   ReportConditionalErrorAndExit(
726       settings.aec_settings_filename && pre_constructed_ap_provided,
727       "Error: The aec_settings_filename cannot be specified when a "
728       "pre-constructed audio processing object is provided.\n");
729 
730   ReportConditionalErrorAndExit(
731       settings.aec_settings_filename && pre_constructed_ap_provided,
732       "Error: The print_aec_parameter_values cannot be set when a "
733       "pre-constructed audio processing object is provided.\n");
734 
735   if (settings.linear_aec_output_filename && pre_constructed_ap_provided) {
736     std::cout << "Warning: For the linear AEC output to be stored, this must "
737                  "be configured in the AEC that is part of the provided "
738                  "AudioProcessing object."
739               << std::endl;
740   }
741 }
742 
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)743 int RunSimulation(rtc::scoped_refptr<AudioProcessing> audio_processing,
744                   std::unique_ptr<AudioProcessingBuilder> ap_builder,
745                   int argc,
746                   char* argv[],
747                   absl::string_view input_aecdump,
748                   std::vector<float>* processed_capture_samples) {
749   std::vector<char*> args = absl::ParseCommandLine(argc, argv);
750   if (args.size() != 1) {
751     printf("%s", kUsageDescription);
752     return 1;
753   }
754   // InitFieldTrialsFromString stores the char*, so the char array must
755   // outlive the application.
756   const std::string field_trials = absl::GetFlag(FLAGS_force_fieldtrials);
757   webrtc::field_trial::InitFieldTrialsFromString(field_trials.c_str());
758 
759   SimulationSettings settings = CreateSettings();
760   if (!input_aecdump.empty()) {
761     settings.aec_dump_input_string = input_aecdump;
762     settings.processed_capture_samples = processed_capture_samples;
763     RTC_CHECK(settings.processed_capture_samples);
764   }
765   PerformBasicParameterSanityChecks(settings, !!audio_processing, !!ap_builder);
766   std::unique_ptr<AudioProcessingSimulator> processor;
767 
768   if (settings.aec_dump_input_filename || settings.aec_dump_input_string) {
769     processor.reset(new AecDumpBasedSimulator(
770         settings, std::move(audio_processing), std::move(ap_builder)));
771   } else {
772     processor.reset(new WavBasedSimulator(settings, std::move(audio_processing),
773                                           std::move(ap_builder)));
774   }
775 
776   if (settings.analysis_only) {
777     processor->Analyze();
778   } else {
779     processor->Process();
780   }
781 
782   if (settings.report_performance) {
783     processor->GetApiCallStatistics().PrintReport();
784   }
785   if (settings.performance_report_output_filename) {
786     processor->GetApiCallStatistics().WriteReportToFile(
787         *settings.performance_report_output_filename);
788   }
789 
790   if (settings.report_bitexactness && settings.aec_dump_input_filename) {
791     if (processor->OutputWasBitexact()) {
792       std::cout << "The processing was bitexact.";
793     } else {
794       std::cout << "The processing was not bitexact.";
795     }
796   }
797 
798   return 0;
799 }
800 
801 }  // namespace
802 
AudioprocFloatImpl(rtc::scoped_refptr<AudioProcessing> audio_processing,int argc,char * argv[])803 int AudioprocFloatImpl(rtc::scoped_refptr<AudioProcessing> audio_processing,
804                        int argc,
805                        char* argv[]) {
806   return RunSimulation(
807       std::move(audio_processing), /*ap_builder=*/nullptr, argc, argv,
808       /*input_aecdump=*/"", /*processed_capture_samples=*/nullptr);
809 }
810 
AudioprocFloatImpl(std::unique_ptr<AudioProcessingBuilder> ap_builder,int argc,char * argv[],absl::string_view input_aecdump,std::vector<float> * processed_capture_samples)811 int AudioprocFloatImpl(std::unique_ptr<AudioProcessingBuilder> ap_builder,
812                        int argc,
813                        char* argv[],
814                        absl::string_view input_aecdump,
815                        std::vector<float>* processed_capture_samples) {
816   return RunSimulation(/*audio_processing=*/nullptr, std::move(ap_builder),
817                        argc, argv, input_aecdump, processed_capture_samples);
818 }
819 
820 }  // namespace test
821 }  // namespace webrtc
822