mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-14 14:20:45 +01:00
AEC3: adding a milder exponential decay parameter that is used for dominant nearend regions when enabled.
Bug: webrtc:13143 Change-Id: Iedc6ff39ed5c7cd372b54a82c86354957c8852de Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/231131 Commit-Queue: Per Åhgren <peah@webrtc.org> Reviewed-by: Per Åhgren <peah@webrtc.org> Cr-Commit-Position: refs/heads/main@{#34947}
This commit is contained in:
parent
634f27950e
commit
7d0203c723
15 changed files with 244 additions and 131 deletions
|
@ -166,6 +166,7 @@ bool EchoCanceller3Config::Validate(EchoCanceller3Config* config) {
|
||||||
|
|
||||||
res = res & Limit(&c->ep_strength.default_gain, 0.f, 1000000.f);
|
res = res & Limit(&c->ep_strength.default_gain, 0.f, 1000000.f);
|
||||||
res = res & Limit(&c->ep_strength.default_len, -1.f, 1.f);
|
res = res & Limit(&c->ep_strength.default_len, -1.f, 1.f);
|
||||||
|
res = res & Limit(&c->ep_strength.nearend_len, -1.0f, 1.0f);
|
||||||
|
|
||||||
res =
|
res =
|
||||||
res & Limit(&c->echo_audibility.low_render_limit, 0.f, 32768.f * 32768.f);
|
res & Limit(&c->echo_audibility.low_render_limit, 0.f, 32768.f * 32768.f);
|
||||||
|
|
|
@ -108,6 +108,7 @@ struct RTC_EXPORT EchoCanceller3Config {
|
||||||
struct EpStrength {
|
struct EpStrength {
|
||||||
float default_gain = 1.f;
|
float default_gain = 1.f;
|
||||||
float default_len = 0.83f;
|
float default_len = 0.83f;
|
||||||
|
float nearend_len = 0.83f;
|
||||||
bool echo_can_saturate = true;
|
bool echo_can_saturate = true;
|
||||||
bool bounded_erl = false;
|
bool bounded_erl = false;
|
||||||
bool erle_onset_compensation_in_dominant_nearend = false;
|
bool erle_onset_compensation_in_dominant_nearend = false;
|
||||||
|
|
|
@ -259,6 +259,7 @@ void Aec3ConfigFromJsonString(absl::string_view json_string,
|
||||||
if (rtc::GetValueFromJsonObject(aec3_root, "ep_strength", §ion)) {
|
if (rtc::GetValueFromJsonObject(aec3_root, "ep_strength", §ion)) {
|
||||||
ReadParam(section, "default_gain", &cfg.ep_strength.default_gain);
|
ReadParam(section, "default_gain", &cfg.ep_strength.default_gain);
|
||||||
ReadParam(section, "default_len", &cfg.ep_strength.default_len);
|
ReadParam(section, "default_len", &cfg.ep_strength.default_len);
|
||||||
|
ReadParam(section, "nearend_len", &cfg.ep_strength.nearend_len);
|
||||||
ReadParam(section, "echo_can_saturate", &cfg.ep_strength.echo_can_saturate);
|
ReadParam(section, "echo_can_saturate", &cfg.ep_strength.echo_can_saturate);
|
||||||
ReadParam(section, "bounded_erl", &cfg.ep_strength.bounded_erl);
|
ReadParam(section, "bounded_erl", &cfg.ep_strength.bounded_erl);
|
||||||
ReadParam(section, "erle_onset_compensation_in_dominant_nearend",
|
ReadParam(section, "erle_onset_compensation_in_dominant_nearend",
|
||||||
|
@ -560,6 +561,7 @@ std::string Aec3ConfigToJsonString(const EchoCanceller3Config& config) {
|
||||||
ost << "\"ep_strength\": {";
|
ost << "\"ep_strength\": {";
|
||||||
ost << "\"default_gain\": " << config.ep_strength.default_gain << ",";
|
ost << "\"default_gain\": " << config.ep_strength.default_gain << ",";
|
||||||
ost << "\"default_len\": " << config.ep_strength.default_len << ",";
|
ost << "\"default_len\": " << config.ep_strength.default_len << ",";
|
||||||
|
ost << "\"nearend_len\": " << config.ep_strength.nearend_len << ",";
|
||||||
ost << "\"echo_can_saturate\": "
|
ost << "\"echo_can_saturate\": "
|
||||||
<< (config.ep_strength.echo_can_saturate ? "true" : "false") << ",";
|
<< (config.ep_strength.echo_can_saturate ? "true" : "false") << ",";
|
||||||
ost << "\"bounded_erl\": "
|
ost << "\"bounded_erl\": "
|
||||||
|
|
|
@ -37,6 +37,8 @@ TEST(EchoCanceller3JsonHelpers, ToStringAndParseJson) {
|
||||||
// Expect unchanged values to remain default.
|
// Expect unchanged values to remain default.
|
||||||
EXPECT_EQ(cfg.ep_strength.default_len,
|
EXPECT_EQ(cfg.ep_strength.default_len,
|
||||||
cfg_transformed.ep_strength.default_len);
|
cfg_transformed.ep_strength.default_len);
|
||||||
|
EXPECT_EQ(cfg.ep_strength.nearend_len,
|
||||||
|
cfg_transformed.ep_strength.nearend_len);
|
||||||
EXPECT_EQ(cfg.suppressor.normal_tuning.mask_lf.enr_suppress,
|
EXPECT_EQ(cfg.suppressor.normal_tuning.mask_lf.enr_suppress,
|
||||||
cfg_transformed.suppressor.normal_tuning.mask_lf.enr_suppress);
|
cfg_transformed.suppressor.normal_tuning.mask_lf.enr_suppress);
|
||||||
|
|
||||||
|
|
|
@ -229,8 +229,9 @@ void AecState::Update(
|
||||||
std::array<float, kFftLengthBy2Plus1> avg_render_spectrum_with_reverb;
|
std::array<float, kFftLengthBy2Plus1> avg_render_spectrum_with_reverb;
|
||||||
|
|
||||||
ComputeAvgRenderReverb(render_buffer.GetSpectrumBuffer(),
|
ComputeAvgRenderReverb(render_buffer.GetSpectrumBuffer(),
|
||||||
delay_state_.MinDirectPathFilterDelay(), ReverbDecay(),
|
delay_state_.MinDirectPathFilterDelay(),
|
||||||
&avg_render_reverb_, avg_render_spectrum_with_reverb);
|
ReverbDecay(/*mild=*/false), &avg_render_reverb_,
|
||||||
|
avg_render_spectrum_with_reverb);
|
||||||
|
|
||||||
if (config_.echo_audibility.use_stationarity_properties) {
|
if (config_.echo_audibility.use_stationarity_properties) {
|
||||||
// Update the echo audibility evaluator.
|
// Update the echo audibility evaluator.
|
||||||
|
|
|
@ -116,8 +116,12 @@ class AecState {
|
||||||
// Takes appropriate action at an echo path change.
|
// Takes appropriate action at an echo path change.
|
||||||
void HandleEchoPathChange(const EchoPathVariability& echo_path_variability);
|
void HandleEchoPathChange(const EchoPathVariability& echo_path_variability);
|
||||||
|
|
||||||
// Returns the decay factor for the echo reverberation.
|
// Returns the decay factor for the echo reverberation. The parameter `mild`
|
||||||
float ReverbDecay() const { return reverb_model_estimator_.ReverbDecay(); }
|
// indicates which exponential decay to return. The default one or a milder
|
||||||
|
// one that can be used during nearend regions.
|
||||||
|
float ReverbDecay(bool mild) const {
|
||||||
|
return reverb_model_estimator_.ReverbDecay(mild);
|
||||||
|
}
|
||||||
|
|
||||||
// Return the frequency response of the reverberant echo.
|
// Return the frequency response of the reverberant echo.
|
||||||
rtc::ArrayView<const float> GetReverbFrequencyResponse() const {
|
rtc::ArrayView<const float> GetReverbFrequencyResponse() const {
|
||||||
|
|
|
@ -267,20 +267,23 @@ EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) {
|
||||||
adjusted_cfg.ep_strength.echo_can_saturate = false;
|
adjusted_cfg.ep_strength.echo_can_saturate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field_trial::IsEnabled("WebRTC-Aec3UseDot2ReverbDefaultLen")) {
|
const std::string use_nearend_reverb_len_tunings =
|
||||||
adjusted_cfg.ep_strength.default_len = 0.2f;
|
field_trial::FindFullName("WebRTC-Aec3UseNearendReverbLen");
|
||||||
} else if (field_trial::IsEnabled("WebRTC-Aec3UseDot3ReverbDefaultLen")) {
|
FieldTrialParameter<double> nearend_reverb_default_len(
|
||||||
adjusted_cfg.ep_strength.default_len = 0.3f;
|
"default_len", adjusted_cfg.ep_strength.default_len);
|
||||||
} else if (field_trial::IsEnabled("WebRTC-Aec3UseDot4ReverbDefaultLen")) {
|
FieldTrialParameter<double> nearend_reverb_nearend_len(
|
||||||
adjusted_cfg.ep_strength.default_len = 0.4f;
|
"nearend_len", adjusted_cfg.ep_strength.nearend_len);
|
||||||
} else if (field_trial::IsEnabled("WebRTC-Aec3UseDot5ReverbDefaultLen")) {
|
|
||||||
adjusted_cfg.ep_strength.default_len = 0.5f;
|
ParseFieldTrial({&nearend_reverb_default_len, &nearend_reverb_nearend_len},
|
||||||
} else if (field_trial::IsEnabled("WebRTC-Aec3UseDot6ReverbDefaultLen")) {
|
use_nearend_reverb_len_tunings);
|
||||||
adjusted_cfg.ep_strength.default_len = 0.6f;
|
float default_len = static_cast<float>(nearend_reverb_default_len.Get());
|
||||||
} else if (field_trial::IsEnabled("WebRTC-Aec3UseDot7ReverbDefaultLen")) {
|
float nearend_len = static_cast<float>(nearend_reverb_nearend_len.Get());
|
||||||
adjusted_cfg.ep_strength.default_len = 0.7f;
|
if (default_len > -1 && default_len < 1 && nearend_len > -1 &&
|
||||||
} else if (field_trial::IsEnabled("WebRTC-Aec3UseDot8ReverbDefaultLen")) {
|
nearend_len < 1) {
|
||||||
adjusted_cfg.ep_strength.default_len = 0.8f;
|
adjusted_cfg.ep_strength.default_len =
|
||||||
|
static_cast<float>(nearend_reverb_default_len.Get());
|
||||||
|
adjusted_cfg.ep_strength.nearend_len =
|
||||||
|
static_cast<float>(nearend_reverb_nearend_len.Get());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (field_trial::IsEnabled("WebRTC-Aec3ShortHeadroomKillSwitch")) {
|
if (field_trial::IsEnabled("WebRTC-Aec3ShortHeadroomKillSwitch")) {
|
||||||
|
@ -459,8 +462,6 @@ EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) {
|
||||||
FieldTrialParameter<int> dominant_nearend_detection_trigger_threshold(
|
FieldTrialParameter<int> dominant_nearend_detection_trigger_threshold(
|
||||||
"dominant_nearend_detection_trigger_threshold",
|
"dominant_nearend_detection_trigger_threshold",
|
||||||
adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold);
|
adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold);
|
||||||
FieldTrialParameter<double> ep_strength_default_len(
|
|
||||||
"ep_strength_default_len", adjusted_cfg.ep_strength.default_len);
|
|
||||||
|
|
||||||
ParseFieldTrial(
|
ParseFieldTrial(
|
||||||
{&nearend_tuning_mask_lf_enr_transparent,
|
{&nearend_tuning_mask_lf_enr_transparent,
|
||||||
|
@ -477,7 +478,7 @@ EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) {
|
||||||
&dominant_nearend_detection_enr_exit_threshold,
|
&dominant_nearend_detection_enr_exit_threshold,
|
||||||
&dominant_nearend_detection_snr_threshold,
|
&dominant_nearend_detection_snr_threshold,
|
||||||
&dominant_nearend_detection_hold_duration,
|
&dominant_nearend_detection_hold_duration,
|
||||||
&dominant_nearend_detection_trigger_threshold, &ep_strength_default_len},
|
&dominant_nearend_detection_trigger_threshold},
|
||||||
suppressor_tuning_override_trial_name);
|
suppressor_tuning_override_trial_name);
|
||||||
|
|
||||||
adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent =
|
adjusted_cfg.suppressor.nearend_tuning.mask_lf.enr_transparent =
|
||||||
|
@ -514,8 +515,6 @@ EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) {
|
||||||
dominant_nearend_detection_hold_duration.Get();
|
dominant_nearend_detection_hold_duration.Get();
|
||||||
adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold =
|
adjusted_cfg.suppressor.dominant_nearend_detection.trigger_threshold =
|
||||||
dominant_nearend_detection_trigger_threshold.Get();
|
dominant_nearend_detection_trigger_threshold.Get();
|
||||||
adjusted_cfg.ep_strength.default_len =
|
|
||||||
static_cast<float>(ep_strength_default_len.Get());
|
|
||||||
|
|
||||||
// Field trial-based overrides of individual suppressor parameters.
|
// Field trial-based overrides of individual suppressor parameters.
|
||||||
RetrieveFieldTrialValue(
|
RetrieveFieldTrialValue(
|
||||||
|
@ -577,15 +576,13 @@ EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) {
|
||||||
"WebRTC-Aec3SuppressorAntiHowlingGainOverride", 0.f, 10.f,
|
"WebRTC-Aec3SuppressorAntiHowlingGainOverride", 0.f, 10.f,
|
||||||
&adjusted_cfg.suppressor.high_bands_suppression.anti_howling_gain);
|
&adjusted_cfg.suppressor.high_bands_suppression.anti_howling_gain);
|
||||||
|
|
||||||
RetrieveFieldTrialValue("WebRTC-Aec3SuppressorEpStrengthDefaultLenOverride",
|
|
||||||
-1.f, 1.f, &adjusted_cfg.ep_strength.default_len);
|
|
||||||
|
|
||||||
// Field trial-based overrides of individual delay estimator parameters.
|
// Field trial-based overrides of individual delay estimator parameters.
|
||||||
RetrieveFieldTrialValue("WebRTC-Aec3DelayEstimateSmoothingOverride", 0.f, 1.f,
|
RetrieveFieldTrialValue("WebRTC-Aec3DelayEstimateSmoothingOverride", 0.f, 1.f,
|
||||||
&adjusted_cfg.delay.delay_estimate_smoothing);
|
&adjusted_cfg.delay.delay_estimate_smoothing);
|
||||||
RetrieveFieldTrialValue(
|
RetrieveFieldTrialValue(
|
||||||
"WebRTC-Aec3DelayEstimateSmoothingDelayFoundOverride", 0.f, 1.f,
|
"WebRTC-Aec3DelayEstimateSmoothingDelayFoundOverride", 0.f, 1.f,
|
||||||
&adjusted_cfg.delay.delay_estimate_smoothing_delay_found);
|
&adjusted_cfg.delay.delay_estimate_smoothing_delay_found);
|
||||||
|
|
||||||
return adjusted_cfg;
|
return adjusted_cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -697,23 +697,6 @@ TEST(EchoCanceller3Messaging, EchoLeakage) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests the parameter functionality for the field trial override for the
|
|
||||||
// default_len parameter.
|
|
||||||
TEST(EchoCanceller3FieldTrials, Aec3SuppressorEpStrengthDefaultLenOverride) {
|
|
||||||
EchoCanceller3Config default_config;
|
|
||||||
EchoCanceller3Config adjusted_config = AdjustConfig(default_config);
|
|
||||||
ASSERT_EQ(default_config.ep_strength.default_len,
|
|
||||||
adjusted_config.ep_strength.default_len);
|
|
||||||
|
|
||||||
webrtc::test::ScopedFieldTrials field_trials(
|
|
||||||
"WebRTC-Aec3SuppressorEpStrengthDefaultLenOverride/-0.02/");
|
|
||||||
adjusted_config = AdjustConfig(default_config);
|
|
||||||
|
|
||||||
ASSERT_NE(default_config.ep_strength.default_len,
|
|
||||||
adjusted_config.ep_strength.default_len);
|
|
||||||
EXPECT_FLOAT_EQ(-0.02f, adjusted_config.ep_strength.default_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests the parameter functionality for the field trial override for the
|
// Tests the parameter functionality for the field trial override for the
|
||||||
// anti-howling gain.
|
// anti-howling gain.
|
||||||
TEST(EchoCanceller3FieldTrials, Aec3SuppressorAntiHowlingGainOverride) {
|
TEST(EchoCanceller3FieldTrials, Aec3SuppressorAntiHowlingGainOverride) {
|
||||||
|
@ -767,7 +750,7 @@ TEST(EchoCanceller3FieldTrials, Aec3SuppressorTuningOverrideAllParams) {
|
||||||
"detection_enr_threshold:1.3,dominant_nearend_detection_enr_exit_"
|
"detection_enr_threshold:1.3,dominant_nearend_detection_enr_exit_"
|
||||||
"threshold:1.4,dominant_nearend_detection_snr_threshold:1.5,dominant_"
|
"threshold:1.4,dominant_nearend_detection_snr_threshold:1.5,dominant_"
|
||||||
"nearend_detection_hold_duration:10,dominant_nearend_detection_trigger_"
|
"nearend_detection_hold_duration:10,dominant_nearend_detection_trigger_"
|
||||||
"threshold:11,ep_strength_default_len:1.6/");
|
"threshold:11/");
|
||||||
|
|
||||||
EchoCanceller3Config default_config;
|
EchoCanceller3Config default_config;
|
||||||
EchoCanceller3Config adjusted_config = AdjustConfig(default_config);
|
EchoCanceller3Config adjusted_config = AdjustConfig(default_config);
|
||||||
|
@ -808,8 +791,6 @@ TEST(EchoCanceller3FieldTrials, Aec3SuppressorTuningOverrideAllParams) {
|
||||||
ASSERT_NE(
|
ASSERT_NE(
|
||||||
adjusted_config.suppressor.dominant_nearend_detection.trigger_threshold,
|
adjusted_config.suppressor.dominant_nearend_detection.trigger_threshold,
|
||||||
default_config.suppressor.dominant_nearend_detection.trigger_threshold);
|
default_config.suppressor.dominant_nearend_detection.trigger_threshold);
|
||||||
ASSERT_NE(adjusted_config.ep_strength.default_len,
|
|
||||||
default_config.ep_strength.default_len);
|
|
||||||
|
|
||||||
EXPECT_FLOAT_EQ(
|
EXPECT_FLOAT_EQ(
|
||||||
adjusted_config.suppressor.nearend_tuning.mask_lf.enr_transparent, 0.1);
|
adjusted_config.suppressor.nearend_tuning.mask_lf.enr_transparent, 0.1);
|
||||||
|
@ -846,7 +827,6 @@ TEST(EchoCanceller3FieldTrials, Aec3SuppressorTuningOverrideAllParams) {
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
adjusted_config.suppressor.dominant_nearend_detection.trigger_threshold,
|
adjusted_config.suppressor.dominant_nearend_detection.trigger_threshold,
|
||||||
11);
|
11);
|
||||||
EXPECT_FLOAT_EQ(adjusted_config.ep_strength.default_len, 1.6);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testing the field trial-based override of the suppressor parameters for
|
// Testing the field trial-based override of the suppressor parameters for
|
||||||
|
@ -900,6 +880,16 @@ TEST(EchoCanceller3FieldTrials, Aec3SuppressorTuningOverrideOneParam) {
|
||||||
0.5);
|
0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Testing the field trial-based that override the exponential decay parameters.
|
||||||
|
TEST(EchoCanceller3FieldTrials, Aec3UseNearendReverb) {
|
||||||
|
webrtc::test::ScopedFieldTrials field_trials(
|
||||||
|
"WebRTC-Aec3UseNearendReverbLen/default_len:0.9,nearend_len:0.8/");
|
||||||
|
EchoCanceller3Config default_config;
|
||||||
|
EchoCanceller3Config adjusted_config = AdjustConfig(default_config);
|
||||||
|
EXPECT_FLOAT_EQ(adjusted_config.ep_strength.default_len, 0.9);
|
||||||
|
EXPECT_FLOAT_EQ(adjusted_config.ep_strength.nearend_len, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||||
|
|
||||||
TEST(EchoCanceller3InputCheckDeathTest, WrongCaptureNumBandsCheckVerification) {
|
TEST(EchoCanceller3InputCheckDeathTest, WrongCaptureNumBandsCheckVerification) {
|
||||||
|
|
|
@ -203,7 +203,8 @@ void ResidualEchoEstimator::Estimate(
|
||||||
LinearEstimate(S2_linear, aec_state.ErleUnbounded(), R2_unbounded);
|
LinearEstimate(S2_linear, aec_state.ErleUnbounded(), R2_unbounded);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateReverb(ReverbType::kLinear, aec_state, render_buffer);
|
UpdateReverb(ReverbType::kLinear, aec_state, render_buffer,
|
||||||
|
dominant_nearend);
|
||||||
AddReverb(R2);
|
AddReverb(R2);
|
||||||
AddReverb(R2_unbounded);
|
AddReverb(R2_unbounded);
|
||||||
} else {
|
} else {
|
||||||
|
@ -240,7 +241,8 @@ void ResidualEchoEstimator::Estimate(
|
||||||
|
|
||||||
if (config_.echo_model.model_reverb_in_nonlinear_mode &&
|
if (config_.echo_model.model_reverb_in_nonlinear_mode &&
|
||||||
!aec_state.TransparentModeActive()) {
|
!aec_state.TransparentModeActive()) {
|
||||||
UpdateReverb(ReverbType::kNonLinear, aec_state, render_buffer);
|
UpdateReverb(ReverbType::kNonLinear, aec_state, render_buffer,
|
||||||
|
dominant_nearend);
|
||||||
AddReverb(R2);
|
AddReverb(R2);
|
||||||
AddReverb(R2_unbounded);
|
AddReverb(R2_unbounded);
|
||||||
}
|
}
|
||||||
|
@ -305,7 +307,8 @@ void ResidualEchoEstimator::UpdateRenderNoisePower(
|
||||||
// Updates the reverb estimation.
|
// Updates the reverb estimation.
|
||||||
void ResidualEchoEstimator::UpdateReverb(ReverbType reverb_type,
|
void ResidualEchoEstimator::UpdateReverb(ReverbType reverb_type,
|
||||||
const AecState& aec_state,
|
const AecState& aec_state,
|
||||||
const RenderBuffer& render_buffer) {
|
const RenderBuffer& render_buffer,
|
||||||
|
bool dominant_nearend) {
|
||||||
// Choose reverb partition based on what type of echo power model is used.
|
// Choose reverb partition based on what type of echo power model is used.
|
||||||
const size_t first_reverb_partition =
|
const size_t first_reverb_partition =
|
||||||
reverb_type == ReverbType::kLinear
|
reverb_type == ReverbType::kLinear
|
||||||
|
@ -330,15 +333,15 @@ void ResidualEchoEstimator::UpdateReverb(ReverbType reverb_type,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the reverb estimate.
|
// Update the reverb estimate.
|
||||||
|
float reverb_decay = aec_state.ReverbDecay(/*mild=*/dominant_nearend);
|
||||||
if (reverb_type == ReverbType::kLinear) {
|
if (reverb_type == ReverbType::kLinear) {
|
||||||
echo_reverb_.UpdateReverb(render_power,
|
echo_reverb_.UpdateReverb(
|
||||||
aec_state.GetReverbFrequencyResponse(),
|
render_power, aec_state.GetReverbFrequencyResponse(), reverb_decay);
|
||||||
aec_state.ReverbDecay());
|
|
||||||
} else {
|
} else {
|
||||||
const float echo_path_gain =
|
const float echo_path_gain =
|
||||||
GetEchoPathGain(aec_state, /*gain_for_early_reflections=*/false);
|
GetEchoPathGain(aec_state, /*gain_for_early_reflections=*/false);
|
||||||
echo_reverb_.UpdateReverbNoFreqShaping(render_power, echo_path_gain,
|
echo_reverb_.UpdateReverbNoFreqShaping(render_power, echo_path_gain,
|
||||||
aec_state.ReverbDecay());
|
reverb_decay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Adds the estimated power of the reverb to the residual echo power.
|
// Adds the estimated power of the reverb to the residual echo power.
|
||||||
|
|
|
@ -56,7 +56,8 @@ class ResidualEchoEstimator {
|
||||||
// Updates the reverb estimation.
|
// Updates the reverb estimation.
|
||||||
void UpdateReverb(ReverbType reverb_type,
|
void UpdateReverb(ReverbType reverb_type,
|
||||||
const AecState& aec_state,
|
const AecState& aec_state,
|
||||||
const RenderBuffer& render_buffer);
|
const RenderBuffer& render_buffer,
|
||||||
|
bool dominant_nearend);
|
||||||
|
|
||||||
// Adds the estimated unmodelled echo power to the residual echo power
|
// Adds the estimated unmodelled echo power to the residual echo power
|
||||||
// estimate.
|
// estimate.
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#include "modules/audio_processing/aec3/residual_echo_estimator.h"
|
#include "modules/audio_processing/aec3/residual_echo_estimator.h"
|
||||||
|
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
#include "api/audio/echo_canceller3_config.h"
|
#include "api/audio/echo_canceller3_config.h"
|
||||||
#include "modules/audio_processing/aec3/aec3_fft.h"
|
#include "modules/audio_processing/aec3/aec3_fft.h"
|
||||||
#include "modules/audio_processing/aec3/aec_state.h"
|
#include "modules/audio_processing/aec3/aec_state.h"
|
||||||
|
@ -21,6 +23,109 @@
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr int kSampleRateHz = 48000;
|
||||||
|
constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
|
||||||
|
constexpr float kEpsilon = 1e-4f;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class ResidualEchoEstimatorTest {
|
||||||
|
public:
|
||||||
|
ResidualEchoEstimatorTest(size_t num_render_channels,
|
||||||
|
size_t num_capture_channels,
|
||||||
|
const EchoCanceller3Config& config)
|
||||||
|
: num_render_channels_(num_render_channels),
|
||||||
|
num_capture_channels_(num_capture_channels),
|
||||||
|
config_(config),
|
||||||
|
estimator_(config_, num_render_channels_),
|
||||||
|
aec_state_(config_, num_capture_channels_),
|
||||||
|
render_delay_buffer_(RenderDelayBuffer::Create(config_,
|
||||||
|
kSampleRateHz,
|
||||||
|
num_render_channels_)),
|
||||||
|
E2_refined_(num_capture_channels_),
|
||||||
|
S2_linear_(num_capture_channels_),
|
||||||
|
Y2_(num_capture_channels_),
|
||||||
|
R2_(num_capture_channels_),
|
||||||
|
R2_unbounded_(num_capture_channels_),
|
||||||
|
x_(kNumBands,
|
||||||
|
std::vector<std::vector<float>>(
|
||||||
|
num_render_channels_,
|
||||||
|
std::vector<float>(kBlockSize, 0.0f))),
|
||||||
|
H2_(num_capture_channels_,
|
||||||
|
std::vector<std::array<float, kFftLengthBy2Plus1>>(10)),
|
||||||
|
h_(num_capture_channels_,
|
||||||
|
std::vector<float>(
|
||||||
|
GetTimeDomainLength(config_.filter.refined.length_blocks),
|
||||||
|
0.0f)),
|
||||||
|
random_generator_(42U),
|
||||||
|
output_(num_capture_channels_) {
|
||||||
|
for (auto& H2_ch : H2_) {
|
||||||
|
for (auto& H2_k : H2_ch) {
|
||||||
|
H2_k.fill(0.01f);
|
||||||
|
}
|
||||||
|
H2_ch[2].fill(10.f);
|
||||||
|
H2_ch[2][0] = 0.1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& subtractor_output : output_) {
|
||||||
|
subtractor_output.Reset();
|
||||||
|
subtractor_output.s_refined.fill(100.f);
|
||||||
|
}
|
||||||
|
y_.fill(0.f);
|
||||||
|
|
||||||
|
constexpr float kLevel = 10.f;
|
||||||
|
for (auto& E2_refined_ch : E2_refined_) {
|
||||||
|
E2_refined_ch.fill(kLevel);
|
||||||
|
}
|
||||||
|
S2_linear_[0].fill(kLevel);
|
||||||
|
for (auto& Y2_ch : Y2_) {
|
||||||
|
Y2_ch.fill(kLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunOneFrame(bool dominant_nearend) {
|
||||||
|
RandomizeSampleVector(&random_generator_, x_[0][0]);
|
||||||
|
render_delay_buffer_->Insert(x_);
|
||||||
|
if (first_frame_) {
|
||||||
|
render_delay_buffer_->Reset();
|
||||||
|
first_frame_ = false;
|
||||||
|
}
|
||||||
|
render_delay_buffer_->PrepareCaptureProcessing();
|
||||||
|
|
||||||
|
aec_state_.Update(delay_estimate_, H2_, h_,
|
||||||
|
*render_delay_buffer_->GetRenderBuffer(), E2_refined_,
|
||||||
|
Y2_, output_);
|
||||||
|
|
||||||
|
estimator_.Estimate(aec_state_, *render_delay_buffer_->GetRenderBuffer(),
|
||||||
|
S2_linear_, Y2_, dominant_nearend, R2_, R2_unbounded_);
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> R2() const {
|
||||||
|
return R2_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const size_t num_render_channels_;
|
||||||
|
const size_t num_capture_channels_;
|
||||||
|
const EchoCanceller3Config& config_;
|
||||||
|
ResidualEchoEstimator estimator_;
|
||||||
|
AecState aec_state_;
|
||||||
|
std::unique_ptr<RenderDelayBuffer> render_delay_buffer_;
|
||||||
|
std::vector<std::array<float, kFftLengthBy2Plus1>> E2_refined_;
|
||||||
|
std::vector<std::array<float, kFftLengthBy2Plus1>> S2_linear_;
|
||||||
|
std::vector<std::array<float, kFftLengthBy2Plus1>> Y2_;
|
||||||
|
std::vector<std::array<float, kFftLengthBy2Plus1>> R2_;
|
||||||
|
std::vector<std::array<float, kFftLengthBy2Plus1>> R2_unbounded_;
|
||||||
|
std::vector<std::vector<std::vector<float>>> x_;
|
||||||
|
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>> H2_;
|
||||||
|
std::vector<std::vector<float>> h_;
|
||||||
|
Random random_generator_;
|
||||||
|
std::vector<SubtractorOutput> output_;
|
||||||
|
std::array<float, kBlockSize> y_;
|
||||||
|
absl::optional<DelayEstimate> delay_estimate_;
|
||||||
|
bool first_frame_ = true;
|
||||||
|
};
|
||||||
|
|
||||||
class ResidualEchoEstimatorMultiChannel
|
class ResidualEchoEstimatorMultiChannel
|
||||||
: public ::testing::Test,
|
: public ::testing::Test,
|
||||||
public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {};
|
public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {};
|
||||||
|
@ -33,77 +138,63 @@ INSTANTIATE_TEST_SUITE_P(MultiChannel,
|
||||||
TEST_P(ResidualEchoEstimatorMultiChannel, BasicTest) {
|
TEST_P(ResidualEchoEstimatorMultiChannel, BasicTest) {
|
||||||
const size_t num_render_channels = std::get<0>(GetParam());
|
const size_t num_render_channels = std::get<0>(GetParam());
|
||||||
const size_t num_capture_channels = std::get<1>(GetParam());
|
const size_t num_capture_channels = std::get<1>(GetParam());
|
||||||
constexpr int kSampleRateHz = 48000;
|
|
||||||
constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
|
|
||||||
|
|
||||||
EchoCanceller3Config config;
|
EchoCanceller3Config config;
|
||||||
ResidualEchoEstimator estimator(config, num_render_channels);
|
ResidualEchoEstimatorTest residual_echo_estimator_test(
|
||||||
AecState aec_state(config, num_capture_channels);
|
num_render_channels, num_capture_channels, config);
|
||||||
std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
|
|
||||||
RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels));
|
|
||||||
|
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> E2_refined(
|
|
||||||
num_capture_channels);
|
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> S2_linear(
|
|
||||||
num_capture_channels);
|
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> Y2(num_capture_channels);
|
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> R2(num_capture_channels);
|
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>> R2_unbounded(
|
|
||||||
num_capture_channels);
|
|
||||||
std::vector<std::vector<std::vector<float>>> x(
|
|
||||||
kNumBands, std::vector<std::vector<float>>(
|
|
||||||
num_render_channels, std::vector<float>(kBlockSize, 0.f)));
|
|
||||||
std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>> H2(
|
|
||||||
num_capture_channels,
|
|
||||||
std::vector<std::array<float, kFftLengthBy2Plus1>>(10));
|
|
||||||
Random random_generator(42U);
|
|
||||||
std::vector<SubtractorOutput> output(num_capture_channels);
|
|
||||||
std::array<float, kBlockSize> y;
|
|
||||||
absl::optional<DelayEstimate> delay_estimate;
|
|
||||||
|
|
||||||
for (auto& H2_ch : H2) {
|
|
||||||
for (auto& H2_k : H2_ch) {
|
|
||||||
H2_k.fill(0.01f);
|
|
||||||
}
|
|
||||||
H2_ch[2].fill(10.f);
|
|
||||||
H2_ch[2][0] = 0.1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::vector<float>> h(
|
|
||||||
num_capture_channels,
|
|
||||||
std::vector<float>(
|
|
||||||
GetTimeDomainLength(config.filter.refined.length_blocks), 0.f));
|
|
||||||
|
|
||||||
for (auto& subtractor_output : output) {
|
|
||||||
subtractor_output.Reset();
|
|
||||||
subtractor_output.s_refined.fill(100.f);
|
|
||||||
}
|
|
||||||
y.fill(0.f);
|
|
||||||
|
|
||||||
constexpr float kLevel = 10.f;
|
|
||||||
for (auto& E2_refined_ch : E2_refined) {
|
|
||||||
E2_refined_ch.fill(kLevel);
|
|
||||||
}
|
|
||||||
S2_linear[0].fill(kLevel);
|
|
||||||
for (auto& Y2_ch : Y2) {
|
|
||||||
Y2_ch.fill(kLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int k = 0; k < 1993; ++k) {
|
for (int k = 0; k < 1993; ++k) {
|
||||||
RandomizeSampleVector(&random_generator, x[0][0]);
|
residual_echo_estimator_test.RunOneFrame(/*dominant_nearend=*/false);
|
||||||
render_delay_buffer->Insert(x);
|
}
|
||||||
if (k == 0) {
|
|
||||||
render_delay_buffer->Reset();
|
|
||||||
}
|
}
|
||||||
render_delay_buffer->PrepareCaptureProcessing();
|
|
||||||
|
|
||||||
aec_state.Update(delay_estimate, H2, h,
|
TEST(ResidualEchoEstimatorMultiChannel, ReverbTest) {
|
||||||
*render_delay_buffer->GetRenderBuffer(), E2_refined, Y2,
|
const size_t num_render_channels = 1;
|
||||||
output);
|
const size_t num_capture_channels = 1;
|
||||||
|
const size_t nFrames = 100;
|
||||||
|
|
||||||
estimator.Estimate(aec_state, *render_delay_buffer->GetRenderBuffer(),
|
EchoCanceller3Config reference_config;
|
||||||
S2_linear, Y2, /*dominant_nearend=*/false, R2,
|
reference_config.ep_strength.default_len = 0.95f;
|
||||||
R2_unbounded);
|
reference_config.ep_strength.nearend_len = 0.95f;
|
||||||
|
EchoCanceller3Config config_use_nearend_len = reference_config;
|
||||||
|
config_use_nearend_len.ep_strength.default_len = 0.95f;
|
||||||
|
config_use_nearend_len.ep_strength.nearend_len = 0.83f;
|
||||||
|
|
||||||
|
ResidualEchoEstimatorTest reference_residual_echo_estimator_test(
|
||||||
|
num_render_channels, num_capture_channels, reference_config);
|
||||||
|
ResidualEchoEstimatorTest use_nearend_len_residual_echo_estimator_test(
|
||||||
|
num_render_channels, num_capture_channels, config_use_nearend_len);
|
||||||
|
|
||||||
|
std::vector<float> acum_energy_reference_R2(num_capture_channels, 0.0f);
|
||||||
|
std::vector<float> acum_energy_R2(num_capture_channels, 0.0f);
|
||||||
|
for (size_t frame = 0; frame < nFrames; ++frame) {
|
||||||
|
bool dominant_nearend = frame <= nFrames / 2 ? false : true;
|
||||||
|
reference_residual_echo_estimator_test.RunOneFrame(dominant_nearend);
|
||||||
|
use_nearend_len_residual_echo_estimator_test.RunOneFrame(dominant_nearend);
|
||||||
|
const auto& reference_R2 = reference_residual_echo_estimator_test.R2();
|
||||||
|
const auto& R2 = use_nearend_len_residual_echo_estimator_test.R2();
|
||||||
|
ASSERT_EQ(reference_R2.size(), R2.size());
|
||||||
|
for (size_t ch = 0; ch < reference_R2.size(); ++ch) {
|
||||||
|
float energy_reference_R2 = std::accumulate(
|
||||||
|
reference_R2[ch].cbegin(), reference_R2[ch].cend(), 0.0f);
|
||||||
|
float energy_R2 = std::accumulate(R2[ch].cbegin(), R2[ch].cend(), 0.0f);
|
||||||
|
if (dominant_nearend) {
|
||||||
|
EXPECT_GE(energy_reference_R2, energy_R2);
|
||||||
|
} else {
|
||||||
|
EXPECT_NEAR(energy_reference_R2, energy_R2, kEpsilon);
|
||||||
|
}
|
||||||
|
acum_energy_reference_R2[ch] += energy_reference_R2;
|
||||||
|
acum_energy_R2[ch] += energy_R2;
|
||||||
|
}
|
||||||
|
if (frame == nFrames / 2 || frame == nFrames - 1) {
|
||||||
|
for (size_t ch = 0; ch < acum_energy_reference_R2.size(); ch++) {
|
||||||
|
if (dominant_nearend) {
|
||||||
|
EXPECT_GT(acum_energy_reference_R2[ch], acum_energy_R2[ch]);
|
||||||
|
} else {
|
||||||
|
EXPECT_NEAR(acum_energy_reference_R2[ch], acum_energy_R2[ch],
|
||||||
|
kEpsilon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,8 @@ ReverbDecayEstimator::ReverbDecayEstimator(const EchoCanceller3Config& config)
|
||||||
late_reverb_start_(kEarlyReverbMinSizeBlocks),
|
late_reverb_start_(kEarlyReverbMinSizeBlocks),
|
||||||
late_reverb_end_(kEarlyReverbMinSizeBlocks),
|
late_reverb_end_(kEarlyReverbMinSizeBlocks),
|
||||||
previous_gains_(config.filter.refined.length_blocks, 0.f),
|
previous_gains_(config.filter.refined.length_blocks, 0.f),
|
||||||
decay_(std::fabs(config.ep_strength.default_len)) {
|
decay_(std::fabs(config.ep_strength.default_len)),
|
||||||
|
mild_decay_(std::fabs(config.ep_strength.nearend_len)) {
|
||||||
RTC_DCHECK_GT(config.filter.refined.length_blocks,
|
RTC_DCHECK_GT(config.filter.refined.length_blocks,
|
||||||
static_cast<size_t>(kEarlyReverbMinSizeBlocks));
|
static_cast<size_t>(kEarlyReverbMinSizeBlocks));
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,15 @@ class ReverbDecayEstimator {
|
||||||
int filter_delay_blocks,
|
int filter_delay_blocks,
|
||||||
bool usable_linear_filter,
|
bool usable_linear_filter,
|
||||||
bool stationary_signal);
|
bool stationary_signal);
|
||||||
// Returns the decay for the exponential model.
|
// Returns the decay for the exponential model. The parameter `mild` indicates
|
||||||
float Decay() const { return decay_; }
|
// which exponential decay to return, the default one or a milder one.
|
||||||
|
float Decay(bool mild) const {
|
||||||
|
if (use_adaptive_echo_decay_) {
|
||||||
|
return decay_;
|
||||||
|
} else {
|
||||||
|
return mild ? mild_decay_ : decay_;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Dumps debug data.
|
// Dumps debug data.
|
||||||
void Dump(ApmDataDumper* data_dumper) const;
|
void Dump(ApmDataDumper* data_dumper) const;
|
||||||
|
|
||||||
|
@ -103,6 +110,7 @@ class ReverbDecayEstimator {
|
||||||
bool estimation_region_identified_ = false;
|
bool estimation_region_identified_ = false;
|
||||||
std::vector<float> previous_gains_;
|
std::vector<float> previous_gains_;
|
||||||
float decay_;
|
float decay_;
|
||||||
|
float mild_decay_;
|
||||||
float tail_gain_ = 0.f;
|
float tail_gain_ = 0.f;
|
||||||
float smoothing_constant_ = 0.f;
|
float smoothing_constant_ = 0.f;
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,9 +43,13 @@ class ReverbModelEstimator {
|
||||||
const std::vector<bool>& usable_linear_estimates,
|
const std::vector<bool>& usable_linear_estimates,
|
||||||
bool stationary_block);
|
bool stationary_block);
|
||||||
|
|
||||||
// Returns the exponential decay of the reverberant echo.
|
// Returns the exponential decay of the reverberant echo. The parameter `mild`
|
||||||
|
// indicates which exponential decay to return, the default one or a milder
|
||||||
|
// one.
|
||||||
// TODO(peah): Correct to properly support multiple channels.
|
// TODO(peah): Correct to properly support multiple channels.
|
||||||
float ReverbDecay() const { return reverb_decay_estimators_[0]->Decay(); }
|
float ReverbDecay(bool mild) const {
|
||||||
|
return reverb_decay_estimators_[0]->Decay(mild);
|
||||||
|
}
|
||||||
|
|
||||||
// Return the frequency response of the reverberant echo.
|
// Return the frequency response of the reverberant echo.
|
||||||
// TODO(peah): Correct to properly support multiple channels.
|
// TODO(peah): Correct to properly support multiple channels.
|
||||||
|
|
|
@ -56,7 +56,9 @@ class ReverbModelEstimatorTest {
|
||||||
CreateImpulseResponseWithDecay();
|
CreateImpulseResponseWithDecay();
|
||||||
}
|
}
|
||||||
void RunEstimator();
|
void RunEstimator();
|
||||||
float GetDecay() { return estimated_decay_; }
|
float GetDecay(bool mild) {
|
||||||
|
return mild ? mild_estimated_decay_ : estimated_decay_;
|
||||||
|
}
|
||||||
float GetTrueDecay() { return kTruePowerDecay; }
|
float GetTrueDecay() { return kTruePowerDecay; }
|
||||||
float GetPowerTailDb() { return 10.f * std::log10(estimated_power_tail_); }
|
float GetPowerTailDb() { return 10.f * std::log10(estimated_power_tail_); }
|
||||||
float GetTruePowerTailDb() { return 10.f * std::log10(true_power_tail_); }
|
float GetTruePowerTailDb() { return 10.f * std::log10(true_power_tail_); }
|
||||||
|
@ -67,6 +69,7 @@ class ReverbModelEstimatorTest {
|
||||||
static constexpr float kTruePowerDecay = 0.5f;
|
static constexpr float kTruePowerDecay = 0.5f;
|
||||||
const EchoCanceller3Config aec3_config_;
|
const EchoCanceller3Config aec3_config_;
|
||||||
float estimated_decay_;
|
float estimated_decay_;
|
||||||
|
float mild_estimated_decay_;
|
||||||
float estimated_power_tail_ = 0.f;
|
float estimated_power_tail_ = 0.f;
|
||||||
float true_power_tail_ = 0.f;
|
float true_power_tail_ = 0.f;
|
||||||
std::vector<std::vector<float>> h_;
|
std::vector<std::vector<float>> h_;
|
||||||
|
@ -121,7 +124,8 @@ void ReverbModelEstimatorTest::RunEstimator() {
|
||||||
estimator.Update(h_, H2_, quality_linear_, filter_delay_blocks,
|
estimator.Update(h_, H2_, quality_linear_, filter_delay_blocks,
|
||||||
usable_linear_estimates, kStationaryBlock);
|
usable_linear_estimates, kStationaryBlock);
|
||||||
}
|
}
|
||||||
estimated_decay_ = estimator.ReverbDecay();
|
estimated_decay_ = estimator.ReverbDecay(/*mild=*/false);
|
||||||
|
mild_estimated_decay_ = estimator.ReverbDecay(/*mild=*/true);
|
||||||
auto freq_resp_tail = estimator.GetReverbFrequencyResponse();
|
auto freq_resp_tail = estimator.GetReverbFrequencyResponse();
|
||||||
estimated_power_tail_ =
|
estimated_power_tail_ =
|
||||||
std::accumulate(freq_resp_tail.begin(), freq_resp_tail.end(), 0.f);
|
std::accumulate(freq_resp_tail.begin(), freq_resp_tail.end(), 0.f);
|
||||||
|
@ -132,7 +136,9 @@ TEST(ReverbModelEstimatorTests, NotChangingDecay) {
|
||||||
for (size_t num_capture_channels : {1, 2, 4, 8}) {
|
for (size_t num_capture_channels : {1, 2, 4, 8}) {
|
||||||
ReverbModelEstimatorTest test(kDefaultDecay, num_capture_channels);
|
ReverbModelEstimatorTest test(kDefaultDecay, num_capture_channels);
|
||||||
test.RunEstimator();
|
test.RunEstimator();
|
||||||
EXPECT_EQ(test.GetDecay(), kDefaultDecay);
|
EXPECT_EQ(test.GetDecay(/*mild=*/false), kDefaultDecay);
|
||||||
|
EXPECT_EQ(test.GetDecay(/*mild=*/true),
|
||||||
|
EchoCanceller3Config().ep_strength.nearend_len);
|
||||||
EXPECT_NEAR(test.GetPowerTailDb(), test.GetTruePowerTailDb(), 5.f);
|
EXPECT_NEAR(test.GetPowerTailDb(), test.GetTruePowerTailDb(), 5.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +148,8 @@ TEST(ReverbModelEstimatorTests, ChangingDecay) {
|
||||||
for (size_t num_capture_channels : {1, 2, 4, 8}) {
|
for (size_t num_capture_channels : {1, 2, 4, 8}) {
|
||||||
ReverbModelEstimatorTest test(kDefaultDecay, num_capture_channels);
|
ReverbModelEstimatorTest test(kDefaultDecay, num_capture_channels);
|
||||||
test.RunEstimator();
|
test.RunEstimator();
|
||||||
EXPECT_NEAR(test.GetDecay(), test.GetTrueDecay(), 0.1);
|
EXPECT_NEAR(test.GetDecay(/*mild=*/false), test.GetTrueDecay(), 0.1f);
|
||||||
|
EXPECT_NEAR(test.GetDecay(/*mild=*/true), test.GetTrueDecay(), 0.1f);
|
||||||
EXPECT_NEAR(test.GetPowerTailDb(), test.GetTruePowerTailDb(), 5.f);
|
EXPECT_NEAR(test.GetPowerTailDb(), test.GetTruePowerTailDb(), 5.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue