diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc index 717e9b0568..ebd7981bd6 100644 --- a/modules/audio_processing/aec3/echo_remover.cc +++ b/modules/audio_processing/aec3/echo_remover.cc @@ -147,7 +147,7 @@ class EchoRemoverImpl final : public EchoRemover { const size_t num_render_channels_; const size_t num_capture_channels_; const bool use_shadow_filter_output_; - std::vector> subtractors_; + Subtractor subtractor_; std::vector> suppression_gains_; std::vector> cngs_; SuppressionFilter suppression_filter_; @@ -190,7 +190,11 @@ EchoRemoverImpl::EchoRemoverImpl(const EchoCanceller3Config& config, num_capture_channels_(num_capture_channels), use_shadow_filter_output_( config_.filter.enable_shadow_filter_output_usage), - subtractors_(num_capture_channels_), + subtractor_(config, + num_render_channels_, + num_capture_channels_, + data_dumper_.get(), + optimization_), suppression_gains_(num_capture_channels_), cngs_(num_capture_channels_), suppression_filter_(optimization_, @@ -219,9 +223,6 @@ EchoRemoverImpl::EchoRemoverImpl(const EchoCanceller3Config& config, for (size_t ch = 0; ch < num_capture_channels_; ++ch) { residual_echo_estimators_[ch] = std::make_unique(config_); - subtractors_[ch] = std::make_unique( - config, num_render_channels_, num_capture_channels_, data_dumper_.get(), - optimization_); suppression_gains_[ch] = std::make_unique( config_, optimization_, sample_rate_hz); cngs_[ch] = std::make_unique(optimization_); @@ -339,9 +340,7 @@ void EchoRemoverImpl::ProcessCapture( } } - for (size_t ch = 0; ch < num_capture_channels_; ++ch) { - subtractors_[ch]->HandleEchoPathChange(echo_path_variability); - } + subtractor_.HandleEchoPathChange(echo_path_variability); aec_state_.HandleEchoPathChange(echo_path_variability); if (echo_path_variability.delay_change != @@ -359,21 +358,21 @@ void EchoRemoverImpl::ProcessCapture( render_signal_analyzer_.Update(*render_buffer, aec_state_.FilterDelayBlocks()); - // Perform linear echo cancellation. + // State transition. if (aec_state_.TransitionTriggered()) { + subtractor_.ExitInitialState(); for (size_t ch = 0; ch < num_capture_channels_; ++ch) { - subtractors_[ch]->ExitInitialState(); suppression_gains_[ch]->SetInitialState(false); } } + // Perform linear echo cancellation. + subtractor_.Process(*render_buffer, (*y)[0], render_signal_analyzer_, + aec_state_, subtractor_output); + for (size_t ch = 0; ch < num_capture_channels_; ++ch) { auto& y_low = (*y)[0][ch]; - // If the delay is known, use the echo subtractor. - subtractors_[ch]->Process(*render_buffer, y_low, render_signal_analyzer_, - aec_state_, &subtractor_output[ch]); - // Compute spectra. FormLinearFilterOutput(subtractor_output[ch], e[ch]); WindowedPaddedFft(fft_, y_low, y_old_[ch], &Y[ch]); @@ -385,9 +384,9 @@ void EchoRemoverImpl::ProcessCapture( // Update the AEC state information. // TODO(bugs.webrtc.org/10913): Take all subtractors into account. - aec_state_.Update(external_delay, subtractors_[0]->FilterFrequencyResponse(), - subtractors_[0]->FilterImpulseResponse(), *render_buffer, - E2[0], Y2[0], subtractor_output[0], y0); + aec_state_.Update(external_delay, subtractor_.FilterFrequencyResponse(), + subtractor_.FilterImpulseResponse(), *render_buffer, E2[0], + Y2[0], subtractor_output[0], y0); // Choose the linear output. const auto& Y_fft = aec_state_.UseLinearFilterOutput() ? E : Y; diff --git a/modules/audio_processing/aec3/subtractor.cc b/modules/audio_processing/aec3/subtractor.cc index 4d86358781..0c52ed64a1 100644 --- a/modules/audio_processing/aec3/subtractor.cc +++ b/modules/audio_processing/aec3/subtractor.cc @@ -65,32 +65,50 @@ Subtractor::Subtractor(const EchoCanceller3Config& config, data_dumper_(data_dumper), optimization_(optimization), config_(config), - main_filter_(config_.filter.main.length_blocks, - config_.filter.main_initial.length_blocks, - config.filter.config_change_duration_blocks, - num_render_channels, - num_capture_channels, - optimization, - data_dumper_), - shadow_filter_(config_.filter.shadow.length_blocks, - config_.filter.shadow_initial.length_blocks, - config.filter.config_change_duration_blocks, - num_render_channels, - num_capture_channels, - optimization, - data_dumper_), - G_main_(config_.filter.main_initial, - config_.filter.config_change_duration_blocks), - G_shadow_(config_.filter.shadow_initial, - config.filter.config_change_duration_blocks), - main_frequency_response_(main_filter_.max_filter_size_partitions(), - std::array()), + num_capture_channels_(num_capture_channels), + main_filter_(num_capture_channels_), + shadow_filter_(num_capture_channels_), + G_main_(num_capture_channels_), + G_shadow_(num_capture_channels_), + filter_misadjustment_estimator_(num_capture_channels_), + poor_shadow_filter_counter_(num_capture_channels_, 0), + main_frequency_response_( + num_capture_channels_, + std::vector>( + std::max(config_.filter.main_initial.length_blocks, + config_.filter.main.length_blocks), + std::array())), main_impulse_response_( - GetTimeDomainLength(main_filter_.max_filter_size_partitions()), - 0.f) { + num_capture_channels_, + std::vector(GetTimeDomainLength(std::max( + config_.filter.main_initial.length_blocks, + config_.filter.main.length_blocks)), + 0.f)) { + for (size_t ch = 0; ch < num_capture_channels_; ++ch) { + main_filter_[ch] = std::make_unique( + config_.filter.main.length_blocks, + config_.filter.main_initial.length_blocks, + config.filter.config_change_duration_blocks, num_render_channels, + num_capture_channels, optimization, data_dumper_); + + shadow_filter_[ch] = std::make_unique( + config_.filter.shadow.length_blocks, + config_.filter.shadow_initial.length_blocks, + config.filter.config_change_duration_blocks, num_render_channels, + num_capture_channels, optimization, data_dumper_); + G_main_[ch] = std::make_unique( + config_.filter.main_initial, + config_.filter.config_change_duration_blocks); + G_shadow_[ch] = std::make_unique( + config_.filter.shadow_initial, + config.filter.config_change_duration_blocks); + } + RTC_DCHECK(data_dumper_); - for (auto& H2_k : main_frequency_response_) { - H2_k.fill(0.f); + for (size_t ch = 0; ch < num_capture_channels_; ++ch) { + for (auto& H2_k : main_frequency_response_[ch]) { + H2_k.fill(0.f); + } } } @@ -99,16 +117,18 @@ Subtractor::~Subtractor() = default; void Subtractor::HandleEchoPathChange( const EchoPathVariability& echo_path_variability) { const auto full_reset = [&]() { - main_filter_.HandleEchoPathChange(); - shadow_filter_.HandleEchoPathChange(); - G_main_.HandleEchoPathChange(echo_path_variability); - G_shadow_.HandleEchoPathChange(); - G_main_.SetConfig(config_.filter.main_initial, true); - G_shadow_.SetConfig(config_.filter.shadow_initial, true); - main_filter_.SetSizePartitions(config_.filter.main_initial.length_blocks, - true); - shadow_filter_.SetSizePartitions( - config_.filter.shadow_initial.length_blocks, true); + for (size_t ch = 0; ch < num_capture_channels_; ++ch) { + main_filter_[ch]->HandleEchoPathChange(); + shadow_filter_[ch]->HandleEchoPathChange(); + G_main_[ch]->HandleEchoPathChange(echo_path_variability); + G_shadow_[ch]->HandleEchoPathChange(); + G_main_[ch]->SetConfig(config_.filter.main_initial, true); + G_shadow_[ch]->SetConfig(config_.filter.shadow_initial, true); + main_filter_[ch]->SetSizePartitions( + config_.filter.main_initial.length_blocks, true); + shadow_filter_[ch]->SetSizePartitions( + config_.filter.shadow_initial.length_blocks, true); + } }; if (echo_path_variability.delay_change != @@ -117,128 +137,149 @@ void Subtractor::HandleEchoPathChange( } if (echo_path_variability.gain_change) { - G_main_.HandleEchoPathChange(echo_path_variability); + for (size_t ch = 0; ch < num_capture_channels_; ++ch) { + G_main_[ch]->HandleEchoPathChange(echo_path_variability); + } } } void Subtractor::ExitInitialState() { - G_main_.SetConfig(config_.filter.main, false); - G_shadow_.SetConfig(config_.filter.shadow, false); - main_filter_.SetSizePartitions(config_.filter.main.length_blocks, false); - shadow_filter_.SetSizePartitions(config_.filter.shadow.length_blocks, false); + for (size_t ch = 0; ch < num_capture_channels_; ++ch) { + G_main_[ch]->SetConfig(config_.filter.main, false); + G_shadow_[ch]->SetConfig(config_.filter.shadow, false); + main_filter_[ch]->SetSizePartitions(config_.filter.main.length_blocks, + false); + shadow_filter_[ch]->SetSizePartitions(config_.filter.shadow.length_blocks, + false); + } } void Subtractor::Process(const RenderBuffer& render_buffer, - const rtc::ArrayView capture, + const std::vector>& capture, const RenderSignalAnalyzer& render_signal_analyzer, const AecState& aec_state, - SubtractorOutput* output) { - RTC_DCHECK_EQ(kBlockSize, capture.size()); - rtc::ArrayView y = capture; - FftData& E_main = output->E_main; - FftData E_shadow; - std::array& e_main = output->e_main; - std::array& e_shadow = output->e_shadow; - - FftData S; - FftData& G = S; - - // Form the outputs of the main and shadow filters. - main_filter_.Filter(render_buffer, &S); - PredictionError(fft_, S, y, &e_main, &output->s_main); - - shadow_filter_.Filter(render_buffer, &S); - PredictionError(fft_, S, y, &e_shadow, &output->s_shadow); - - // Compute the signal powers in the subtractor output. - output->ComputeMetrics(y); - - // Adjust the filter if needed. - bool main_filter_adjusted = false; - filter_misadjustment_estimator_.Update(*output); - if (filter_misadjustment_estimator_.IsAdjustmentNeeded()) { - float scale = filter_misadjustment_estimator_.GetMisadjustment(); - main_filter_.ScaleFilter(scale); - for (auto& h_k : main_impulse_response_) { - h_k *= scale; - } - ScaleFilterOutput(y, scale, e_main, output->s_main); - filter_misadjustment_estimator_.Reset(); - main_filter_adjusted = true; - } - - // Compute the FFts of the main and shadow filter outputs. - fft_.ZeroPaddedFft(e_main, Aec3Fft::Window::kHanning, &E_main); - fft_.ZeroPaddedFft(e_shadow, Aec3Fft::Window::kHanning, &E_shadow); - - // Compute spectra for future use. - E_shadow.Spectrum(optimization_, output->E2_shadow); - E_main.Spectrum(optimization_, output->E2_main); + rtc::ArrayView outputs) { + RTC_DCHECK_EQ(num_capture_channels_, capture.size()); // Compute the render powers. std::array X2_main; std::array X2_shadow_data; std::array& X2_shadow = - main_filter_.SizePartitions() == shadow_filter_.SizePartitions() + main_filter_[0]->SizePartitions() == shadow_filter_[0]->SizePartitions() ? X2_main : X2_shadow_data; - if (main_filter_.SizePartitions() == shadow_filter_.SizePartitions()) { - render_buffer.SpectralSum(main_filter_.SizePartitions(), &X2_main); - } else if (main_filter_.SizePartitions() > shadow_filter_.SizePartitions()) { - render_buffer.SpectralSums(shadow_filter_.SizePartitions(), - main_filter_.SizePartitions(), &X2_shadow, + if (main_filter_[0]->SizePartitions() == + shadow_filter_[0]->SizePartitions()) { + render_buffer.SpectralSum(main_filter_[0]->SizePartitions(), &X2_main); + } else if (main_filter_[0]->SizePartitions() > + shadow_filter_[0]->SizePartitions()) { + render_buffer.SpectralSums(shadow_filter_[0]->SizePartitions(), + main_filter_[0]->SizePartitions(), &X2_shadow, &X2_main); } else { - render_buffer.SpectralSums(main_filter_.SizePartitions(), - shadow_filter_.SizePartitions(), &X2_main, + render_buffer.SpectralSums(main_filter_[0]->SizePartitions(), + shadow_filter_[0]->SizePartitions(), &X2_main, &X2_shadow); } - // Update the main filter. - if (!main_filter_adjusted) { - std::array erl; - ComputeErl(optimization_, main_frequency_response_, erl); - G_main_.Compute(X2_main, render_signal_analyzer, *output, erl, - main_filter_.SizePartitions(), aec_state.SaturatedCapture(), - &G); - } else { - G.re.fill(0.f); - G.im.fill(0.f); + // Process all capture channels + for (size_t ch = 0; ch < num_capture_channels_; ++ch) { + RTC_DCHECK_EQ(kBlockSize, capture[ch].size()); + SubtractorOutput& output = outputs[ch]; + rtc::ArrayView y = capture[ch]; + FftData& E_main = output.E_main; + FftData E_shadow; + std::array& e_main = output.e_main; + std::array& e_shadow = output.e_shadow; + + FftData S; + FftData& G = S; + + // Form the outputs of the main and shadow filters. + main_filter_[ch]->Filter(render_buffer, &S); + PredictionError(fft_, S, y, &e_main, &output.s_main); + + shadow_filter_[ch]->Filter(render_buffer, &S); + PredictionError(fft_, S, y, &e_shadow, &output.s_shadow); + + // Compute the signal powers in the subtractor output. + output.ComputeMetrics(y); + + // Adjust the filter if needed. + bool main_filter_adjusted = false; + filter_misadjustment_estimator_[ch].Update(output); + if (filter_misadjustment_estimator_[ch].IsAdjustmentNeeded()) { + float scale = filter_misadjustment_estimator_[ch].GetMisadjustment(); + main_filter_[ch]->ScaleFilter(scale); + for (auto& h_k : main_impulse_response_[ch]) { + h_k *= scale; + } + ScaleFilterOutput(y, scale, e_main, output.s_main); + filter_misadjustment_estimator_[ch].Reset(); + main_filter_adjusted = true; + } + + // Compute the FFts of the main and shadow filter outputs. + fft_.ZeroPaddedFft(e_main, Aec3Fft::Window::kHanning, &E_main); + fft_.ZeroPaddedFft(e_shadow, Aec3Fft::Window::kHanning, &E_shadow); + + // Compute spectra for future use. + E_shadow.Spectrum(optimization_, output.E2_shadow); + E_main.Spectrum(optimization_, output.E2_main); + + // Update the main filter. + if (!main_filter_adjusted) { + std::array erl; + ComputeErl(optimization_, main_frequency_response_[ch], erl); + G_main_[ch]->Compute(X2_main, render_signal_analyzer, output, erl, + main_filter_[ch]->SizePartitions(), + aec_state.SaturatedCapture(), &G); + } else { + G.re.fill(0.f); + G.im.fill(0.f); + } + main_filter_[ch]->Adapt(render_buffer, G, &main_impulse_response_[ch]); + main_filter_[ch]->ComputeFrequencyResponse(&main_frequency_response_[ch]); + + if (ch == 0) { + data_dumper_->DumpRaw("aec3_subtractor_G_main", G.re); + data_dumper_->DumpRaw("aec3_subtractor_G_main", G.im); + } + + // Update the shadow filter. + poor_shadow_filter_counter_[ch] = output.e2_main < output.e2_shadow + ? poor_shadow_filter_counter_[ch] + 1 + : 0; + if (poor_shadow_filter_counter_[ch] < 5) { + G_shadow_[ch]->Compute(X2_shadow, render_signal_analyzer, E_shadow, + shadow_filter_[ch]->SizePartitions(), + aec_state.SaturatedCapture(), &G); + } else { + poor_shadow_filter_counter_[ch] = 0; + shadow_filter_[ch]->SetFilter(main_filter_[ch]->GetFilter()); + G_shadow_[ch]->Compute(X2_shadow, render_signal_analyzer, E_main, + shadow_filter_[ch]->SizePartitions(), + aec_state.SaturatedCapture(), &G); + } + + shadow_filter_[ch]->Adapt(render_buffer, G); + if (ch == 0) { + data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.re); + data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.im); + filter_misadjustment_estimator_[ch].Dump(data_dumper_); + DumpFilters(); + } + + std::for_each(e_main.begin(), e_main.end(), + [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); }); + + if (ch == 0) { + data_dumper_->DumpWav("aec3_main_filter_output", kBlockSize, &e_main[0], + 16000, 1); + data_dumper_->DumpWav("aec3_shadow_filter_output", kBlockSize, + &e_shadow[0], 16000, 1); + } } - main_filter_.Adapt(render_buffer, G, &main_impulse_response_); - main_filter_.ComputeFrequencyResponse(&main_frequency_response_); - - data_dumper_->DumpRaw("aec3_subtractor_G_main", G.re); - data_dumper_->DumpRaw("aec3_subtractor_G_main", G.im); - - // Update the shadow filter. - poor_shadow_filter_counter_ = - output->e2_main < output->e2_shadow ? poor_shadow_filter_counter_ + 1 : 0; - if (poor_shadow_filter_counter_ < 5) { - G_shadow_.Compute(X2_shadow, render_signal_analyzer, E_shadow, - shadow_filter_.SizePartitions(), - aec_state.SaturatedCapture(), &G); - } else { - poor_shadow_filter_counter_ = 0; - shadow_filter_.SetFilter(main_filter_.GetFilter()); - G_shadow_.Compute(X2_shadow, render_signal_analyzer, E_main, - shadow_filter_.SizePartitions(), - aec_state.SaturatedCapture(), &G); - } - - shadow_filter_.Adapt(render_buffer, G); - data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.re); - data_dumper_->DumpRaw("aec3_subtractor_G_shadow", G.im); - filter_misadjustment_estimator_.Dump(data_dumper_); - DumpFilters(); - - std::for_each(e_main.begin(), e_main.end(), - [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); }); - - data_dumper_->DumpWav("aec3_main_filter_output", kBlockSize, &e_main[0], - 16000, 1); - data_dumper_->DumpWav("aec3_shadow_filter_output", kBlockSize, &e_shadow[0], - 16000, 1); } void Subtractor::FilterMisadjustmentEstimator::Update( diff --git a/modules/audio_processing/aec3/subtractor.h b/modules/audio_processing/aec3/subtractor.h index 7c3c5e0930..c5fb765e54 100644 --- a/modules/audio_processing/aec3/subtractor.h +++ b/modules/audio_processing/aec3/subtractor.h @@ -48,35 +48,40 @@ class Subtractor { // Performs the echo subtraction. void Process(const RenderBuffer& render_buffer, - const rtc::ArrayView capture, + const std::vector>& capture, const RenderSignalAnalyzer& render_signal_analyzer, const AecState& aec_state, - SubtractorOutput* output); + rtc::ArrayView outputs); void HandleEchoPathChange(const EchoPathVariability& echo_path_variability); // Exits the initial state. void ExitInitialState(); - // Returns the block-wise frequency response for the main adaptive filter. + // Returns the block-wise frequency responses for the main adaptive filters. + // TODO(bugs.webrtc.org/10913): Return the frequency responses for all capture + // channels. const std::vector>& FilterFrequencyResponse() const { - return main_frequency_response_; + return main_frequency_response_[0]; } - // Returns the estimate of the impulse response for the main adaptive filter. + // Returns the estimates of the impulse responses for the main adaptive + // filters. + // TODO(bugs.webrtc.org/10913): Return the impulse responses for all capture + // channels. const std::vector& FilterImpulseResponse() const { - return main_impulse_response_; + return main_impulse_response_[0]; } void DumpFilters() { - size_t current_size = main_impulse_response_.size(); - main_impulse_response_.resize(main_impulse_response_.capacity()); - data_dumper_->DumpRaw("aec3_subtractor_h_main", main_impulse_response_); - main_impulse_response_.resize(current_size); + size_t current_size = main_impulse_response_[0].size(); + main_impulse_response_[0].resize(main_impulse_response_[0].capacity()); + data_dumper_->DumpRaw("aec3_subtractor_h_main", main_impulse_response_[0]); + main_impulse_response_[0].resize(current_size); - main_filter_.DumpFilter("aec3_subtractor_H_main"); - shadow_filter_.DumpFilter("aec3_subtractor_H_shadow"); + main_filter_[0]->DumpFilter("aec3_subtractor_H_main"); + shadow_filter_[0]->DumpFilter("aec3_subtractor_H_shadow"); } private: @@ -115,15 +120,17 @@ class Subtractor { ApmDataDumper* data_dumper_; const Aec3Optimization optimization_; const EchoCanceller3Config config_; + const size_t num_capture_channels_; - AdaptiveFirFilter main_filter_; - AdaptiveFirFilter shadow_filter_; - MainFilterUpdateGain G_main_; - ShadowFilterUpdateGain G_shadow_; - FilterMisadjustmentEstimator filter_misadjustment_estimator_; - size_t poor_shadow_filter_counter_ = 0; - std::vector> main_frequency_response_; - std::vector main_impulse_response_; + std::vector> main_filter_; + std::vector> shadow_filter_; + std::vector> G_main_; + std::vector> G_shadow_; + std::vector filter_misadjustment_estimator_; + std::vector poor_shadow_filter_counter_; + std::vector>> + main_frequency_response_; + std::vector> main_impulse_response_; }; } // namespace webrtc diff --git a/modules/audio_processing/aec3/subtractor_unittest.cc b/modules/audio_processing/aec3/subtractor_unittest.cc index 40d8569ffd..daacbd37db 100644 --- a/modules/audio_processing/aec3/subtractor_unittest.cc +++ b/modules/audio_processing/aec3/subtractor_unittest.cc @@ -43,9 +43,9 @@ float RunSubtractorTest(int num_blocks_to_process, std::vector>> x( kNumBands, std::vector>( kNumChannels, std::vector(kBlockSize, 0.f))); - std::vector y(kBlockSize, 0.f); + std::vector> y(1, std::vector(kBlockSize, 0.f)); std::array x_old; - SubtractorOutput output; + std::array output; config.delay.default_delay = 1; std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(config, kSampleRateHz, kNumChannels)); @@ -65,9 +65,9 @@ float RunSubtractorTest(int num_blocks_to_process, for (int k = 0; k < num_blocks_to_process; ++k) { RandomizeSampleVector(&random_generator, x[0][0]); if (uncorrelated_inputs) { - RandomizeSampleVector(&random_generator, y); + RandomizeSampleVector(&random_generator, y[0]); } else { - delay_buffer.Delay(x[0][0], y); + delay_buffer.Delay(x[0][0], y[0]); } render_delay_buffer->Insert(x); if (k == 0) { @@ -86,19 +86,21 @@ float RunSubtractorTest(int num_blocks_to_process, false)); } subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y, - render_signal_analyzer, aec_state, &output); + render_signal_analyzer, aec_state, output); aec_state.HandleEchoPathChange(EchoPathVariability( false, EchoPathVariability::DelayAdjustment::kNone, false)); aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(), subtractor.FilterImpulseResponse(), *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, - output, y); + output[0], y[0]); } - const float output_power = std::inner_product( - output.e_main.begin(), output.e_main.end(), output.e_main.begin(), 0.f); - const float y_power = std::inner_product(y.begin(), y.end(), y.begin(), 0.f); + const float output_power = + std::inner_product(output[0].e_main.begin(), output[0].e_main.end(), + output[0].e_main.begin(), 0.f); + const float y_power = + std::inner_product(y[0].begin(), y[0].end(), y[0].begin(), 0.f); if (y_power == 0.f) { ADD_FAILURE(); return -1.0; @@ -124,24 +126,6 @@ TEST(Subtractor, NullDataDumper) { ""); } -// Verifies the check for null subtractor output. -// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH -// tests on test bots has been fixed. -TEST(Subtractor, DISABLED_NullOutput) { - ApmDataDumper data_dumper(42); - EchoCanceller3Config config; - Subtractor subtractor(config, 1, 1, &data_dumper, DetectOptimization()); - std::unique_ptr render_delay_buffer( - RenderDelayBuffer::Create(config, 48000, 1)); - RenderSignalAnalyzer render_signal_analyzer(config); - std::vector y(kBlockSize, 0.f); - - EXPECT_DEATH( - subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y, - render_signal_analyzer, AecState(config), nullptr), - ""); -} - // Verifies the check for the capture signal size. TEST(Subtractor, WrongCaptureSize) { ApmDataDumper data_dumper(42); @@ -150,12 +134,12 @@ TEST(Subtractor, WrongCaptureSize) { std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(config, 48000, 1)); RenderSignalAnalyzer render_signal_analyzer(config); - std::vector y(kBlockSize - 1, 0.f); - SubtractorOutput output; + std::vector> y(1, std::vector(kBlockSize - 1, 0.f)); + std::array output; EXPECT_DEATH( subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y, - render_signal_analyzer, AecState(config), &output), + render_signal_analyzer, AecState(config), output), ""); }