diff --git a/modules/video_coding/timing/jitter_estimator.cc b/modules/video_coding/timing/jitter_estimator.cc index a314abd3fc..22fdcacf03 100644 --- a/modules/video_coding/timing/jitter_estimator.cc +++ b/modules/video_coding/timing/jitter_estimator.cc @@ -50,7 +50,7 @@ constexpr double kDefaultMaxFrameSizePercentile = 0.95; 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 @@ JitterEstimator::Config JitterEstimator::Config::ParseAndValidate( } // 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 @@ void JitterEstimator::UpdateEstimate(TimeDelta frame_delay, 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 dd55907421..c615be10e4 100644 --- a/modules/video_coding/timing/jitter_estimator.h +++ b/modules/video_coding/timing/jitter_estimator.h @@ -48,6 +48,7 @@ class JitterEstimator { "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 @@ class JitterEstimator { // The length of the percentile filters' window, in number of frames. absl::optional 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 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 b018d48055..2602b0d4de 100644 --- a/modules/video_coding/timing/jitter_estimator_unittest.cc +++ b/modules/video_coding/timing/jitter_estimator_unittest.cc @@ -166,6 +166,7 @@ TEST_F(JitterEstimatorTest, EmptyFieldTrialsParsesToUnsetConfig) { 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 @@ class FieldTrialsOverriddenJitterEstimatorTest : public JitterEstimatorTest { "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 @@ TEST_F(FieldTrialsOverriddenJitterEstimatorTest, FieldTrialsParsesCorrectly) { 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 @@ class MisconfiguredFieldTrialsJitterEstimatorTest : public JitterEstimatorTest { "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 @@ TEST_F(MisconfiguredFieldTrialsJitterEstimatorTest, FieldTrialsAreValidated) { 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); }