diff --git a/modules/audio_processing/aec3/aec_state.cc b/modules/audio_processing/aec3/aec_state.cc index f6ce23bdef..119b0ee8cf 100644 --- a/modules/audio_processing/aec3/aec_state.cc +++ b/modules/audio_processing/aec3/aec_state.cc @@ -103,24 +103,10 @@ void AecState::HandleEchoPathChange( // TODO(peah): Refine the reset scheme according to the type of gain and // delay adjustment. - if (echo_path_variability.gain_change) { - full_reset(); - } if (echo_path_variability.delay_change != - EchoPathVariability::DelayAdjustment::kBufferReadjustment) { + EchoPathVariability::DelayAdjustment::kNone) { full_reset(); - } else if (echo_path_variability.delay_change != - EchoPathVariability::DelayAdjustment::kBufferFlush) { - full_reset(); - } else if (echo_path_variability.delay_change != - EchoPathVariability::DelayAdjustment::kDelayReset) { - full_reset(); - } else if (echo_path_variability.delay_change != - EchoPathVariability::DelayAdjustment::kNewDetectedDelay) { - full_reset(); - } else if (echo_path_variability.gain_change) { - blocks_since_reset_ = kNumBlocksPerSecond; } subtractor_output_analyzer_.HandleEchoPathChange(); diff --git a/modules/audio_processing/aec3/aec_state_unittest.cc b/modules/audio_processing/aec3/aec_state_unittest.cc index 6111979f82..ef05707142 100644 --- a/modules/audio_processing/aec3/aec_state_unittest.cc +++ b/modules/audio_processing/aec3/aec_state_unittest.cc @@ -70,7 +70,7 @@ TEST(AecState, NormalUsage) { // Verify that linear AEC usability becomes false after an echo path change is // reported state.HandleEchoPathChange(EchoPathVariability( - true, EchoPathVariability::DelayAdjustment::kNone, false)); + false, EchoPathVariability::DelayAdjustment::kBufferReadjustment, false)); state.Update(delay_estimate, converged_filter_frequency_response, impulse_response, *render_delay_buffer->GetRenderBuffer(), E2_main, Y2, output, y); diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc index 2e692980fb..67929b147a 100644 --- a/modules/audio_processing/aec3/echo_remover.cc +++ b/modules/audio_processing/aec3/echo_remover.cc @@ -31,6 +31,7 @@ #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/atomicops.h" #include "rtc_base/constructormagic.h" +#include "rtc_base/logging.h" namespace webrtc { @@ -66,7 +67,7 @@ class EchoRemoverImpl final : public EchoRemover { // Removes the echo from a block of samples from the capture signal. The // supplied render signal is assumed to be pre-aligned with the capture // signal. - void ProcessCapture(const EchoPathVariability& echo_path_variability, + void ProcessCapture(EchoPathVariability echo_path_variability, bool capture_signal_saturation, const absl::optional& external_delay, RenderBuffer* render_buffer, @@ -104,6 +105,8 @@ class EchoRemoverImpl final : public EchoRemover { std::array e_old_; std::array x_old_; std::array y_old_; + size_t block_counter_ = 0; + int gain_change_hangover_ = 0; RTC_DISALLOW_COPY_AND_ASSIGN(EchoRemoverImpl); }; @@ -141,11 +144,12 @@ void EchoRemoverImpl::GetMetrics(EchoControl::Metrics* metrics) const { } void EchoRemoverImpl::ProcessCapture( - const EchoPathVariability& echo_path_variability, + EchoPathVariability echo_path_variability, bool capture_signal_saturation, const absl::optional& external_delay, RenderBuffer* render_buffer, std::vector>* capture) { + ++block_counter_; const std::vector>& x = render_buffer->Block(0); std::vector>* y = capture; RTC_DCHECK(render_buffer); @@ -167,10 +171,29 @@ void EchoRemoverImpl::ProcessCapture( aec_state_.UpdateCaptureSaturation(capture_signal_saturation); if (echo_path_variability.AudioPathChanged()) { + // Ensure that the gain change is only acted on once per frame. + if (echo_path_variability.gain_change) { + if (gain_change_hangover_ == 0) { + constexpr int kMaxBlocksPerFrame = 3; + gain_change_hangover_ = kMaxBlocksPerFrame; + RTC_LOG(LS_WARNING) + << "Gain change detected at block " << block_counter_; + } else { + echo_path_variability.gain_change = false; + } + } + subtractor_.HandleEchoPathChange(echo_path_variability); aec_state_.HandleEchoPathChange(echo_path_variability); - suppression_gain_.SetInitialState(true); - initial_state_ = true; + + if (echo_path_variability.delay_change != + EchoPathVariability::DelayAdjustment::kNone) { + suppression_gain_.SetInitialState(true); + initial_state_ = true; + } + } + if (gain_change_hangover_ > 0) { + --gain_change_hangover_; } std::array Y2; diff --git a/modules/audio_processing/aec3/echo_remover.h b/modules/audio_processing/aec3/echo_remover.h index 710afacb3e..cc8dae9c17 100644 --- a/modules/audio_processing/aec3/echo_remover.h +++ b/modules/audio_processing/aec3/echo_remover.h @@ -36,7 +36,7 @@ class EchoRemover { // supplied render signal is assumed to be pre-aligned with the capture // signal. virtual void ProcessCapture( - const EchoPathVariability& echo_path_variability, + EchoPathVariability echo_path_variability, bool capture_signal_saturation, const absl::optional& external_delay, RenderBuffer* render_buffer, diff --git a/modules/audio_processing/aec3/main_filter_update_gain.cc b/modules/audio_processing/aec3/main_filter_update_gain.cc index 6aa57802a9..6d31ed00c2 100644 --- a/modules/audio_processing/aec3/main_filter_update_gain.cc +++ b/modules/audio_processing/aec3/main_filter_update_gain.cc @@ -22,6 +22,7 @@ namespace webrtc { namespace { constexpr float kHErrorInitial = 10000.f; +constexpr float kHErrorGainChange = 10000.f; constexpr int kPoorExcitationCounterInitial = 1000; } // namespace @@ -46,10 +47,19 @@ MainFilterUpdateGain::~MainFilterUpdateGain() {} void MainFilterUpdateGain::HandleEchoPathChange( const EchoPathVariability& echo_path_variability) { - // TODO(peah): Add even-specific behavior. - H_error_.fill(kHErrorInitial); - poor_excitation_counter_ = kPoorExcitationCounterInitial; - call_counter_ = 0; + if (echo_path_variability.gain_change) { + H_error_.fill(kHErrorGainChange); + } + + if (echo_path_variability.delay_change != + EchoPathVariability::DelayAdjustment::kNone) { + H_error_.fill(kHErrorInitial); + } + + if (!echo_path_variability.gain_change) { + poor_excitation_counter_ = kPoorExcitationCounterInitial; + call_counter_ = 0; + } } void MainFilterUpdateGain::Compute( diff --git a/modules/audio_processing/aec3/mock/mock_echo_remover.h b/modules/audio_processing/aec3/mock/mock_echo_remover.h index 0eb95081b6..6b64785621 100644 --- a/modules/audio_processing/aec3/mock/mock_echo_remover.h +++ b/modules/audio_processing/aec3/mock/mock_echo_remover.h @@ -27,7 +27,7 @@ class MockEchoRemover : public EchoRemover { virtual ~MockEchoRemover() = default; MOCK_METHOD5(ProcessCapture, - void(const EchoPathVariability& echo_path_variability, + void(EchoPathVariability echo_path_variability, bool capture_signal_saturation, const absl::optional& delay_estimate, RenderBuffer* render_buffer, diff --git a/modules/audio_processing/aec3/subtractor.cc b/modules/audio_processing/aec3/subtractor.cc index a9a3e6faa3..123ad7de24 100644 --- a/modules/audio_processing/aec3/subtractor.cc +++ b/modules/audio_processing/aec3/subtractor.cc @@ -16,6 +16,7 @@ #include "api/array_view.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/checks.h" +#include "rtc_base/logging.h" #include "rtc_base/numerics/safe_minmax.h" #include "system_wrappers/include/field_trial.h" @@ -23,6 +24,10 @@ namespace webrtc { namespace { +bool EnableAgcGainChangeResponse() { + return !field_trial::IsEnabled("WebRTC-Aec3AgcGainChangeResponseKillSwitch"); +} + bool EnableAdaptationDuringSaturation() { return !field_trial::IsEnabled("WebRTC-Aec3RapidAgcGainRecoveryKillSwitch"); } @@ -77,6 +82,7 @@ Subtractor::Subtractor(const EchoCanceller3Config& config, config_(config), adaptation_during_saturation_(EnableAdaptationDuringSaturation()), enable_misadjustment_estimator_(EnableMisadjustmentEstimator()), + enable_agc_gain_change_response_(EnableAgcGainChangeResponse()), main_filter_(config_.filter.main.length_blocks, config_.filter.main_initial.length_blocks, config.filter.config_change_duration_blocks, @@ -117,19 +123,16 @@ void Subtractor::HandleEchoPathChange( config_.filter.shadow_initial.length_blocks, true); }; - // TODO(peah): Add delay-change specific reset behavior. - if ((echo_path_variability.delay_change == - EchoPathVariability::DelayAdjustment::kBufferFlush) || - (echo_path_variability.delay_change == - EchoPathVariability::DelayAdjustment::kDelayReset)) { - full_reset(); - } else if (echo_path_variability.delay_change == - EchoPathVariability::DelayAdjustment::kNewDetectedDelay) { - full_reset(); - } else if (echo_path_variability.delay_change == - EchoPathVariability::DelayAdjustment::kBufferReadjustment) { + if (echo_path_variability.delay_change != + EchoPathVariability::DelayAdjustment::kNone) { full_reset(); } + + if (echo_path_variability.gain_change && enable_agc_gain_change_response_) { + RTC_LOG(LS_WARNING) << "Resetting main filter adaptation speed due to " + "microphone gain change"; + G_main_.HandleEchoPathChange(echo_path_variability); + } } void Subtractor::ExitInitialState() { diff --git a/modules/audio_processing/aec3/subtractor.h b/modules/audio_processing/aec3/subtractor.h index 67ecdc02c6..9af649982a 100644 --- a/modules/audio_processing/aec3/subtractor.h +++ b/modules/audio_processing/aec3/subtractor.h @@ -106,6 +106,7 @@ class Subtractor { const EchoCanceller3Config config_; const bool adaptation_during_saturation_; const bool enable_misadjustment_estimator_; + const bool enable_agc_gain_change_response_; AdaptiveFirFilter main_filter_; AdaptiveFirFilter shadow_filter_; MainFilterUpdateGain G_main_; diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc index e87d2cf21c..7e5955a98f 100644 --- a/modules/audio_processing/audio_processing_impl.cc +++ b/modules/audio_processing/audio_processing_impl.cc @@ -1198,9 +1198,13 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() { } if (private_submodules_->echo_controller) { - // TODO(peah): Reactivate analogue AGC gain detection once the analogue AGC - // issues have been addressed. - capture_.echo_path_gain_change = false; + // Detect and flag any change in the analog gain. + int analog_mic_level = gain_control()->stream_analog_level(); + capture_.echo_path_gain_change = + capture_.prev_analog_mic_level != analog_mic_level && + capture_.prev_analog_mic_level != -1; + capture_.prev_analog_mic_level = analog_mic_level; + private_submodules_->echo_controller->AnalyzeCapture(capture_buffer); } @@ -2049,7 +2053,8 @@ AudioProcessingImpl::ApmCaptureState::ApmCaptureState( transient_suppressor_enabled(transient_suppressor_enabled), capture_processing_format(kSampleRate16kHz), split_rate(kSampleRate16kHz), - echo_path_gain_change(false) {} + echo_path_gain_change(false), + prev_analog_mic_level(-1) {} AudioProcessingImpl::ApmCaptureState::~ApmCaptureState() = default; diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h index 8a5d245d1c..44d0d087a5 100644 --- a/modules/audio_processing/audio_processing_impl.h +++ b/modules/audio_processing/audio_processing_impl.h @@ -390,6 +390,7 @@ class AudioProcessingImpl : public AudioProcessing { StreamConfig capture_processing_format; int split_rate; bool echo_path_gain_change; + int prev_analog_mic_level; } capture_ RTC_GUARDED_BY(crit_capture_); struct ApmCaptureNonLockedState { diff --git a/test/fuzzers/audio_processing_configs_fuzzer.cc b/test/fuzzers/audio_processing_configs_fuzzer.cc index 46f8918bf6..545e455e7e 100644 --- a/test/fuzzers/audio_processing_configs_fuzzer.cc +++ b/test/fuzzers/audio_processing_configs_fuzzer.cc @@ -45,7 +45,8 @@ const std::string kFieldTrialNames[] = { "WebRTC-Aec3RapidAgcGainRecoveryKillSwitch", "WebRTC-Aec3SlowFilterAdaptationKillSwitch", "WebRTC-Aec3SmoothUpdatesTailFreqRespKillSwitch", - "WebRTC-Aec3SuppressorNearendAveragingKillSwitch"}; + "WebRTC-Aec3SuppressorNearendAveragingKillSwitch", + "WebRTC-Aec3AgcGainChangeResponseKillSwitch"}; std::unique_ptr CreateApm(test::FuzzDataHelper* fuzz_data, std::string* field_trial_string) {