JitterEstimator: add field trial for overriding frame delay variation clamping

Bug: webrtc:14151
Change-Id: Ib1f26cfaf92ca56000d5904432901d5db225b05a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/275203
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Commit-Queue: Rasmus Brandt <brandtr@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#38092}
diff --git a/modules/video_coding/timing/jitter_estimator.cc b/modules/video_coding/timing/jitter_estimator.cc
index a314abd..22fdcac 100644
--- a/modules/video_coding/timing/jitter_estimator.cc
+++ b/modules/video_coding/timing/jitter_estimator.cc
@@ -50,7 +50,7 @@
 constexpr int kDefaultFrameSizeWindow = 30 * 10;
 
 // Outlier rejection constants.
-constexpr double kDefaultMaxTimestampDeviationInSigmas = 3.5;
+constexpr double kNumStdDevDelayClamp = 3.5;
 constexpr double kNumStdDevDelayOutlier = 15.0;
 constexpr double kNumStdDevSizeOutlier = 3.0;
 constexpr double kCongestionRejectionFactor = -0.25;
@@ -109,6 +109,11 @@
   }
 
   // General sanity checks.
+  if (config.num_stddev_delay_clamp && config.num_stddev_delay_clamp < 0.0) {
+    RTC_LOG(LS_ERROR) << "Skipping invalid num_stddev_delay_clamp="
+                      << *config.num_stddev_delay_clamp;
+    config.num_stddev_delay_clamp = 0.0;
+  }
   if (config.num_stddev_delay_outlier &&
       config.num_stddev_delay_outlier < 0.0) {
     RTC_LOG(LS_ERROR) << "Skipping invalid num_stddev_delay_outlier="
@@ -219,8 +224,10 @@
   prev_frame_size_ = frame_size;
 
   // Cap frame_delay based on the current time deviation noise.
-  TimeDelta max_time_deviation = TimeDelta::Millis(
-      kDefaultMaxTimestampDeviationInSigmas * sqrt(var_noise_ms2_) + 0.5);
+  double num_stddev_delay_clamp =
+      config_.num_stddev_delay_clamp.value_or(kNumStdDevDelayClamp);
+  TimeDelta max_time_deviation =
+      TimeDelta::Millis(num_stddev_delay_clamp * sqrt(var_noise_ms2_) + 0.5);
   frame_delay.Clamp(-max_time_deviation, max_time_deviation);
 
   double delay_deviation_ms =
diff --git a/modules/video_coding/timing/jitter_estimator.h b/modules/video_coding/timing/jitter_estimator.h
index dd55907..c615be1 100644
--- a/modules/video_coding/timing/jitter_estimator.h
+++ b/modules/video_coding/timing/jitter_estimator.h
@@ -48,6 +48,7 @@
           "avg_frame_size_median", &avg_frame_size_median,
           "max_frame_size_percentile", &max_frame_size_percentile,
           "frame_size_window", &frame_size_window,
+          "num_stddev_delay_clamp", &num_stddev_delay_clamp,
           "num_stddev_delay_outlier", &num_stddev_delay_outlier,
           "num_stddev_size_outlier", &num_stddev_size_outlier,
           "congestion_rejection_factor", &congestion_rejection_factor);
@@ -69,6 +70,12 @@
     // The length of the percentile filters' window, in number of frames.
     absl::optional<int> frame_size_window = absl::nullopt;
 
+    // The incoming frame delay variation samples are clamped to be at most
+    // this number of standard deviations away from zero.
+    //
+    // Increasing this value clamps fewer samples.
+    absl::optional<double> num_stddev_delay_clamp = absl::nullopt;
+
     // A (relative) frame delay variation sample is an outlier if its absolute
     // deviation from the Kalman filter model falls outside this number of
     // sample standard deviations.
diff --git a/modules/video_coding/timing/jitter_estimator_unittest.cc b/modules/video_coding/timing/jitter_estimator_unittest.cc
index b018d48..2602b0d 100644
--- a/modules/video_coding/timing/jitter_estimator_unittest.cc
+++ b/modules/video_coding/timing/jitter_estimator_unittest.cc
@@ -166,6 +166,7 @@
   EXPECT_FALSE(config.avg_frame_size_median);
   EXPECT_FALSE(config.max_frame_size_percentile.has_value());
   EXPECT_FALSE(config.frame_size_window.has_value());
+  EXPECT_FALSE(config.num_stddev_delay_clamp.has_value());
   EXPECT_FALSE(config.num_stddev_delay_outlier.has_value());
   EXPECT_FALSE(config.num_stddev_size_outlier.has_value());
   EXPECT_FALSE(config.congestion_rejection_factor.has_value());
@@ -179,6 +180,7 @@
             "avg_frame_size_median:true,"
             "max_frame_size_percentile:0.9,"
             "frame_size_window:30,"
+            "num_stddev_delay_clamp:1.1,"
             "num_stddev_delay_outlier:2,"
             "num_stddev_size_outlier:3.1,"
             "congestion_rejection_factor:-1.55/") {}
@@ -190,6 +192,7 @@
   EXPECT_TRUE(config.avg_frame_size_median);
   EXPECT_EQ(*config.max_frame_size_percentile, 0.9);
   EXPECT_EQ(*config.frame_size_window, 30);
+  EXPECT_EQ(*config.num_stddev_delay_clamp, 1.1);
   EXPECT_EQ(*config.num_stddev_delay_outlier, 2.0);
   EXPECT_EQ(*config.num_stddev_size_outlier, 3.1);
   EXPECT_EQ(*config.congestion_rejection_factor, -1.55);
@@ -243,6 +246,7 @@
             "WebRTC-JitterEstimatorConfig/"
             "max_frame_size_percentile:-0.9,"
             "frame_size_window:-1,"
+            "num_stddev_delay_clamp:-1.9,"
             "num_stddev_delay_outlier:-2,"
             "num_stddev_size_outlier:-23.1/") {}
   ~MisconfiguredFieldTrialsJitterEstimatorTest() {}
@@ -252,6 +256,7 @@
   JitterEstimator::Config config = estimator_.GetConfigForTest();
   EXPECT_EQ(*config.max_frame_size_percentile, 0.0);
   EXPECT_EQ(*config.frame_size_window, 1);
+  EXPECT_EQ(*config.num_stddev_delay_clamp, 0.0);
   EXPECT_EQ(*config.num_stddev_delay_outlier, 0.0);
   EXPECT_EQ(*config.num_stddev_size_outlier, 0.0);
 }