1 /*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/video_coding/timing/jitter_estimator.h"
12
13 #include <math.h>
14 #include <string.h>
15
16 #include <algorithm>
17 #include <cstdint>
18
19 #include "absl/types/optional.h"
20 #include "api/field_trials_view.h"
21 #include "api/units/data_size.h"
22 #include "api/units/frequency.h"
23 #include "api/units/time_delta.h"
24 #include "api/units/timestamp.h"
25 #include "modules/video_coding/timing/rtt_filter.h"
26 #include "rtc_base/checks.h"
27 #include "rtc_base/logging.h"
28 #include "rtc_base/numerics/safe_conversions.h"
29 #include "system_wrappers/include/clock.h"
30
31 namespace webrtc {
32 namespace {
33
34 // Number of frames to wait for before post processing estimate. Also used in
35 // the frame rate estimator ramp-up.
36 constexpr size_t kFrameProcessingStartupCount = 30;
37
38 // Number of frames to wait for before enabling the frame size filters.
39 constexpr size_t kFramesUntilSizeFiltering = 5;
40
41 // Initial value for frame size filters.
42 constexpr double kInitialAvgAndMaxFrameSizeBytes = 500.0;
43
44 // Time constant for average frame size filter.
45 constexpr double kPhi = 0.97;
46 // Time constant for max frame size filter.
47 constexpr double kPsi = 0.9999;
48 // Default constants for percentile frame size filter.
49 constexpr double kDefaultMaxFrameSizePercentile = 0.95;
50 constexpr int kDefaultFrameSizeWindow = 30 * 10;
51
52 // Outlier rejection constants.
53 constexpr double kNumStdDevDelayClamp = 3.5;
54 constexpr double kNumStdDevDelayOutlier = 15.0;
55 constexpr double kNumStdDevSizeOutlier = 3.0;
56 constexpr double kCongestionRejectionFactor = -0.25;
57
58 // Rampup constant for deviation noise filters.
59 constexpr size_t kAlphaCountMax = 400;
60
61 // Noise threshold constants.
62 // ~Less than 1% chance (look up in normal distribution table)...
63 constexpr double kNoiseStdDevs = 2.33;
64 // ...of getting 30 ms freezes
65 constexpr double kNoiseStdDevOffset = 30.0;
66
67 // Jitter estimate clamping limits.
68 constexpr TimeDelta kMinJitterEstimate = TimeDelta::Millis(1);
69 constexpr TimeDelta kMaxJitterEstimate = TimeDelta::Seconds(10);
70
71 // A constant describing the delay from the jitter buffer to the delay on the
72 // receiving side which is not accounted for by the jitter buffer nor the
73 // decoding delay estimate.
74 constexpr TimeDelta OPERATING_SYSTEM_JITTER = TimeDelta::Millis(10);
75
76 // Time constant for reseting the NACK count.
77 constexpr TimeDelta kNackCountTimeout = TimeDelta::Seconds(60);
78
79 // RTT mult activation.
80 constexpr size_t kNackLimit = 3;
81
82 // Frame rate estimate clamping limit.
83 constexpr Frequency kMaxFramerateEstimate = Frequency::Hertz(200);
84
85 } // namespace
86
87 constexpr char JitterEstimator::Config::kFieldTrialsKey[];
88
ParseAndValidate(absl::string_view field_trial)89 JitterEstimator::Config JitterEstimator::Config::ParseAndValidate(
90 absl::string_view field_trial) {
91 Config config;
92 config.Parser()->Parse(field_trial);
93
94 // The `MovingPercentileFilter` RTC_CHECKs on the validity of the
95 // percentile and window length, so we'd better validate the field trial
96 // provided values here.
97 if (config.max_frame_size_percentile) {
98 double original = *config.max_frame_size_percentile;
99 config.max_frame_size_percentile = std::min(std::max(0.0, original), 1.0);
100 if (config.max_frame_size_percentile != original) {
101 RTC_LOG(LS_ERROR) << "Skipping invalid max_frame_size_percentile="
102 << original;
103 }
104 }
105 if (config.frame_size_window && config.frame_size_window < 1) {
106 RTC_LOG(LS_ERROR) << "Skipping invalid frame_size_window="
107 << *config.frame_size_window;
108 config.frame_size_window = 1;
109 }
110
111 // General sanity checks.
112 if (config.num_stddev_delay_clamp && config.num_stddev_delay_clamp < 0.0) {
113 RTC_LOG(LS_ERROR) << "Skipping invalid num_stddev_delay_clamp="
114 << *config.num_stddev_delay_clamp;
115 config.num_stddev_delay_clamp = 0.0;
116 }
117 if (config.num_stddev_delay_outlier &&
118 config.num_stddev_delay_outlier < 0.0) {
119 RTC_LOG(LS_ERROR) << "Skipping invalid num_stddev_delay_outlier="
120 << *config.num_stddev_delay_outlier;
121 config.num_stddev_delay_outlier = 0.0;
122 }
123 if (config.num_stddev_size_outlier && config.num_stddev_size_outlier < 0.0) {
124 RTC_LOG(LS_ERROR) << "Skipping invalid num_stddev_size_outlier="
125 << *config.num_stddev_size_outlier;
126 config.num_stddev_size_outlier = 0.0;
127 }
128
129 return config;
130 }
131
JitterEstimator(Clock * clock,const FieldTrialsView & field_trials)132 JitterEstimator::JitterEstimator(Clock* clock,
133 const FieldTrialsView& field_trials)
134 : config_(Config::ParseAndValidate(
135 field_trials.Lookup(Config::kFieldTrialsKey))),
136 avg_frame_size_median_bytes_(static_cast<size_t>(
137 config_.frame_size_window.value_or(kDefaultFrameSizeWindow))),
138 max_frame_size_bytes_percentile_(
139 config_.max_frame_size_percentile.value_or(
140 kDefaultMaxFrameSizePercentile),
141 static_cast<size_t>(
142 config_.frame_size_window.value_or(kDefaultFrameSizeWindow))),
143 fps_counter_(30), // TODO(sprang): Use an estimator with limit based
144 // on time, rather than number of samples.
145 clock_(clock) {
146 Reset();
147 }
148
149 JitterEstimator::~JitterEstimator() = default;
150
151 // Resets the JitterEstimate.
Reset()152 void JitterEstimator::Reset() {
153 avg_frame_size_bytes_ = kInitialAvgAndMaxFrameSizeBytes;
154 max_frame_size_bytes_ = kInitialAvgAndMaxFrameSizeBytes;
155 var_frame_size_bytes2_ = 100;
156 avg_frame_size_median_bytes_.Reset();
157 max_frame_size_bytes_percentile_.Reset();
158 last_update_time_ = absl::nullopt;
159 prev_estimate_ = absl::nullopt;
160 prev_frame_size_ = absl::nullopt;
161 avg_noise_ms_ = 0.0;
162 var_noise_ms2_ = 4.0;
163 alpha_count_ = 1;
164 filter_jitter_estimate_ = TimeDelta::Zero();
165 latest_nack_ = Timestamp::Zero();
166 nack_count_ = 0;
167 startup_frame_size_sum_bytes_ = 0;
168 startup_frame_size_count_ = 0;
169 startup_count_ = 0;
170 rtt_filter_.Reset();
171 fps_counter_.Reset();
172
173 kalman_filter_ = FrameDelayVariationKalmanFilter();
174 }
175
176 // Updates the estimates with the new measurements.
UpdateEstimate(TimeDelta frame_delay,DataSize frame_size)177 void JitterEstimator::UpdateEstimate(TimeDelta frame_delay,
178 DataSize frame_size) {
179 if (frame_size.IsZero()) {
180 return;
181 }
182 // Can't use DataSize since this can be negative.
183 double delta_frame_bytes =
184 frame_size.bytes() - prev_frame_size_.value_or(DataSize::Zero()).bytes();
185 if (startup_frame_size_count_ < kFramesUntilSizeFiltering) {
186 startup_frame_size_sum_bytes_ += frame_size.bytes();
187 startup_frame_size_count_++;
188 } else if (startup_frame_size_count_ == kFramesUntilSizeFiltering) {
189 // Give the frame size filter.
190 avg_frame_size_bytes_ = startup_frame_size_sum_bytes_ /
191 static_cast<double>(startup_frame_size_count_);
192 startup_frame_size_count_++;
193 }
194
195 double avg_frame_size_bytes =
196 kPhi * avg_frame_size_bytes_ + (1 - kPhi) * frame_size.bytes();
197 double deviation_size_bytes = 2 * sqrt(var_frame_size_bytes2_);
198 if (frame_size.bytes() < avg_frame_size_bytes_ + deviation_size_bytes) {
199 // Only update the average frame size if this sample wasn't a key frame.
200 avg_frame_size_bytes_ = avg_frame_size_bytes;
201 }
202
203 double delta_bytes = frame_size.bytes() - avg_frame_size_bytes;
204 var_frame_size_bytes2_ = std::max(
205 kPhi * var_frame_size_bytes2_ + (1 - kPhi) * (delta_bytes * delta_bytes),
206 1.0);
207
208 // Update non-linear IIR estimate of max frame size.
209 max_frame_size_bytes_ =
210 std::max<double>(kPsi * max_frame_size_bytes_, frame_size.bytes());
211
212 // Maybe update percentile estimates of frame sizes.
213 if (config_.avg_frame_size_median) {
214 avg_frame_size_median_bytes_.Insert(frame_size.bytes());
215 }
216 if (config_.MaxFrameSizePercentileEnabled()) {
217 max_frame_size_bytes_percentile_.Insert(frame_size.bytes());
218 }
219
220 if (!prev_frame_size_) {
221 prev_frame_size_ = frame_size;
222 return;
223 }
224 prev_frame_size_ = frame_size;
225
226 // Cap frame_delay based on the current time deviation noise.
227 double num_stddev_delay_clamp =
228 config_.num_stddev_delay_clamp.value_or(kNumStdDevDelayClamp);
229 TimeDelta max_time_deviation =
230 TimeDelta::Millis(num_stddev_delay_clamp * sqrt(var_noise_ms2_) + 0.5);
231 frame_delay.Clamp(-max_time_deviation, max_time_deviation);
232
233 double delay_deviation_ms =
234 frame_delay.ms() -
235 kalman_filter_.GetFrameDelayVariationEstimateTotal(delta_frame_bytes);
236
237 // Outlier rejection: these conditions depend on filtered versions of the
238 // delay and frame size _means_, respectively, together with a configurable
239 // number of standard deviations. If a sample is large with respect to the
240 // corresponding mean and dispersion (defined by the number of
241 // standard deviations and the sample standard deviation), it is deemed an
242 // outlier. This "empirical rule" is further described in
243 // https://en.wikipedia.org/wiki/68-95-99.7_rule. Note that neither of the
244 // estimated means are true sample means, which implies that they are possibly
245 // not normally distributed. Hence, this rejection method is just a heuristic.
246 double num_stddev_delay_outlier =
247 config_.num_stddev_delay_outlier.value_or(kNumStdDevDelayOutlier);
248 // Delay outlier rejection is two-sided.
249 bool abs_delay_is_not_outlier =
250 fabs(delay_deviation_ms) <
251 num_stddev_delay_outlier * sqrt(var_noise_ms2_);
252 // The reasoning above means, in particular, that we should use the sample
253 // mean-style `avg_frame_size_bytes_` estimate, as opposed to the
254 // median-filtered version, even if configured to use latter for the
255 // calculation in `CalculateEstimate()`.
256 // Size outlier rejection is one-sided.
257 double num_stddev_size_outlier =
258 config_.num_stddev_size_outlier.value_or(kNumStdDevSizeOutlier);
259 bool size_is_positive_outlier =
260 frame_size.bytes() >
261 avg_frame_size_bytes_ +
262 num_stddev_size_outlier * sqrt(var_frame_size_bytes2_);
263
264 // Only update the Kalman filter if the sample is not considered an extreme
265 // outlier. Even if it is an extreme outlier from a delay point of view, if
266 // the frame size also is large the deviation is probably due to an incorrect
267 // line slope.
268 if (abs_delay_is_not_outlier || size_is_positive_outlier) {
269 // Prevent updating with frames which have been congested by a large frame,
270 // and therefore arrives almost at the same time as that frame.
271 // This can occur when we receive a large frame (key frame) which has been
272 // delayed. The next frame is of normal size (delta frame), and thus deltaFS
273 // will be << 0. This removes all frame samples which arrives after a key
274 // frame.
275 double congestion_rejection_factor =
276 config_.congestion_rejection_factor.value_or(
277 kCongestionRejectionFactor);
278 double filtered_max_frame_size_bytes =
279 config_.MaxFrameSizePercentileEnabled()
280 ? max_frame_size_bytes_percentile_.GetFilteredValue()
281 : max_frame_size_bytes_;
282 bool is_not_congested =
283 delta_frame_bytes >
284 congestion_rejection_factor * filtered_max_frame_size_bytes;
285
286 if (is_not_congested || config_.estimate_noise_when_congested) {
287 // Update the variance of the deviation from the line given by the Kalman
288 // filter.
289 EstimateRandomJitter(delay_deviation_ms);
290 }
291 if (is_not_congested) {
292 // Neither a delay outlier nor a congested frame, so we can safely update
293 // the Kalman filter with the sample.
294 kalman_filter_.PredictAndUpdate(frame_delay.ms(), delta_frame_bytes,
295 filtered_max_frame_size_bytes,
296 var_noise_ms2_);
297 }
298 } else {
299 // Delay outliers affect the noise estimate through a value equal to the
300 // outlier rejection threshold.
301 double num_stddev = (delay_deviation_ms >= 0) ? num_stddev_delay_outlier
302 : -num_stddev_delay_outlier;
303 EstimateRandomJitter(num_stddev * sqrt(var_noise_ms2_));
304 }
305 // Post process the total estimated jitter
306 if (startup_count_ >= kFrameProcessingStartupCount) {
307 PostProcessEstimate();
308 } else {
309 startup_count_++;
310 }
311 }
312
313 // Updates the nack/packet ratio.
FrameNacked()314 void JitterEstimator::FrameNacked() {
315 if (nack_count_ < kNackLimit) {
316 nack_count_++;
317 }
318 latest_nack_ = clock_->CurrentTime();
319 }
320
UpdateRtt(TimeDelta rtt)321 void JitterEstimator::UpdateRtt(TimeDelta rtt) {
322 rtt_filter_.Update(rtt);
323 }
324
GetConfigForTest() const325 JitterEstimator::Config JitterEstimator::GetConfigForTest() const {
326 return config_;
327 }
328
329 // Estimates the random jitter by calculating the variance of the sample
330 // distance from the line given by the Kalman filter.
EstimateRandomJitter(double d_dT)331 void JitterEstimator::EstimateRandomJitter(double d_dT) {
332 Timestamp now = clock_->CurrentTime();
333 if (last_update_time_.has_value()) {
334 fps_counter_.AddSample((now - *last_update_time_).us());
335 }
336 last_update_time_ = now;
337
338 if (alpha_count_ == 0) {
339 RTC_DCHECK_NOTREACHED();
340 return;
341 }
342 double alpha =
343 static_cast<double>(alpha_count_ - 1) / static_cast<double>(alpha_count_);
344 alpha_count_++;
345 if (alpha_count_ > kAlphaCountMax)
346 alpha_count_ = kAlphaCountMax;
347
348 // In order to avoid a low frame rate stream to react slower to changes,
349 // scale the alpha weight relative a 30 fps stream.
350 Frequency fps = GetFrameRate();
351 if (fps > Frequency::Zero()) {
352 constexpr Frequency k30Fps = Frequency::Hertz(30);
353 double rate_scale = k30Fps / fps;
354 // At startup, there can be a lot of noise in the fps estimate.
355 // Interpolate rate_scale linearly, from 1.0 at sample #1, to 30.0 / fps
356 // at sample #kFrameProcessingStartupCount.
357 if (alpha_count_ < kFrameProcessingStartupCount) {
358 rate_scale = (alpha_count_ * rate_scale +
359 (kFrameProcessingStartupCount - alpha_count_)) /
360 kFrameProcessingStartupCount;
361 }
362 alpha = pow(alpha, rate_scale);
363 }
364
365 double avg_noise_ms = alpha * avg_noise_ms_ + (1 - alpha) * d_dT;
366 double var_noise_ms2 = alpha * var_noise_ms2_ + (1 - alpha) *
367 (d_dT - avg_noise_ms_) *
368 (d_dT - avg_noise_ms_);
369 avg_noise_ms_ = avg_noise_ms;
370 var_noise_ms2_ = var_noise_ms2;
371 if (var_noise_ms2_ < 1.0) {
372 // The variance should never be zero, since we might get stuck and consider
373 // all samples as outliers.
374 var_noise_ms2_ = 1.0;
375 }
376 }
377
NoiseThreshold() const378 double JitterEstimator::NoiseThreshold() const {
379 double noise_threshold_ms =
380 kNoiseStdDevs * sqrt(var_noise_ms2_) - kNoiseStdDevOffset;
381 if (noise_threshold_ms < 1.0) {
382 noise_threshold_ms = 1.0;
383 }
384 return noise_threshold_ms;
385 }
386
387 // Calculates the current jitter estimate from the filtered estimates.
CalculateEstimate()388 TimeDelta JitterEstimator::CalculateEstimate() {
389 // Using median- and percentile-filtered versions of the frame sizes may be
390 // more robust than using sample mean-style estimates.
391 double filtered_avg_frame_size_bytes =
392 config_.avg_frame_size_median
393 ? avg_frame_size_median_bytes_.GetFilteredValue()
394 : avg_frame_size_bytes_;
395 double filtered_max_frame_size_bytes =
396 config_.MaxFrameSizePercentileEnabled()
397 ? max_frame_size_bytes_percentile_.GetFilteredValue()
398 : max_frame_size_bytes_;
399 double worst_case_frame_size_deviation_bytes =
400 filtered_max_frame_size_bytes - filtered_avg_frame_size_bytes;
401 double ret_ms = kalman_filter_.GetFrameDelayVariationEstimateSizeBased(
402 worst_case_frame_size_deviation_bytes) +
403 NoiseThreshold();
404 TimeDelta ret = TimeDelta::Millis(ret_ms);
405
406 // A very low estimate (or negative) is neglected.
407 if (ret < kMinJitterEstimate) {
408 ret = prev_estimate_.value_or(kMinJitterEstimate);
409 // Sanity check to make sure that no other method has set `prev_estimate_`
410 // to a value lower than `kMinJitterEstimate`.
411 RTC_DCHECK_GE(ret, kMinJitterEstimate);
412 } else if (ret > kMaxJitterEstimate) { // Sanity
413 ret = kMaxJitterEstimate;
414 }
415 prev_estimate_ = ret;
416 return ret;
417 }
418
PostProcessEstimate()419 void JitterEstimator::PostProcessEstimate() {
420 filter_jitter_estimate_ = CalculateEstimate();
421 }
422
423 // Returns the current filtered estimate if available,
424 // otherwise tries to calculate an estimate.
GetJitterEstimate(double rtt_multiplier,absl::optional<TimeDelta> rtt_mult_add_cap)425 TimeDelta JitterEstimator::GetJitterEstimate(
426 double rtt_multiplier,
427 absl::optional<TimeDelta> rtt_mult_add_cap) {
428 TimeDelta jitter = CalculateEstimate() + OPERATING_SYSTEM_JITTER;
429 Timestamp now = clock_->CurrentTime();
430
431 if (now - latest_nack_ > kNackCountTimeout)
432 nack_count_ = 0;
433
434 if (filter_jitter_estimate_ > jitter)
435 jitter = filter_jitter_estimate_;
436 if (nack_count_ >= kNackLimit) {
437 if (rtt_mult_add_cap.has_value()) {
438 jitter += std::min(rtt_filter_.Rtt() * rtt_multiplier,
439 rtt_mult_add_cap.value());
440 } else {
441 jitter += rtt_filter_.Rtt() * rtt_multiplier;
442 }
443 }
444
445 static const Frequency kJitterScaleLowThreshold = Frequency::Hertz(5);
446 static const Frequency kJitterScaleHighThreshold = Frequency::Hertz(10);
447 Frequency fps = GetFrameRate();
448 // Ignore jitter for very low fps streams.
449 if (fps < kJitterScaleLowThreshold) {
450 if (fps.IsZero()) {
451 return std::max(TimeDelta::Zero(), jitter);
452 }
453 return TimeDelta::Zero();
454 }
455
456 // Semi-low frame rate; scale by factor linearly interpolated from 0.0 at
457 // kJitterScaleLowThreshold to 1.0 at kJitterScaleHighThreshold.
458 if (fps < kJitterScaleHighThreshold) {
459 jitter = (1.0 / (kJitterScaleHighThreshold - kJitterScaleLowThreshold)) *
460 (fps - kJitterScaleLowThreshold) * jitter;
461 }
462
463 return std::max(TimeDelta::Zero(), jitter);
464 }
465
GetFrameRate() const466 Frequency JitterEstimator::GetFrameRate() const {
467 TimeDelta mean_frame_period = TimeDelta::Micros(fps_counter_.ComputeMean());
468 if (mean_frame_period <= TimeDelta::Zero())
469 return Frequency::Zero();
470
471 Frequency fps = 1 / mean_frame_period;
472 // Sanity check.
473 RTC_DCHECK_GE(fps, Frequency::Zero());
474 return std::min(fps, kMaxFramerateEstimate);
475 }
476 } // namespace webrtc
477