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 VCMRttFilter::VCMRttFilter() 22 : _filtFactMax(35), 23 _jumpStdDevs(2.5), 24 _driftStdDevs(3.5), 25 _detectThreshold(kMaxDriftJumpCount) { 26 Reset(); 27 } 28 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 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 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 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 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 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 162 int64_t VCMRttFilter::RttMs() const { 163 return static_cast<int64_t>(_maxRtt + 0.5); 164 } 165 } // namespace webrtc 166