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