AEC3: Remove remaining kill-switches
This CL concludes the post-launch removal of kill-switches is AEC3. Kill-switches removed: WebRTC-Aec3AdaptErleOnLowRenderKillSwitch WebRTC-Aec3AgcGainChangeResponseKillSwitch WebRTC-Aec3BoundedNearendKillSwitch WebRTC-Aec3EarlyShadowFilterJumpstartKillSwitch WebRTC-Aec3EnableAdaptiveEchoReverbEstimation WebRTC-Aec3EnforceSkewHysteresis1 WebRTC-Aec3EnforceSkewHysteresis2 WebRTC-Aec3FilterAnalyzerPreprocessorKillSwitch WebRTC-Aec3MisadjustmentEstimatorKillSwitch WebRTC-Aec3OverrideEchoPathGainKillSwitch WebRTC-Aec3RapidAgcGainRecoveryKillSwitch WebRTC-Aec3ResetErleAtGainChangesKillSwitch WebRTC-Aec3ShadowFilterBoostedJumpstartKillSwitch WebRTC-Aec3ShadowFilterJumpstartKillSwitch WebRTC-Aec3SmoothSignalTransitionsKillSwitch WebRTC-Aec3SmoothUpdatesTailFreqRespKillSwitch WebRTC-Aec3SoftTransparentModeKillSwitch WebRTC-Aec3StandardNonlinearReverbModelKillSwitch WebRTC-Aec3StrictDivergenceCheckKillSwitch WebRTC-Aec3UseOffsetBlocks WebRTC-Aec3UseStationarityPropertiesKillSwitch WebRTC-Aec3UtilizeShadowFilterOutputKillSwitch WebRTC-Aec3ZeroExternalDelayHeadroomKillSwitch WebRTC-Aec3FilterQualityStateKillSwitch WebRTC-Aec3NewSaturationBehaviorKillSwitch WebRTC-Aec3GainLimiterDeactivationKillSwitch WebRTC-Aec3EnableErleUpdatesDuringReverbKillSwitch The change has been tested for bit-exactness. Bug: webrtc:8671 Change-Id: I42816b9d1c875cec0347034c6e2ed4ff5db6ec0f Reviewed-on: https://webrtc-review.googlesource.com/c/119942 Commit-Queue: Gustaf Ullberg <gustaf@webrtc.org> Reviewed-by: Sam Zackrisson <saza@webrtc.org> Cr-Commit-Position: refs/heads/master@{#26443}
This commit is contained in:
committed by
Commit Bot
parent
649a4c2ea3
commit
68d6d44197
@ -120,8 +120,6 @@ rtc_static_library("aec3") {
|
||||
"suppression_filter.h",
|
||||
"suppression_gain.cc",
|
||||
"suppression_gain.h",
|
||||
"suppression_gain_limiter.cc",
|
||||
"suppression_gain_limiter.h",
|
||||
"vector_buffer.cc",
|
||||
"vector_buffer.h",
|
||||
"vector_math.h",
|
||||
@ -145,7 +143,6 @@ rtc_static_library("aec3") {
|
||||
"../../../rtc_base:safe_minmax",
|
||||
"../../../rtc_base/system:arch",
|
||||
"../../../system_wrappers:cpu_features_api",
|
||||
"../../../system_wrappers:field_trial",
|
||||
"../../../system_wrappers:metrics",
|
||||
"../utility:ooura_fft",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
|
||||
#include "modules/audio_processing/aec3/fft_data.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -417,21 +416,12 @@ void ApplyFilter_SSE2(const RenderBuffer& render_buffer,
|
||||
|
||||
} // namespace aec3
|
||||
|
||||
namespace {
|
||||
|
||||
bool EnablePartialFilterReset() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3PartialFilterResetKillSwitch");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AdaptiveFirFilter::AdaptiveFirFilter(size_t max_size_partitions,
|
||||
size_t initial_size_partitions,
|
||||
size_t size_change_duration_blocks,
|
||||
Aec3Optimization optimization,
|
||||
ApmDataDumper* data_dumper)
|
||||
: data_dumper_(data_dumper),
|
||||
use_partial_filter_reset_(EnablePartialFilterReset()),
|
||||
fft_(),
|
||||
optimization_(optimization),
|
||||
max_size_partitions_(max_size_partitions),
|
||||
@ -464,18 +454,14 @@ AdaptiveFirFilter::~AdaptiveFirFilter() = default;
|
||||
void AdaptiveFirFilter::HandleEchoPathChange() {
|
||||
size_t current_h_size = h_.size();
|
||||
h_.resize(GetTimeDomainLength(max_size_partitions_));
|
||||
const size_t begin_coeffficient =
|
||||
use_partial_filter_reset_ ? current_h_size : 0;
|
||||
std::fill(h_.begin() + begin_coeffficient, h_.end(), 0.f);
|
||||
std::fill(h_.begin() + current_h_size, h_.end(), 0.f);
|
||||
h_.resize(current_h_size);
|
||||
|
||||
size_t current_size_partitions = H_.size();
|
||||
H_.resize(max_size_partitions_);
|
||||
H2_.resize(max_size_partitions_);
|
||||
|
||||
const size_t begin_partition =
|
||||
use_partial_filter_reset_ ? current_size_partitions : 0;
|
||||
for (size_t k = begin_partition; k < max_size_partitions_; ++k) {
|
||||
for (size_t k = current_size_partitions; k < max_size_partitions_; ++k) {
|
||||
H_[k].Clear();
|
||||
H2_[k].fill(0.f);
|
||||
}
|
||||
|
||||
@ -164,7 +164,6 @@ class AdaptiveFirFilter {
|
||||
void UpdateSize();
|
||||
|
||||
ApmDataDumper* const data_dumper_;
|
||||
const bool use_partial_filter_reset_;
|
||||
const Aec3Fft fft_;
|
||||
const Aec3Optimization optimization_;
|
||||
const size_t max_size_partitions_;
|
||||
|
||||
@ -21,31 +21,10 @@
|
||||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||
#include "rtc_base/atomic_ops.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
bool EnableErleResetsAtGainChanges() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3ResetErleAtGainChangesKillSwitch");
|
||||
}
|
||||
|
||||
bool UseLegacyFilterQualityState() {
|
||||
return field_trial::IsEnabled("WebRTC-Aec3FilterQualityStateKillSwitch");
|
||||
}
|
||||
|
||||
bool EnableLegacySaturationBehavior() {
|
||||
return field_trial::IsEnabled("WebRTC-Aec3NewSaturationBehaviorKillSwitch");
|
||||
}
|
||||
|
||||
bool UseSuppressionGainLimiter() {
|
||||
return field_trial::IsEnabled("WebRTC-Aec3GainLimiterDeactivationKillSwitch");
|
||||
}
|
||||
bool EnableErleUpdatesDuringReverb() {
|
||||
return !field_trial::IsEnabled(
|
||||
"WebRTC-Aec3EnableErleUpdatesDuringReverbKillSwitch");
|
||||
}
|
||||
|
||||
constexpr size_t kBlocksSinceConvergencedFilterInit = 10000;
|
||||
constexpr size_t kBlocksSinceConsistentEstimateInit = 10000;
|
||||
|
||||
@ -68,7 +47,7 @@ void AecState::GetResidualEchoScaling(
|
||||
}
|
||||
|
||||
absl::optional<float> AecState::ErleUncertainty() const {
|
||||
if (SaturatedEcho() && use_legacy_saturation_behavior_) {
|
||||
if (SaturatedEcho()) {
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
@ -79,11 +58,6 @@ AecState::AecState(const EchoCanceller3Config& config)
|
||||
: data_dumper_(
|
||||
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
|
||||
config_(config),
|
||||
use_legacy_saturation_behavior_(EnableLegacySaturationBehavior()),
|
||||
enable_erle_resets_at_gain_changes_(EnableErleResetsAtGainChanges()),
|
||||
enable_erle_updates_during_reverb_(EnableErleUpdatesDuringReverb()),
|
||||
use_legacy_filter_quality_(UseLegacyFilterQualityState()),
|
||||
use_suppressor_gain_limiter_(UseSuppressionGainLimiter()),
|
||||
initial_state_(config_),
|
||||
delay_state_(config_),
|
||||
transparent_state_(config_),
|
||||
@ -92,7 +66,6 @@ AecState::AecState(const EchoCanceller3Config& config)
|
||||
legacy_saturation_detector_(config_),
|
||||
erl_estimator_(2 * kNumBlocksPerSecond),
|
||||
erle_estimator_(2 * kNumBlocksPerSecond, config_),
|
||||
suppression_gain_limiter_(config_),
|
||||
filter_analyzer_(config_),
|
||||
echo_audibility_(
|
||||
config_.echo_audibility.use_stationarity_properties_at_init),
|
||||
@ -107,21 +80,12 @@ void AecState::HandleEchoPathChange(
|
||||
capture_signal_saturation_ = false;
|
||||
strong_not_saturated_render_blocks_ = 0;
|
||||
blocks_with_active_render_ = 0;
|
||||
if (use_suppressor_gain_limiter_) {
|
||||
suppression_gain_limiter_.Reset();
|
||||
}
|
||||
initial_state_.Reset();
|
||||
transparent_state_.Reset();
|
||||
if (use_legacy_saturation_behavior_) {
|
||||
legacy_saturation_detector_.Reset();
|
||||
}
|
||||
erle_estimator_.Reset(true);
|
||||
erl_estimator_.Reset();
|
||||
if (use_legacy_filter_quality_) {
|
||||
legacy_filter_quality_state_.Reset();
|
||||
} else {
|
||||
filter_quality_state_.Reset();
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(peah): Refine the reset scheme according to the type of gain and
|
||||
@ -130,8 +94,7 @@ void AecState::HandleEchoPathChange(
|
||||
if (echo_path_variability.delay_change !=
|
||||
EchoPathVariability::DelayAdjustment::kNone) {
|
||||
full_reset();
|
||||
} else if (enable_erle_resets_at_gain_changes_ &&
|
||||
echo_path_variability.gain_change) {
|
||||
} else if (echo_path_variability.gain_change) {
|
||||
erle_estimator_.Reset(false);
|
||||
}
|
||||
subtractor_output_analyzer_.HandleEchoPathChange();
|
||||
@ -172,17 +135,6 @@ void AecState::Update(
|
||||
strong_not_saturated_render_blocks_ +=
|
||||
active_render && !SaturatedCapture() ? 1 : 0;
|
||||
|
||||
if (use_suppressor_gain_limiter_) {
|
||||
// Update the limit on the echo suppression after an echo path change to
|
||||
// avoid an initial echo burst.
|
||||
suppression_gain_limiter_.Update(render_buffer.GetRenderActivity(),
|
||||
TransparentMode());
|
||||
|
||||
if (subtractor_output_analyzer_.ConvergedFilter()) {
|
||||
suppression_gain_limiter_.Deactivate();
|
||||
}
|
||||
}
|
||||
|
||||
std::array<float, kFftLengthBy2Plus1> X2_reverb;
|
||||
render_reverb_.Apply(
|
||||
render_buffer.GetSpectrumBuffer(), delay_state_.DirectPathFilterDelay(),
|
||||
@ -203,8 +155,7 @@ void AecState::Update(
|
||||
}
|
||||
|
||||
const auto& X2 = render_buffer.Spectrum(delay_state_.DirectPathFilterDelay());
|
||||
const auto& X2_input_erle =
|
||||
enable_erle_updates_during_reverb_ ? X2_reverb : X2;
|
||||
const auto& X2_input_erle = X2_reverb;
|
||||
|
||||
erle_estimator_.Update(render_buffer, adaptive_filter_frequency_response,
|
||||
X2_input_erle, Y2, E2_main,
|
||||
@ -214,14 +165,9 @@ void AecState::Update(
|
||||
erl_estimator_.Update(subtractor_output_analyzer_.ConvergedFilter(), X2, Y2);
|
||||
|
||||
// Detect and flag echo saturation.
|
||||
if (use_legacy_saturation_behavior_) {
|
||||
legacy_saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
|
||||
EchoPathGain());
|
||||
} else {
|
||||
saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
|
||||
UsableLinearEstimate(), subtractor_output,
|
||||
EchoPathGain());
|
||||
}
|
||||
saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
|
||||
UsableLinearEstimate(), subtractor_output,
|
||||
EchoPathGain());
|
||||
|
||||
// Update the decision on whether to use the initial state parameter set.
|
||||
initial_state_.Update(active_render, SaturatedCapture());
|
||||
@ -234,17 +180,10 @@ void AecState::Update(
|
||||
active_render, SaturatedCapture());
|
||||
|
||||
// Analyze the quality of the filter.
|
||||
if (use_legacy_filter_quality_) {
|
||||
legacy_filter_quality_state_.Update(
|
||||
SaturatedEcho(), active_render, SaturatedCapture(), TransparentMode(),
|
||||
external_delay, subtractor_output_analyzer_.ConvergedFilter(),
|
||||
subtractor_output_analyzer_.DivergedFilter());
|
||||
} else {
|
||||
filter_quality_state_.Update(active_render, TransparentMode(),
|
||||
SaturatedCapture(),
|
||||
filter_analyzer_.Consistent(), external_delay,
|
||||
subtractor_output_analyzer_.ConvergedFilter());
|
||||
}
|
||||
filter_quality_state_.Update(active_render, TransparentMode(),
|
||||
SaturatedCapture(),
|
||||
filter_analyzer_.Consistent(), external_delay,
|
||||
subtractor_output_analyzer_.ConvergedFilter());
|
||||
|
||||
// Update the reverb estimate.
|
||||
const bool stationary_block =
|
||||
@ -268,7 +207,6 @@ void AecState::Update(
|
||||
|
||||
data_dumper_->DumpRaw("aec3_consistent_filter",
|
||||
filter_analyzer_.Consistent());
|
||||
data_dumper_->DumpRaw("aec3_suppression_gain_limit", SuppressionGainLimit());
|
||||
data_dumper_->DumpRaw("aec3_initial_state",
|
||||
initial_state_.InitialStateActive());
|
||||
data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture());
|
||||
@ -280,8 +218,6 @@ void AecState::Update(
|
||||
|
||||
data_dumper_->DumpRaw("aec3_external_delay_avaliable",
|
||||
external_delay ? 1 : 0);
|
||||
data_dumper_->DumpRaw("aec3_suppresion_gain_limiter_running",
|
||||
IsSuppressionGainLimitActive());
|
||||
data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est",
|
||||
GetReverbFrequencyResponse());
|
||||
}
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
#include "modules/audio_processing/aec3/reverb_model_estimator.h"
|
||||
#include "modules/audio_processing/aec3/subtractor_output.h"
|
||||
#include "modules/audio_processing/aec3/subtractor_output_analyzer.h"
|
||||
#include "modules/audio_processing/aec3/suppression_gain_limiter.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -46,17 +45,11 @@ class AecState {
|
||||
// Returns whether the echo subtractor can be used to determine the residual
|
||||
// echo.
|
||||
bool UsableLinearEstimate() const {
|
||||
if (use_legacy_filter_quality_) {
|
||||
return legacy_filter_quality_state_.LinearFilterUsable();
|
||||
}
|
||||
return filter_quality_state_.LinearFilterUsable();
|
||||
}
|
||||
|
||||
// Returns whether the echo subtractor output should be used as output.
|
||||
bool UseLinearFilterOutput() const {
|
||||
if (use_legacy_filter_quality_) {
|
||||
return legacy_filter_quality_state_.LinearFilterUsable();
|
||||
}
|
||||
return filter_quality_state_.LinearFilterUsable();
|
||||
}
|
||||
|
||||
@ -105,11 +98,7 @@ class AecState {
|
||||
bool SaturatedCapture() const { return capture_signal_saturation_; }
|
||||
|
||||
// Returns whether the echo signal is saturated.
|
||||
bool SaturatedEcho() const {
|
||||
return use_legacy_saturation_behavior_
|
||||
? legacy_saturation_detector_.SaturatedEcho()
|
||||
: saturation_detector_.SaturatedEcho();
|
||||
}
|
||||
bool SaturatedEcho() const { return saturation_detector_.SaturatedEcho(); }
|
||||
|
||||
// Updates the capture signal saturation.
|
||||
void UpdateCaptureSaturation(bool capture_signal_saturation) {
|
||||
@ -130,20 +119,6 @@ class AecState {
|
||||
return reverb_model_estimator_.GetReverbFrequencyResponse();
|
||||
}
|
||||
|
||||
// Returns the upper limit for the echo suppression gain.
|
||||
float SuppressionGainLimit() const {
|
||||
if (use_suppressor_gain_limiter_) {
|
||||
return suppression_gain_limiter_.Limit();
|
||||
} else {
|
||||
return 1.f;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns whether the suppression gain limiter is active.
|
||||
bool IsSuppressionGainLimitActive() const {
|
||||
return suppression_gain_limiter_.IsActive();
|
||||
}
|
||||
|
||||
// Returns whether the transition for going out of the initial stated has
|
||||
// been triggered.
|
||||
bool TransitionTriggered() const {
|
||||
@ -170,11 +145,6 @@ class AecState {
|
||||
static int instance_count_;
|
||||
std::unique_ptr<ApmDataDumper> data_dumper_;
|
||||
const EchoCanceller3Config config_;
|
||||
const bool use_legacy_saturation_behavior_;
|
||||
const bool enable_erle_resets_at_gain_changes_;
|
||||
const bool enable_erle_updates_during_reverb_;
|
||||
const bool use_legacy_filter_quality_;
|
||||
const bool use_suppressor_gain_limiter_;
|
||||
|
||||
// Class for controlling the transition from the intial state, which in turn
|
||||
// controls when the filter parameters for the initial state should be used.
|
||||
@ -378,8 +348,6 @@ class AecState {
|
||||
size_t strong_not_saturated_render_blocks_ = 0;
|
||||
size_t blocks_with_active_render_ = 0;
|
||||
bool capture_signal_saturation_ = false;
|
||||
|
||||
SuppressionGainUpperLimiter suppression_gain_limiter_;
|
||||
FilterAnalyzer filter_analyzer_;
|
||||
absl::optional<DelayEstimate> external_delay_;
|
||||
EchoAudibility echo_audibility_;
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||
#include "rtc_base/atomic_ops.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
|
||||
@ -35,26 +35,11 @@
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "rtc_base/logging.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
bool UseShadowFilterOutput() {
|
||||
return !field_trial::IsEnabled(
|
||||
"WebRTC-Aec3UtilizeShadowFilterOutputKillSwitch");
|
||||
}
|
||||
|
||||
bool UseSmoothSignalTransitions() {
|
||||
return !field_trial::IsEnabled(
|
||||
"WebRTC-Aec3SmoothSignalTransitionsKillSwitch");
|
||||
}
|
||||
|
||||
bool EnableBoundedNearend() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3BoundedNearendKillSwitch");
|
||||
}
|
||||
|
||||
void LinearEchoPower(const FftData& E,
|
||||
const FftData& Y,
|
||||
std::array<float, kFftLengthBy2Plus1>* S2) {
|
||||
@ -127,8 +112,7 @@ class EchoRemoverImpl final : public EchoRemover {
|
||||
// Selects which of the shadow and main linear filter outputs that is most
|
||||
// appropriate to pass to the suppressor and forms the linear filter output by
|
||||
// smoothly transition between those.
|
||||
void FormLinearFilterOutput(bool smooth_transition,
|
||||
const SubtractorOutput& subtractor_output,
|
||||
void FormLinearFilterOutput(const SubtractorOutput& subtractor_output,
|
||||
rtc::ArrayView<float> output);
|
||||
|
||||
static int instance_count_;
|
||||
@ -138,8 +122,6 @@ class EchoRemoverImpl final : public EchoRemover {
|
||||
const Aec3Optimization optimization_;
|
||||
const int sample_rate_hz_;
|
||||
const bool use_shadow_filter_output_;
|
||||
const bool use_smooth_signal_transitions_;
|
||||
const bool enable_bounded_nearend_;
|
||||
Subtractor subtractor_;
|
||||
SuppressionGain suppression_gain_;
|
||||
ComfortNoiseGenerator cng_;
|
||||
@ -171,10 +153,7 @@ EchoRemoverImpl::EchoRemoverImpl(const EchoCanceller3Config& config,
|
||||
optimization_(DetectOptimization()),
|
||||
sample_rate_hz_(sample_rate_hz),
|
||||
use_shadow_filter_output_(
|
||||
UseShadowFilterOutput() &&
|
||||
config_.filter.enable_shadow_filter_output_usage),
|
||||
use_smooth_signal_transitions_(UseSmoothSignalTransitions()),
|
||||
enable_bounded_nearend_(EnableBoundedNearend()),
|
||||
subtractor_(config, data_dumper_.get(), optimization_),
|
||||
suppression_gain_(config_, optimization_, sample_rate_hz),
|
||||
cng_(optimization_),
|
||||
@ -275,7 +254,7 @@ void EchoRemoverImpl::ProcessCapture(
|
||||
subtractor_.Process(*render_buffer, y0, render_signal_analyzer_, aec_state_,
|
||||
&subtractor_output);
|
||||
std::array<float, kBlockSize> e;
|
||||
FormLinearFilterOutput(use_smooth_signal_transitions_, subtractor_output, e);
|
||||
FormLinearFilterOutput(subtractor_output, e);
|
||||
|
||||
// Compute spectra.
|
||||
WindowedPaddedFft(fft_, y0, y_old_, &Y);
|
||||
@ -293,14 +272,13 @@ void EchoRemoverImpl::ProcessCapture(
|
||||
data_dumper_->DumpWav("aec3_output_linear2", kBlockSize, &e[0],
|
||||
LowestBandRate(sample_rate_hz_), 1);
|
||||
if (aec_state_.UseLinearFilterOutput()) {
|
||||
if (!linear_filter_output_last_selected_ &&
|
||||
use_smooth_signal_transitions_) {
|
||||
if (!linear_filter_output_last_selected_) {
|
||||
SignalTransition(y0, e, y0);
|
||||
} else {
|
||||
std::copy(e.begin(), e.end(), y0.begin());
|
||||
}
|
||||
} else {
|
||||
if (linear_filter_output_last_selected_ && use_smooth_signal_transitions_) {
|
||||
if (linear_filter_output_last_selected_) {
|
||||
SignalTransition(e, y0, y0);
|
||||
}
|
||||
}
|
||||
@ -322,12 +300,8 @@ void EchoRemoverImpl::ProcessCapture(
|
||||
aec_state_.UsableLinearEstimate() ? S2_linear : R2;
|
||||
|
||||
std::array<float, kFftLengthBy2Plus1> E2_bounded;
|
||||
if (enable_bounded_nearend_) {
|
||||
std::transform(E2.begin(), E2.end(), Y2.begin(), E2_bounded.begin(),
|
||||
[](float a, float b) { return std::min(a, b); });
|
||||
} else {
|
||||
std::copy(E2.begin(), E2.end(), E2_bounded.begin());
|
||||
}
|
||||
std::transform(E2.begin(), E2.end(), Y2.begin(), E2_bounded.begin(),
|
||||
[](float a, float b) { return std::min(a, b); });
|
||||
|
||||
suppression_gain_.GetGain(E2, E2_bounded, echo_spectrum, R2,
|
||||
cng_.NoiseSpectrum(), E, Y, render_signal_analyzer_,
|
||||
@ -367,7 +341,6 @@ void EchoRemoverImpl::ProcessCapture(
|
||||
}
|
||||
|
||||
void EchoRemoverImpl::FormLinearFilterOutput(
|
||||
bool smooth_transition,
|
||||
const SubtractorOutput& subtractor_output,
|
||||
rtc::ArrayView<float> output) {
|
||||
RTC_DCHECK_EQ(subtractor_output.e_main.size(), output.size());
|
||||
@ -393,7 +366,7 @@ void EchoRemoverImpl::FormLinearFilterOutput(
|
||||
}
|
||||
|
||||
if (use_main_output) {
|
||||
if (!main_filter_output_last_selected_ && smooth_transition) {
|
||||
if (!main_filter_output_last_selected_) {
|
||||
SignalTransition(subtractor_output.e_shadow, subtractor_output.e_main,
|
||||
output);
|
||||
} else {
|
||||
@ -401,7 +374,7 @@ void EchoRemoverImpl::FormLinearFilterOutput(
|
||||
subtractor_output.e_main.end(), output.begin());
|
||||
}
|
||||
} else {
|
||||
if (main_filter_output_last_selected_ && smooth_transition) {
|
||||
if (main_filter_output_last_selected_) {
|
||||
SignalTransition(subtractor_output.e_main, subtractor_output.e_shadow,
|
||||
output);
|
||||
} else {
|
||||
|
||||
@ -20,7 +20,6 @@
|
||||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||
#include "rtc_base/atomic_ops.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
@ -43,16 +42,6 @@ size_t FindPeakIndex(rtc::ArrayView<const float> filter_time_domain,
|
||||
return peak_index_out;
|
||||
}
|
||||
|
||||
bool EnableFilterPreprocessing() {
|
||||
return !field_trial::IsEnabled(
|
||||
"WebRTC-Aec3FilterAnalyzerPreprocessorKillSwitch");
|
||||
}
|
||||
|
||||
bool EnableIncrementalAnalysis() {
|
||||
return !field_trial::IsEnabled(
|
||||
"WebRTC-Aec3FilterAnalyzerIncrementalAnalysisKillSwitch");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int FilterAnalyzer::instance_count_ = 0;
|
||||
@ -60,10 +49,8 @@ int FilterAnalyzer::instance_count_ = 0;
|
||||
FilterAnalyzer::FilterAnalyzer(const EchoCanceller3Config& config)
|
||||
: data_dumper_(
|
||||
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
|
||||
use_preprocessed_filter_(EnableFilterPreprocessing()),
|
||||
bounded_erl_(config.ep_strength.bounded_erl),
|
||||
default_gain_(config.ep_strength.lf),
|
||||
use_incremental_analysis_(EnableIncrementalAnalysis()),
|
||||
h_highpass_(GetTimeDomainLength(config.filter.main.length_blocks), 0.f),
|
||||
filter_length_blocks_(config.filter.main_initial.length_blocks),
|
||||
consistent_filter_detector_(config) {
|
||||
@ -99,19 +86,17 @@ void FilterAnalyzer::AnalyzeRegion(
|
||||
PreProcessFilter(filter_time_domain);
|
||||
data_dumper_->DumpRaw("aec3_linear_filter_processed_td", h_highpass_);
|
||||
|
||||
const auto& filter_to_analyze =
|
||||
use_preprocessed_filter_ ? h_highpass_ : filter_time_domain;
|
||||
RTC_DCHECK_EQ(filter_to_analyze.size(), filter_time_domain.size());
|
||||
RTC_DCHECK_EQ(h_highpass_.size(), filter_time_domain.size());
|
||||
|
||||
peak_index_ = FindPeakIndex(filter_to_analyze, peak_index_,
|
||||
region_.start_sample_, region_.end_sample_);
|
||||
peak_index_ = FindPeakIndex(h_highpass_, peak_index_, region_.start_sample_,
|
||||
region_.end_sample_);
|
||||
delay_blocks_ = peak_index_ >> kBlockSizeLog2;
|
||||
UpdateFilterGain(filter_to_analyze, peak_index_);
|
||||
UpdateFilterGain(h_highpass_, peak_index_);
|
||||
filter_length_blocks_ = filter_time_domain.size() * (1.f / kBlockSize);
|
||||
|
||||
consistent_estimate_ = consistent_filter_detector_.Detect(
|
||||
filter_to_analyze, region_, render_buffer.Block(-delay_blocks_)[0],
|
||||
peak_index_, delay_blocks_);
|
||||
h_highpass_, region_, render_buffer.Block(-delay_blocks_)[0], peak_index_,
|
||||
delay_blocks_);
|
||||
}
|
||||
|
||||
void FilterAnalyzer::UpdateFilterGain(
|
||||
@ -159,17 +144,11 @@ void FilterAnalyzer::SetRegionToAnalyze(
|
||||
rtc::ArrayView<const float> filter_time_domain) {
|
||||
constexpr size_t kNumberBlocksToUpdate = 1;
|
||||
auto& r = region_;
|
||||
if (use_incremental_analysis_) {
|
||||
r.start_sample_ =
|
||||
r.end_sample_ == filter_time_domain.size() - 1 ? 0 : r.end_sample_ + 1;
|
||||
r.end_sample_ =
|
||||
std::min(r.start_sample_ + kNumberBlocksToUpdate * kBlockSize - 1,
|
||||
filter_time_domain.size() - 1);
|
||||
|
||||
} else {
|
||||
r.start_sample_ = 0;
|
||||
r.end_sample_ = filter_time_domain.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
FilterAnalyzer::ConsistentFilterDetector::ConsistentFilterDetector(
|
||||
|
||||
@ -97,10 +97,8 @@ class FilterAnalyzer {
|
||||
|
||||
static int instance_count_;
|
||||
std::unique_ptr<ApmDataDumper> data_dumper_;
|
||||
const bool use_preprocessed_filter_;
|
||||
const bool bounded_erl_;
|
||||
const float default_gain_;
|
||||
const bool use_incremental_analysis_;
|
||||
std::vector<float> h_highpass_;
|
||||
int delay_blocks_ = 0;
|
||||
size_t blocks_since_reset_ = 0;
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
#include "rtc_base/atomic_ops.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
@ -19,70 +18,36 @@
|
||||
#include "modules/audio_processing/aec3/reverb_model.h"
|
||||
#include "modules/audio_processing/aec3/reverb_model_fallback.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
bool EnableSoftTransparentMode() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3SoftTransparentModeKillSwitch");
|
||||
}
|
||||
|
||||
bool OverrideEstimatedEchoPathGain() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3OverrideEchoPathGainKillSwitch");
|
||||
}
|
||||
|
||||
bool UseFixedNonLinearReverbModel() {
|
||||
return field_trial::IsEnabled(
|
||||
"WebRTC-Aec3StandardNonlinearReverbModelKillSwitch");
|
||||
}
|
||||
|
||||
// Computes the indexes that will be used for computing spectral power over
|
||||
// the blocks surrounding the delay.
|
||||
void GetRenderIndexesToAnalyze(
|
||||
const VectorBuffer& spectrum_buffer,
|
||||
const EchoCanceller3Config::EchoModel& echo_model,
|
||||
int filter_delay_blocks,
|
||||
bool gain_limiter_running,
|
||||
int headroom,
|
||||
int* idx_start,
|
||||
int* idx_stop) {
|
||||
RTC_DCHECK(idx_start);
|
||||
RTC_DCHECK(idx_stop);
|
||||
if (gain_limiter_running) {
|
||||
if (static_cast<size_t>(headroom) >
|
||||
echo_model.render_post_window_size_init) {
|
||||
*idx_start = spectrum_buffer.OffsetIndex(
|
||||
spectrum_buffer.read,
|
||||
-static_cast<int>(echo_model.render_post_window_size_init));
|
||||
} else {
|
||||
*idx_start = spectrum_buffer.IncIndex(spectrum_buffer.write);
|
||||
}
|
||||
|
||||
*idx_stop = spectrum_buffer.OffsetIndex(
|
||||
spectrum_buffer.read, echo_model.render_pre_window_size_init);
|
||||
} else {
|
||||
size_t window_start;
|
||||
size_t window_end;
|
||||
window_start =
|
||||
std::max(0, filter_delay_blocks -
|
||||
static_cast<int>(echo_model.render_pre_window_size));
|
||||
window_end = filter_delay_blocks +
|
||||
static_cast<int>(echo_model.render_post_window_size);
|
||||
*idx_start =
|
||||
spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_start);
|
||||
*idx_stop =
|
||||
spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_end + 1);
|
||||
}
|
||||
size_t window_start;
|
||||
size_t window_end;
|
||||
window_start =
|
||||
std::max(0, filter_delay_blocks -
|
||||
static_cast<int>(echo_model.render_pre_window_size));
|
||||
window_end = filter_delay_blocks +
|
||||
static_cast<int>(echo_model.render_post_window_size);
|
||||
*idx_start = spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_start);
|
||||
*idx_stop = spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_end + 1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ResidualEchoEstimator::ResidualEchoEstimator(const EchoCanceller3Config& config)
|
||||
: config_(config),
|
||||
soft_transparent_mode_(EnableSoftTransparentMode()),
|
||||
override_estimated_echo_path_gain_(OverrideEstimatedEchoPathGain()),
|
||||
use_fixed_nonlinear_reverb_model_(UseFixedNonLinearReverbModel()) {
|
||||
: config_(config) {
|
||||
if (config_.ep_strength.reverb_based_on_render) {
|
||||
echo_reverb_.reset(new ReverbModel());
|
||||
} else {
|
||||
@ -136,7 +101,6 @@ void ResidualEchoEstimator::Estimate(
|
||||
|
||||
EchoGeneratingPower(render_buffer.GetSpectrumBuffer(), config_.echo_model,
|
||||
render_buffer.Headroom(), aec_state.FilterDelayBlocks(),
|
||||
aec_state.IsSuppressionGainLimitActive(),
|
||||
!aec_state.UseStationaryProperties(), &X2);
|
||||
|
||||
// Subtract the stationary noise power to avoid stationary noise causing
|
||||
@ -148,15 +112,8 @@ void ResidualEchoEstimator::Estimate(
|
||||
});
|
||||
|
||||
float echo_path_gain;
|
||||
if (override_estimated_echo_path_gain_) {
|
||||
echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_
|
||||
? 0.01f
|
||||
: config_.ep_strength.lf;
|
||||
} else {
|
||||
echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_
|
||||
? 0.01f
|
||||
: aec_state.EchoPathGain();
|
||||
}
|
||||
echo_path_gain =
|
||||
aec_state.TransparentMode() ? 0.01f : config_.ep_strength.lf;
|
||||
NonLinearEstimate(echo_path_gain, X2, Y2, R2);
|
||||
|
||||
// When there is saturated echo, assume the same spectral content as is
|
||||
@ -165,7 +122,7 @@ void ResidualEchoEstimator::Estimate(
|
||||
std::copy(Y2.begin(), Y2.end(), R2->begin());
|
||||
}
|
||||
|
||||
if (!(aec_state.TransparentMode() && soft_transparent_mode_)) {
|
||||
if (!(aec_state.TransparentMode())) {
|
||||
if (echo_reverb_) {
|
||||
echo_reverb_->AddReverbNoFreqShaping(
|
||||
render_buffer.Spectrum(aec_state.FilterDelayBlocks() + 1),
|
||||
@ -190,14 +147,6 @@ void ResidualEchoEstimator::Estimate(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!soft_transparent_mode_) {
|
||||
// If the echo is deemed inaudible, set the residual echo to zero.
|
||||
if (aec_state.TransparentMode()) {
|
||||
R2->fill(0.f);
|
||||
R2_old_.fill(0.f);
|
||||
R2_hold_counter_.fill(0.f);
|
||||
}
|
||||
}
|
||||
|
||||
std::copy(R2->begin(), R2->end(), R2_old_.begin());
|
||||
}
|
||||
@ -243,22 +192,6 @@ void ResidualEchoEstimator::NonLinearEstimate(
|
||||
std::transform(X2.begin(), X2.end(), R2->begin(), [echo_path_gain](float a) {
|
||||
return a * echo_path_gain * echo_path_gain;
|
||||
});
|
||||
|
||||
if (use_fixed_nonlinear_reverb_model_) {
|
||||
for (size_t k = 0; k < R2->size(); ++k) {
|
||||
// Update hold counter.
|
||||
R2_hold_counter_[k] = R2_old_[k] < (*R2)[k] ? 0 : R2_hold_counter_[k] + 1;
|
||||
|
||||
// Compute the residual echo by holding a maximum echo powers and an echo
|
||||
// fading corresponding to a room with an RT60 value of about 50 ms.
|
||||
(*R2)[k] =
|
||||
R2_hold_counter_[k] < config_.echo_model.nonlinear_hold
|
||||
? std::max((*R2)[k], R2_old_[k])
|
||||
: std::min((*R2)[k] +
|
||||
R2_old_[k] * config_.echo_model.nonlinear_release,
|
||||
Y2[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResidualEchoEstimator::EchoGeneratingPower(
|
||||
@ -266,15 +199,14 @@ void ResidualEchoEstimator::EchoGeneratingPower(
|
||||
const EchoCanceller3Config::EchoModel& echo_model,
|
||||
int headroom_spectrum_buffer,
|
||||
int filter_delay_blocks,
|
||||
bool gain_limiter_running,
|
||||
bool apply_noise_gating,
|
||||
std::array<float, kFftLengthBy2Plus1>* X2) const {
|
||||
int idx_stop, idx_start;
|
||||
|
||||
RTC_DCHECK(X2);
|
||||
GetRenderIndexesToAnalyze(spectrum_buffer, config_.echo_model,
|
||||
filter_delay_blocks, gain_limiter_running,
|
||||
headroom_spectrum_buffer, &idx_start, &idx_stop);
|
||||
filter_delay_blocks, headroom_spectrum_buffer,
|
||||
&idx_start, &idx_stop);
|
||||
|
||||
X2->fill(0.f);
|
||||
for (int k = idx_start; k != idx_stop; k = spectrum_buffer.IncIndex(k)) {
|
||||
|
||||
@ -72,7 +72,6 @@ class ResidualEchoEstimator {
|
||||
const EchoCanceller3Config::EchoModel& echo_model,
|
||||
int headroom_spectrum_buffer,
|
||||
int filter_delay_blocks,
|
||||
bool gain_limiter_running,
|
||||
bool apply_noise_gating,
|
||||
std::array<float, kFftLengthBy2Plus1>* X2) const;
|
||||
|
||||
@ -88,9 +87,6 @@ class ResidualEchoEstimator {
|
||||
std::array<int, kFftLengthBy2Plus1> R2_hold_counter_;
|
||||
std::array<float, kFftLengthBy2Plus1> X2_noise_floor_;
|
||||
std::array<int, kFftLengthBy2Plus1> X2_noise_floor_counter_;
|
||||
const bool soft_transparent_mode_;
|
||||
const bool override_estimated_echo_path_gain_;
|
||||
const bool use_fixed_nonlinear_reverb_model_;
|
||||
std::unique_ptr<ReverbModel> echo_reverb_;
|
||||
std::unique_ptr<ReverbModelFallback> echo_reverb_fallback;
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ResidualEchoEstimator);
|
||||
|
||||
@ -19,17 +19,11 @@
|
||||
#include "api/audio/echo_canceller3_config.h"
|
||||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
bool EnforceAdaptiveEchoReverbEstimation() {
|
||||
return field_trial::IsEnabled(
|
||||
"WebRTC-Aec3EnableAdaptiveEchoReverbEstimation");
|
||||
}
|
||||
|
||||
constexpr int kEarlyReverbMinSizeBlocks = 3;
|
||||
constexpr int kBlocksPerSection = 6;
|
||||
// Linear regression approach assumes symmetric index around 0.
|
||||
@ -92,8 +86,7 @@ float BlockEnergyAverage(rtc::ArrayView<const float> h, int block_index) {
|
||||
ReverbDecayEstimator::ReverbDecayEstimator(const EchoCanceller3Config& config)
|
||||
: filter_length_blocks_(config.filter.main.length_blocks),
|
||||
filter_length_coefficients_(GetTimeDomainLength(filter_length_blocks_)),
|
||||
use_adaptive_echo_decay_(config.ep_strength.default_len < 0.f ||
|
||||
EnforceAdaptiveEchoReverbEstimation()),
|
||||
use_adaptive_echo_decay_(config.ep_strength.default_len < 0.f),
|
||||
early_reverb_estimator_(config.filter.main.length_blocks -
|
||||
kEarlyReverbMinSizeBlocks),
|
||||
late_reverb_start_(kEarlyReverbMinSizeBlocks),
|
||||
|
||||
@ -18,17 +18,11 @@
|
||||
#include "api/array_view.h"
|
||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
bool EnableSmoothUpdatesTailFreqResp() {
|
||||
return !field_trial::IsEnabled(
|
||||
"WebRTC-Aec3SmoothUpdatesTailFreqRespKillSwitch");
|
||||
}
|
||||
|
||||
// Computes the ratio of the energies between the direct path and the tail. The
|
||||
// energy is computed in the power spectrum domain discarding the DC
|
||||
// contributions.
|
||||
@ -54,8 +48,7 @@ float AverageDecayWithinFilter(
|
||||
|
||||
} // namespace
|
||||
|
||||
ReverbFrequencyResponse::ReverbFrequencyResponse()
|
||||
: enable_smooth_tail_response_updates_(EnableSmoothUpdatesTailFreqResp()) {
|
||||
ReverbFrequencyResponse::ReverbFrequencyResponse() {
|
||||
tail_response_.fill(0.f);
|
||||
}
|
||||
ReverbFrequencyResponse::~ReverbFrequencyResponse() = default;
|
||||
@ -66,10 +59,6 @@ void ReverbFrequencyResponse::Update(
|
||||
int filter_delay_blocks,
|
||||
const absl::optional<float>& linear_filter_quality,
|
||||
bool stationary_block) {
|
||||
if (!enable_smooth_tail_response_updates_) {
|
||||
Update(frequency_response, filter_delay_blocks, 0.5f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stationary_block || !linear_filter_quality) {
|
||||
return;
|
||||
|
||||
@ -44,7 +44,6 @@ class ReverbFrequencyResponse {
|
||||
int filter_delay_blocks,
|
||||
float linear_filter_quality);
|
||||
|
||||
const bool enable_smooth_tail_response_updates_;
|
||||
float average_decay_ = 0.f;
|
||||
std::array<float, kFftLengthBy2Plus1> tail_response_;
|
||||
};
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/numerics/safe_minmax.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -26,10 +25,6 @@ constexpr int kBlocksToHoldErle = 100;
|
||||
constexpr int kBlocksForOnsetDetection = kBlocksToHoldErle + 150;
|
||||
constexpr int kPointsToAccumulate = 6;
|
||||
|
||||
bool EnableAdaptErleOnLowRender() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3AdaptErleOnLowRenderKillSwitch");
|
||||
}
|
||||
|
||||
std::array<float, kFftLengthBy2Plus1> SetMaxErleBands(float max_erle_l,
|
||||
float max_erle_h) {
|
||||
std::array<float, kFftLengthBy2Plus1> max_erle;
|
||||
@ -42,8 +37,7 @@ std::array<float, kFftLengthBy2Plus1> SetMaxErleBands(float max_erle_l,
|
||||
|
||||
SubbandErleEstimator::SubbandErleEstimator(const EchoCanceller3Config& config)
|
||||
: min_erle_(config.erle.min),
|
||||
max_erle_(SetMaxErleBands(config.erle.max_l, config.erle.max_h)),
|
||||
adapt_on_low_render_(EnableAdaptErleOnLowRender()) {
|
||||
max_erle_(SetMaxErleBands(config.erle.max_l, config.erle.max_h)) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
@ -151,43 +145,23 @@ void SubbandErleEstimator::UpdateAccumulatedSpectra(
|
||||
rtc::ArrayView<const float> Y2,
|
||||
rtc::ArrayView<const float> E2) {
|
||||
auto& st = accum_spectra_;
|
||||
if (adapt_on_low_render_) {
|
||||
if (st.num_points_[0] == kPointsToAccumulate) {
|
||||
st.num_points_[0] = 0;
|
||||
st.Y2_.fill(0.f);
|
||||
st.E2_.fill(0.f);
|
||||
st.low_render_energy_.fill(false);
|
||||
}
|
||||
std::transform(Y2.begin(), Y2.end(), st.Y2_.begin(), st.Y2_.begin(),
|
||||
std::plus<float>());
|
||||
std::transform(E2.begin(), E2.end(), st.E2_.begin(), st.E2_.begin(),
|
||||
std::plus<float>());
|
||||
|
||||
for (size_t k = 0; k < X2.size(); ++k) {
|
||||
st.low_render_energy_[k] =
|
||||
st.low_render_energy_[k] || X2[k] < kX2BandEnergyThreshold;
|
||||
}
|
||||
st.num_points_[0]++;
|
||||
st.num_points_.fill(st.num_points_[0]);
|
||||
|
||||
} else {
|
||||
// The update is always done using high render energy signals and
|
||||
// therefore the field accum_spectra_.low_render_energy_ does not need to
|
||||
// be modified.
|
||||
for (size_t k = 0; k < X2.size(); ++k) {
|
||||
if (X2[k] > kX2BandEnergyThreshold) {
|
||||
if (st.num_points_[k] == kPointsToAccumulate) {
|
||||
st.Y2_[k] = 0.f;
|
||||
st.E2_[k] = 0.f;
|
||||
st.num_points_[k] = 0;
|
||||
}
|
||||
st.Y2_[k] += Y2[k];
|
||||
st.E2_[k] += E2[k];
|
||||
st.num_points_[k]++;
|
||||
}
|
||||
RTC_DCHECK_EQ(st.low_render_energy_[k], false);
|
||||
}
|
||||
if (st.num_points_[0] == kPointsToAccumulate) {
|
||||
st.num_points_[0] = 0;
|
||||
st.Y2_.fill(0.f);
|
||||
st.E2_.fill(0.f);
|
||||
st.low_render_energy_.fill(false);
|
||||
}
|
||||
std::transform(Y2.begin(), Y2.end(), st.Y2_.begin(), st.Y2_.begin(),
|
||||
std::plus<float>());
|
||||
std::transform(E2.begin(), E2.end(), st.E2_.begin(), st.E2_.begin(),
|
||||
std::plus<float>());
|
||||
|
||||
for (size_t k = 0; k < X2.size(); ++k) {
|
||||
st.low_render_energy_[k] =
|
||||
st.low_render_energy_[k] || X2[k] < kX2BandEnergyThreshold;
|
||||
}
|
||||
st.num_points_[0]++;
|
||||
st.num_points_.fill(st.num_points_[0]);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -66,7 +66,6 @@ class SubbandErleEstimator {
|
||||
|
||||
const float min_erle_;
|
||||
const std::array<float, kFftLengthBy2Plus1> max_erle_;
|
||||
const bool adapt_on_low_render_;
|
||||
AccumulatedSpectra accum_spectra_;
|
||||
std::array<float, kFftLengthBy2Plus1> erle_;
|
||||
std::array<float, kFftLengthBy2Plus1> erle_onsets_;
|
||||
|
||||
@ -18,44 +18,16 @@
|
||||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/numerics/safe_minmax.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
bool EnableAgcGainChangeResponse() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3AgcGainChangeResponseKillSwitch");
|
||||
}
|
||||
|
||||
bool EnableAdaptationDuringSaturation() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3RapidAgcGainRecoveryKillSwitch");
|
||||
}
|
||||
|
||||
bool EnableMisadjustmentEstimator() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3MisadjustmentEstimatorKillSwitch");
|
||||
}
|
||||
|
||||
bool EnableShadowFilterJumpstart() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3ShadowFilterJumpstartKillSwitch");
|
||||
}
|
||||
|
||||
bool EnableShadowFilterBoostedJumpstart() {
|
||||
return !field_trial::IsEnabled(
|
||||
"WebRTC-Aec3ShadowFilterBoostedJumpstartKillSwitch");
|
||||
}
|
||||
|
||||
bool EnableEarlyShadowFilterJumpstart() {
|
||||
return !field_trial::IsEnabled(
|
||||
"WebRTC-Aec3EarlyShadowFilterJumpstartKillSwitch");
|
||||
}
|
||||
|
||||
void PredictionError(const Aec3Fft& fft,
|
||||
const FftData& S,
|
||||
rtc::ArrayView<const float> y,
|
||||
std::array<float, kBlockSize>* e,
|
||||
std::array<float, kBlockSize>* s,
|
||||
bool adaptation_during_saturation,
|
||||
bool* saturation) {
|
||||
std::array<float, kFftLength> tmp;
|
||||
fft.Ifft(S, &tmp);
|
||||
@ -77,12 +49,7 @@ void PredictionError(const Aec3Fft& fft,
|
||||
*saturation = *result.first <= -32768 || *result.first >= 32767;
|
||||
}
|
||||
|
||||
if (!adaptation_during_saturation) {
|
||||
std::for_each(e->begin(), e->end(),
|
||||
[](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
|
||||
} else {
|
||||
*saturation = false;
|
||||
}
|
||||
*saturation = false;
|
||||
}
|
||||
|
||||
void ScaleFilterOutput(rtc::ArrayView<const float> y,
|
||||
@ -106,13 +73,6 @@ Subtractor::Subtractor(const EchoCanceller3Config& config,
|
||||
data_dumper_(data_dumper),
|
||||
optimization_(optimization),
|
||||
config_(config),
|
||||
adaptation_during_saturation_(EnableAdaptationDuringSaturation()),
|
||||
enable_misadjustment_estimator_(EnableMisadjustmentEstimator()),
|
||||
enable_agc_gain_change_response_(EnableAgcGainChangeResponse()),
|
||||
enable_shadow_filter_jumpstart_(EnableShadowFilterJumpstart()),
|
||||
enable_shadow_filter_boosted_jumpstart_(
|
||||
EnableShadowFilterBoostedJumpstart()),
|
||||
enable_early_shadow_filter_jumpstart_(EnableEarlyShadowFilterJumpstart()),
|
||||
main_filter_(config_.filter.main.length_blocks,
|
||||
config_.filter.main_initial.length_blocks,
|
||||
config.filter.config_change_duration_blocks,
|
||||
@ -152,7 +112,7 @@ void Subtractor::HandleEchoPathChange(
|
||||
full_reset();
|
||||
}
|
||||
|
||||
if (echo_path_variability.gain_change && enable_agc_gain_change_response_) {
|
||||
if (echo_path_variability.gain_change) {
|
||||
G_main_.HandleEchoPathChange(echo_path_variability);
|
||||
}
|
||||
}
|
||||
@ -182,28 +142,24 @@ void Subtractor::Process(const RenderBuffer& render_buffer,
|
||||
// Form the outputs of the main and shadow filters.
|
||||
main_filter_.Filter(render_buffer, &S);
|
||||
bool main_saturation = false;
|
||||
PredictionError(fft_, S, y, &e_main, &output->s_main,
|
||||
adaptation_during_saturation_, &main_saturation);
|
||||
PredictionError(fft_, S, y, &e_main, &output->s_main, &main_saturation);
|
||||
|
||||
shadow_filter_.Filter(render_buffer, &S);
|
||||
bool shadow_saturation = false;
|
||||
PredictionError(fft_, S, y, &e_shadow, &output->s_shadow,
|
||||
adaptation_during_saturation_, &shadow_saturation);
|
||||
PredictionError(fft_, S, y, &e_shadow, &output->s_shadow, &shadow_saturation);
|
||||
|
||||
// Compute the signal powers in the subtractor output.
|
||||
output->ComputeMetrics(y);
|
||||
|
||||
// Adjust the filter if needed.
|
||||
bool main_filter_adjusted = false;
|
||||
if (enable_misadjustment_estimator_) {
|
||||
filter_misadjustment_estimator_.Update(*output);
|
||||
if (filter_misadjustment_estimator_.IsAdjustmentNeeded()) {
|
||||
float scale = filter_misadjustment_estimator_.GetMisadjustment();
|
||||
main_filter_.ScaleFilter(scale);
|
||||
ScaleFilterOutput(y, scale, e_main, output->s_main);
|
||||
filter_misadjustment_estimator_.Reset();
|
||||
main_filter_adjusted = true;
|
||||
}
|
||||
filter_misadjustment_estimator_.Update(*output);
|
||||
if (filter_misadjustment_estimator_.IsAdjustmentNeeded()) {
|
||||
float scale = filter_misadjustment_estimator_.GetMisadjustment();
|
||||
main_filter_.ScaleFilter(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.
|
||||
@ -248,40 +204,26 @@ void Subtractor::Process(const RenderBuffer& render_buffer,
|
||||
// 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 &&
|
||||
enable_early_shadow_filter_jumpstart_) ||
|
||||
(poor_shadow_filter_counter_ < 10 &&
|
||||
!enable_early_shadow_filter_jumpstart_)) ||
|
||||
!enable_shadow_filter_jumpstart_) {
|
||||
if (poor_shadow_filter_counter_ < 5) {
|
||||
G_shadow_.Compute(X2_shadow, render_signal_analyzer, E_shadow,
|
||||
shadow_filter_.SizePartitions(),
|
||||
aec_state.SaturatedCapture() || shadow_saturation, &G);
|
||||
shadow_filter_.Adapt(render_buffer, G);
|
||||
} else {
|
||||
poor_shadow_filter_counter_ = 0;
|
||||
if (enable_shadow_filter_boosted_jumpstart_) {
|
||||
shadow_filter_.SetFilter(main_filter_.GetFilter());
|
||||
G_shadow_.Compute(X2_shadow, render_signal_analyzer, E_main,
|
||||
shadow_filter_.SizePartitions(),
|
||||
aec_state.SaturatedCapture() || main_saturation, &G);
|
||||
shadow_filter_.Adapt(render_buffer, G);
|
||||
} else {
|
||||
G.re.fill(0.f);
|
||||
G.im.fill(0.f);
|
||||
shadow_filter_.Adapt(render_buffer, G);
|
||||
shadow_filter_.SetFilter(main_filter_.GetFilter());
|
||||
}
|
||||
shadow_filter_.SetFilter(main_filter_.GetFilter());
|
||||
G_shadow_.Compute(X2_shadow, render_signal_analyzer, E_main,
|
||||
shadow_filter_.SizePartitions(),
|
||||
aec_state.SaturatedCapture() || main_saturation, &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();
|
||||
|
||||
if (adaptation_during_saturation_) {
|
||||
std::for_each(e_main.begin(), e_main.end(),
|
||||
[](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
|
||||
}
|
||||
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);
|
||||
|
||||
@ -107,12 +107,6 @@ class Subtractor {
|
||||
ApmDataDumper* data_dumper_;
|
||||
const Aec3Optimization optimization_;
|
||||
const EchoCanceller3Config config_;
|
||||
const bool adaptation_during_saturation_;
|
||||
const bool enable_misadjustment_estimator_;
|
||||
const bool enable_agc_gain_change_response_;
|
||||
const bool enable_shadow_filter_jumpstart_;
|
||||
const bool enable_shadow_filter_boosted_jumpstart_;
|
||||
const bool enable_early_shadow_filter_jumpstart_;
|
||||
|
||||
AdaptiveFirFilter main_filter_;
|
||||
AdaptiveFirFilter shadow_filter_;
|
||||
|
||||
@ -13,19 +13,10 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
bool EnableStrictDivergenceCheck() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3StrictDivergenceCheckKillSwitch");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SubtractorOutputAnalyzer::SubtractorOutputAnalyzer()
|
||||
: strict_divergence_check_(EnableStrictDivergenceCheck()) {}
|
||||
SubtractorOutputAnalyzer::SubtractorOutputAnalyzer() {}
|
||||
|
||||
void SubtractorOutputAnalyzer::Update(
|
||||
const SubtractorOutput& subtractor_output) {
|
||||
@ -37,8 +28,7 @@ void SubtractorOutputAnalyzer::Update(
|
||||
main_filter_converged_ = e2_main < 0.5f * y2 && y2 > kConvergenceThreshold;
|
||||
shadow_filter_converged_ =
|
||||
e2_shadow < 0.05f * y2 && y2 > kConvergenceThreshold;
|
||||
float min_e2 =
|
||||
strict_divergence_check_ ? std::min(e2_main, e2_shadow) : e2_main;
|
||||
float min_e2 = std::min(e2_main, e2_shadow);
|
||||
filter_diverged_ = min_e2 > 1.5f * y2 && y2 > 30.f * 30.f * kBlockSize;
|
||||
}
|
||||
|
||||
|
||||
@ -34,7 +34,6 @@ class SubtractorOutputAnalyzer {
|
||||
void HandleEchoPathChange();
|
||||
|
||||
private:
|
||||
const bool strict_divergence_check_;
|
||||
bool shadow_filter_converged_ = false;
|
||||
bool main_filter_converged_ = false;
|
||||
bool filter_diverged_ = false;
|
||||
|
||||
@ -346,14 +346,6 @@ void SuppressionGain::GetGain(
|
||||
nearend_average, residual_echo_spectrum, comfort_noise_spectrum,
|
||||
low_band_gain);
|
||||
|
||||
// Limit the gain of the lower bands during start up and after resets.
|
||||
const float gain_upper_bound = aec_state.SuppressionGainLimit();
|
||||
if (gain_upper_bound < 1.f) {
|
||||
for (size_t k = 0; k < low_band_gain->size(); ++k) {
|
||||
(*low_band_gain)[k] = std::min((*low_band_gain)[k], gain_upper_bound);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the gain for the upper bands.
|
||||
const absl::optional<int> narrow_peak_band =
|
||||
render_signal_analyzer.NarrowPeakBand();
|
||||
|
||||
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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 "modules/audio_processing/aec3/suppression_gain_limiter.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
// Computes the gain rampup factor to use.
|
||||
float ComputeGainRampupIncrease(
|
||||
const EchoCanceller3Config::EchoRemovalControl::GainRampup& rampup_config) {
|
||||
return powf(1.f / rampup_config.first_non_zero_gain,
|
||||
1.f / rampup_config.non_zero_gain_blocks);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
SuppressionGainUpperLimiter::SuppressionGainUpperLimiter(
|
||||
const EchoCanceller3Config& config)
|
||||
: rampup_config_(config.echo_removal_control.gain_rampup),
|
||||
gain_rampup_increase_(ComputeGainRampupIncrease(rampup_config_)) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void SuppressionGainUpperLimiter::Reset() {
|
||||
recent_reset_ = true;
|
||||
}
|
||||
|
||||
void SuppressionGainUpperLimiter::Update(bool render_activity,
|
||||
bool transparent_mode) {
|
||||
if (transparent_mode) {
|
||||
active_render_seen_ = true;
|
||||
call_startup_phase_ = false;
|
||||
recent_reset_ = false;
|
||||
suppressor_gain_limit_ = 1.f;
|
||||
return;
|
||||
}
|
||||
|
||||
if (recent_reset_ && !call_startup_phase_) {
|
||||
// Only enforce 250 ms full suppression after in-call resets,
|
||||
constexpr int kMuteFramesAfterReset = kNumBlocksPerSecond / 4;
|
||||
realignment_counter_ = kMuteFramesAfterReset;
|
||||
} else if (!active_render_seen_ && render_activity) {
|
||||
// Enforce a tailormade suppression limiting during call startup.
|
||||
active_render_seen_ = true;
|
||||
realignment_counter_ = rampup_config_.full_gain_blocks;
|
||||
} else if (realignment_counter_ > 0) {
|
||||
if (--realignment_counter_ == 0) {
|
||||
call_startup_phase_ = false;
|
||||
}
|
||||
}
|
||||
recent_reset_ = false;
|
||||
|
||||
// Do not enforce any gain limit on the suppressor.
|
||||
if (!IsActive()) {
|
||||
suppressor_gain_limit_ = 1.f;
|
||||
return;
|
||||
}
|
||||
|
||||
// Enforce full suppression.
|
||||
if (realignment_counter_ > rampup_config_.non_zero_gain_blocks ||
|
||||
(!call_startup_phase_ && realignment_counter_ > 0)) {
|
||||
suppressor_gain_limit_ = rampup_config_.initial_gain;
|
||||
return;
|
||||
}
|
||||
|
||||
// Start increasing the gain limit.
|
||||
if (realignment_counter_ == rampup_config_.non_zero_gain_blocks) {
|
||||
suppressor_gain_limit_ = rampup_config_.first_non_zero_gain;
|
||||
return;
|
||||
}
|
||||
|
||||
// Increase the gain limit until it reaches 1.f.
|
||||
RTC_DCHECK_LT(0.f, suppressor_gain_limit_);
|
||||
suppressor_gain_limit_ =
|
||||
std::min(1.f, suppressor_gain_limit_ * gain_rampup_increase_);
|
||||
RTC_DCHECK_GE(1.f, suppressor_gain_limit_);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018 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.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_
|
||||
#define MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "api/audio/echo_canceller3_config.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Class for applying a smoothly increasing limit for the suppression gain
|
||||
// during call startup and after in-call resets.
|
||||
class SuppressionGainUpperLimiter {
|
||||
public:
|
||||
explicit SuppressionGainUpperLimiter(const EchoCanceller3Config& config);
|
||||
|
||||
// Reset the limiting behavior.
|
||||
void Reset();
|
||||
|
||||
// Updates the limiting behavior for the current capture bloc.
|
||||
void Update(bool render_activity, bool transparent_mode);
|
||||
|
||||
// Returns the current suppressor gain limit.
|
||||
float Limit() const { return suppressor_gain_limit_; }
|
||||
|
||||
// Return whether the suppressor gain limit is active.
|
||||
bool IsActive() const { return (realignment_counter_ > 0); }
|
||||
|
||||
// Inactivate limiter.
|
||||
void Deactivate() {
|
||||
realignment_counter_ = 0;
|
||||
suppressor_gain_limit_ = 1.f;
|
||||
}
|
||||
|
||||
private:
|
||||
const EchoCanceller3Config::EchoRemovalControl::GainRampup rampup_config_;
|
||||
const float gain_rampup_increase_;
|
||||
bool call_startup_phase_ = true;
|
||||
int realignment_counter_ = 0;
|
||||
bool active_render_seen_ = false;
|
||||
float suppressor_gain_limit_ = 1.f;
|
||||
bool recent_reset_ = false;
|
||||
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(SuppressionGainUpperLimiter);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_
|
||||
Reference in New Issue
Block a user