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 "webrtc/modules/video_coding/rtt_filter.h"
12
13 #include <math.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include "webrtc/modules/video_coding/internal_defines.h"
18
19 namespace webrtc {
20
VCMRttFilter()21 VCMRttFilter::VCMRttFilter()
22 : _filtFactMax(35),
23 _jumpStdDevs(2.5),
24 _driftStdDevs(3.5),
25 _detectThreshold(kMaxDriftJumpCount) {
26 Reset();
27 }
28
operator =(const VCMRttFilter & rhs)29 VCMRttFilter& VCMRttFilter::operator=(const VCMRttFilter& rhs) {
30 if (this != &rhs) {
31 _gotNonZeroUpdate = rhs._gotNonZeroUpdate;
32 _avgRtt = rhs._avgRtt;
33 _varRtt = rhs._varRtt;
34 _maxRtt = rhs._maxRtt;
35 _filtFactCount = rhs._filtFactCount;
36 _jumpCount = rhs._jumpCount;
37 _driftCount = rhs._driftCount;
38 memcpy(_jumpBuf, rhs._jumpBuf, sizeof(_jumpBuf));
39 memcpy(_driftBuf, rhs._driftBuf, sizeof(_driftBuf));
40 }
41 return *this;
42 }
43
Reset()44 void VCMRttFilter::Reset() {
45 _gotNonZeroUpdate = false;
46 _avgRtt = 0;
47 _varRtt = 0;
48 _maxRtt = 0;
49 _filtFactCount = 1;
50 _jumpCount = 0;
51 _driftCount = 0;
52 memset(_jumpBuf, 0, kMaxDriftJumpCount);
53 memset(_driftBuf, 0, kMaxDriftJumpCount);
54 }
55
Update(int64_t rttMs)56 void VCMRttFilter::Update(int64_t rttMs) {
57 if (!_gotNonZeroUpdate) {
58 if (rttMs == 0) {
59 return;
60 }
61 _gotNonZeroUpdate = true;
62 }
63
64 // Sanity check
65 if (rttMs > 3000) {
66 rttMs = 3000;
67 }
68
69 double filtFactor = 0;
70 if (_filtFactCount > 1) {
71 filtFactor = static_cast<double>(_filtFactCount - 1) / _filtFactCount;
72 }
73 _filtFactCount++;
74 if (_filtFactCount > _filtFactMax) {
75 // This prevents filtFactor from going above
76 // (_filtFactMax - 1) / _filtFactMax,
77 // e.g., _filtFactMax = 50 => filtFactor = 49/50 = 0.98
78 _filtFactCount = _filtFactMax;
79 }
80 double oldAvg = _avgRtt;
81 double oldVar = _varRtt;
82 _avgRtt = filtFactor * _avgRtt + (1 - filtFactor) * rttMs;
83 _varRtt = filtFactor * _varRtt +
84 (1 - filtFactor) * (rttMs - _avgRtt) * (rttMs - _avgRtt);
85 _maxRtt = VCM_MAX(rttMs, _maxRtt);
86 if (!JumpDetection(rttMs) || !DriftDetection(rttMs)) {
87 // In some cases we don't want to update the statistics
88 _avgRtt = oldAvg;
89 _varRtt = oldVar;
90 }
91 }
92
JumpDetection(int64_t rttMs)93 bool VCMRttFilter::JumpDetection(int64_t rttMs) {
94 double diffFromAvg = _avgRtt - rttMs;
95 if (fabs(diffFromAvg) > _jumpStdDevs * sqrt(_varRtt)) {
96 int diffSign = (diffFromAvg >= 0) ? 1 : -1;
97 int jumpCountSign = (_jumpCount >= 0) ? 1 : -1;
98 if (diffSign != jumpCountSign) {
99 // Since the signs differ the samples currently
100 // in the buffer is useless as they represent a
101 // jump in a different direction.
102 _jumpCount = 0;
103 }
104 if (abs(_jumpCount) < kMaxDriftJumpCount) {
105 // Update the buffer used for the short time
106 // statistics.
107 // The sign of the diff is used for updating the counter since
108 // we want to use the same buffer for keeping track of when
109 // the RTT jumps down and up.
110 _jumpBuf[abs(_jumpCount)] = rttMs;
111 _jumpCount += diffSign;
112 }
113 if (abs(_jumpCount) >= _detectThreshold) {
114 // Detected an RTT jump
115 ShortRttFilter(_jumpBuf, abs(_jumpCount));
116 _filtFactCount = _detectThreshold + 1;
117 _jumpCount = 0;
118 } else {
119 return false;
120 }
121 } else {
122 _jumpCount = 0;
123 }
124 return true;
125 }
126
DriftDetection(int64_t rttMs)127 bool VCMRttFilter::DriftDetection(int64_t rttMs) {
128 if (_maxRtt - _avgRtt > _driftStdDevs * sqrt(_varRtt)) {
129 if (_driftCount < kMaxDriftJumpCount) {
130 // Update the buffer used for the short time
131 // statistics.
132 _driftBuf[_driftCount] = rttMs;
133 _driftCount++;
134 }
135 if (_driftCount >= _detectThreshold) {
136 // Detected an RTT drift
137 ShortRttFilter(_driftBuf, _driftCount);
138 _filtFactCount = _detectThreshold + 1;
139 _driftCount = 0;
140 }
141 } else {
142 _driftCount = 0;
143 }
144 return true;
145 }
146
ShortRttFilter(int64_t * buf,uint32_t length)147 void VCMRttFilter::ShortRttFilter(int64_t* buf, uint32_t length) {
148 if (length == 0) {
149 return;
150 }
151 _maxRtt = 0;
152 _avgRtt = 0;
153 for (uint32_t i = 0; i < length; i++) {
154 if (buf[i] > _maxRtt) {
155 _maxRtt = buf[i];
156 }
157 _avgRtt += buf[i];
158 }
159 _avgRtt = _avgRtt / static_cast<double>(length);
160 }
161
RttMs() const162 int64_t VCMRttFilter::RttMs() const {
163 return static_cast<int64_t>(_maxRtt + 0.5);
164 }
165 } // namespace webrtc
166