AEC3: Avoid overcompensating for render onsets during dominant nearend

The ERLE is used to estimate residual echo for echo suppression. The
ERLE is reduced during far-end offset to avoid echo leakage. When there
is a strong near-end present this can cause unnecessary transparency loss.

This change adds an ERLE estimation that does not compensate for onsets and
uses it for residual echo estimation when the suppressor considers the near-end to be dominant.

Bug: webrtc:12686
Change-Id: Ida78eeacf1f95c6e62403f86ba3f2ff055898a84
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/215323
Commit-Queue: Gustaf Ullberg <gustaf@webrtc.org>
Reviewed-by: Jesus de Vicente Pena <devicentepena@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33786}
This commit is contained in:
Gustaf Ullberg 2021-04-20 13:48:57 +02:00 committed by Commit Bot
parent 1153974c89
commit 437d129ef5
18 changed files with 140 additions and 58 deletions

View File

@ -109,6 +109,7 @@ struct RTC_EXPORT EchoCanceller3Config {
float default_len = 0.83f;
bool echo_can_saturate = true;
bool bounded_erl = false;
bool erle_onset_compensation_in_dominant_nearend = false;
} ep_strength;
struct EchoAudibility {

View File

@ -253,6 +253,8 @@ void Aec3ConfigFromJsonString(absl::string_view json_string,
ReadParam(section, "default_len", &cfg.ep_strength.default_len);
ReadParam(section, "echo_can_saturate", &cfg.ep_strength.echo_can_saturate);
ReadParam(section, "bounded_erl", &cfg.ep_strength.bounded_erl);
ReadParam(section, "erle_onset_compensation_in_dominant_nearend",
&cfg.ep_strength.erle_onset_compensation_in_dominant_nearend);
}
if (rtc::GetValueFromJsonObject(aec3_root, "echo_audibility", &section)) {
@ -542,8 +544,11 @@ std::string Aec3ConfigToJsonString(const EchoCanceller3Config& config) {
ost << "\"echo_can_saturate\": "
<< (config.ep_strength.echo_can_saturate ? "true" : "false") << ",";
ost << "\"bounded_erl\": "
<< (config.ep_strength.bounded_erl ? "true" : "false");
<< (config.ep_strength.bounded_erl ? "true" : "false") << ",";
ost << "\"erle_onset_compensation_in_dominant_nearend\": "
<< (config.ep_strength.erle_onset_compensation_in_dominant_nearend
? "true"
: "false");
ost << "},";
ost << "\"echo_audibility\": {";

View File

@ -294,7 +294,9 @@ void AecState::Update(
data_dumper_->DumpRaw("aec3_active_render", active_render);
data_dumper_->DumpRaw("aec3_erl", Erl());
data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain());
data_dumper_->DumpRaw("aec3_erle", Erle()[0]);
data_dumper_->DumpRaw("aec3_erle", Erle(/*onset_compensated=*/false)[0]);
data_dumper_->DumpRaw("aec3_erle_onset_compensated",
Erle(/*onset_compensated=*/true)[0]);
data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate());
data_dumper_->DumpRaw("aec3_transparent_mode", TransparentModeActive());
data_dumper_->DumpRaw("aec3_filter_delay",

View File

@ -70,8 +70,9 @@ class AecState {
}
// Returns the ERLE.
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle() const {
return erle_estimator_.Erle();
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle(
bool onset_compensated) const {
return erle_estimator_.Erle(onset_compensated);
}
// Returns the fullband ERLE estimate in log2 units.

View File

@ -182,7 +182,7 @@ void RunNormalUsageTest(size_t num_render_channels,
{
// Note that the render spectrum is built so it does not have energy in
// the odd bands but just in the even bands.
const auto& erle = state.Erle()[0];
const auto& erle = state.Erle(/*onset_compensated=*/true)[0];
EXPECT_EQ(erle[0], erle[1]);
constexpr size_t kLowFrequencyLimit = 32;
for (size_t k = 2; k < kLowFrequencyLimit; k = k + 2) {
@ -210,7 +210,7 @@ void RunNormalUsageTest(size_t num_render_channels,
ASSERT_TRUE(state.UsableLinearEstimate());
{
const auto& erle = state.Erle()[0];
const auto& erle = state.Erle(/*onset_compensated=*/true)[0];
EXPECT_EQ(erle[0], erle[1]);
constexpr size_t kLowFrequencyLimit = 32;
for (size_t k = 1; k < kLowFrequencyLimit; ++k) {

View File

@ -406,6 +406,7 @@ void EchoRemoverImpl::ProcessCapture(
if (capture_output_used_) {
// Estimate the residual echo power.
residual_echo_estimator_.Estimate(aec_state_, *render_buffer, S2_linear, Y2,
suppression_gain_.IsDominantNearend(),
R2);
// Suppressor nearend estimate.

View File

@ -52,8 +52,9 @@ void ErleEstimator::Update(
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
subtractor_spectra,
const std::vector<bool>& converged_filters) {
RTC_DCHECK_EQ(subband_erle_estimator_.Erle().size(), capture_spectra.size());
RTC_DCHECK_EQ(subband_erle_estimator_.Erle().size(),
RTC_DCHECK_EQ(subband_erle_estimator_.Erle(/*onset_compensated=*/true).size(),
capture_spectra.size());
RTC_DCHECK_EQ(subband_erle_estimator_.Erle(/*onset_compensated=*/true).size(),
subtractor_spectra.size());
const auto& X2_reverb = avg_render_spectrum_with_reverb;
const auto& Y2 = capture_spectra;
@ -68,7 +69,9 @@ void ErleEstimator::Update(
if (signal_dependent_erle_estimator_) {
signal_dependent_erle_estimator_->Update(
render_buffer, filter_frequency_responses, X2_reverb, Y2, E2,
subband_erle_estimator_.Erle(), converged_filters);
subband_erle_estimator_.Erle(/*onset_compensated=*/false),
subband_erle_estimator_.Erle(/*onset_compensated=*/true),
converged_filters);
}
fullband_erle_estimator_.Update(X2_reverb, Y2, E2, converged_filters);

View File

@ -55,17 +55,18 @@ class ErleEstimator {
const std::vector<bool>& converged_filters);
// Returns the most recent subband ERLE estimates.
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle() const {
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle(
bool onset_compensated) const {
return signal_dependent_erle_estimator_
? signal_dependent_erle_estimator_->Erle()
: subband_erle_estimator_.Erle();
? signal_dependent_erle_estimator_->Erle(onset_compensated)
: subband_erle_estimator_.Erle(onset_compensated);
}
// Returns the subband ERLE that are estimated during onsets (only used for
// testing).
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> ErleOnsets()
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> ErleDuringOnsets()
const {
return subband_erle_estimator_.ErleOnsets();
return subband_erle_estimator_.ErleDuringOnsets();
}
// Returns the fullband ERLE estimate.

View File

@ -178,8 +178,9 @@ TEST_P(ErleEstimatorMultiChannel, VerifyErleIncreaseAndHold) {
estimator.Update(*render_delay_buffer->GetRenderBuffer(),
filter_frequency_response, X2, Y2, E2, converged_filters);
}
VerifyErle(estimator.Erle(), std::pow(2.f, estimator.FullbandErleLog2()),
config.erle.max_l, config.erle.max_h);
VerifyErle(estimator.Erle(/*onset_compensated=*/true),
std::pow(2.f, estimator.FullbandErleLog2()), config.erle.max_l,
config.erle.max_h);
FormNearendFrame(&x, &X2, E2, Y2);
// Verifies that the ERLE is not immediately decreased during nearend
@ -190,8 +191,9 @@ TEST_P(ErleEstimatorMultiChannel, VerifyErleIncreaseAndHold) {
estimator.Update(*render_delay_buffer->GetRenderBuffer(),
filter_frequency_response, X2, Y2, E2, converged_filters);
}
VerifyErle(estimator.Erle(), std::pow(2.f, estimator.FullbandErleLog2()),
config.erle.max_l, config.erle.max_h);
VerifyErle(estimator.Erle(/*onset_compensated=*/true),
std::pow(2.f, estimator.FullbandErleLog2()), config.erle.max_l,
config.erle.max_h);
}
TEST_P(ErleEstimatorMultiChannel, VerifyErleTrackingOnOnsets) {
@ -253,7 +255,8 @@ TEST_P(ErleEstimatorMultiChannel, VerifyErleTrackingOnOnsets) {
converged_filters);
}
}
VerifyErleBands(estimator.ErleOnsets(), config.erle.min, config.erle.min);
VerifyErleBands(estimator.ErleDuringOnsets(), config.erle.min,
config.erle.min);
FormNearendFrame(&x, &X2, E2, Y2);
for (size_t k = 0; k < 1000; k++) {
estimator.Update(*render_delay_buffer->GetRenderBuffer(),
@ -261,8 +264,9 @@ TEST_P(ErleEstimatorMultiChannel, VerifyErleTrackingOnOnsets) {
}
// Verifies that during ne activity, Erle converges to the Erle for
// onsets.
VerifyErle(estimator.Erle(), std::pow(2.f, estimator.FullbandErleLog2()),
config.erle.min, config.erle.min);
VerifyErle(estimator.Erle(/*onset_compensated=*/true),
std::pow(2.f, estimator.FullbandErleLog2()), config.erle.min,
config.erle.min);
}
} // namespace webrtc

View File

@ -45,6 +45,13 @@ float GetLateReflectionsDefaultModeGain(
return config.default_gain;
}
bool UseErleOnsetCompensationInDominantNearend(
const EchoCanceller3Config::EpStrength& config) {
return config.erle_onset_compensation_in_dominant_nearend ||
field_trial::IsEnabled(
"WebRTC-Aec3UseErleOnsetCompensationInDominantNearend");
}
// Computes the indexes that will be used for computing spectral power over
// the blocks surrounding the delay.
void GetRenderIndexesToAnalyze(
@ -156,7 +163,9 @@ ResidualEchoEstimator::ResidualEchoEstimator(const EchoCanceller3Config& config,
early_reflections_general_gain_(
GetEarlyReflectionsDefaultModeGain(config_.ep_strength)),
late_reflections_general_gain_(
GetLateReflectionsDefaultModeGain(config_.ep_strength)) {
GetLateReflectionsDefaultModeGain(config_.ep_strength)),
erle_onset_compensation_in_dominant_nearend_(
UseErleOnsetCompensationInDominantNearend(config_.ep_strength)) {
Reset();
}
@ -167,6 +176,7 @@ void ResidualEchoEstimator::Estimate(
const RenderBuffer& render_buffer,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> S2_linear,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
bool dominant_nearend,
rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> R2) {
RTC_DCHECK_EQ(R2.size(), Y2.size());
RTC_DCHECK_EQ(R2.size(), S2_linear.size());
@ -185,7 +195,9 @@ void ResidualEchoEstimator::Estimate(
std::copy(Y2[ch].begin(), Y2[ch].end(), R2[ch].begin());
}
} else {
LinearEstimate(S2_linear, aec_state.Erle(), R2);
const bool onset_compensated =
erle_onset_compensation_in_dominant_nearend_ || !dominant_nearend;
LinearEstimate(S2_linear, aec_state.Erle(onset_compensated), R2);
}
AddReverb(ReverbType::kLinear, aec_state, render_buffer, R2);

View File

@ -39,6 +39,7 @@ class ResidualEchoEstimator {
const RenderBuffer& render_buffer,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> S2_linear,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
bool dominant_nearend,
rtc::ArrayView<std::array<float, kFftLengthBy2Plus1>> R2);
private:
@ -68,6 +69,7 @@ class ResidualEchoEstimator {
const float late_reflections_transparent_mode_gain_;
const float early_reflections_general_gain_;
const float late_reflections_general_gain_;
const bool erle_onset_compensation_in_dominant_nearend_;
std::array<float, kFftLengthBy2Plus1> X2_noise_floor_;
std::array<int, kFftLengthBy2Plus1> X2_noise_floor_counter_;
ReverbModel echo_reverb_;

View File

@ -100,7 +100,7 @@ TEST_P(ResidualEchoEstimatorMultiChannel, BasicTest) {
output);
estimator.Estimate(aec_state, *render_delay_buffer->GetRenderBuffer(),
S2_linear, Y2, R2);
S2_linear, Y2, /*dominant_nearend=*/false, R2);
}
}

View File

@ -131,7 +131,9 @@ SignalDependentErleEstimator::SignalDependentErleEstimator(
section_boundaries_blocks_(SetSectionsBoundaries(delay_headroom_blocks_,
num_blocks_,
num_sections_)),
use_onset_detection_(config.erle.onset_detection),
erle_(num_capture_channels),
erle_onset_compensated_(num_capture_channels),
S2_section_accum_(
num_capture_channels,
std::vector<std::array<float, kFftLengthBy2Plus1>>(num_sections_)),
@ -154,6 +156,7 @@ SignalDependentErleEstimator::~SignalDependentErleEstimator() = default;
void SignalDependentErleEstimator::Reset() {
for (size_t ch = 0; ch < erle_.size(); ++ch) {
erle_[ch].fill(min_erle_);
erle_onset_compensated_[ch].fill(min_erle_);
for (auto& erle_estimator : erle_estimators_[ch]) {
erle_estimator.fill(min_erle_);
}
@ -180,6 +183,8 @@ void SignalDependentErleEstimator::Update(
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> average_erle,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
average_erle_onset_compensated,
const std::vector<bool>& converged_filters) {
RTC_DCHECK_GT(num_sections_, 1);
@ -202,6 +207,11 @@ void SignalDependentErleEstimator::Update(
[band_to_subband_[k]];
erle_[ch][k] = rtc::SafeClamp(average_erle[ch][k] * correction_factor,
min_erle_, max_erle_[band_to_subband_[k]]);
if (use_onset_detection_) {
erle_onset_compensated_[ch][k] = rtc::SafeClamp(
average_erle_onset_compensated[ch][k] * correction_factor,
min_erle_, max_erle_[band_to_subband_[k]]);
}
}
}
}

View File

@ -37,8 +37,10 @@ class SignalDependentErleEstimator {
void Reset();
// Returns the Erle per frequency subband.
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle() const {
return erle_;
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle(
bool onset_compensated) const {
return onset_compensated && use_onset_detection_ ? erle_onset_compensated_
: erle_;
}
// Updates the Erle estimate. The Erle that is passed as an input is required
@ -51,6 +53,8 @@ class SignalDependentErleEstimator {
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> average_erle,
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
average_erle_onset_compensated,
const std::vector<bool>& converged_filters);
void Dump(const std::unique_ptr<ApmDataDumper>& data_dumper) const;
@ -83,7 +87,9 @@ class SignalDependentErleEstimator {
const std::array<size_t, kFftLengthBy2Plus1> band_to_subband_;
const std::array<float, kSubbands> max_erle_;
const std::vector<size_t> section_boundaries_blocks_;
const bool use_onset_detection_;
std::vector<std::array<float, kFftLengthBy2Plus1>> erle_;
std::vector<std::array<float, kFftLengthBy2Plus1>> erle_onset_compensated_;
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>>
S2_section_accum_;
std::vector<std::vector<std::array<float, kSubbands>>> erle_estimators_;

View File

@ -172,7 +172,7 @@ TEST_P(SignalDependentErleEstimatorMultiChannel, SweepSettings) {
for (size_t n = 0; n < 10; ++n) {
inputs.Update();
s.Update(inputs.GetRenderBuffer(), inputs.GetH2(), inputs.GetX2(),
inputs.GetY2(), inputs.GetE2(), average_erle,
inputs.GetY2(), inputs.GetE2(), average_erle, average_erle,
inputs.GetConvergedFilters());
}
}
@ -201,7 +201,7 @@ TEST_P(SignalDependentErleEstimatorMultiChannel, LongerRun) {
for (size_t n = 0; n < 200; ++n) {
inputs.Update();
s.Update(inputs.GetRenderBuffer(), inputs.GetH2(), inputs.GetX2(),
inputs.GetY2(), inputs.GetE2(), average_erle,
inputs.GetY2(), inputs.GetE2(), average_erle, average_erle,
inputs.GetConvergedFilters());
}
}

View File

@ -48,7 +48,8 @@ SubbandErleEstimator::SubbandErleEstimator(const EchoCanceller3Config& config,
use_min_erle_during_onsets_(EnableMinErleDuringOnsets()),
accum_spectra_(num_capture_channels),
erle_(num_capture_channels),
erle_onsets_(num_capture_channels),
erle_onset_compensated_(num_capture_channels),
erle_during_onsets_(num_capture_channels),
coming_onset_(num_capture_channels),
hold_counters_(num_capture_channels) {
Reset();
@ -57,11 +58,11 @@ SubbandErleEstimator::SubbandErleEstimator(const EchoCanceller3Config& config,
SubbandErleEstimator::~SubbandErleEstimator() = default;
void SubbandErleEstimator::Reset() {
for (auto& erle : erle_) {
erle.fill(min_erle_);
}
for (size_t ch = 0; ch < erle_onsets_.size(); ++ch) {
erle_onsets_[ch].fill(min_erle_);
const size_t num_capture_channels = erle_.size();
for (size_t ch = 0; ch < num_capture_channels; ++ch) {
erle_[ch].fill(min_erle_);
erle_onset_compensated_[ch].fill(min_erle_);
erle_during_onsets_[ch].fill(min_erle_);
coming_onset_[ch].fill(true);
hold_counters_[ch].fill(0);
}
@ -80,15 +81,21 @@ void SubbandErleEstimator::Update(
DecreaseErlePerBandForLowRenderSignals();
}
for (auto& erle : erle_) {
const size_t num_capture_channels = erle_.size();
for (size_t ch = 0; ch < num_capture_channels; ++ch) {
auto& erle = erle_[ch];
erle[0] = erle[1];
erle[kFftLengthBy2] = erle[kFftLengthBy2 - 1];
auto& erle_oc = erle_onset_compensated_[ch];
erle_oc[0] = erle_oc[1];
erle_oc[kFftLengthBy2] = erle_oc[kFftLengthBy2 - 1];
}
}
void SubbandErleEstimator::Dump(
const std::unique_ptr<ApmDataDumper>& data_dumper) const {
data_dumper->DumpRaw("aec3_erle_onset", ErleOnsets()[0]);
data_dumper->DumpRaw("aec3_erle_onset", ErleDuringOnsets()[0]);
}
void SubbandErleEstimator::UpdateBands(
@ -102,13 +109,16 @@ void SubbandErleEstimator::UpdateBands(
continue;
}
if (accum_spectra_.num_points[ch] != kPointsToAccumulate) {
continue;
}
std::array<float, kFftLengthBy2> new_erle;
std::array<bool, kFftLengthBy2> is_erle_updated;
is_erle_updated.fill(false);
for (size_t k = 1; k < kFftLengthBy2; ++k) {
if (accum_spectra_.num_points[ch] == kPointsToAccumulate &&
accum_spectra_.E2[ch][k] > 0.f) {
if (accum_spectra_.E2[ch][k] > 0.f) {
new_erle[k] = accum_spectra_.Y2[ch][k] / accum_spectra_.E2[ch][k];
is_erle_updated[k] = true;
}
@ -120,10 +130,11 @@ void SubbandErleEstimator::UpdateBands(
if (coming_onset_[ch][k]) {
coming_onset_[ch][k] = false;
if (!use_min_erle_during_onsets_) {
float alpha = new_erle[k] < erle_onsets_[ch][k] ? 0.3f : 0.15f;
erle_onsets_[ch][k] = rtc::SafeClamp(
erle_onsets_[ch][k] +
alpha * (new_erle[k] - erle_onsets_[ch][k]),
float alpha =
new_erle[k] < erle_during_onsets_[ch][k] ? 0.3f : 0.15f;
erle_during_onsets_[ch][k] = rtc::SafeClamp(
erle_during_onsets_[ch][k] +
alpha * (new_erle[k] - erle_during_onsets_[ch][k]),
min_erle_, max_erle_[k]);
}
}
@ -132,15 +143,26 @@ void SubbandErleEstimator::UpdateBands(
}
}
auto update_erle_band = [](float& erle, float new_erle,
bool low_render_energy, float min_erle,
float max_erle) {
float alpha = 0.05f;
if (new_erle < erle) {
alpha = low_render_energy ? 0.f : 0.1f;
}
erle =
rtc::SafeClamp(erle + alpha * (new_erle - erle), min_erle, max_erle);
};
for (size_t k = 1; k < kFftLengthBy2; ++k) {
if (is_erle_updated[k]) {
float alpha = 0.05f;
if (new_erle[k] < erle_[ch][k]) {
alpha = accum_spectra_.low_render_energy[ch][k] ? 0.f : 0.1f;
const bool low_render_energy = accum_spectra_.low_render_energy[ch][k];
update_erle_band(erle_[ch][k], new_erle[k], low_render_energy,
min_erle_, max_erle_[k]);
if (use_onset_detection_) {
update_erle_band(erle_onset_compensated_[ch][k], new_erle[k],
low_render_energy, min_erle_, max_erle_[k]);
}
erle_[ch][k] =
rtc::SafeClamp(erle_[ch][k] + alpha * (new_erle[k] - erle_[ch][k]),
min_erle_, max_erle_[k]);
}
}
}
@ -153,9 +175,11 @@ void SubbandErleEstimator::DecreaseErlePerBandForLowRenderSignals() {
--hold_counters_[ch][k];
if (hold_counters_[ch][k] <=
(kBlocksForOnsetDetection - kBlocksToHoldErle)) {
if (erle_[ch][k] > erle_onsets_[ch][k]) {
erle_[ch][k] = std::max(erle_onsets_[ch][k], 0.97f * erle_[ch][k]);
RTC_DCHECK_LE(min_erle_, erle_[ch][k]);
if (erle_onset_compensated_[ch][k] > erle_during_onsets_[ch][k]) {
erle_onset_compensated_[ch][k] =
std::max(erle_during_onsets_[ch][k],
0.97f * erle_onset_compensated_[ch][k]);
RTC_DCHECK_LE(min_erle_, erle_onset_compensated_[ch][k]);
}
if (hold_counters_[ch][k] <= 0) {
coming_onset_[ch][k] = true;
@ -167,7 +191,7 @@ void SubbandErleEstimator::DecreaseErlePerBandForLowRenderSignals() {
}
void SubbandErleEstimator::ResetAccumulatedSpectra() {
for (size_t ch = 0; ch < erle_onsets_.size(); ++ch) {
for (size_t ch = 0; ch < erle_during_onsets_.size(); ++ch) {
accum_spectra_.Y2[ch].fill(0.f);
accum_spectra_.E2[ch].fill(0.f);
accum_spectra_.num_points[ch] = 0;

View File

@ -41,14 +41,16 @@ class SubbandErleEstimator {
const std::vector<bool>& converged_filters);
// Returns the ERLE estimate.
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle() const {
return erle_;
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle(
bool onset_compensated) const {
return onset_compensated && use_onset_detection_ ? erle_onset_compensated_
: erle_;
}
// Returns the ERLE estimate at onsets (only used for testing).
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> ErleOnsets()
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> ErleDuringOnsets()
const {
return erle_onsets_;
return erle_during_onsets_;
}
void Dump(const std::unique_ptr<ApmDataDumper>& data_dumper) const;
@ -82,8 +84,12 @@ class SubbandErleEstimator {
const std::array<float, kFftLengthBy2Plus1> max_erle_;
const bool use_min_erle_during_onsets_;
AccumulatedSpectra accum_spectra_;
// ERLE without special handling of render onsets.
std::vector<std::array<float, kFftLengthBy2Plus1>> erle_;
std::vector<std::array<float, kFftLengthBy2Plus1>> erle_onsets_;
// ERLE lowered during render onsets.
std::vector<std::array<float, kFftLengthBy2Plus1>> erle_onset_compensated_;
// Estimation of ERLE during render onsets.
std::vector<std::array<float, kFftLengthBy2Plus1>> erle_during_onsets_;
std::vector<std::array<bool, kFftLengthBy2Plus1>> coming_onset_;
std::vector<std::array<int, kFftLengthBy2Plus1>> hold_counters_;
};

View File

@ -51,6 +51,10 @@ class SuppressionGain {
float* high_bands_gain,
std::array<float, kFftLengthBy2Plus1>* low_band_gain);
bool IsDominantNearend() {
return dominant_nearend_detector_->IsNearendState();
}
// Toggles the usage of the initial state.
void SetInitialState(bool state);