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:
parent
c14d9bbb27
commit
88cf0501f3
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user