audio_processing/aec: Turn SignalBasedDelayCorrection to after 15 seconds

The delay agnostic AEC uses a signal based delay correction method to adjust buffer synchronization between loudspeaker and microphone. On Mac in particular we have seen deviations in UMA stats that point towards an echo already at startup. This is likely due to an early and incorrect correction based on poor audio data.
By waiting 15 seconds before we turn on the ability to correct we can avoid a majority of these.
The reported delay values are in general accurate enough and relying on them in the beginning is fine. The value 15 seconds is chosen because we have seen from UMA data that a significant amount of calls tend to end before 15 seconds when being in the UseDelayAgnosticAEC Finch experiment.

We turn this "feature" on for all platforms but Android, where the reported system delays are inaccurate and we want to take action as soon as possible.
In addition, the set of "good" delay values has been increased from 25% to 75% of the filter length.

BUG=webrtc:3504
R=henrik.lundin@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/50199004

Cr-Commit-Position: refs/heads/master@{#9376}
This commit is contained in:
Bjorn Volcker 2015-06-05 09:40:40 +02:00
parent 85cf3c0794
commit 7dbc076f34
2 changed files with 27 additions and 7 deletions

View File

@ -98,9 +98,13 @@ ALIGN16_BEG const float ALIGN16_END WebRtcAec_overDriveCurve[65] = {
1.9354f, 1.9437f, 1.9520f, 1.9601f, 1.9682f, 1.9763f, 1.9843f, 1.9922f, 1.9354f, 1.9437f, 1.9520f, 1.9601f, 1.9682f, 1.9763f, 1.9843f, 1.9922f,
2.0000f}; 2.0000f};
// TODO(bjornv): These parameters will be tuned. // Delay Agnostic AEC parameters, still under development and may change.
static const float kDelayQualityThresholdMax = 0.07f; static const float kDelayQualityThresholdMax = 0.07f;
static const float kDelayQualityThresholdMin = 0.01f;
static const int kInitialShiftOffset = 5; static const int kInitialShiftOffset = 5;
#if !defined(WEBRTC_ANDROID)
static const int kDelayCorrectionStart = 1500; // 10 ms chunks
#endif
// Target suppression levels for nlp modes. // Target suppression levels for nlp modes.
// log{0.001, 0.00001, 0.00000001} // log{0.001, 0.00001, 0.00000001}
@ -857,6 +861,16 @@ static int SignalBasedDelayCorrection(AecCore* self) {
int delay_correction = 0; int delay_correction = 0;
int last_delay = -2; int last_delay = -2;
assert(self != NULL); assert(self != NULL);
#if !defined(WEBRTC_ANDROID)
// On desktops, turn on correction after |kDelayCorrectionStart| frames. This
// is to let the delay estimation get a chance to converge. Also, if the
// playout audio volume is low (or even muted) the delay estimation can return
// a very large delay, which will break the AEC if it is applied.
if (self->frame_count < kDelayCorrectionStart) {
return 0;
}
#endif
// 1. Check for non-negative delay estimate. Note that the estimates we get // 1. Check for non-negative delay estimate. Note that the estimates we get
// from the delay estimation are not compensated for lookahead. Hence, a // from the delay estimation are not compensated for lookahead. Hence, a
// negative |last_delay| is an invalid one. // negative |last_delay| is an invalid one.
@ -874,11 +888,14 @@ static int SignalBasedDelayCorrection(AecCore* self) {
(WebRtc_last_delay_quality(self->delay_estimator) > (WebRtc_last_delay_quality(self->delay_estimator) >
self->delay_quality_threshold)) { self->delay_quality_threshold)) {
int delay = last_delay - WebRtc_lookahead(self->delay_estimator); int delay = last_delay - WebRtc_lookahead(self->delay_estimator);
// Allow for a slack in the actual delay. The adaptive echo cancellation // Allow for a slack in the actual delay, defined by a |lower_bound| and an
// filter is currently |num_partitions| (of 64 samples) long. If the // |upper_bound|. The adaptive echo cancellation filter is currently
// delay estimate indicates a delay of at least one quarter of the filter // |num_partitions| (of 64 samples) long. If the delay estimate is negative
// length we open up for correction. // or at least 3/4 of the filter length we open up for correction.
if (delay <= 0 || delay > (self->num_partitions / 4)) { const int lower_bound = 0;
const int upper_bound = self->num_partitions * 3 / 4;
const int do_correction = delay <= lower_bound || delay > upper_bound;
if (do_correction == 1) {
int available_read = (int)WebRtc_available_read(self->far_buf); int available_read = (int)WebRtc_available_read(self->far_buf);
// Adjust w.r.t. a |shift_offset| to account for not as reliable estimates // Adjust w.r.t. a |shift_offset| to account for not as reliable estimates
// in the beginning, hence we are more conservative. // in the beginning, hence we are more conservative.
@ -1583,7 +1600,7 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
aec->previous_delay = -2; // (-2): Uninitialized. aec->previous_delay = -2; // (-2): Uninitialized.
aec->delay_correction_count = 0; aec->delay_correction_count = 0;
aec->shift_offset = kInitialShiftOffset; aec->shift_offset = kInitialShiftOffset;
aec->delay_quality_threshold = 0; aec->delay_quality_threshold = kDelayQualityThresholdMin;
#ifdef WEBRTC_ANDROID #ifdef WEBRTC_ANDROID
aec->reported_delay_enabled = 0; // Disabled by default. aec->reported_delay_enabled = 0; // Disabled by default.
@ -1603,6 +1620,7 @@ int WebRtcAec_InitAec(AecCore* aec, int sampFreq) {
// all the time and the APIs to turn it on/off will be removed. Hence, remove // all the time and the APIs to turn it on/off will be removed. Hence, remove
// this line then. // this line then.
WebRtc_enable_robust_validation(aec->delay_estimator, 1); WebRtc_enable_robust_validation(aec->delay_estimator, 1);
aec->frame_count = 0;
// Default target suppression mode. // Default target suppression mode.
aec->nlp_mode = 1; aec->nlp_mode = 1;
@ -1725,6 +1743,7 @@ void WebRtcAec_ProcessFrames(AecCore* aec,
int i, j; int i, j;
int out_elements = 0; int out_elements = 0;
aec->frame_count++;
// For each frame the process is as follows: // For each frame the process is as follows:
// 1) If the system_delay indicates on being too small for processing a // 1) If the system_delay indicates on being too small for processing a
// frame we stuff the buffer with enough data for 10 ms. // frame we stuff the buffer with enough data for 10 ms.

View File

@ -142,6 +142,7 @@ struct AecCore {
int delay_correction_count; int delay_correction_count;
int shift_offset; int shift_offset;
float delay_quality_threshold; float delay_quality_threshold;
int frame_count;
// 0 = reported delay mode disabled (signal based delay correction enabled). // 0 = reported delay mode disabled (signal based delay correction enabled).
// otherwise enabled // otherwise enabled