blob: 87848aec0683089a1b53a0659176f4577d8e6247 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/video_coding/jitter_estimator.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
niklase@google.com470e71d2011-07-07 08:21:25 +000013#include <math.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020015
Erik Språngb1e031a2018-11-01 11:20:49 +010016#include <algorithm>
Yves Gerey3e707812018-11-28 16:47:49 +010017#include <cstdint>
philipel9d3ab612015-12-21 04:12:39 -080018
Erik Språngb1e031a2018-11-01 11:20:49 +010019#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/video_coding/internal_defines.h"
21#include "modules/video_coding/rtt_filter.h"
Erik Språngb1e031a2018-11-01 11:20:49 +010022#include "rtc_base/experiments/jitter_upper_bound_experiment.h"
Yves Gerey3e707812018-11-28 16:47:49 +010023#include "rtc_base/numerics/safe_conversions.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "system_wrappers/include/clock.h"
Åsa Persson3361af32020-05-18 11:01:33 +020025#include "system_wrappers/include/field_trial.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000026
27namespace webrtc {
Erik Språngb1e031a2018-11-01 11:20:49 +010028namespace {
29static constexpr uint32_t kStartupDelaySamples = 30;
30static constexpr int64_t kFsAccuStartupSamples = 5;
31static constexpr double kMaxFramerateEstimate = 200.0;
32static constexpr int64_t kNackCountTimeoutMs = 60000;
33static constexpr double kDefaultMaxTimestampDeviationInSigmas = 3.5;
34} // namespace
sprang@webrtc.org70e2d112014-09-24 14:06:56 +000035
Åsa Persson3fcc5be2019-04-04 09:40:27 +020036VCMJitterEstimator::VCMJitterEstimator(Clock* clock)
37 : _phi(0.97),
stefan@webrtc.org34c5da62014-04-11 14:08:35 +000038 _psi(0.9999),
39 _alphaCountMax(400),
40 _thetaLow(0.000001),
41 _nackLimit(3),
42 _numStdDevDelayOutlier(15),
43 _numStdDevFrameSizeOutlier(3),
44 _noiseStdDevs(2.33), // ~Less than 1% chance
45 // (look up in normal distribution table)...
46 _noiseStdDevOffset(30.0), // ...of getting 30 ms freezes
sprang@webrtc.org70e2d112014-09-24 14:06:56 +000047 _rttFilter(),
48 fps_counter_(30), // TODO(sprang): Use an estimator with limit based on
49 // time, rather than number of samples.
Erik Språngb1e031a2018-11-01 11:20:49 +010050 time_deviation_upper_bound_(
51 JitterUpperBoundExperiment::GetUpperBoundSigmas().value_or(
52 kDefaultMaxTimestampDeviationInSigmas)),
Åsa Persson3361af32020-05-18 11:01:33 +020053 enable_reduced_delay_(
54 !field_trial::IsEnabled("WebRTC-ReducedJitterDelayKillSwitch")),
sprang@webrtc.org70e2d112014-09-24 14:06:56 +000055 clock_(clock) {
56 Reset();
57}
58
philipel9d3ab612015-12-21 04:12:39 -080059VCMJitterEstimator::~VCMJitterEstimator() {}
niklase@google.com470e71d2011-07-07 08:21:25 +000060
philipel9d3ab612015-12-21 04:12:39 -080061VCMJitterEstimator& VCMJitterEstimator::operator=(
62 const VCMJitterEstimator& rhs) {
63 if (this != &rhs) {
64 memcpy(_thetaCov, rhs._thetaCov, sizeof(_thetaCov));
65 memcpy(_Qcov, rhs._Qcov, sizeof(_Qcov));
niklase@google.com470e71d2011-07-07 08:21:25 +000066
philipel9d3ab612015-12-21 04:12:39 -080067 _avgFrameSize = rhs._avgFrameSize;
68 _varFrameSize = rhs._varFrameSize;
69 _maxFrameSize = rhs._maxFrameSize;
70 _fsSum = rhs._fsSum;
71 _fsCount = rhs._fsCount;
72 _lastUpdateT = rhs._lastUpdateT;
73 _prevEstimate = rhs._prevEstimate;
74 _prevFrameSize = rhs._prevFrameSize;
75 _avgNoise = rhs._avgNoise;
76 _alphaCount = rhs._alphaCount;
77 _filterJitterEstimate = rhs._filterJitterEstimate;
78 _startupCount = rhs._startupCount;
79 _latestNackTimestamp = rhs._latestNackTimestamp;
80 _nackCount = rhs._nackCount;
81 _rttFilter = rhs._rttFilter;
Erik Språngb1e031a2018-11-01 11:20:49 +010082 clock_ = rhs.clock_;
philipel9d3ab612015-12-21 04:12:39 -080083 }
84 return *this;
niklase@google.com470e71d2011-07-07 08:21:25 +000085}
86
Åsa Persson3fcc5be2019-04-04 09:40:27 +020087// Resets the JitterEstimate.
philipel9d3ab612015-12-21 04:12:39 -080088void VCMJitterEstimator::Reset() {
89 _theta[0] = 1 / (512e3 / 8);
90 _theta[1] = 0;
91 _varNoise = 4.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000092
philipel9d3ab612015-12-21 04:12:39 -080093 _thetaCov[0][0] = 1e-4;
94 _thetaCov[1][1] = 1e2;
95 _thetaCov[0][1] = _thetaCov[1][0] = 0;
96 _Qcov[0][0] = 2.5e-10;
97 _Qcov[1][1] = 1e-10;
98 _Qcov[0][1] = _Qcov[1][0] = 0;
99 _avgFrameSize = 500;
100 _maxFrameSize = 500;
101 _varFrameSize = 100;
102 _lastUpdateT = -1;
103 _prevEstimate = -1.0;
104 _prevFrameSize = 0;
105 _avgNoise = 0.0;
106 _alphaCount = 1;
107 _filterJitterEstimate = 0.0;
108 _latestNackTimestamp = 0;
109 _nackCount = 0;
Gustavo Garciaf7a7c8a2018-01-08 15:23:38 +0100110 _latestNackTimestamp = 0;
philipel9d3ab612015-12-21 04:12:39 -0800111 _fsSum = 0;
112 _fsCount = 0;
113 _startupCount = 0;
114 _rttFilter.Reset();
115 fps_counter_.Reset();
niklase@google.com470e71d2011-07-07 08:21:25 +0000116}
117
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200118// Updates the estimates with the new measurements.
philipel9d3ab612015-12-21 04:12:39 -0800119void VCMJitterEstimator::UpdateEstimate(int64_t frameDelayMS,
120 uint32_t frameSizeBytes,
121 bool incompleteFrame /* = false */) {
122 if (frameSizeBytes == 0) {
123 return;
124 }
125 int deltaFS = frameSizeBytes - _prevFrameSize;
126 if (_fsCount < kFsAccuStartupSamples) {
127 _fsSum += frameSizeBytes;
128 _fsCount++;
129 } else if (_fsCount == kFsAccuStartupSamples) {
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200130 // Give the frame size filter.
philipel9d3ab612015-12-21 04:12:39 -0800131 _avgFrameSize = static_cast<double>(_fsSum) / static_cast<double>(_fsCount);
132 _fsCount++;
133 }
134 if (!incompleteFrame || frameSizeBytes > _avgFrameSize) {
135 double avgFrameSize = _phi * _avgFrameSize + (1 - _phi) * frameSizeBytes;
136 if (frameSizeBytes < _avgFrameSize + 2 * sqrt(_varFrameSize)) {
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200137 // Only update the average frame size if this sample wasn't a key frame.
philipel9d3ab612015-12-21 04:12:39 -0800138 _avgFrameSize = avgFrameSize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000139 }
philipel9d3ab612015-12-21 04:12:39 -0800140 // Update the variance anyway since we want to capture cases where we only
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200141 // get key frames.
Yves Gerey665174f2018-06-19 15:03:05 +0200142 _varFrameSize = VCM_MAX(
143 _phi * _varFrameSize + (1 - _phi) * (frameSizeBytes - avgFrameSize) *
144 (frameSizeBytes - avgFrameSize),
145 1.0);
philipel9d3ab612015-12-21 04:12:39 -0800146 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000147
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200148 // Update max frameSize estimate.
philipel9d3ab612015-12-21 04:12:39 -0800149 _maxFrameSize =
150 VCM_MAX(_psi * _maxFrameSize, static_cast<double>(frameSizeBytes));
niklase@google.com470e71d2011-07-07 08:21:25 +0000151
philipel9d3ab612015-12-21 04:12:39 -0800152 if (_prevFrameSize == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000153 _prevFrameSize = frameSizeBytes;
philipel9d3ab612015-12-21 04:12:39 -0800154 return;
155 }
156 _prevFrameSize = frameSizeBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000157
Erik Språngb1e031a2018-11-01 11:20:49 +0100158 // Cap frameDelayMS based on the current time deviation noise.
159 int64_t max_time_deviation_ms =
160 static_cast<int64_t>(time_deviation_upper_bound_ * sqrt(_varNoise) + 0.5);
161 frameDelayMS = std::max(std::min(frameDelayMS, max_time_deviation_ms),
162 -max_time_deviation_ms);
163
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200164 // Only update the Kalman filter if the sample is not considered an extreme
165 // outlier. Even if it is an extreme outlier from a delay point of view, if
166 // the frame size also is large the deviation is probably due to an incorrect
167 // line slope.
philipel9d3ab612015-12-21 04:12:39 -0800168 double deviation = DeviationFromExpectedDelay(frameDelayMS, deltaFS);
niklase@google.com470e71d2011-07-07 08:21:25 +0000169
philipel9d3ab612015-12-21 04:12:39 -0800170 if (fabs(deviation) < _numStdDevDelayOutlier * sqrt(_varNoise) ||
171 frameSizeBytes >
172 _avgFrameSize + _numStdDevFrameSizeOutlier * sqrt(_varFrameSize)) {
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200173 // Update the variance of the deviation from the line given by the Kalman
174 // filter.
philipel9d3ab612015-12-21 04:12:39 -0800175 EstimateRandomJitter(deviation, incompleteFrame);
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200176 // Prevent updating with frames which have been congested by a large frame,
177 // and therefore arrives almost at the same time as that frame.
178 // This can occur when we receive a large frame (key frame) which has been
179 // delayed. The next frame is of normal size (delta frame), and thus deltaFS
180 // will be << 0. This removes all frame samples which arrives after a key
181 // frame.
philipel9d3ab612015-12-21 04:12:39 -0800182 if ((!incompleteFrame || deviation >= 0.0) &&
183 static_cast<double>(deltaFS) > -0.25 * _maxFrameSize) {
184 // Update the Kalman filter with the new data
185 KalmanEstimateChannel(frameDelayMS, deltaFS);
niklase@google.com470e71d2011-07-07 08:21:25 +0000186 }
philipel9d3ab612015-12-21 04:12:39 -0800187 } else {
188 int nStdDev =
189 (deviation >= 0) ? _numStdDevDelayOutlier : -_numStdDevDelayOutlier;
190 EstimateRandomJitter(nStdDev * sqrt(_varNoise), incompleteFrame);
191 }
192 // Post process the total estimated jitter
193 if (_startupCount >= kStartupDelaySamples) {
194 PostProcessEstimate();
195 } else {
196 _startupCount++;
197 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000198}
199
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200200// Updates the nack/packet ratio.
philipel9d3ab612015-12-21 04:12:39 -0800201void VCMJitterEstimator::FrameNacked() {
philipel9d3ab612015-12-21 04:12:39 -0800202 if (_nackCount < _nackLimit) {
203 _nackCount++;
204 }
Gustavo Garciaf7a7c8a2018-01-08 15:23:38 +0100205 _latestNackTimestamp = clock_->TimeInMicroseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +0000206}
207
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200208// Updates Kalman estimate of the channel.
niklase@google.com470e71d2011-07-07 08:21:25 +0000209// The caller is expected to sanity check the inputs.
philipel9d3ab612015-12-21 04:12:39 -0800210void VCMJitterEstimator::KalmanEstimateChannel(int64_t frameDelayMS,
211 int32_t deltaFSBytes) {
212 double Mh[2];
213 double hMh_sigma;
214 double kalmanGain[2];
215 double measureRes;
216 double t00, t01;
niklase@google.com470e71d2011-07-07 08:21:25 +0000217
philipel9d3ab612015-12-21 04:12:39 -0800218 // Kalman filtering
niklase@google.com470e71d2011-07-07 08:21:25 +0000219
philipel9d3ab612015-12-21 04:12:39 -0800220 // Prediction
221 // M = M + Q
222 _thetaCov[0][0] += _Qcov[0][0];
223 _thetaCov[0][1] += _Qcov[0][1];
224 _thetaCov[1][0] += _Qcov[1][0];
225 _thetaCov[1][1] += _Qcov[1][1];
niklase@google.com470e71d2011-07-07 08:21:25 +0000226
philipel9d3ab612015-12-21 04:12:39 -0800227 // Kalman gain
228 // K = M*h'/(sigma2n + h*M*h') = M*h'/(1 + h*M*h')
229 // h = [dFS 1]
230 // Mh = M*h'
231 // hMh_sigma = h*M*h' + R
232 Mh[0] = _thetaCov[0][0] * deltaFSBytes + _thetaCov[0][1];
233 Mh[1] = _thetaCov[1][0] * deltaFSBytes + _thetaCov[1][1];
234 // sigma weights measurements with a small deltaFS as noisy and
235 // measurements with large deltaFS as good
236 if (_maxFrameSize < 1.0) {
237 return;
238 }
239 double sigma = (300.0 * exp(-fabs(static_cast<double>(deltaFSBytes)) /
240 (1e0 * _maxFrameSize)) +
241 1) *
242 sqrt(_varNoise);
243 if (sigma < 1.0) {
244 sigma = 1.0;
245 }
246 hMh_sigma = deltaFSBytes * Mh[0] + Mh[1] + sigma;
247 if ((hMh_sigma < 1e-9 && hMh_sigma >= 0) ||
248 (hMh_sigma > -1e-9 && hMh_sigma <= 0)) {
Artem Titovd3251962021-11-15 16:57:07 +0100249 RTC_DCHECK_NOTREACHED();
philipel9d3ab612015-12-21 04:12:39 -0800250 return;
251 }
252 kalmanGain[0] = Mh[0] / hMh_sigma;
253 kalmanGain[1] = Mh[1] / hMh_sigma;
niklase@google.com470e71d2011-07-07 08:21:25 +0000254
philipel9d3ab612015-12-21 04:12:39 -0800255 // Correction
256 // theta = theta + K*(dT - h*theta)
257 measureRes = frameDelayMS - (deltaFSBytes * _theta[0] + _theta[1]);
258 _theta[0] += kalmanGain[0] * measureRes;
259 _theta[1] += kalmanGain[1] * measureRes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000260
philipel9d3ab612015-12-21 04:12:39 -0800261 if (_theta[0] < _thetaLow) {
262 _theta[0] = _thetaLow;
263 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000264
philipel9d3ab612015-12-21 04:12:39 -0800265 // M = (I - K*h)*M
266 t00 = _thetaCov[0][0];
267 t01 = _thetaCov[0][1];
268 _thetaCov[0][0] = (1 - kalmanGain[0] * deltaFSBytes) * t00 -
269 kalmanGain[0] * _thetaCov[1][0];
270 _thetaCov[0][1] = (1 - kalmanGain[0] * deltaFSBytes) * t01 -
271 kalmanGain[0] * _thetaCov[1][1];
272 _thetaCov[1][0] = _thetaCov[1][0] * (1 - kalmanGain[1]) -
273 kalmanGain[1] * deltaFSBytes * t00;
274 _thetaCov[1][1] = _thetaCov[1][1] * (1 - kalmanGain[1]) -
275 kalmanGain[1] * deltaFSBytes * t01;
niklase@google.com470e71d2011-07-07 08:21:25 +0000276
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200277 // Covariance matrix, must be positive semi-definite.
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200278 RTC_DCHECK(_thetaCov[0][0] + _thetaCov[1][1] >= 0 &&
279 _thetaCov[0][0] * _thetaCov[1][1] -
280 _thetaCov[0][1] * _thetaCov[1][0] >=
281 0 &&
282 _thetaCov[0][0] >= 0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000283}
284
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200285// Calculate difference in delay between a sample and the expected delay
286// estimated by the Kalman filter
philipel9d3ab612015-12-21 04:12:39 -0800287double VCMJitterEstimator::DeviationFromExpectedDelay(
288 int64_t frameDelayMS,
289 int32_t deltaFSBytes) const {
290 return frameDelayMS - (_theta[0] * deltaFSBytes + _theta[1]);
niklase@google.com470e71d2011-07-07 08:21:25 +0000291}
292
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200293// Estimates the random jitter by calculating the variance of the sample
294// distance from the line given by theta.
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000295void VCMJitterEstimator::EstimateRandomJitter(double d_dT,
296 bool incompleteFrame) {
297 uint64_t now = clock_->TimeInMicroseconds();
298 if (_lastUpdateT != -1) {
299 fps_counter_.AddSample(now - _lastUpdateT);
300 }
301 _lastUpdateT = now;
302
303 if (_alphaCount == 0) {
Artem Titovd3251962021-11-15 16:57:07 +0100304 RTC_DCHECK_NOTREACHED();
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000305 return;
306 }
307 double alpha =
308 static_cast<double>(_alphaCount - 1) / static_cast<double>(_alphaCount);
309 _alphaCount++;
310 if (_alphaCount > _alphaCountMax)
311 _alphaCount = _alphaCountMax;
312
Erik Språngb1e031a2018-11-01 11:20:49 +0100313 // In order to avoid a low frame rate stream to react slower to changes,
314 // scale the alpha weight relative a 30 fps stream.
315 double fps = GetFrameRate();
316 if (fps > 0.0) {
317 double rate_scale = 30.0 / fps;
318 // At startup, there can be a lot of noise in the fps estimate.
319 // Interpolate rate_scale linearly, from 1.0 at sample #1, to 30.0 / fps
320 // at sample #kStartupDelaySamples.
321 if (_alphaCount < kStartupDelaySamples) {
322 rate_scale =
323 (_alphaCount * rate_scale + (kStartupDelaySamples - _alphaCount)) /
324 kStartupDelaySamples;
niklase@google.com470e71d2011-07-07 08:21:25 +0000325 }
Erik Språngb1e031a2018-11-01 11:20:49 +0100326 alpha = pow(alpha, rate_scale);
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000327 }
328
329 double avgNoise = alpha * _avgNoise + (1 - alpha) * d_dT;
330 double varNoise =
331 alpha * _varNoise + (1 - alpha) * (d_dT - _avgNoise) * (d_dT - _avgNoise);
332 if (!incompleteFrame || varNoise > _varNoise) {
333 _avgNoise = avgNoise;
334 _varNoise = varNoise;
335 }
336 if (_varNoise < 1.0) {
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200337 // The variance should never be zero, since we might get stuck and consider
338 // all samples as outliers.
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000339 _varNoise = 1.0;
340 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000341}
342
philipel9d3ab612015-12-21 04:12:39 -0800343double VCMJitterEstimator::NoiseThreshold() const {
344 double noiseThreshold = _noiseStdDevs * sqrt(_varNoise) - _noiseStdDevOffset;
345 if (noiseThreshold < 1.0) {
346 noiseThreshold = 1.0;
347 }
348 return noiseThreshold;
niklase@google.com470e71d2011-07-07 08:21:25 +0000349}
350
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200351// Calculates the current jitter estimate from the filtered estimates.
philipel9d3ab612015-12-21 04:12:39 -0800352double VCMJitterEstimator::CalculateEstimate() {
353 double ret = _theta[0] * (_maxFrameSize - _avgFrameSize) + NoiseThreshold();
niklase@google.com470e71d2011-07-07 08:21:25 +0000354
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200355 // A very low estimate (or negative) is neglected.
philipel9d3ab612015-12-21 04:12:39 -0800356 if (ret < 1.0) {
357 if (_prevEstimate <= 0.01) {
358 ret = 1.0;
359 } else {
360 ret = _prevEstimate;
niklase@google.com470e71d2011-07-07 08:21:25 +0000361 }
philipel9d3ab612015-12-21 04:12:39 -0800362 }
363 if (ret > 10000.0) { // Sanity
364 ret = 10000.0;
365 }
366 _prevEstimate = ret;
367 return ret;
niklase@google.com470e71d2011-07-07 08:21:25 +0000368}
369
philipel9d3ab612015-12-21 04:12:39 -0800370void VCMJitterEstimator::PostProcessEstimate() {
371 _filterJitterEstimate = CalculateEstimate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000372}
373
philipel9d3ab612015-12-21 04:12:39 -0800374void VCMJitterEstimator::UpdateRtt(int64_t rttMs) {
375 _rttFilter.Update(rttMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000376}
377
niklase@google.com470e71d2011-07-07 08:21:25 +0000378// Returns the current filtered estimate if available,
379// otherwise tries to calculate an estimate.
“Michaele0f37042019-06-04 10:04:12 -0500380int VCMJitterEstimator::GetJitterEstimate(
381 double rttMultiplier,
382 absl::optional<double> rttMultAddCapMs) {
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000383 double jitterMS = CalculateEstimate() + OPERATING_SYSTEM_JITTER;
Gustavo Garciaf7a7c8a2018-01-08 15:23:38 +0100384 uint64_t now = clock_->TimeInMicroseconds();
385
386 if (now - _latestNackTimestamp > kNackCountTimeoutMs * 1000)
387 _nackCount = 0;
388
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000389 if (_filterJitterEstimate > jitterMS)
390 jitterMS = _filterJitterEstimate;
“Michaele0f37042019-06-04 10:04:12 -0500391 if (_nackCount >= _nackLimit) {
392 if (rttMultAddCapMs.has_value()) {
393 jitterMS +=
394 std::min(_rttFilter.RttMs() * rttMultiplier, rttMultAddCapMs.value());
395 } else {
396 jitterMS += _rttFilter.RttMs() * rttMultiplier;
397 }
398 }
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000399
Åsa Persson3361af32020-05-18 11:01:33 +0200400 if (enable_reduced_delay_) {
401 static const double kJitterScaleLowThreshold = 5.0;
402 static const double kJitterScaleHighThreshold = 10.0;
403 double fps = GetFrameRate();
404 // Ignore jitter for very low fps streams.
405 if (fps < kJitterScaleLowThreshold) {
406 if (fps == 0.0) {
407 return rtc::checked_cast<int>(std::max(0.0, jitterMS) + 0.5);
408 }
409 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000410 }
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000411
Åsa Persson3361af32020-05-18 11:01:33 +0200412 // Semi-low frame rate; scale by factor linearly interpolated from 0.0 at
413 // kJitterScaleLowThreshold to 1.0 at kJitterScaleHighThreshold.
414 if (fps < kJitterScaleHighThreshold) {
415 jitterMS =
416 (1.0 / (kJitterScaleHighThreshold - kJitterScaleLowThreshold)) *
417 (fps - kJitterScaleLowThreshold) * jitterMS;
418 }
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000419 }
Erik Språngb1e031a2018-11-01 11:20:49 +0100420
421 return rtc::checked_cast<int>(std::max(0.0, jitterMS) + 0.5);
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000422}
423
424double VCMJitterEstimator::GetFrameRate() const {
Sebastian Jansson7a994332019-06-11 10:28:20 +0200425 if (fps_counter_.ComputeMean() <= 0.0)
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000426 return 0;
427
428 double fps = 1000000.0 / fps_counter_.ComputeMean();
429 // Sanity check.
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200430 RTC_DCHECK_GE(fps, 0.0);
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000431 if (fps > kMaxFramerateEstimate) {
432 fps = kMaxFramerateEstimate;
433 }
434 return fps;
niklase@google.com470e71d2011-07-07 08:21:25 +0000435}
philipel9d3ab612015-12-21 04:12:39 -0800436} // namespace webrtc