Line data Source code
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 :
21 0 : VCMRttFilter::VCMRttFilter()
22 : : _filtFactMax(35),
23 : _jumpStdDevs(2.5),
24 : _driftStdDevs(3.5),
25 0 : _detectThreshold(kMaxDriftJumpCount) {
26 0 : Reset();
27 0 : }
28 :
29 0 : VCMRttFilter& VCMRttFilter::operator=(const VCMRttFilter& rhs) {
30 0 : if (this != &rhs) {
31 0 : _gotNonZeroUpdate = rhs._gotNonZeroUpdate;
32 0 : _avgRtt = rhs._avgRtt;
33 0 : _varRtt = rhs._varRtt;
34 0 : _maxRtt = rhs._maxRtt;
35 0 : _filtFactCount = rhs._filtFactCount;
36 0 : _jumpCount = rhs._jumpCount;
37 0 : _driftCount = rhs._driftCount;
38 0 : memcpy(_jumpBuf, rhs._jumpBuf, sizeof(_jumpBuf));
39 0 : memcpy(_driftBuf, rhs._driftBuf, sizeof(_driftBuf));
40 : }
41 0 : return *this;
42 : }
43 :
44 0 : void VCMRttFilter::Reset() {
45 0 : _gotNonZeroUpdate = false;
46 0 : _avgRtt = 0;
47 0 : _varRtt = 0;
48 0 : _maxRtt = 0;
49 0 : _filtFactCount = 1;
50 0 : _jumpCount = 0;
51 0 : _driftCount = 0;
52 0 : memset(_jumpBuf, 0, sizeof(_jumpBuf));
53 0 : memset(_driftBuf, 0, sizeof(_driftBuf));
54 0 : }
55 :
56 0 : void VCMRttFilter::Update(int64_t rttMs) {
57 0 : if (!_gotNonZeroUpdate) {
58 0 : if (rttMs == 0) {
59 0 : return;
60 : }
61 0 : _gotNonZeroUpdate = true;
62 : }
63 :
64 : // Sanity check
65 0 : if (rttMs > 3000) {
66 0 : rttMs = 3000;
67 : }
68 :
69 0 : double filtFactor = 0;
70 0 : if (_filtFactCount > 1) {
71 0 : filtFactor = static_cast<double>(_filtFactCount - 1) / _filtFactCount;
72 : }
73 0 : _filtFactCount++;
74 0 : 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 0 : _filtFactCount = _filtFactMax;
79 : }
80 0 : double oldAvg = _avgRtt;
81 0 : double oldVar = _varRtt;
82 0 : _avgRtt = filtFactor * _avgRtt + (1 - filtFactor) * rttMs;
83 0 : _varRtt = filtFactor * _varRtt +
84 0 : (1 - filtFactor) * (rttMs - _avgRtt) * (rttMs - _avgRtt);
85 0 : _maxRtt = VCM_MAX(rttMs, _maxRtt);
86 0 : if (!JumpDetection(rttMs) || !DriftDetection(rttMs)) {
87 : // In some cases we don't want to update the statistics
88 0 : _avgRtt = oldAvg;
89 0 : _varRtt = oldVar;
90 : }
91 : }
92 :
93 0 : bool VCMRttFilter::JumpDetection(int64_t rttMs) {
94 0 : double diffFromAvg = _avgRtt - rttMs;
95 0 : if (fabs(diffFromAvg) > _jumpStdDevs * sqrt(_varRtt)) {
96 0 : int diffSign = (diffFromAvg >= 0) ? 1 : -1;
97 0 : int jumpCountSign = (_jumpCount >= 0) ? 1 : -1;
98 0 : 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 0 : _jumpCount = 0;
103 : }
104 0 : 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 0 : _jumpBuf[abs(_jumpCount)] = rttMs;
111 0 : _jumpCount += diffSign;
112 : }
113 0 : if (abs(_jumpCount) >= _detectThreshold) {
114 : // Detected an RTT jump
115 0 : ShortRttFilter(_jumpBuf, abs(_jumpCount));
116 0 : _filtFactCount = _detectThreshold + 1;
117 0 : _jumpCount = 0;
118 : } else {
119 0 : return false;
120 : }
121 : } else {
122 0 : _jumpCount = 0;
123 : }
124 0 : return true;
125 : }
126 :
127 0 : bool VCMRttFilter::DriftDetection(int64_t rttMs) {
128 0 : if (_maxRtt - _avgRtt > _driftStdDevs * sqrt(_varRtt)) {
129 0 : if (_driftCount < kMaxDriftJumpCount) {
130 : // Update the buffer used for the short time
131 : // statistics.
132 0 : _driftBuf[_driftCount] = rttMs;
133 0 : _driftCount++;
134 : }
135 0 : if (_driftCount >= _detectThreshold) {
136 : // Detected an RTT drift
137 0 : ShortRttFilter(_driftBuf, _driftCount);
138 0 : _filtFactCount = _detectThreshold + 1;
139 0 : _driftCount = 0;
140 : }
141 : } else {
142 0 : _driftCount = 0;
143 : }
144 0 : return true;
145 : }
146 :
147 0 : void VCMRttFilter::ShortRttFilter(int64_t* buf, uint32_t length) {
148 0 : if (length == 0) {
149 0 : return;
150 : }
151 0 : _maxRtt = 0;
152 0 : _avgRtt = 0;
153 0 : for (uint32_t i = 0; i < length; i++) {
154 0 : if (buf[i] > _maxRtt) {
155 0 : _maxRtt = buf[i];
156 : }
157 0 : _avgRtt += buf[i];
158 : }
159 0 : _avgRtt = _avgRtt / static_cast<double>(length);
160 : }
161 :
162 0 : int64_t VCMRttFilter::RttMs() const {
163 0 : return static_cast<int64_t>(_maxRtt + 0.5);
164 : }
165 : } // namespace webrtc
|