• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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