| 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..6cb614db32f45240099a7484c5c8d2b6d21bc1f6
|
| --- /dev/null
|
| +++ b/webrtc/modules/audio_processing/test/audio_processing_simulator.cc
|
| @@ -0,0 +1,334 @@
|
| +/*
|
| + * 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 <iostream>
|
| +#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() {
|
| + int64_t interval = rtc::TimeNanos() - 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) {
|
| + std::cout << "Sample rates:" << std::endl;
|
| + std::cout << " Forward input: " << input_sample_rate_hz << std::endl;
|
| + std::cout << " Forward output: " << output_sample_rate_hz << std::endl;
|
| + std::cout << " Reverse input: " << reverse_input_sample_rate_hz
|
| + << std::endl;
|
| + std::cout << " Reverse output: " << reverse_output_sample_rate_hz
|
| + << std::endl;
|
| + std::cout << "Number of channels: " << std::endl;
|
| + std::cout << " Forward input: " << input_num_channels << std::endl;
|
| + std::cout << " Forward output: " << output_num_channels << std::endl;
|
| + std::cout << " Reverse input: " << reverse_input_num_channels << std::endl;
|
| + std::cout << " Reverse output: " << reverse_output_num_channels
|
| + << std::endl;
|
| + }
|
| +
|
| + 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
|
|
|