Index: webrtc/modules/audio_processing/test/audio_processing_simulator.cc |
diff --git a/webrtc/modules/audio_processing/test/audio_processing_simulator.cc b/webrtc/modules/audio_processing/test/audio_processing_simulator.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2f7a6e0337b6ab2e0d86fe7748f243f81a25c977 |
--- /dev/null |
+++ b/webrtc/modules/audio_processing/test/audio_processing_simulator.cc |
@@ -0,0 +1,330 @@ |
+/* |
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+#include "webrtc/modules/audio_processing/test/audio_processing_simulator.h" |
+ |
+#include <algorithm> |
+#include <sstream> |
+#include <string> |
+#include <vector> |
+ |
+#include "webrtc/base/stringutils.h" |
+#include "webrtc/common_audio/include/audio_util.h" |
+#include "webrtc/modules/audio_processing/include/audio_processing.h" |
+ |
+namespace webrtc { |
+namespace test { |
+namespace { |
+ |
+void CopyFromAudioFrame(const AudioFrame& src, ChannelBuffer<float>* dest) { |
+ RTC_CHECK_EQ(src.num_channels_, dest->num_channels()); |
+ RTC_CHECK_EQ(src.samples_per_channel_, dest->num_frames()); |
+ // Copy the data from the input buffer. |
+ std::vector<float> tmp(src.samples_per_channel_ * src.num_channels_); |
+ S16ToFloat(src.data_, tmp.size(), tmp.data()); |
+ Deinterleave(tmp.data(), src.samples_per_channel_, src.num_channels_, |
+ dest->channels()); |
+} |
+ |
+std::string GetIndexedOutputWavFilename(const std::string& wav_name, |
+ int counter) { |
+ std::stringstream ss; |
+ ss << wav_name.substr(0, wav_name.size() - 4) << "_" << counter |
+ << wav_name.substr(wav_name.size() - 4); |
+ return ss.str(); |
+} |
+ |
+} // namespace |
+ |
+void CopyToAudioFrame(const ChannelBuffer<float>& src, AudioFrame* dest) { |
+ RTC_CHECK_EQ(src.num_channels(), dest->num_channels_); |
+ RTC_CHECK_EQ(src.num_frames(), dest->samples_per_channel_); |
+ for (size_t ch = 0; ch < dest->num_channels_; ++ch) { |
+ for (size_t sample = 0; sample < dest->samples_per_channel_; ++sample) { |
+ dest->data_[sample * dest->num_channels_ + ch] = |
+ src.channels()[ch][sample] * 32767; |
+ } |
+ } |
+} |
+ |
+AudioProcessingSimulator::ScopedTimer::~ScopedTimer() { |
+ TickInterval interval = TickTime::Now() - start_time_; |
+ proc_time_->sum += interval; |
+ proc_time_->max = std::max(proc_time_->max, interval); |
+ proc_time_->min = std::min(proc_time_->min, interval); |
+} |
+ |
+void AudioProcessingSimulator::ProcessStream(bool fixed_interface) { |
+ if (fixed_interface) { |
+ { |
+ const auto st = ScopedTimer(mutable_proc_time()); |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, ap_->ProcessStream(&fwd_frame_)); |
+ } |
+ CopyFromAudioFrame(fwd_frame_, out_buf_.get()); |
+ } else { |
+ const auto st = ScopedTimer(mutable_proc_time()); |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->ProcessStream(in_buf_->channels(), in_config_, |
+ out_config_, out_buf_->channels())); |
+ } |
+ |
+ if (buffer_writer_) { |
+ buffer_writer_->Write(*out_buf_); |
+ } |
+ |
+ ++num_process_stream_calls_; |
+} |
+ |
+void AudioProcessingSimulator::ProcessReverseStream(bool fixed_interface) { |
+ if (fixed_interface) { |
+ const auto st = ScopedTimer(mutable_proc_time()); |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, ap_->ProcessStream(&rev_frame_)); |
+ CopyFromAudioFrame(rev_frame_, reverse_out_buf_.get()); |
+ |
+ } else { |
+ const auto st = ScopedTimer(mutable_proc_time()); |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->ProcessReverseStream( |
+ reverse_in_buf_->channels(), reverse_in_config_, |
+ reverse_out_config_, reverse_out_buf_->channels())); |
+ } |
+ |
+ if (reverse_buffer_writer_) { |
+ reverse_buffer_writer_->Write(*reverse_out_buf_); |
+ } |
+ |
+ ++num_reverse_process_stream_calls_; |
+} |
+ |
+void AudioProcessingSimulator::SetupBuffersConfigsOutputs( |
+ int input_sample_rate_hz, |
+ int output_sample_rate_hz, |
+ int reverse_input_sample_rate_hz, |
+ int reverse_output_sample_rate_hz, |
+ int input_num_channels, |
+ int output_num_channels, |
+ int reverse_input_num_channels, |
+ int reverse_output_num_channels) { |
+ in_config_ = StreamConfig(input_sample_rate_hz, input_num_channels); |
+ in_buf_.reset(new ChannelBuffer<float>( |
+ rtc::CheckedDivExact(input_sample_rate_hz, kChunksPerSecond), |
+ input_num_channels)); |
+ |
+ reverse_in_config_ = |
+ StreamConfig(reverse_input_sample_rate_hz, reverse_input_num_channels); |
+ reverse_in_buf_.reset(new ChannelBuffer<float>( |
+ rtc::CheckedDivExact(reverse_input_sample_rate_hz, kChunksPerSecond), |
+ reverse_input_num_channels)); |
+ |
+ out_config_ = StreamConfig(output_sample_rate_hz, output_num_channels); |
+ out_buf_.reset(new ChannelBuffer<float>( |
+ rtc::CheckedDivExact(output_sample_rate_hz, kChunksPerSecond), |
+ output_num_channels)); |
+ |
+ reverse_out_config_ = |
+ StreamConfig(reverse_output_sample_rate_hz, reverse_output_num_channels); |
+ reverse_out_buf_.reset(new ChannelBuffer<float>( |
+ rtc::CheckedDivExact(reverse_output_sample_rate_hz, kChunksPerSecond), |
+ reverse_output_num_channels)); |
+ |
+ fwd_frame_.sample_rate_hz_ = input_sample_rate_hz; |
+ fwd_frame_.samples_per_channel_ = |
+ rtc::CheckedDivExact(fwd_frame_.sample_rate_hz_, kChunksPerSecond); |
+ fwd_frame_.num_channels_ = input_num_channels; |
+ |
+ rev_frame_.sample_rate_hz_ = reverse_input_sample_rate_hz; |
+ rev_frame_.samples_per_channel_ = |
+ rtc::CheckedDivExact(rev_frame_.sample_rate_hz_, kChunksPerSecond); |
+ rev_frame_.num_channels_ = reverse_input_num_channels; |
+ |
+ if (settings_.use_verbose_logging) { |
+ printf("Sample rates:\n"); |
+ printf(" Forward input: %d\n", input_sample_rate_hz); |
+ printf(" Forward output: %d\n", output_sample_rate_hz); |
+ printf(" Reverse input: %d\n", reverse_input_sample_rate_hz); |
+ printf(" Reverse output: %d\n", reverse_output_sample_rate_hz); |
+ printf("Number of channels:\n"); |
+ printf(" Forward input: %d\n", input_num_channels); |
+ printf(" Forward output: %d\n", output_num_channels); |
+ printf(" Reverse input: %d\n", reverse_input_num_channels); |
+ printf(" Reverse output: %d\n", reverse_output_num_channels); |
+ } |
+ |
+ SetupOutput(); |
+} |
+ |
+void AudioProcessingSimulator::SetupOutput() { |
+ if (settings_.output_filename) { |
+ std::string filename; |
+ if (settings_.store_intermediate_output) { |
+ filename = GetIndexedOutputWavFilename(*settings_.output_filename, |
+ output_reset_counter_); |
+ } else { |
+ filename = *settings_.output_filename; |
+ } |
+ |
+ 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))); |
+ } |
+ |
+ if (settings_.reverse_output_filename) { |
+ std::string filename; |
+ if (settings_.store_intermediate_output) { |
+ filename = GetIndexedOutputWavFilename(*settings_.reverse_output_filename, |
+ output_reset_counter_); |
+ } else { |
+ filename = *settings_.reverse_output_filename; |
+ } |
+ |
+ 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( |
+ new ChannelBufferWavWriter(std::move(reverse_out_file))); |
+ } |
+ |
+ ++output_reset_counter_; |
+} |
+ |
+void AudioProcessingSimulator::DestroyAudioProcessor() { |
+ if (settings_.aec_dump_output_filename) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, ap_->StopDebugRecording()); |
+ } |
+} |
+ |
+void AudioProcessingSimulator::CreateAudioProcessor() { |
+ Config config; |
+ if (settings_.use_bf && *settings_.use_bf) { |
+ config.Set<Beamforming>(new Beamforming( |
+ true, ParseArrayGeometry(*settings_.microphone_positions), |
+ SphericalPointf(DegreesToRadians(settings_.target_angle_degrees), 0.f, |
+ 1.f))); |
+ } |
+ if (settings_.use_ts) { |
+ config.Set<ExperimentalNs>(new ExperimentalNs(*settings_.use_ts)); |
+ } |
+ if (settings_.use_ie) { |
+ config.Set<Intelligibility>(new Intelligibility(*settings_.use_ie)); |
+ } |
+ if (settings_.use_aec3) { |
+ config.Set<EchoCanceller3>(new EchoCanceller3(*settings_.use_aec3)); |
+ } |
+ if (settings_.use_refined_adaptive_filter) { |
+ config.Set<RefinedAdaptiveFilter>( |
+ new RefinedAdaptiveFilter(*settings_.use_refined_adaptive_filter)); |
+ } |
+ config.Set<ExtendedFilter>(new ExtendedFilter( |
+ !settings_.use_extended_filter || *settings_.use_extended_filter)); |
+ config.Set<DelayAgnostic>(new DelayAgnostic(!settings_.use_delay_agnostic || |
+ *settings_.use_delay_agnostic)); |
+ |
+ ap_.reset(AudioProcessing::Create(config)); |
+ |
+ if (settings_.use_aec) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->echo_cancellation()->Enable(*settings_.use_aec)); |
+ } |
+ if (settings_.use_aecm) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->echo_control_mobile()->Enable(*settings_.use_aecm)); |
+ } |
+ if (settings_.use_agc) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->gain_control()->Enable(*settings_.use_agc)); |
+ } |
+ if (settings_.use_hpf) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->high_pass_filter()->Enable(*settings_.use_hpf)); |
+ } |
+ if (settings_.use_ns) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->noise_suppression()->Enable(*settings_.use_ns)); |
+ } |
+ if (settings_.use_le) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->level_estimator()->Enable(*settings_.use_le)); |
+ } |
+ if (settings_.use_vad) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->voice_detection()->Enable(*settings_.use_vad)); |
+ } |
+ if (settings_.use_agc_limiter) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, ap_->gain_control()->enable_limiter( |
+ *settings_.use_agc_limiter)); |
+ } |
+ if (settings_.agc_target_level) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->gain_control()->set_target_level_dbfs( |
+ *settings_.agc_target_level)); |
+ } |
+ |
+ if (settings_.agc_mode) { |
+ RTC_CHECK_EQ( |
+ AudioProcessing::kNoError, |
+ ap_->gain_control()->set_mode( |
+ static_cast<webrtc::GainControl::Mode>(*settings_.agc_mode))); |
+ } |
+ |
+ if (settings_.use_drift_compensation) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->echo_cancellation()->enable_drift_compensation( |
+ *settings_.use_drift_compensation)); |
+ } |
+ |
+ if (settings_.aec_suppression_level) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->echo_cancellation()->set_suppression_level( |
+ static_cast<webrtc::EchoCancellation::SuppressionLevel>( |
+ *settings_.aec_suppression_level))); |
+ } |
+ |
+ if (settings_.aecm_routing_mode) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->echo_control_mobile()->set_routing_mode( |
+ static_cast<webrtc::EchoControlMobile::RoutingMode>( |
+ *settings_.aecm_routing_mode))); |
+ } |
+ |
+ if (settings_.use_aecm_comfort_noise) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->echo_control_mobile()->enable_comfort_noise( |
+ *settings_.use_aecm_comfort_noise)); |
+ } |
+ |
+ if (settings_.vad_likelihood) { |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->voice_detection()->set_likelihood( |
+ static_cast<webrtc::VoiceDetection::Likelihood>( |
+ *settings_.vad_likelihood))); |
+ } |
+ if (settings_.ns_level) { |
+ RTC_CHECK_EQ( |
+ AudioProcessing::kNoError, |
+ ap_->noise_suppression()->set_level( |
+ static_cast<NoiseSuppression::Level>(*settings_.ns_level))); |
+ } |
+ |
+ if (settings_.use_ts) { |
+ ap_->set_stream_key_pressed(*settings_.use_ts); |
+ } |
+ |
+ if (settings_.aec_dump_output_filename) { |
+ size_t kMaxFilenameSize = AudioProcessing::kMaxFilenameSize; |
+ RTC_CHECK_LE(settings_.aec_dump_output_filename->size(), kMaxFilenameSize); |
+ RTC_CHECK_EQ(AudioProcessing::kNoError, |
+ ap_->StartDebugRecording( |
+ settings_.aec_dump_output_filename->c_str(), -1)); |
+ } |
+} |
+ |
+} // namespace test |
+} // namespace webrtc |