AEC3: Adding explicit handling of microphone gain changes

This CL re-activates the explicit handling of microphone
gain changes in the AEC3 code. The implementation is done
beneath a kill-switch so that when that switch is active
the changes in this CL are bitexact.


Bug: webrtc:9526,chromium:863826
Change-Id: I58e93d8bc0bce7bec91e102de9891ad48ebc55d8
Reviewed-on: https://webrtc-review.googlesource.com/88620
Commit-Queue: Per Åhgren <peah@webrtc.org>
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23986}
This commit is contained in:
Per Åhgren 2018-07-16 17:08:41 +02:00 committed by Commit Bot
parent c14d9bbb27
commit 88cf0501f3
11 changed files with 72 additions and 42 deletions

View File

@ -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();

View File

@ -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);

View File

@ -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<DelayEstimate>& external_delay,
RenderBuffer* render_buffer,
@ -104,6 +105,8 @@ class EchoRemoverImpl final : public EchoRemover {
std::array<float, kFftLengthBy2> e_old_;
std::array<float, kFftLengthBy2> x_old_;
std::array<float, kFftLengthBy2> 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<DelayEstimate>& external_delay,
RenderBuffer* render_buffer,
std::vector<std::vector<float>>* capture) {
++block_counter_;
const std::vector<std::vector<float>>& x = render_buffer->Block(0);
std::vector<std::vector<float>>* 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<float, kFftLengthBy2Plus1> Y2;

View File

@ -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<DelayEstimate>& external_delay,
RenderBuffer* render_buffer,

View File

@ -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(

View File

@ -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<DelayEstimate>& delay_estimate,
RenderBuffer* render_buffer,

View File

@ -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() {

View File

@ -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_;

View File

@ -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;

View File

@ -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 {

View File

@ -45,7 +45,8 @@ const std::string kFieldTrialNames[] = {
"WebRTC-Aec3RapidAgcGainRecoveryKillSwitch",
"WebRTC-Aec3SlowFilterAdaptationKillSwitch",
"WebRTC-Aec3SmoothUpdatesTailFreqRespKillSwitch",
"WebRTC-Aec3SuppressorNearendAveragingKillSwitch"};
"WebRTC-Aec3SuppressorNearendAveragingKillSwitch",
"WebRTC-Aec3AgcGainChangeResponseKillSwitch"};
std::unique_ptr<AudioProcessing> CreateApm(test::FuzzDataHelper* fuzz_data,
std::string* field_trial_string) {