blob: cd505835d11280be5a6c4dd517646f3b31ef009d [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
henrik.lundin@webrtc.org7d8c72e2011-12-21 15:24:01 +000013#include <assert.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014#include <math.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000015#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020016
Erik Språngb1e031a2018-11-01 11:20:49 +010017#include <algorithm>
Yves Gerey3e707812018-11-28 16:47:49 +010018#include <cstdint>
philipel9d3ab612015-12-21 04:12:39 -080019
Erik Språngb1e031a2018-11-01 11:20:49 +010020#include "absl/types/optional.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "modules/video_coding/internal_defines.h"
22#include "modules/video_coding/rtt_filter.h"
Erik Språngb1e031a2018-11-01 11:20:49 +010023#include "rtc_base/experiments/jitter_upper_bound_experiment.h"
Yves Gerey3e707812018-11-28 16:47:49 +010024#include "rtc_base/numerics/safe_conversions.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "system_wrappers/include/clock.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)),
sprang@webrtc.org70e2d112014-09-24 14:06:56 +000053 clock_(clock) {
54 Reset();
55}
56
philipel9d3ab612015-12-21 04:12:39 -080057VCMJitterEstimator::~VCMJitterEstimator() {}
niklase@google.com470e71d2011-07-07 08:21:25 +000058
philipel9d3ab612015-12-21 04:12:39 -080059VCMJitterEstimator& VCMJitterEstimator::operator=(
60 const VCMJitterEstimator& rhs) {
61 if (this != &rhs) {
62 memcpy(_thetaCov, rhs._thetaCov, sizeof(_thetaCov));
63 memcpy(_Qcov, rhs._Qcov, sizeof(_Qcov));
niklase@google.com470e71d2011-07-07 08:21:25 +000064
philipel9d3ab612015-12-21 04:12:39 -080065 _avgFrameSize = rhs._avgFrameSize;
66 _varFrameSize = rhs._varFrameSize;
67 _maxFrameSize = rhs._maxFrameSize;
68 _fsSum = rhs._fsSum;
69 _fsCount = rhs._fsCount;
70 _lastUpdateT = rhs._lastUpdateT;
71 _prevEstimate = rhs._prevEstimate;
72 _prevFrameSize = rhs._prevFrameSize;
73 _avgNoise = rhs._avgNoise;
74 _alphaCount = rhs._alphaCount;
75 _filterJitterEstimate = rhs._filterJitterEstimate;
76 _startupCount = rhs._startupCount;
77 _latestNackTimestamp = rhs._latestNackTimestamp;
78 _nackCount = rhs._nackCount;
79 _rttFilter = rhs._rttFilter;
Erik Språngb1e031a2018-11-01 11:20:49 +010080 clock_ = rhs.clock_;
philipel9d3ab612015-12-21 04:12:39 -080081 }
82 return *this;
niklase@google.com470e71d2011-07-07 08:21:25 +000083}
84
Åsa Persson3fcc5be2019-04-04 09:40:27 +020085// Resets the JitterEstimate.
philipel9d3ab612015-12-21 04:12:39 -080086void VCMJitterEstimator::Reset() {
87 _theta[0] = 1 / (512e3 / 8);
88 _theta[1] = 0;
89 _varNoise = 4.0;
niklase@google.com470e71d2011-07-07 08:21:25 +000090
philipel9d3ab612015-12-21 04:12:39 -080091 _thetaCov[0][0] = 1e-4;
92 _thetaCov[1][1] = 1e2;
93 _thetaCov[0][1] = _thetaCov[1][0] = 0;
94 _Qcov[0][0] = 2.5e-10;
95 _Qcov[1][1] = 1e-10;
96 _Qcov[0][1] = _Qcov[1][0] = 0;
97 _avgFrameSize = 500;
98 _maxFrameSize = 500;
99 _varFrameSize = 100;
100 _lastUpdateT = -1;
101 _prevEstimate = -1.0;
102 _prevFrameSize = 0;
103 _avgNoise = 0.0;
104 _alphaCount = 1;
105 _filterJitterEstimate = 0.0;
106 _latestNackTimestamp = 0;
107 _nackCount = 0;
Gustavo Garciaf7a7c8a2018-01-08 15:23:38 +0100108 _latestNackTimestamp = 0;
philipel9d3ab612015-12-21 04:12:39 -0800109 _fsSum = 0;
110 _fsCount = 0;
111 _startupCount = 0;
112 _rttFilter.Reset();
113 fps_counter_.Reset();
niklase@google.com470e71d2011-07-07 08:21:25 +0000114}
115
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200116// Updates the estimates with the new measurements.
philipel9d3ab612015-12-21 04:12:39 -0800117void VCMJitterEstimator::UpdateEstimate(int64_t frameDelayMS,
118 uint32_t frameSizeBytes,
119 bool incompleteFrame /* = false */) {
120 if (frameSizeBytes == 0) {
121 return;
122 }
123 int deltaFS = frameSizeBytes - _prevFrameSize;
124 if (_fsCount < kFsAccuStartupSamples) {
125 _fsSum += frameSizeBytes;
126 _fsCount++;
127 } else if (_fsCount == kFsAccuStartupSamples) {
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200128 // Give the frame size filter.
philipel9d3ab612015-12-21 04:12:39 -0800129 _avgFrameSize = static_cast<double>(_fsSum) / static_cast<double>(_fsCount);
130 _fsCount++;
131 }
132 if (!incompleteFrame || frameSizeBytes > _avgFrameSize) {
133 double avgFrameSize = _phi * _avgFrameSize + (1 - _phi) * frameSizeBytes;
134 if (frameSizeBytes < _avgFrameSize + 2 * sqrt(_varFrameSize)) {
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200135 // Only update the average frame size if this sample wasn't a key frame.
philipel9d3ab612015-12-21 04:12:39 -0800136 _avgFrameSize = avgFrameSize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 }
philipel9d3ab612015-12-21 04:12:39 -0800138 // Update the variance anyway since we want to capture cases where we only
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200139 // get key frames.
Yves Gerey665174f2018-06-19 15:03:05 +0200140 _varFrameSize = VCM_MAX(
141 _phi * _varFrameSize + (1 - _phi) * (frameSizeBytes - avgFrameSize) *
142 (frameSizeBytes - avgFrameSize),
143 1.0);
philipel9d3ab612015-12-21 04:12:39 -0800144 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000145
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200146 // Update max frameSize estimate.
philipel9d3ab612015-12-21 04:12:39 -0800147 _maxFrameSize =
148 VCM_MAX(_psi * _maxFrameSize, static_cast<double>(frameSizeBytes));
niklase@google.com470e71d2011-07-07 08:21:25 +0000149
philipel9d3ab612015-12-21 04:12:39 -0800150 if (_prevFrameSize == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 _prevFrameSize = frameSizeBytes;
philipel9d3ab612015-12-21 04:12:39 -0800152 return;
153 }
154 _prevFrameSize = frameSizeBytes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000155
Erik Språngb1e031a2018-11-01 11:20:49 +0100156 // Cap frameDelayMS based on the current time deviation noise.
157 int64_t max_time_deviation_ms =
158 static_cast<int64_t>(time_deviation_upper_bound_ * sqrt(_varNoise) + 0.5);
159 frameDelayMS = std::max(std::min(frameDelayMS, max_time_deviation_ms),
160 -max_time_deviation_ms);
161
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200162 // Only update the Kalman filter if the sample is not considered an extreme
163 // outlier. Even if it is an extreme outlier from a delay point of view, if
164 // the frame size also is large the deviation is probably due to an incorrect
165 // line slope.
philipel9d3ab612015-12-21 04:12:39 -0800166 double deviation = DeviationFromExpectedDelay(frameDelayMS, deltaFS);
niklase@google.com470e71d2011-07-07 08:21:25 +0000167
philipel9d3ab612015-12-21 04:12:39 -0800168 if (fabs(deviation) < _numStdDevDelayOutlier * sqrt(_varNoise) ||
169 frameSizeBytes >
170 _avgFrameSize + _numStdDevFrameSizeOutlier * sqrt(_varFrameSize)) {
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200171 // Update the variance of the deviation from the line given by the Kalman
172 // filter.
philipel9d3ab612015-12-21 04:12:39 -0800173 EstimateRandomJitter(deviation, incompleteFrame);
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200174 // Prevent updating with frames which have been congested by a large frame,
175 // and therefore arrives almost at the same time as that frame.
176 // This can occur when we receive a large frame (key frame) which has been
177 // delayed. The next frame is of normal size (delta frame), and thus deltaFS
178 // will be << 0. This removes all frame samples which arrives after a key
179 // frame.
philipel9d3ab612015-12-21 04:12:39 -0800180 if ((!incompleteFrame || deviation >= 0.0) &&
181 static_cast<double>(deltaFS) > -0.25 * _maxFrameSize) {
182 // Update the Kalman filter with the new data
183 KalmanEstimateChannel(frameDelayMS, deltaFS);
niklase@google.com470e71d2011-07-07 08:21:25 +0000184 }
philipel9d3ab612015-12-21 04:12:39 -0800185 } else {
186 int nStdDev =
187 (deviation >= 0) ? _numStdDevDelayOutlier : -_numStdDevDelayOutlier;
188 EstimateRandomJitter(nStdDev * sqrt(_varNoise), incompleteFrame);
189 }
190 // Post process the total estimated jitter
191 if (_startupCount >= kStartupDelaySamples) {
192 PostProcessEstimate();
193 } else {
194 _startupCount++;
195 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000196}
197
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200198// Updates the nack/packet ratio.
philipel9d3ab612015-12-21 04:12:39 -0800199void VCMJitterEstimator::FrameNacked() {
philipel9d3ab612015-12-21 04:12:39 -0800200 if (_nackCount < _nackLimit) {
201 _nackCount++;
202 }
Gustavo Garciaf7a7c8a2018-01-08 15:23:38 +0100203 _latestNackTimestamp = clock_->TimeInMicroseconds();
niklase@google.com470e71d2011-07-07 08:21:25 +0000204}
205
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200206// Updates Kalman estimate of the channel.
niklase@google.com470e71d2011-07-07 08:21:25 +0000207// The caller is expected to sanity check the inputs.
philipel9d3ab612015-12-21 04:12:39 -0800208void VCMJitterEstimator::KalmanEstimateChannel(int64_t frameDelayMS,
209 int32_t deltaFSBytes) {
210 double Mh[2];
211 double hMh_sigma;
212 double kalmanGain[2];
213 double measureRes;
214 double t00, t01;
niklase@google.com470e71d2011-07-07 08:21:25 +0000215
philipel9d3ab612015-12-21 04:12:39 -0800216 // Kalman filtering
niklase@google.com470e71d2011-07-07 08:21:25 +0000217
philipel9d3ab612015-12-21 04:12:39 -0800218 // Prediction
219 // M = M + Q
220 _thetaCov[0][0] += _Qcov[0][0];
221 _thetaCov[0][1] += _Qcov[0][1];
222 _thetaCov[1][0] += _Qcov[1][0];
223 _thetaCov[1][1] += _Qcov[1][1];
niklase@google.com470e71d2011-07-07 08:21:25 +0000224
philipel9d3ab612015-12-21 04:12:39 -0800225 // Kalman gain
226 // K = M*h'/(sigma2n + h*M*h') = M*h'/(1 + h*M*h')
227 // h = [dFS 1]
228 // Mh = M*h'
229 // hMh_sigma = h*M*h' + R
230 Mh[0] = _thetaCov[0][0] * deltaFSBytes + _thetaCov[0][1];
231 Mh[1] = _thetaCov[1][0] * deltaFSBytes + _thetaCov[1][1];
232 // sigma weights measurements with a small deltaFS as noisy and
233 // measurements with large deltaFS as good
234 if (_maxFrameSize < 1.0) {
235 return;
236 }
237 double sigma = (300.0 * exp(-fabs(static_cast<double>(deltaFSBytes)) /
238 (1e0 * _maxFrameSize)) +
239 1) *
240 sqrt(_varNoise);
241 if (sigma < 1.0) {
242 sigma = 1.0;
243 }
244 hMh_sigma = deltaFSBytes * Mh[0] + Mh[1] + sigma;
245 if ((hMh_sigma < 1e-9 && hMh_sigma >= 0) ||
246 (hMh_sigma > -1e-9 && hMh_sigma <= 0)) {
247 assert(false);
248 return;
249 }
250 kalmanGain[0] = Mh[0] / hMh_sigma;
251 kalmanGain[1] = Mh[1] / hMh_sigma;
niklase@google.com470e71d2011-07-07 08:21:25 +0000252
philipel9d3ab612015-12-21 04:12:39 -0800253 // Correction
254 // theta = theta + K*(dT - h*theta)
255 measureRes = frameDelayMS - (deltaFSBytes * _theta[0] + _theta[1]);
256 _theta[0] += kalmanGain[0] * measureRes;
257 _theta[1] += kalmanGain[1] * measureRes;
niklase@google.com470e71d2011-07-07 08:21:25 +0000258
philipel9d3ab612015-12-21 04:12:39 -0800259 if (_theta[0] < _thetaLow) {
260 _theta[0] = _thetaLow;
261 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000262
philipel9d3ab612015-12-21 04:12:39 -0800263 // M = (I - K*h)*M
264 t00 = _thetaCov[0][0];
265 t01 = _thetaCov[0][1];
266 _thetaCov[0][0] = (1 - kalmanGain[0] * deltaFSBytes) * t00 -
267 kalmanGain[0] * _thetaCov[1][0];
268 _thetaCov[0][1] = (1 - kalmanGain[0] * deltaFSBytes) * t01 -
269 kalmanGain[0] * _thetaCov[1][1];
270 _thetaCov[1][0] = _thetaCov[1][0] * (1 - kalmanGain[1]) -
271 kalmanGain[1] * deltaFSBytes * t00;
272 _thetaCov[1][1] = _thetaCov[1][1] * (1 - kalmanGain[1]) -
273 kalmanGain[1] * deltaFSBytes * t01;
niklase@google.com470e71d2011-07-07 08:21:25 +0000274
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200275 // Covariance matrix, must be positive semi-definite.
philipel9d3ab612015-12-21 04:12:39 -0800276 assert(_thetaCov[0][0] + _thetaCov[1][1] >= 0 &&
277 _thetaCov[0][0] * _thetaCov[1][1] -
278 _thetaCov[0][1] * _thetaCov[1][0] >=
279 0 &&
280 _thetaCov[0][0] >= 0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000281}
282
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200283// Calculate difference in delay between a sample and the expected delay
284// estimated by the Kalman filter
philipel9d3ab612015-12-21 04:12:39 -0800285double VCMJitterEstimator::DeviationFromExpectedDelay(
286 int64_t frameDelayMS,
287 int32_t deltaFSBytes) const {
288 return frameDelayMS - (_theta[0] * deltaFSBytes + _theta[1]);
niklase@google.com470e71d2011-07-07 08:21:25 +0000289}
290
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200291// Estimates the random jitter by calculating the variance of the sample
292// distance from the line given by theta.
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000293void VCMJitterEstimator::EstimateRandomJitter(double d_dT,
294 bool incompleteFrame) {
295 uint64_t now = clock_->TimeInMicroseconds();
296 if (_lastUpdateT != -1) {
297 fps_counter_.AddSample(now - _lastUpdateT);
298 }
299 _lastUpdateT = now;
300
301 if (_alphaCount == 0) {
302 assert(false);
303 return;
304 }
305 double alpha =
306 static_cast<double>(_alphaCount - 1) / static_cast<double>(_alphaCount);
307 _alphaCount++;
308 if (_alphaCount > _alphaCountMax)
309 _alphaCount = _alphaCountMax;
310
Erik Språngb1e031a2018-11-01 11:20:49 +0100311 // In order to avoid a low frame rate stream to react slower to changes,
312 // scale the alpha weight relative a 30 fps stream.
313 double fps = GetFrameRate();
314 if (fps > 0.0) {
315 double rate_scale = 30.0 / fps;
316 // At startup, there can be a lot of noise in the fps estimate.
317 // Interpolate rate_scale linearly, from 1.0 at sample #1, to 30.0 / fps
318 // at sample #kStartupDelaySamples.
319 if (_alphaCount < kStartupDelaySamples) {
320 rate_scale =
321 (_alphaCount * rate_scale + (kStartupDelaySamples - _alphaCount)) /
322 kStartupDelaySamples;
niklase@google.com470e71d2011-07-07 08:21:25 +0000323 }
Erik Språngb1e031a2018-11-01 11:20:49 +0100324 alpha = pow(alpha, rate_scale);
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000325 }
326
327 double avgNoise = alpha * _avgNoise + (1 - alpha) * d_dT;
328 double varNoise =
329 alpha * _varNoise + (1 - alpha) * (d_dT - _avgNoise) * (d_dT - _avgNoise);
330 if (!incompleteFrame || varNoise > _varNoise) {
331 _avgNoise = avgNoise;
332 _varNoise = varNoise;
333 }
334 if (_varNoise < 1.0) {
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200335 // The variance should never be zero, since we might get stuck and consider
336 // all samples as outliers.
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000337 _varNoise = 1.0;
338 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000339}
340
philipel9d3ab612015-12-21 04:12:39 -0800341double VCMJitterEstimator::NoiseThreshold() const {
342 double noiseThreshold = _noiseStdDevs * sqrt(_varNoise) - _noiseStdDevOffset;
343 if (noiseThreshold < 1.0) {
344 noiseThreshold = 1.0;
345 }
346 return noiseThreshold;
niklase@google.com470e71d2011-07-07 08:21:25 +0000347}
348
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200349// Calculates the current jitter estimate from the filtered estimates.
philipel9d3ab612015-12-21 04:12:39 -0800350double VCMJitterEstimator::CalculateEstimate() {
351 double ret = _theta[0] * (_maxFrameSize - _avgFrameSize) + NoiseThreshold();
niklase@google.com470e71d2011-07-07 08:21:25 +0000352
Åsa Persson3fcc5be2019-04-04 09:40:27 +0200353 // A very low estimate (or negative) is neglected.
philipel9d3ab612015-12-21 04:12:39 -0800354 if (ret < 1.0) {
355 if (_prevEstimate <= 0.01) {
356 ret = 1.0;
357 } else {
358 ret = _prevEstimate;
niklase@google.com470e71d2011-07-07 08:21:25 +0000359 }
philipel9d3ab612015-12-21 04:12:39 -0800360 }
361 if (ret > 10000.0) { // Sanity
362 ret = 10000.0;
363 }
364 _prevEstimate = ret;
365 return ret;
niklase@google.com470e71d2011-07-07 08:21:25 +0000366}
367
philipel9d3ab612015-12-21 04:12:39 -0800368void VCMJitterEstimator::PostProcessEstimate() {
369 _filterJitterEstimate = CalculateEstimate();
niklase@google.com470e71d2011-07-07 08:21:25 +0000370}
371
philipel9d3ab612015-12-21 04:12:39 -0800372void VCMJitterEstimator::UpdateRtt(int64_t rttMs) {
373 _rttFilter.Update(rttMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000374}
375
niklase@google.com470e71d2011-07-07 08:21:25 +0000376// Returns the current filtered estimate if available,
377// otherwise tries to calculate an estimate.
“Michaele0f37042019-06-04 10:04:12 -0500378int VCMJitterEstimator::GetJitterEstimate(
379 double rttMultiplier,
380 absl::optional<double> rttMultAddCapMs) {
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000381 double jitterMS = CalculateEstimate() + OPERATING_SYSTEM_JITTER;
Gustavo Garciaf7a7c8a2018-01-08 15:23:38 +0100382 uint64_t now = clock_->TimeInMicroseconds();
383
384 if (now - _latestNackTimestamp > kNackCountTimeoutMs * 1000)
385 _nackCount = 0;
386
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000387 if (_filterJitterEstimate > jitterMS)
388 jitterMS = _filterJitterEstimate;
“Michaele0f37042019-06-04 10:04:12 -0500389 if (_nackCount >= _nackLimit) {
390 if (rttMultAddCapMs.has_value()) {
391 jitterMS +=
392 std::min(_rttFilter.RttMs() * rttMultiplier, rttMultAddCapMs.value());
393 } else {
394 jitterMS += _rttFilter.RttMs() * rttMultiplier;
395 }
396 }
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000397
Erik Språngb1e031a2018-11-01 11:20:49 +0100398 static const double kJitterScaleLowThreshold = 5.0;
399 static const double kJitterScaleHighThreshold = 10.0;
400 double fps = GetFrameRate();
401 // Ignore jitter for very low fps streams.
402 if (fps < kJitterScaleLowThreshold) {
403 if (fps == 0.0) {
404 return rtc::checked_cast<int>(std::max(0.0, jitterMS) + 0.5);
niklase@google.com470e71d2011-07-07 08:21:25 +0000405 }
Erik Språngb1e031a2018-11-01 11:20:49 +0100406 return 0;
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000407 }
408
Erik Språngb1e031a2018-11-01 11:20:49 +0100409 // Semi-low frame rate; scale by factor linearly interpolated from 0.0 at
410 // kJitterScaleLowThreshold to 1.0 at kJitterScaleHighThreshold.
411 if (fps < kJitterScaleHighThreshold) {
412 jitterMS = (1.0 / (kJitterScaleHighThreshold - kJitterScaleLowThreshold)) *
413 (fps - kJitterScaleLowThreshold) * jitterMS;
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000414 }
Erik Språngb1e031a2018-11-01 11:20:49 +0100415
416 return rtc::checked_cast<int>(std::max(0.0, jitterMS) + 0.5);
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000417}
418
419double VCMJitterEstimator::GetFrameRate() const {
Sebastian Jansson7a994332019-06-11 10:28:20 +0200420 if (fps_counter_.ComputeMean() <= 0.0)
sprang@webrtc.org70e2d112014-09-24 14:06:56 +0000421 return 0;
422
423 double fps = 1000000.0 / fps_counter_.ComputeMean();
424 // Sanity check.
425 assert(fps >= 0.0);
426 if (fps > kMaxFramerateEstimate) {
427 fps = kMaxFramerateEstimate;
428 }
429 return fps;
niklase@google.com470e71d2011-07-07 08:21:25 +0000430}
philipel9d3ab612015-12-21 04:12:39 -0800431} // namespace webrtc