diff --git a/api/test/audioproc_float.cc b/api/test/audioproc_float.cc index bba9c622a1..c8d7ff7193 100644 --- a/api/test/audioproc_float.cc +++ b/api/test/audioproc_float.cc @@ -17,6 +17,12 @@ namespace webrtc { namespace test { +int AudioprocFloat(rtc::scoped_refptr audio_processing, + int argc, + char* argv[]) { + return AudioprocFloatImpl(std::move(audio_processing), argc, argv); +} + int AudioprocFloat(std::unique_ptr ap_builder, int argc, char* argv[]) { diff --git a/api/test/audioproc_float.h b/api/test/audioproc_float.h index 2625e6ad9a..fec2ad11fa 100644 --- a/api/test/audioproc_float.h +++ b/api/test/audioproc_float.h @@ -19,6 +19,22 @@ namespace webrtc { namespace test { +// This is an interface for the audio processing simulation utility. This +// utility can be used to simulate the audioprocessing module using a recording +// (either an AEC dump or wav files), and generate the output as a wav file. +// Any audio_processing object specified in the input is used for the +// simulation. The optional |audio_processing| object provides the +// AudioProcessing instance that is used during the simulation. Note that when +// the audio_processing object is specified all functionality that relies on +// using the AudioProcessingBuilder is deactivated, since the AudioProcessing +// object is already created and the builder is not used in the simulation. It +// is needed to pass the command line flags as |argc| and |argv|, so these can +// be interpreted properly by the utility. To see a list of all supported +// command line flags, run the executable with the '--help' flag. +int AudioprocFloat(rtc::scoped_refptr audio_processing, + int argc, + char* argv[]); + // This is an interface for the audio processing simulation utility. This // utility can be used to simulate the audioprocessing module using a recording // (either an AEC dump or wav files), and generate the output as a wav file. diff --git a/modules/audio_processing/test/aec_dump_based_simulator.cc b/modules/audio_processing/test/aec_dump_based_simulator.cc index b3b113da44..f5bd6452e3 100644 --- a/modules/audio_processing/test/aec_dump_based_simulator.cc +++ b/modules/audio_processing/test/aec_dump_based_simulator.cc @@ -66,8 +66,11 @@ bool VerifyFloatBitExactness(const webrtc::audioproc::Stream& msg, AecDumpBasedSimulator::AecDumpBasedSimulator( const SimulationSettings& settings, + rtc::scoped_refptr audio_processing, std::unique_ptr ap_builder) - : AudioProcessingSimulator(settings, std::move(ap_builder)) { + : AudioProcessingSimulator(settings, + std::move(audio_processing), + std::move(ap_builder)) { MaybeOpenCallOrderFile(); } @@ -206,7 +209,8 @@ void AecDumpBasedSimulator::PrepareReverseProcessStreamCall( } void AecDumpBasedSimulator::Process() { - CreateAudioProcessor(); + ConfigureAudioProcessor(); + if (settings_.artificial_nearend_filename) { std::unique_ptr artificial_nearend_file( new WavReader(settings_.artificial_nearend_filename->c_str())); @@ -237,7 +241,7 @@ void AecDumpBasedSimulator::Process() { fclose(dump_input_file_); } - DestroyAudioProcessor(); + DetachAecDump(); } void AecDumpBasedSimulator::HandleEvent( diff --git a/modules/audio_processing/test/aec_dump_based_simulator.h b/modules/audio_processing/test/aec_dump_based_simulator.h index ef032d0316..092b82bdbc 100644 --- a/modules/audio_processing/test/aec_dump_based_simulator.h +++ b/modules/audio_processing/test/aec_dump_based_simulator.h @@ -33,6 +33,7 @@ namespace test { class AecDumpBasedSimulator final : public AudioProcessingSimulator { public: AecDumpBasedSimulator(const SimulationSettings& settings, + rtc::scoped_refptr audio_processing, std::unique_ptr ap_builder); ~AecDumpBasedSimulator() override; diff --git a/modules/audio_processing/test/audio_processing_simulator.cc b/modules/audio_processing/test/audio_processing_simulator.cc index a37a83f1e3..adbc298e9e 100644 --- a/modules/audio_processing/test/audio_processing_simulator.cc +++ b/modules/audio_processing/test/audio_processing_simulator.cc @@ -113,10 +113,10 @@ SimulationSettings::~SimulationSettings() = default; AudioProcessingSimulator::AudioProcessingSimulator( const SimulationSettings& settings, + rtc::scoped_refptr audio_processing, std::unique_ptr ap_builder) : settings_(settings), - ap_builder_(ap_builder ? std::move(ap_builder) - : std::make_unique()), + ap_(std::move(audio_processing)), analog_mic_level_(settings.initial_mic_level), fake_recording_device_( settings.initial_mic_level, @@ -139,6 +139,51 @@ AudioProcessingSimulator::AudioProcessingSimulator( if (settings_.simulate_mic_gain) RTC_LOG(LS_VERBOSE) << "Simulating analog mic gain"; + + // Create the audio processing object. + RTC_CHECK(!(ap_ && ap_builder)) + << "The AudioProcessing and the AudioProcessingBuilder cannot both be " + "specified at the same time."; + + if (ap_) { + RTC_CHECK(!settings_.aec_settings_filename); + RTC_CHECK(!settings_.print_aec_parameter_values); + } else { + // Use specied builder if such is provided, otherwise create a new builder. + std::unique_ptr builder = + !!ap_builder ? std::move(ap_builder) + : std::make_unique(); + + // Create and set an EchoCanceller3Factory if needed. + const bool use_aec = settings_.use_aec && *settings_.use_aec; + if (use_aec) { + EchoCanceller3Config cfg; + if (settings_.aec_settings_filename) { + if (settings_.use_verbose_logging) { + std::cout << "Reading AEC Parameters from JSON input." << std::endl; + } + cfg = ReadAec3ConfigFromJsonFile(*settings_.aec_settings_filename); + } + + if (settings_.linear_aec_output_filename) { + cfg.filter.export_linear_aec_output = true; + } + + if (settings_.print_aec_parameter_values) { + if (!settings_.use_quiet_output) { + std::cout << "AEC settings:" << std::endl; + } + std::cout << Aec3ConfigToJsonString(cfg) << std::endl; + } + + auto echo_control_factory = std::make_unique(cfg); + builder->SetEchoControlFactory(std::move(echo_control_factory)); + } + + // Create an audio processing object. + ap_ = builder->Create(); + RTC_CHECK(ap_); + } } AudioProcessingSimulator::~AudioProcessingSimulator() { @@ -369,16 +414,14 @@ void AudioProcessingSimulator::SetupOutput() { ++output_reset_counter_; } -void AudioProcessingSimulator::DestroyAudioProcessor() { +void AudioProcessingSimulator::DetachAecDump() { if (settings_.aec_dump_output_filename) { ap_->DetachAecDump(); } } -void AudioProcessingSimulator::CreateAudioProcessor() { - Config config; +void AudioProcessingSimulator::ConfigureAudioProcessor() { AudioProcessing::Config apm_config; - std::unique_ptr echo_control_factory; if (settings_.use_ts) { apm_config.transient_suppression.enabled = *settings_.use_ts; } @@ -421,29 +464,6 @@ void AudioProcessingSimulator::CreateAudioProcessor() { apm_config.echo_canceller.export_linear_aec_output = !!settings_.linear_aec_output_filename; - if (use_aec) { - EchoCanceller3Config cfg; - if (settings_.aec_settings_filename) { - if (settings_.use_verbose_logging) { - std::cout << "Reading AEC Parameters from JSON input." << std::endl; - } - cfg = ReadAec3ConfigFromJsonFile(*settings_.aec_settings_filename); - } - - if (settings_.linear_aec_output_filename) { - cfg.filter.export_linear_aec_output = true; - } - - echo_control_factory.reset(new EchoCanceller3Factory(cfg)); - - if (settings_.print_aec_parameter_values) { - if (!settings_.use_quiet_output) { - std::cout << "AEC settings:" << std::endl; - } - std::cout << Aec3ConfigToJsonString(cfg) << std::endl; - } - } - if (settings_.use_hpf) { apm_config.high_pass_filter.enabled = *settings_.use_hpf; } @@ -512,14 +532,6 @@ void AudioProcessingSimulator::CreateAudioProcessor() { *settings_.ns_analysis_on_linear_aec_output; } - RTC_CHECK(ap_builder_); - if (echo_control_factory) { - ap_builder_->SetEchoControlFactory(std::move(echo_control_factory)); - } - ap_.reset((*ap_builder_).Create(config)); - - RTC_CHECK(ap_); - ap_->ApplyConfig(apm_config); if (settings_.use_ts) { diff --git a/modules/audio_processing/test/audio_processing_simulator.h b/modules/audio_processing/test/audio_processing_simulator.h index fa6efc2842..8579f4b4d0 100644 --- a/modules/audio_processing/test/audio_processing_simulator.h +++ b/modules/audio_processing/test/audio_processing_simulator.h @@ -150,8 +150,8 @@ struct SimulationSettings { // Provides common functionality for performing audioprocessing simulations. class AudioProcessingSimulator { public: - AudioProcessingSimulator(const SimulationSettings& settings, + rtc::scoped_refptr audio_processing, std::unique_ptr ap_builder); virtual ~AudioProcessingSimulator(); @@ -174,8 +174,8 @@ class AudioProcessingSimulator { protected: void ProcessStream(bool fixed_interface); void ProcessReverseStream(bool fixed_interface); - void CreateAudioProcessor(); - void DestroyAudioProcessor(); + void ConfigureAudioProcessor(); + void DetachAecDump(); void SetupBuffersConfigsOutputs(int input_sample_rate_hz, int output_sample_rate_hz, int reverse_input_sample_rate_hz, @@ -186,8 +186,7 @@ class AudioProcessingSimulator { int reverse_output_num_channels); const SimulationSettings settings_; - std::unique_ptr ap_; - std::unique_ptr ap_builder_; + rtc::scoped_refptr ap_; std::unique_ptr> in_buf_; std::unique_ptr> out_buf_; diff --git a/modules/audio_processing/test/audioproc_float_impl.cc b/modules/audio_processing/test/audioproc_float_impl.cc index d9a4227eb7..ab395f1018 100644 --- a/modules/audio_processing/test/audioproc_float_impl.cc +++ b/modules/audio_processing/test/audioproc_float_impl.cc @@ -457,7 +457,10 @@ void ReportConditionalErrorAndExit(bool condition, const std::string& message) { } } -void PerformBasicParameterSanityChecks(const SimulationSettings& settings) { +void PerformBasicParameterSanityChecks( + const SimulationSettings& settings, + bool pre_constructed_ap_provided, + bool pre_constructed_ap_builder_provided) { if (settings.input_filename || settings.reverse_input_filename) { ReportConditionalErrorAndExit( !!settings.aec_dump_input_filename, @@ -624,21 +627,41 @@ void PerformBasicParameterSanityChecks(const SimulationSettings& settings) { settings.pre_amplifier_gain_factor.has_value(), "Error: --pre_amplifier_gain_factor needs --pre_amplifier to be " "specified and set.\n"); + + ReportConditionalErrorAndExit( + pre_constructed_ap_provided && pre_constructed_ap_builder_provided, + "Error: The AudioProcessing and the AudioProcessingBuilder cannot both " + "be specified at the same time.\n"); + + ReportConditionalErrorAndExit( + settings.aec_settings_filename && pre_constructed_ap_provided, + "Error: The aec_settings_filename cannot be specified when a " + "pre-constructed audio processing object is provided.\n"); + + ReportConditionalErrorAndExit( + settings.aec_settings_filename && pre_constructed_ap_provided, + "Error: The print_aec_parameter_values cannot be set when a " + "pre-constructed audio processing object is provided.\n"); + + if (settings.linear_aec_output_filename && pre_constructed_ap_provided) { + std::cout << "Warning: For the linear AEC output to be stored, this must " + "be configured in the AEC that is part of the provided " + "AudioProcessing object." + << std::endl; + } } -} // namespace - -int AudioprocFloatImpl(std::unique_ptr ap_builder, - int argc, - char* argv[], - absl::string_view input_aecdump, - std::vector* processed_capture_samples) { +int RunSimulation(rtc::scoped_refptr audio_processing, + std::unique_ptr ap_builder, + int argc, + char* argv[], + absl::string_view input_aecdump, + std::vector* processed_capture_samples) { std::vector args = absl::ParseCommandLine(argc, argv); if (args.size() != 1) { printf("%s", kUsageDescription); return 1; } - // InitFieldTrialsFromString stores the char*, so the char array must // outlive the application. const std::string field_trials = absl::GetFlag(FLAGS_force_fieldtrials); @@ -650,13 +673,15 @@ int AudioprocFloatImpl(std::unique_ptr ap_builder, settings.processed_capture_samples = processed_capture_samples; RTC_CHECK(settings.processed_capture_samples); } - PerformBasicParameterSanityChecks(settings); + PerformBasicParameterSanityChecks(settings, !!audio_processing, !!ap_builder); std::unique_ptr processor; if (settings.aec_dump_input_filename || settings.aec_dump_input_string) { - processor.reset(new AecDumpBasedSimulator(settings, std::move(ap_builder))); + processor.reset(new AecDumpBasedSimulator( + settings, std::move(audio_processing), std::move(ap_builder))); } else { - processor.reset(new WavBasedSimulator(settings, std::move(ap_builder))); + processor.reset(new WavBasedSimulator(settings, std::move(audio_processing), + std::move(ap_builder))); } processor->Process(); @@ -680,5 +705,24 @@ int AudioprocFloatImpl(std::unique_ptr ap_builder, return 0; } +} // namespace + +int AudioprocFloatImpl(rtc::scoped_refptr audio_processing, + int argc, + char* argv[]) { + return RunSimulation( + std::move(audio_processing), /*ap_builder=*/nullptr, argc, argv, + /*input_aecdump=*/"", /*processed_capture_samples=*/nullptr); +} + +int AudioprocFloatImpl(std::unique_ptr ap_builder, + int argc, + char* argv[], + absl::string_view input_aecdump, + std::vector* processed_capture_samples) { + return RunSimulation(/*audio_processing=*/nullptr, std::move(ap_builder), + argc, argv, input_aecdump, processed_capture_samples); +} + } // namespace test } // namespace webrtc diff --git a/modules/audio_processing/test/audioproc_float_impl.h b/modules/audio_processing/test/audioproc_float_impl.h index 9a9013c644..0687c43a5d 100644 --- a/modules/audio_processing/test/audioproc_float_impl.h +++ b/modules/audio_processing/test/audioproc_float_impl.h @@ -18,6 +18,21 @@ namespace webrtc { namespace test { +// This function implements the audio processing simulation utility. Pass +// |input_aecdump| to provide the content of an AEC dump file as a string; if +// |input_aecdump| is not passed, a WAV or AEC input dump file must be specified +// via the |argv| argument. Pass |processed_capture_samples| to write in it the +// samples processed on the capture side; if |processed_capture_samples| is not +// passed, the output file can optionally be specified via the |argv| argument. +// Any audio_processing object specified in the input is used for the +// simulation. Note that when the audio_processing object is specified all +// functionality that relies on using the internal builder is deactivated, +// since the AudioProcessing object is already created and the builder is not +// used in the simulation. +int AudioprocFloatImpl(rtc::scoped_refptr audio_processing, + int argc, + char* argv[]); + // This function implements the audio processing simulation utility. Pass // |input_aecdump| to provide the content of an AEC dump file as a string; if // |input_aecdump| is not passed, a WAV or AEC input dump file must be specified diff --git a/modules/audio_processing/test/wav_based_simulator.cc b/modules/audio_processing/test/wav_based_simulator.cc index 7179fc3431..75946fb3fa 100644 --- a/modules/audio_processing/test/wav_based_simulator.cc +++ b/modules/audio_processing/test/wav_based_simulator.cc @@ -56,8 +56,18 @@ WavBasedSimulator::GetCustomEventChain(const std::string& filename) { WavBasedSimulator::WavBasedSimulator( const SimulationSettings& settings, + rtc::scoped_refptr audio_processing, std::unique_ptr ap_builder) - : AudioProcessingSimulator(settings, std::move(ap_builder)) {} + : AudioProcessingSimulator(settings, + std::move(audio_processing), + std::move(ap_builder)) { + if (settings_.call_order_input_filename) { + call_chain_ = WavBasedSimulator::GetCustomEventChain( + *settings_.call_order_input_filename); + } else { + call_chain_ = WavBasedSimulator::GetDefaultEventChain(); + } +} WavBasedSimulator::~WavBasedSimulator() = default; @@ -89,13 +99,7 @@ void WavBasedSimulator::PrepareReverseProcessStreamCall() { } void WavBasedSimulator::Process() { - if (settings_.call_order_input_filename) { - call_chain_ = WavBasedSimulator::GetCustomEventChain( - *settings_.call_order_input_filename); - } else { - call_chain_ = WavBasedSimulator::GetDefaultEventChain(); - } - CreateAudioProcessor(); + ConfigureAudioProcessor(); Initialize(); @@ -120,7 +124,7 @@ void WavBasedSimulator::Process() { call_chain_index = (call_chain_index + 1) % call_chain_.size(); } - DestroyAudioProcessor(); + DetachAecDump(); } bool WavBasedSimulator::HandleProcessStreamCall() { diff --git a/modules/audio_processing/test/wav_based_simulator.h b/modules/audio_processing/test/wav_based_simulator.h index 991f1dbaad..3adbe7022c 100644 --- a/modules/audio_processing/test/wav_based_simulator.h +++ b/modules/audio_processing/test/wav_based_simulator.h @@ -23,6 +23,7 @@ namespace test { class WavBasedSimulator final : public AudioProcessingSimulator { public: WavBasedSimulator(const SimulationSettings& settings, + rtc::scoped_refptr audio_processing, std::unique_ptr ap_builder); ~WavBasedSimulator() override;