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