pre echo delay: adding different options for detecting pre echoes.
Bug: webrtc:14205 Change-Id: I9de13c8525914278a2961bd1193b1ce2472c8c02 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280900 Reviewed-by: Per Åhgren <peah@webrtc.org> Commit-Queue: Jesus de Vicente Pena <devicentepena@webrtc.org> Reviewed-by: Lionel Koenig <lionelk@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38511}
This commit is contained in:
committed by
WebRTC LUCI CQ
parent
f6e48bf4d1
commit
b24ebc535b
@ -228,6 +228,7 @@ rtc_source_set("matched_filter") {
|
|||||||
deps = [
|
deps = [
|
||||||
":aec3_common",
|
":aec3_common",
|
||||||
"../../../api:array_view",
|
"../../../api:array_view",
|
||||||
|
"../../../rtc_base:gtest_prod",
|
||||||
"../../../rtc_base/system:arch",
|
"../../../rtc_base/system:arch",
|
||||||
]
|
]
|
||||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||||
|
|||||||
@ -29,7 +29,9 @@
|
|||||||
#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
|
#include "modules/audio_processing/aec3/downsampled_render_buffer.h"
|
||||||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
|
#include "rtc_base/experiments/field_trial_parser.h"
|
||||||
#include "rtc_base/logging.h"
|
#include "rtc_base/logging.h"
|
||||||
|
#include "system_wrappers/include/field_trial.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -53,23 +55,89 @@ void UpdateAccumulatedError(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ComputePreEchoLag(const rtc::ArrayView<float> accumulated_error,
|
size_t ComputePreEchoLag(
|
||||||
size_t lag,
|
const webrtc::MatchedFilter::PreEchoConfiguration& pre_echo_configuration,
|
||||||
size_t alignment_shift_winner) {
|
const rtc::ArrayView<const float> accumulated_error,
|
||||||
|
size_t lag,
|
||||||
|
size_t alignment_shift_winner) {
|
||||||
|
RTC_DCHECK_GE(lag, alignment_shift_winner);
|
||||||
size_t pre_echo_lag_estimate = lag - alignment_shift_winner;
|
size_t pre_echo_lag_estimate = lag - alignment_shift_winner;
|
||||||
size_t maximum_pre_echo_lag =
|
size_t maximum_pre_echo_lag =
|
||||||
std::min(pre_echo_lag_estimate / kAccumulatedErrorSubSampleRate,
|
std::min(pre_echo_lag_estimate / kAccumulatedErrorSubSampleRate,
|
||||||
accumulated_error.size());
|
accumulated_error.size());
|
||||||
for (size_t k = 1; k < maximum_pre_echo_lag; ++k) {
|
switch (pre_echo_configuration.mode) {
|
||||||
if (accumulated_error[k] < 0.5f * accumulated_error[k - 1] &&
|
case 0:
|
||||||
accumulated_error[k] < 0.5f) {
|
// Mode 0: Pre echo lag is defined as the first coefficient with an error
|
||||||
pre_echo_lag_estimate = (k + 1) * kAccumulatedErrorSubSampleRate - 1;
|
// lower than a threshold with a certain decrease slope.
|
||||||
|
for (size_t k = 1; k < maximum_pre_echo_lag; ++k) {
|
||||||
|
if (accumulated_error[k] <
|
||||||
|
pre_echo_configuration.threshold * accumulated_error[k - 1] &&
|
||||||
|
accumulated_error[k] < pre_echo_configuration.threshold) {
|
||||||
|
pre_echo_lag_estimate = (k + 1) * kAccumulatedErrorSubSampleRate - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// Mode 1: Pre echo lag is defined as the first coefficient with an error
|
||||||
|
// lower than a certain threshold.
|
||||||
|
for (size_t k = 0; k < maximum_pre_echo_lag; ++k) {
|
||||||
|
if (accumulated_error[k] < pre_echo_configuration.threshold) {
|
||||||
|
pre_echo_lag_estimate = (k + 1) * kAccumulatedErrorSubSampleRate - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// Mode 2: Pre echo lag is defined as the closest coefficient to the lag
|
||||||
|
// with an error lower than a certain threshold.
|
||||||
|
for (int k = static_cast<int>(maximum_pre_echo_lag) - 1; k >= 0; --k) {
|
||||||
|
if (accumulated_error[k] > pre_echo_configuration.threshold) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pre_echo_lag_estimate = (k + 1) * kAccumulatedErrorSubSampleRate - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
RTC_DCHECK_NOTREACHED();
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return pre_echo_lag_estimate + alignment_shift_winner;
|
return pre_echo_lag_estimate + alignment_shift_winner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
webrtc::MatchedFilter::PreEchoConfiguration FetchPreEchoConfiguration() {
|
||||||
|
float threshold = 0.5f;
|
||||||
|
int mode = 0;
|
||||||
|
const std::string pre_echo_configuration_field_trial =
|
||||||
|
webrtc::field_trial::FindFullName("WebRTC-Aec3PreEchoConfiguration");
|
||||||
|
webrtc::FieldTrialParameter<double> threshold_field_trial_parameter(
|
||||||
|
/*key=*/"threshold", /*default_value=*/threshold);
|
||||||
|
webrtc::FieldTrialParameter<int> mode_field_trial_parameter(
|
||||||
|
/*key=*/"mode", /*default_value=*/mode);
|
||||||
|
webrtc::ParseFieldTrial(
|
||||||
|
{&threshold_field_trial_parameter, &mode_field_trial_parameter},
|
||||||
|
pre_echo_configuration_field_trial);
|
||||||
|
float threshold_read =
|
||||||
|
static_cast<float>(threshold_field_trial_parameter.Get());
|
||||||
|
int mode_read = mode_field_trial_parameter.Get();
|
||||||
|
if (threshold_read < 1.0f && threshold_read > 0.0f) {
|
||||||
|
threshold = threshold_read;
|
||||||
|
} else {
|
||||||
|
RTC_LOG(LS_ERROR)
|
||||||
|
<< "AEC3: Pre echo configuration: wrong input, threshold = "
|
||||||
|
<< threshold_read << ".";
|
||||||
|
}
|
||||||
|
if (mode_read >= 0 && mode_read <= 3) {
|
||||||
|
mode = mode_read;
|
||||||
|
} else {
|
||||||
|
RTC_LOG(LS_ERROR) << "AEC3: Pre echo configuration: wrong input, mode = "
|
||||||
|
<< mode_read << ".";
|
||||||
|
}
|
||||||
|
RTC_LOG(LS_INFO) << "AEC3: Pre echo configuration: threshold = " << threshold
|
||||||
|
<< ", mode = " << mode << ".";
|
||||||
|
return {.threshold = threshold, .mode = mode};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -612,7 +680,8 @@ MatchedFilter::MatchedFilter(ApmDataDumper* data_dumper,
|
|||||||
smoothing_fast_(smoothing_fast),
|
smoothing_fast_(smoothing_fast),
|
||||||
smoothing_slow_(smoothing_slow),
|
smoothing_slow_(smoothing_slow),
|
||||||
matching_filter_threshold_(matching_filter_threshold),
|
matching_filter_threshold_(matching_filter_threshold),
|
||||||
detect_pre_echo_(detect_pre_echo) {
|
detect_pre_echo_(detect_pre_echo),
|
||||||
|
pre_echo_config_(FetchPreEchoConfiguration()) {
|
||||||
RTC_DCHECK(data_dumper);
|
RTC_DCHECK(data_dumper);
|
||||||
RTC_DCHECK_LT(0, window_size_sub_blocks);
|
RTC_DCHECK_LT(0, window_size_sub_blocks);
|
||||||
RTC_DCHECK((kBlockSize % sub_block_size) == 0);
|
RTC_DCHECK((kBlockSize % sub_block_size) == 0);
|
||||||
@ -753,7 +822,8 @@ void MatchedFilter::Update(const DownsampledRenderBuffer& render_buffer,
|
|||||||
1.0f / error_sum_anchor);
|
1.0f / error_sum_anchor);
|
||||||
}
|
}
|
||||||
reported_lag_estimate_->pre_echo_lag = ComputePreEchoLag(
|
reported_lag_estimate_->pre_echo_lag = ComputePreEchoLag(
|
||||||
accumulated_error_[winner_index], winner_lag_.value(),
|
pre_echo_config_, accumulated_error_[winner_index],
|
||||||
|
winner_lag_.value(),
|
||||||
winner_index * filter_intra_lag_shift_ /*alignment_shift_winner*/);
|
winner_index * filter_intra_lag_shift_ /*alignment_shift_winner*/);
|
||||||
}
|
}
|
||||||
last_detected_best_lag_filter_ = winner_index;
|
last_detected_best_lag_filter_ = winner_index;
|
||||||
@ -794,9 +864,10 @@ void MatchedFilter::Dump() {
|
|||||||
"aec3_correlator_error_" + std::to_string(n) + "_h";
|
"aec3_correlator_error_" + std::to_string(n) + "_h";
|
||||||
data_dumper_->DumpRaw(dumper_error.c_str(), accumulated_error_[n]);
|
data_dumper_->DumpRaw(dumper_error.c_str(), accumulated_error_[n]);
|
||||||
|
|
||||||
size_t pre_echo_lag = ComputePreEchoLag(
|
size_t pre_echo_lag =
|
||||||
accumulated_error_[n], lag_estimate + n * filter_intra_lag_shift_,
|
ComputePreEchoLag(pre_echo_config_, accumulated_error_[n],
|
||||||
n * filter_intra_lag_shift_);
|
lag_estimate + n * filter_intra_lag_shift_,
|
||||||
|
n * filter_intra_lag_shift_);
|
||||||
std::string dumper_pre_lag =
|
std::string dumper_pre_lag =
|
||||||
"aec3_correlator_pre_echo_lag_" + std::to_string(n);
|
"aec3_correlator_pre_echo_lag_" + std::to_string(n);
|
||||||
data_dumper_->DumpRaw(dumper_pre_lag.c_str(), pre_echo_lag);
|
data_dumper_->DumpRaw(dumper_pre_lag.c_str(), pre_echo_lag);
|
||||||
|
|||||||
@ -18,6 +18,7 @@
|
|||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "api/array_view.h"
|
#include "api/array_view.h"
|
||||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||||
|
#include "rtc_base/gtest_prod_util.h"
|
||||||
#include "rtc_base/system/arch.h"
|
#include "rtc_base/system/arch.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -105,6 +106,11 @@ class MatchedFilter {
|
|||||||
size_t pre_echo_lag = 0;
|
size_t pre_echo_lag = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PreEchoConfiguration {
|
||||||
|
const float threshold;
|
||||||
|
const int mode;
|
||||||
|
};
|
||||||
|
|
||||||
MatchedFilter(ApmDataDumper* data_dumper,
|
MatchedFilter(ApmDataDumper* data_dumper,
|
||||||
Aec3Optimization optimization,
|
Aec3Optimization optimization,
|
||||||
size_t sub_block_size,
|
size_t sub_block_size,
|
||||||
@ -147,6 +153,15 @@ class MatchedFilter {
|
|||||||
size_t downsampling_factor) const;
|
size_t downsampling_factor) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
FRIEND_TEST_ALL_PREFIXES(MatchedFilterFieldTrialTest,
|
||||||
|
PreEchoConfigurationTest);
|
||||||
|
FRIEND_TEST_ALL_PREFIXES(MatchedFilterFieldTrialTest,
|
||||||
|
WrongPreEchoConfigurationTest);
|
||||||
|
|
||||||
|
// Only for testing. Gets the pre echo detection configuration.
|
||||||
|
const PreEchoConfiguration& GetPreEchoConfiguration() const {
|
||||||
|
return pre_echo_config_;
|
||||||
|
}
|
||||||
void Dump();
|
void Dump();
|
||||||
|
|
||||||
ApmDataDumper* const data_dumper_;
|
ApmDataDumper* const data_dumper_;
|
||||||
@ -166,6 +181,7 @@ class MatchedFilter {
|
|||||||
const float smoothing_slow_;
|
const float smoothing_slow_;
|
||||||
const float matching_filter_threshold_;
|
const float matching_filter_threshold_;
|
||||||
const bool detect_pre_echo_;
|
const bool detect_pre_echo_;
|
||||||
|
const PreEchoConfiguration pre_echo_config_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
#include "rtc_base/random.h"
|
#include "rtc_base/random.h"
|
||||||
#include "rtc_base/strings/string_builder.h"
|
#include "rtc_base/strings/string_builder.h"
|
||||||
#include "system_wrappers/include/cpu_features_wrapper.h"
|
#include "system_wrappers/include/cpu_features_wrapper.h"
|
||||||
|
#include "test/field_trial.h"
|
||||||
#include "test/gtest.h"
|
#include "test/gtest.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -555,4 +556,57 @@ INSTANTIATE_TEST_SUITE_P(_,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace aec3
|
} // namespace aec3
|
||||||
|
|
||||||
|
TEST(MatchedFilterFieldTrialTest, PreEchoConfigurationTest) {
|
||||||
|
float threshold_in = 0.1f;
|
||||||
|
int mode_in = 2;
|
||||||
|
rtc::StringBuilder field_trial_name;
|
||||||
|
field_trial_name << "WebRTC-Aec3PreEchoConfiguration/threshold:"
|
||||||
|
<< threshold_in << ",mode:" << mode_in << "/";
|
||||||
|
webrtc::test::ScopedFieldTrials field_trials(field_trial_name.str());
|
||||||
|
ApmDataDumper data_dumper(0);
|
||||||
|
EchoCanceller3Config config;
|
||||||
|
MatchedFilter matched_filter(
|
||||||
|
&data_dumper, DetectOptimization(),
|
||||||
|
kBlockSize / config.delay.down_sampling_factor,
|
||||||
|
aec3::kWindowSizeSubBlocks, aec3::kNumMatchedFilters,
|
||||||
|
aec3::kAlignmentShiftSubBlocks,
|
||||||
|
config.render_levels.poor_excitation_render_limit,
|
||||||
|
config.delay.delay_estimate_smoothing,
|
||||||
|
config.delay.delay_estimate_smoothing_delay_found,
|
||||||
|
config.delay.delay_candidate_detection_threshold,
|
||||||
|
config.delay.detect_pre_echo);
|
||||||
|
|
||||||
|
auto& pre_echo_config = matched_filter.GetPreEchoConfiguration();
|
||||||
|
EXPECT_EQ(pre_echo_config.threshold, threshold_in);
|
||||||
|
EXPECT_EQ(pre_echo_config.mode, mode_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MatchedFilterFieldTrialTest, WrongPreEchoConfigurationTest) {
|
||||||
|
constexpr float kDefaultThreshold = 0.5f;
|
||||||
|
constexpr int kDefaultMode = 0;
|
||||||
|
float threshold_in = -0.1f;
|
||||||
|
int mode_in = 5;
|
||||||
|
rtc::StringBuilder field_trial_name;
|
||||||
|
field_trial_name << "WebRTC-Aec3PreEchoConfiguration/threshold:"
|
||||||
|
<< threshold_in << ",mode:" << mode_in << "/";
|
||||||
|
webrtc::test::ScopedFieldTrials field_trials(field_trial_name.str());
|
||||||
|
ApmDataDumper data_dumper(0);
|
||||||
|
EchoCanceller3Config config;
|
||||||
|
MatchedFilter matched_filter(
|
||||||
|
&data_dumper, DetectOptimization(),
|
||||||
|
kBlockSize / config.delay.down_sampling_factor,
|
||||||
|
aec3::kWindowSizeSubBlocks, aec3::kNumMatchedFilters,
|
||||||
|
aec3::kAlignmentShiftSubBlocks,
|
||||||
|
config.render_levels.poor_excitation_render_limit,
|
||||||
|
config.delay.delay_estimate_smoothing,
|
||||||
|
config.delay.delay_estimate_smoothing_delay_found,
|
||||||
|
config.delay.delay_candidate_detection_threshold,
|
||||||
|
config.delay.detect_pre_echo);
|
||||||
|
|
||||||
|
auto& pre_echo_config = matched_filter.GetPreEchoConfiguration();
|
||||||
|
EXPECT_EQ(pre_echo_config.threshold, kDefaultThreshold);
|
||||||
|
EXPECT_EQ(pre_echo_config.mode, kDefaultMode);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|||||||
Reference in New Issue
Block a user