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}
This commit is contained in:
peah
2016-12-09 02:43:40 -08:00
committed by Commit bot
parent a90799d5fb
commit df80fd1259
4 changed files with 67 additions and 3 deletions

View File

@ -62,6 +62,11 @@ bool VerifyFloatBitExactness(const webrtc::audioproc::Stream& msg,
} // namespace } // namespace
AecDumpBasedSimulator::AecDumpBasedSimulator(const SimulationSettings& settings)
: AudioProcessingSimulator(settings) {}
AecDumpBasedSimulator::~AecDumpBasedSimulator() = default;
void AecDumpBasedSimulator::PrepareProcessStreamCall( void AecDumpBasedSimulator::PrepareProcessStreamCall(
const webrtc::audioproc::Stream& msg, const webrtc::audioproc::Stream& msg,
bool* set_stream_analog_level_called) { 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<int16_t>(
fwd_frame_.data_[k] +
static_cast<int16_t>(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 (!settings_.stream_delay) {
if (msg.has_delay()) { if (msg.has_delay()) {
RTC_CHECK_EQ(AudioProcessing::kNoError, RTC_CHECK_EQ(AudioProcessing::kNoError,
@ -189,6 +222,22 @@ void AecDumpBasedSimulator::Process() {
CreateAudioProcessor(); CreateAudioProcessor();
dump_input_file_ = OpenFile(settings_.aec_dump_input_filename->c_str(), "rb"); 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()));
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<float>(
rtc::CheckedDivExact(artificial_nearend_file->sample_rate(),
kChunksPerSecond),
1));
}
webrtc::audioproc::Event event_msg; webrtc::audioproc::Event event_msg;
int num_forward_chunks_processed = 0; int num_forward_chunks_processed = 0;
const float kOneBykChunksPerSecond = const float kOneBykChunksPerSecond =

View File

@ -30,9 +30,8 @@ namespace test {
// Used to perform an audio processing simulation from an aec dump. // Used to perform an audio processing simulation from an aec dump.
class AecDumpBasedSimulator final : public AudioProcessingSimulator { class AecDumpBasedSimulator final : public AudioProcessingSimulator {
public: public:
explicit AecDumpBasedSimulator(const SimulationSettings& settings) explicit AecDumpBasedSimulator(const SimulationSettings& settings);
: AudioProcessingSimulator(settings) {} ~AecDumpBasedSimulator() override;
~AecDumpBasedSimulator() override {}
// Processes the messages in the aecdump file. // Processes the messages in the aecdump file.
void Process() override; void Process() override;
@ -55,6 +54,9 @@ class AecDumpBasedSimulator final : public AudioProcessingSimulator {
}; };
FILE* dump_input_file_; FILE* dump_input_file_;
std::unique_ptr<ChannelBuffer<float>> artificial_nearend_buf_;
std::unique_ptr<ChannelBufferWavReader> artificial_nearend_buffer_reader_;
bool artificial_nearend_eof_reported_ = false;
InterfaceType interface_used_ = InterfaceType::kNotSpecified; InterfaceType interface_used_ = InterfaceType::kNotSpecified;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AecDumpBasedSimulator); RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AecDumpBasedSimulator);

View File

@ -44,6 +44,7 @@ struct SimulationSettings {
rtc::Optional<std::string> reverse_output_filename; rtc::Optional<std::string> reverse_output_filename;
rtc::Optional<std::string> input_filename; rtc::Optional<std::string> input_filename;
rtc::Optional<std::string> reverse_input_filename; rtc::Optional<std::string> reverse_input_filename;
rtc::Optional<std::string> artificial_nearend_filename;
rtc::Optional<bool> use_aec; rtc::Optional<bool> use_aec;
rtc::Optional<bool> use_aecm; rtc::Optional<bool> use_aecm;
rtc::Optional<bool> use_ed; // Residual Echo Detector. rtc::Optional<bool> use_ed; // Residual Echo Detector.

View File

@ -40,6 +40,7 @@ DEFINE_string(i, "", "Forward stream input wav filename");
DEFINE_string(o, "", "Forward stream output wav filename"); DEFINE_string(o, "", "Forward stream output wav filename");
DEFINE_string(ri, "", "Reverse stream input wav filename"); DEFINE_string(ri, "", "Reverse stream input wav filename");
DEFINE_string(ro, "", "Reverse stream output wav filename"); DEFINE_string(ro, "", "Reverse stream output wav filename");
DEFINE_string(artificial_nearend, "", "Artificial nearend wav filename");
DEFINE_int32(output_num_channels, DEFINE_int32(output_num_channels,
kParameterNotSpecifiedValue, kParameterNotSpecifiedValue,
"Number of forward stream output channels"); "Number of forward stream output channels");
@ -208,6 +209,8 @@ SimulationSettings CreateSettings() {
SetSettingIfSpecified(FLAGS_o, &settings.output_filename); SetSettingIfSpecified(FLAGS_o, &settings.output_filename);
SetSettingIfSpecified(FLAGS_ri, &settings.reverse_input_filename); SetSettingIfSpecified(FLAGS_ri, &settings.reverse_input_filename);
SetSettingIfSpecified(FLAGS_ro, &settings.reverse_output_filename); SetSettingIfSpecified(FLAGS_ro, &settings.reverse_output_filename);
SetSettingIfSpecified(FLAGS_artificial_nearend,
&settings.artificial_nearend_filename);
SetSettingIfSpecified(FLAGS_output_num_channels, SetSettingIfSpecified(FLAGS_output_num_channels,
&settings.output_num_channels); &settings.output_num_channels);
SetSettingIfSpecified(FLAGS_reverse_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 " "Error: The aec dump cannot be specified "
"together with input wav files!\n"); "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, ReportConditionalErrorAndExit(!settings.input_filename,
"Error: When operating at wav files, the " "Error: When operating at wav files, the "
"input wav filename must be " "input wav filename must be "
@ -389,6 +396,11 @@ void PerformBasicParameterSanityChecks(const SimulationSettings& settings) {
settings.reverse_output_filename && settings.reverse_output_filename &&
(!valid_wav_name(*settings.reverse_output_filename)), (!valid_wav_name(*settings.reverse_output_filename)),
"Error: --ro must be a valid .wav file name.\n"); "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 } // namespace