AEC3: Rounding of estimated call skew

This CL fixes the rounding of the estimated average call skew. Before it
was rounded down (toward INT_MIN). Now it is rounded to the nearest integer.
This avoids unnecessary fluctuations of the estimated call skew (and
unnecessary resets).

Bug: webrtc:9283,chromium:888042
Change-Id: Id5b3c593f812f5f9fd3dcdafb7e388a6ef1ac153
Reviewed-on: https://webrtc-review.googlesource.com/77684
Commit-Queue: Gustaf Ullberg <gustaf@webrtc.org>
Reviewed-by: Per Ã…hgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23338}
diff --git a/modules/audio_processing/aec3/skew_estimator.cc b/modules/audio_processing/aec3/skew_estimator.cc
index 608a707..5a453a0 100644
--- a/modules/audio_processing/aec3/skew_estimator.cc
+++ b/modules/audio_processing/aec3/skew_estimator.cc
@@ -38,9 +38,9 @@
     sufficient_skew_stored_ = true;
   }
 
-  return sufficient_skew_stored_
-             ? rtc::Optional<int>(skew_sum_ >> skew_history_size_log2_)
-             : rtc::nullopt;
+  const int bias = static_cast<int>(skew_history_.size()) >> 1;
+  const int average = (skew_sum_ + bias) >> skew_history_size_log2_;
+  return sufficient_skew_stored_ ? rtc::Optional<int>(average) : rtc::nullopt;
 }
 
 }  // namespace webrtc
diff --git a/modules/audio_processing/aec3/skew_estimator_unittest.cc b/modules/audio_processing/aec3/skew_estimator_unittest.cc
index a1a679f..168470a 100644
--- a/modules/audio_processing/aec3/skew_estimator_unittest.cc
+++ b/modules/audio_processing/aec3/skew_estimator_unittest.cc
@@ -120,5 +120,38 @@
     EXPECT_FALSE(skew);
   }
 }
+
+// Tests that the skew estimator properly rounds the average skew.
+TEST(SkewEstimator, SkewRounding) {
+  constexpr int kNumSkewsLog2 = 4;
+  constexpr int kNumSkews = 1 << kNumSkewsLog2;
+
+  SkewEstimator estimator(kNumSkewsLog2);
+
+  rtc::Optional<int> skew;
+  for (int k = 0; k < kNumSkews; ++k) {
+    if (k == kNumSkews - 1) {
+      // Reverse call order once.
+      skew = estimator.GetSkewFromCapture();
+      estimator.LogRenderCall();
+    } else {
+      // Normal call order.
+      estimator.LogRenderCall();
+      skew = estimator.GetSkewFromCapture();
+    }
+  }
+  EXPECT_EQ(*skew, 0);
+
+  estimator.Reset();
+  for (int k = 0; k < kNumSkews; ++k) {
+    estimator.LogRenderCall();
+    estimator.LogRenderCall();
+    estimator.LogRenderCall();
+    estimator.GetSkewFromCapture();
+    estimator.GetSkewFromCapture();
+    skew = estimator.GetSkewFromCapture();
+  }
+  EXPECT_EQ(*skew, 1);
+}
 }  // namespace aec3
 }  // namespace webrtc