From df80fd125989fae30eff04e8413d63178d98c3e5 Mon Sep 17 00:00:00 2001 From: peah Date: Fri, 9 Dec 2016 02:43:40 -0800 Subject: [PATCH] When recreating a call based on an aecdump recording the nearend used is the one stored in the aecdump. During AEC development, it is handy to be able to simulate different doubletalk scenarios. This CL adds the ability to add an artificial nearend on top of that present in the aecdump, which allows for the developer to artificially customize the scenario being tested BUG=webrtc:6018 Review-Url: https://codereview.webrtc.org/2562593003 Cr-Commit-Position: refs/heads/master@{#15502} --- .../test/aec_dump_based_simulator.cc | 49 +++++++++++++++++++ .../test/aec_dump_based_simulator.h | 8 +-- .../test/audio_processing_simulator.h | 1 + .../audio_processing/test/audioproc_float.cc | 12 +++++ 4 files changed, 67 insertions(+), 3 deletions(-) diff --git a/webrtc/modules/audio_processing/test/aec_dump_based_simulator.cc b/webrtc/modules/audio_processing/test/aec_dump_based_simulator.cc index 694f2cd90c..b117dbbebe 100644 --- a/webrtc/modules/audio_processing/test/aec_dump_based_simulator.cc +++ b/webrtc/modules/audio_processing/test/aec_dump_based_simulator.cc @@ -62,6 +62,11 @@ bool VerifyFloatBitExactness(const webrtc::audioproc::Stream& msg, } // namespace +AecDumpBasedSimulator::AecDumpBasedSimulator(const SimulationSettings& settings) + : AudioProcessingSimulator(settings) {} + +AecDumpBasedSimulator::~AecDumpBasedSimulator() = default; + void AecDumpBasedSimulator::PrepareProcessStreamCall( const webrtc::audioproc::Stream& msg, bool* set_stream_analog_level_called) { @@ -96,6 +101,34 @@ void AecDumpBasedSimulator::PrepareProcessStreamCall( } } + if (artificial_nearend_buffer_reader_) { + if (artificial_nearend_buffer_reader_->Read( + artificial_nearend_buf_.get())) { + if (msg.has_input_data()) { + for (size_t k = 0; k < in_buf_->num_frames(); ++k) { + fwd_frame_.data_[k] = rtc::saturated_cast( + fwd_frame_.data_[k] + + static_cast(32767 * + artificial_nearend_buf_->channels()[0][k])); + } + } else { + for (int i = 0; i < msg.input_channel_size(); ++i) { + for (size_t k = 0; k < in_buf_->num_frames(); ++k) { + in_buf_->channels()[i][k] += + artificial_nearend_buf_->channels()[0][k]; + in_buf_->channels()[i][k] = std::min( + 32767.f, std::max(-32768.f, in_buf_->channels()[i][k])); + } + } + } + } else { + if (!artificial_nearend_eof_reported_) { + std::cout << "The artificial nearend file ended before the recording."; + artificial_nearend_eof_reported_ = true; + } + } + } + if (!settings_.stream_delay) { if (msg.has_delay()) { RTC_CHECK_EQ(AudioProcessing::kNoError, @@ -189,6 +222,22 @@ void AecDumpBasedSimulator::Process() { CreateAudioProcessor(); dump_input_file_ = OpenFile(settings_.aec_dump_input_filename->c_str(), "rb"); + if (settings_.artificial_nearend_filename) { + std::unique_ptr artificial_nearend_file( + new WavReader(settings_.artificial_nearend_filename->c_str())); + + RTC_CHECK_EQ(1, artificial_nearend_file->num_channels()) + << "Only mono files for the artificial nearend are supported, " + "reverted to not using the artificial nearend file"; + + artificial_nearend_buffer_reader_.reset( + new ChannelBufferWavReader(std::move(artificial_nearend_file))); + artificial_nearend_buf_.reset(new ChannelBuffer( + rtc::CheckedDivExact(artificial_nearend_file->sample_rate(), + kChunksPerSecond), + 1)); + } + webrtc::audioproc::Event event_msg; int num_forward_chunks_processed = 0; const float kOneBykChunksPerSecond = diff --git a/webrtc/modules/audio_processing/test/aec_dump_based_simulator.h b/webrtc/modules/audio_processing/test/aec_dump_based_simulator.h index 7f98f43b66..5f7d138aa4 100644 --- a/webrtc/modules/audio_processing/test/aec_dump_based_simulator.h +++ b/webrtc/modules/audio_processing/test/aec_dump_based_simulator.h @@ -30,9 +30,8 @@ namespace test { // Used to perform an audio processing simulation from an aec dump. class AecDumpBasedSimulator final : public AudioProcessingSimulator { public: - explicit AecDumpBasedSimulator(const SimulationSettings& settings) - : AudioProcessingSimulator(settings) {} - ~AecDumpBasedSimulator() override {} + explicit AecDumpBasedSimulator(const SimulationSettings& settings); + ~AecDumpBasedSimulator() override; // Processes the messages in the aecdump file. void Process() override; @@ -55,6 +54,9 @@ class AecDumpBasedSimulator final : public AudioProcessingSimulator { }; FILE* dump_input_file_; + std::unique_ptr> artificial_nearend_buf_; + std::unique_ptr artificial_nearend_buffer_reader_; + bool artificial_nearend_eof_reported_ = false; InterfaceType interface_used_ = InterfaceType::kNotSpecified; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AecDumpBasedSimulator); diff --git a/webrtc/modules/audio_processing/test/audio_processing_simulator.h b/webrtc/modules/audio_processing/test/audio_processing_simulator.h index 7becdb9a6b..2564dc4bf2 100644 --- a/webrtc/modules/audio_processing/test/audio_processing_simulator.h +++ b/webrtc/modules/audio_processing/test/audio_processing_simulator.h @@ -44,6 +44,7 @@ struct SimulationSettings { rtc::Optional reverse_output_filename; rtc::Optional input_filename; rtc::Optional reverse_input_filename; + rtc::Optional artificial_nearend_filename; rtc::Optional use_aec; rtc::Optional use_aecm; rtc::Optional use_ed; // Residual Echo Detector. diff --git a/webrtc/modules/audio_processing/test/audioproc_float.cc b/webrtc/modules/audio_processing/test/audioproc_float.cc index a91480d265..edc775986f 100644 --- a/webrtc/modules/audio_processing/test/audioproc_float.cc +++ b/webrtc/modules/audio_processing/test/audioproc_float.cc @@ -40,6 +40,7 @@ DEFINE_string(i, "", "Forward stream input wav filename"); DEFINE_string(o, "", "Forward stream output wav filename"); DEFINE_string(ri, "", "Reverse stream input wav filename"); DEFINE_string(ro, "", "Reverse stream output wav filename"); +DEFINE_string(artificial_nearend, "", "Artificial nearend wav filename"); DEFINE_int32(output_num_channels, kParameterNotSpecifiedValue, "Number of forward stream output channels"); @@ -208,6 +209,8 @@ SimulationSettings CreateSettings() { SetSettingIfSpecified(FLAGS_o, &settings.output_filename); SetSettingIfSpecified(FLAGS_ri, &settings.reverse_input_filename); SetSettingIfSpecified(FLAGS_ro, &settings.reverse_output_filename); + SetSettingIfSpecified(FLAGS_artificial_nearend, + &settings.artificial_nearend_filename); SetSettingIfSpecified(FLAGS_output_num_channels, &settings.output_num_channels); SetSettingIfSpecified(FLAGS_reverse_output_num_channels, @@ -277,6 +280,10 @@ void PerformBasicParameterSanityChecks(const SimulationSettings& settings) { "Error: The aec dump cannot be specified " "together with input wav files!\n"); + ReportConditionalErrorAndExit(!!settings.artificial_nearend_filename, + "Error: The artificial nearend cannot be " + "specified together with input wav files!\n"); + ReportConditionalErrorAndExit(!settings.input_filename, "Error: When operating at wav files, the " "input wav filename must be " @@ -389,6 +396,11 @@ void PerformBasicParameterSanityChecks(const SimulationSettings& settings) { settings.reverse_output_filename && (!valid_wav_name(*settings.reverse_output_filename)), "Error: --ro must be a valid .wav file name.\n"); + + ReportConditionalErrorAndExit( + settings.artificial_nearend_filename && + !valid_wav_name(*settings.artificial_nearend_filename), + "Error: --artifical_nearend must be a valid .wav file name.\n"); } } // namespace