audioproc_f: input AEC dump as string, output audio to vector
This CL adds the following options:
pass an input AEC dump as a string (currently, the tool can only accept a path to an AEC dump file)
write the processed capture samples to a given vector
Bug: webrtc:10808
Change-Id: I02863c97ec3cd8c03ade2ea8521836f2e7417050
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/145208
Commit-Queue: Sonia-Florina Horchidan <soniahorchidan@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Per Ã…hgren <peah@webrtc.org>
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Reviewed-by: Ivo Creusen <ivoc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28826}
diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn
index b03b40d..eaa8826 100644
--- a/modules/audio_processing/BUILD.gn
+++ b/modules/audio_processing/BUILD.gn
@@ -755,6 +755,7 @@
"../../rtc_base:protobuf_utils",
"../../rtc_base:rtc_base_approved",
"../../rtc_base/system:arch",
+ "//third_party/abseil-cpp/absl/memory:memory",
]
}
diff --git a/modules/audio_processing/test/aec_dump_based_simulator.cc b/modules/audio_processing/test/aec_dump_based_simulator.cc
index 00fd25e..0d6bdd1 100644
--- a/modules/audio_processing/test/aec_dump_based_simulator.cc
+++ b/modules/audio_processing/test/aec_dump_based_simulator.cc
@@ -212,8 +212,6 @@
void AecDumpBasedSimulator::Process() {
CreateAudioProcessor();
- dump_input_file_ = OpenFile(settings_.aec_dump_input_filename->c_str(), "rb");
-
if (settings_.artificial_nearend_filename) {
std::unique_ptr<WavReader> artificial_nearend_file(
new WavReader(settings_.artificial_nearend_filename->c_str()));
@@ -231,39 +229,52 @@
webrtc::audioproc::Event event_msg;
int num_forward_chunks_processed = 0;
- while (ReadMessageFromFile(dump_input_file_, &event_msg)) {
- switch (event_msg.type()) {
- case webrtc::audioproc::Event::INIT:
- RTC_CHECK(event_msg.has_init());
- HandleMessage(event_msg.init());
- break;
- case webrtc::audioproc::Event::STREAM:
- RTC_CHECK(event_msg.has_stream());
- HandleMessage(event_msg.stream());
- ++num_forward_chunks_processed;
- break;
- case webrtc::audioproc::Event::REVERSE_STREAM:
- RTC_CHECK(event_msg.has_reverse_stream());
- HandleMessage(event_msg.reverse_stream());
- break;
- case webrtc::audioproc::Event::CONFIG:
- RTC_CHECK(event_msg.has_config());
- HandleMessage(event_msg.config());
- break;
- case webrtc::audioproc::Event::RUNTIME_SETTING:
- HandleMessage(event_msg.runtime_setting());
- break;
- case webrtc::audioproc::Event::UNKNOWN_EVENT:
- RTC_CHECK(false);
- break;
- }
+ if (settings_.aec_dump_input_string.has_value()) {
+ std::stringstream input;
+ input << settings_.aec_dump_input_string.value();
+ while (ReadMessageFromString(&input, &event_msg))
+ HandleEvent(event_msg, &num_forward_chunks_processed);
+ } else {
+ dump_input_file_ =
+ OpenFile(settings_.aec_dump_input_filename->c_str(), "rb");
+ while (ReadMessageFromFile(dump_input_file_, &event_msg))
+ HandleEvent(event_msg, &num_forward_chunks_processed);
+ fclose(dump_input_file_);
}
- fclose(dump_input_file_);
-
DestroyAudioProcessor();
}
+void AecDumpBasedSimulator::HandleEvent(
+ const webrtc::audioproc::Event& event_msg,
+ int* num_forward_chunks_processed) {
+ switch (event_msg.type()) {
+ case webrtc::audioproc::Event::INIT:
+ RTC_CHECK(event_msg.has_init());
+ HandleMessage(event_msg.init());
+ break;
+ case webrtc::audioproc::Event::STREAM:
+ RTC_CHECK(event_msg.has_stream());
+ HandleMessage(event_msg.stream());
+ ++num_forward_chunks_processed;
+ break;
+ case webrtc::audioproc::Event::REVERSE_STREAM:
+ RTC_CHECK(event_msg.has_reverse_stream());
+ HandleMessage(event_msg.reverse_stream());
+ break;
+ case webrtc::audioproc::Event::CONFIG:
+ RTC_CHECK(event_msg.has_config());
+ HandleMessage(event_msg.config());
+ break;
+ case webrtc::audioproc::Event::RUNTIME_SETTING:
+ HandleMessage(event_msg.runtime_setting());
+ break;
+ case webrtc::audioproc::Event::UNKNOWN_EVENT:
+ RTC_CHECK(false);
+ break;
+ }
+}
+
void AecDumpBasedSimulator::HandleMessage(
const webrtc::audioproc::Config& msg) {
if (settings_.use_verbose_logging) {
diff --git a/modules/audio_processing/test/aec_dump_based_simulator.h b/modules/audio_processing/test/aec_dump_based_simulator.h
index 1181979..ef032d0 100644
--- a/modules/audio_processing/test/aec_dump_based_simulator.h
+++ b/modules/audio_processing/test/aec_dump_based_simulator.h
@@ -40,6 +40,8 @@
void Process() override;
private:
+ void HandleEvent(const webrtc::audioproc::Event& event_msg,
+ int* num_forward_chunks_processed);
void HandleMessage(const webrtc::audioproc::Init& msg);
void HandleMessage(const webrtc::audioproc::Stream& msg);
void HandleMessage(const webrtc::audioproc::ReverseStream& msg);
diff --git a/modules/audio_processing/test/audio_processing_simulator.cc b/modules/audio_processing/test/audio_processing_simulator.cc
index a212125..65a52d5 100644
--- a/modules/audio_processing/test/audio_processing_simulator.cc
+++ b/modules/audio_processing/test/audio_processing_simulator.cc
@@ -222,9 +222,12 @@
if (settings_.simulate_mic_gain) {
fake_recording_device_.SetMicLevel(analog_mic_level_);
}
-
- if (buffer_writer_) {
- buffer_writer_->Write(*out_buf_);
+ if (buffer_memory_writer_) {
+ RTC_CHECK(!buffer_file_writer_);
+ buffer_memory_writer_->Write(*out_buf_);
+ } else if (buffer_file_writer_) {
+ RTC_CHECK(!buffer_memory_writer_);
+ buffer_file_writer_->Write(*out_buf_);
}
if (residual_echo_likelihood_graph_writer_.is_open()) {
@@ -254,8 +257,8 @@
reverse_out_config_, reverse_out_buf_->channels()));
}
- if (reverse_buffer_writer_) {
- reverse_buffer_writer_->Write(*reverse_out_buf_);
+ if (reverse_buffer_file_writer_) {
+ reverse_buffer_file_writer_->Write(*reverse_out_buf_);
}
++num_reverse_process_stream_calls_;
@@ -336,7 +339,10 @@
std::unique_ptr<WavWriter> out_file(
new WavWriter(filename, out_config_.sample_rate_hz(),
static_cast<size_t>(out_config_.num_channels())));
- buffer_writer_.reset(new ChannelBufferWavWriter(std::move(out_file)));
+ buffer_file_writer_.reset(new ChannelBufferWavWriter(std::move(out_file)));
+ } else if (settings_.aec_dump_input_string.has_value()) {
+ buffer_memory_writer_ = absl::make_unique<ChannelBufferVectorWriter>(
+ settings_.processed_capture_samples);
}
if (settings_.reverse_output_filename) {
@@ -351,7 +357,7 @@
std::unique_ptr<WavWriter> reverse_out_file(
new WavWriter(filename, reverse_out_config_.sample_rate_hz(),
static_cast<size_t>(reverse_out_config_.num_channels())));
- reverse_buffer_writer_.reset(
+ reverse_buffer_file_writer_.reset(
new ChannelBufferWavWriter(std::move(reverse_out_file)));
}
diff --git a/modules/audio_processing/test/audio_processing_simulator.h b/modules/audio_processing/test/audio_processing_simulator.h
index 7800afa..6f84813 100644
--- a/modules/audio_processing/test/audio_processing_simulator.h
+++ b/modules/audio_processing/test/audio_processing_simulator.h
@@ -101,6 +101,8 @@
absl::optional<std::string> call_order_input_filename;
absl::optional<std::string> call_order_output_filename;
absl::optional<std::string> aec_settings_filename;
+ absl::optional<absl::string_view> aec_dump_input_string;
+ std::vector<float>* processed_capture_samples = nullptr;
};
// Copies samples present in a ChannelBuffer into an AudioFrame.
@@ -172,8 +174,9 @@
size_t num_process_stream_calls_ = 0;
size_t num_reverse_process_stream_calls_ = 0;
- std::unique_ptr<ChannelBufferWavWriter> buffer_writer_;
- std::unique_ptr<ChannelBufferWavWriter> reverse_buffer_writer_;
+ std::unique_ptr<ChannelBufferWavWriter> buffer_file_writer_;
+ std::unique_ptr<ChannelBufferWavWriter> reverse_buffer_file_writer_;
+ std::unique_ptr<ChannelBufferVectorWriter> buffer_memory_writer_;
ApiCallStatistics api_call_statistics_;
std::ofstream residual_echo_likelihood_graph_writer_;
int analog_mic_level_;
diff --git a/modules/audio_processing/test/audioproc_float_impl.cc b/modules/audio_processing/test/audioproc_float_impl.cc
index 3764282..41d137b 100644
--- a/modules/audio_processing/test/audioproc_float_impl.cc
+++ b/modules/audio_processing/test/audioproc_float_impl.cc
@@ -462,9 +462,15 @@
void PerformBasicParameterSanityChecks(const SimulationSettings& settings) {
if (settings.input_filename || settings.reverse_input_filename) {
- ReportConditionalErrorAndExit(!!settings.aec_dump_input_filename,
- "Error: The aec dump cannot be specified "
- "together with input wav files!\n");
+ ReportConditionalErrorAndExit(
+ !!settings.aec_dump_input_filename,
+ "Error: The aec dump file cannot be specified "
+ "together with input wav files!\n");
+
+ ReportConditionalErrorAndExit(
+ !!settings.aec_dump_input_string,
+ "Error: The aec dump input string cannot be specified "
+ "together with input wav files!\n");
ReportConditionalErrorAndExit(!!settings.artificial_nearend_filename,
"Error: The artificial nearend cannot be "
@@ -480,9 +486,14 @@
"Error: When operating at wav files, the reverse input wav filename "
"must be specified if the reverse output wav filename is specified!\n");
} else {
- ReportConditionalErrorAndExit(!settings.aec_dump_input_filename,
- "Error: Either the aec dump or the wav "
- "input files must be specified!\n");
+ ReportConditionalErrorAndExit(
+ !settings.aec_dump_input_filename && !settings.aec_dump_input_string,
+ "Error: Either the aec dump input file, the wav "
+ "input file or the aec dump input string must be specified!\n");
+ ReportConditionalErrorAndExit(
+ settings.aec_dump_input_filename && settings.aec_dump_input_string,
+ "Error: The aec dump input file cannot be specified together with the "
+ "aec dump input string!\n");
}
ReportConditionalErrorAndExit(
@@ -624,7 +635,9 @@
int AudioprocFloatImpl(std::unique_ptr<AudioProcessingBuilder> ap_builder,
int argc,
- char* argv[]) {
+ char* argv[],
+ absl::string_view input_aecdump,
+ std::vector<float>* processed_capture_samples) {
std::vector<char*> args = absl::ParseCommandLine(argc, argv);
if (args.size() != 1) {
printf("%s", kUsageDescription);
@@ -632,10 +645,15 @@
}
SimulationSettings settings = CreateSettings();
+ if (!input_aecdump.empty()) {
+ settings.aec_dump_input_string = input_aecdump;
+ settings.processed_capture_samples = processed_capture_samples;
+ RTC_CHECK(settings.processed_capture_samples);
+ }
PerformBasicParameterSanityChecks(settings);
std::unique_ptr<AudioProcessingSimulator> processor;
- if (settings.aec_dump_input_filename) {
+ if (settings.aec_dump_input_filename || settings.aec_dump_input_string) {
processor.reset(new AecDumpBasedSimulator(settings, std::move(ap_builder)));
} else {
processor.reset(new WavBasedSimulator(settings, std::move(ap_builder)));
diff --git a/modules/audio_processing/test/audioproc_float_impl.h b/modules/audio_processing/test/audioproc_float_impl.h
index 063ecb4..9a9013c 100644
--- a/modules/audio_processing/test/audioproc_float_impl.h
+++ b/modules/audio_processing/test/audioproc_float_impl.h
@@ -18,10 +18,17 @@
namespace webrtc {
namespace test {
-// This function implements the audio processing simulation utility.
+// 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.
int AudioprocFloatImpl(std::unique_ptr<AudioProcessingBuilder> ap_builder,
int argc,
- char* argv[]);
+ char* argv[],
+ absl::string_view input_aecdump,
+ std::vector<float>* processed_capture_samples);
} // namespace test
} // namespace webrtc
diff --git a/modules/audio_processing/test/protobuf_utils.cc b/modules/audio_processing/test/protobuf_utils.cc
index f3c97ee..3042bce 100644
--- a/modules/audio_processing/test/protobuf_utils.cc
+++ b/modules/audio_processing/test/protobuf_utils.cc
@@ -10,8 +10,31 @@
#include "modules/audio_processing/test/protobuf_utils.h"
+#include "absl/memory/memory.h"
#include "rtc_base/system/arch.h"
+namespace {
+// Allocates new memory in the memory owned by the unique_ptr to fit the raw
+// message and returns the number of bytes read when having a string stream as
+// input.
+size_t ReadMessageBytesFromString(std::stringstream* input,
+ std::unique_ptr<uint8_t[]>* bytes) {
+ int32_t size = 0;
+ input->read(reinterpret_cast<char*>(&size), sizeof(int32_t));
+ int32_t size_read = input->gcount();
+ if (size_read != sizeof(int32_t))
+ return 0;
+ if (size <= 0)
+ return 0;
+
+ *bytes = absl::make_unique<uint8_t[]>(size);
+ input->read(reinterpret_cast<char*>(bytes->get()),
+ size * sizeof((*bytes)[0]));
+ size_read = input->gcount();
+ return size_read == size ? size : 0;
+}
+} // namespace
+
namespace webrtc {
size_t ReadMessageBytesFromFile(FILE* file, std::unique_ptr<uint8_t[]>* bytes) {
@@ -26,7 +49,7 @@
if (size <= 0)
return 0;
- bytes->reset(new uint8_t[size]);
+ *bytes = absl::make_unique<uint8_t[]>(size);
return fread(bytes->get(), sizeof((*bytes)[0]), size, file);
}
@@ -41,4 +64,15 @@
return msg->ParseFromArray(bytes.get(), size);
}
+// Returns true on success, false on error or end of string stream.
+bool ReadMessageFromString(std::stringstream* input, MessageLite* msg) {
+ std::unique_ptr<uint8_t[]> bytes;
+ size_t size = ReadMessageBytesFromString(input, &bytes);
+ if (!size)
+ return false;
+
+ msg->Clear();
+ return msg->ParseFromArray(bytes.get(), size);
+}
+
} // namespace webrtc
diff --git a/modules/audio_processing/test/protobuf_utils.h b/modules/audio_processing/test/protobuf_utils.h
index dded9b4..b9c2e81 100644
--- a/modules/audio_processing/test/protobuf_utils.h
+++ b/modules/audio_processing/test/protobuf_utils.h
@@ -12,6 +12,7 @@
#define MODULES_AUDIO_PROCESSING_TEST_PROTOBUF_UTILS_H_
#include <memory>
+#include <sstream> // no-presubmit-check TODO(webrtc:8982)
#include "rtc_base/ignore_wundef.h"
#include "rtc_base/protobuf_utils.h"
@@ -29,6 +30,11 @@
// Returns true on success, false on error or end-of-file.
bool ReadMessageFromFile(FILE* file, MessageLite* msg);
+// Returns true on success, false on error or end of string stream.
+bool ReadMessageFromString(
+ std::stringstream* input, // no-presubmit-check TODO(webrtc:8982)
+ MessageLite* msg);
+
} // namespace webrtc
#endif // MODULES_AUDIO_PROCESSING_TEST_PROTOBUF_UTILS_H_
diff --git a/modules/audio_processing/test/test_utils.cc b/modules/audio_processing/test/test_utils.cc
index c02bc76..d8d51bc 100644
--- a/modules/audio_processing/test/test_utils.cc
+++ b/modules/audio_processing/test/test_utils.cc
@@ -68,6 +68,24 @@
file_->WriteSamples(&interleaved_[0], interleaved_.size());
}
+ChannelBufferVectorWriter::ChannelBufferVectorWriter(std::vector<float>* output)
+ : output_(output) {
+ RTC_DCHECK(output_);
+}
+
+ChannelBufferVectorWriter::~ChannelBufferVectorWriter() = default;
+
+void ChannelBufferVectorWriter::Write(const ChannelBuffer<float>& buffer) {
+ // Account for sample rate changes throughout a simulation.
+ interleaved_buffer_.resize(buffer.size());
+ Interleave(buffer.channels(), buffer.num_frames(), buffer.num_channels(),
+ interleaved_buffer_.data());
+ size_t old_size = output_->size();
+ output_->resize(old_size + interleaved_buffer_.size());
+ FloatToFloatS16(interleaved_buffer_.data(), interleaved_buffer_.size(),
+ output_->data() + old_size);
+}
+
void WriteIntData(const int16_t* data,
size_t length,
WavWriter* wav_file,
diff --git a/modules/audio_processing/test/test_utils.h b/modules/audio_processing/test/test_utils.h
index 0dd4a40..341f2b2 100644
--- a/modules/audio_processing/test/test_utils.h
+++ b/modules/audio_processing/test/test_utils.h
@@ -77,6 +77,26 @@
RTC_DISALLOW_COPY_AND_ASSIGN(ChannelBufferWavWriter);
};
+// Takes a pointer to a vector. Allows appending the samples of channel buffers
+// to the given vector, by interleaving the samples and converting them to float
+// S16.
+class ChannelBufferVectorWriter final {
+ public:
+ explicit ChannelBufferVectorWriter(std::vector<float>* output);
+ ChannelBufferVectorWriter(const ChannelBufferVectorWriter&) = delete;
+ ChannelBufferVectorWriter& operator=(const ChannelBufferVectorWriter&) =
+ delete;
+ ~ChannelBufferVectorWriter();
+
+ // Creates an interleaved copy of |buffer|, converts the samples to float S16
+ // and appends the result to output_.
+ void Write(const ChannelBuffer<float>& buffer);
+
+ private:
+ std::vector<float> interleaved_buffer_;
+ std::vector<float>* output_;
+};
+
void WriteIntData(const int16_t* data,
size_t length,
WavWriter* wav_file,