diff options
Diffstat (limited to 'webrtc/modules/video_coding/main/source/rtt_filter.cc')
-rw-r--r-- | webrtc/modules/video_coding/main/source/rtt_filter.cc | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/webrtc/modules/video_coding/main/source/rtt_filter.cc b/webrtc/modules/video_coding/main/source/rtt_filter.cc new file mode 100644 index 0000000000..5742e8fa89 --- /dev/null +++ b/webrtc/modules/video_coding/main/source/rtt_filter.cc @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/modules/video_coding/main/source/internal_defines.h" +#include "webrtc/modules/video_coding/main/source/rtt_filter.h" + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +namespace webrtc { + +VCMRttFilter::VCMRttFilter() + : _filtFactMax(35), + _jumpStdDevs(2.5), + _driftStdDevs(3.5), + _detectThreshold(kMaxDriftJumpCount) { + Reset(); +} + +VCMRttFilter& +VCMRttFilter::operator=(const VCMRttFilter& rhs) +{ + if (this != &rhs) + { + _gotNonZeroUpdate = rhs._gotNonZeroUpdate; + _avgRtt = rhs._avgRtt; + _varRtt = rhs._varRtt; + _maxRtt = rhs._maxRtt; + _filtFactCount = rhs._filtFactCount; + _jumpCount = rhs._jumpCount; + _driftCount = rhs._driftCount; + memcpy(_jumpBuf, rhs._jumpBuf, sizeof(_jumpBuf)); + memcpy(_driftBuf, rhs._driftBuf, sizeof(_driftBuf)); + } + return *this; +} + +void +VCMRttFilter::Reset() +{ + _gotNonZeroUpdate = false; + _avgRtt = 0; + _varRtt = 0; + _maxRtt = 0; + _filtFactCount = 1; + _jumpCount = 0; + _driftCount = 0; + memset(_jumpBuf, 0, kMaxDriftJumpCount); + memset(_driftBuf, 0, kMaxDriftJumpCount); +} + +void +VCMRttFilter::Update(int64_t rttMs) +{ + if (!_gotNonZeroUpdate) + { + if (rttMs == 0) + { + return; + } + _gotNonZeroUpdate = true; + } + + // Sanity check + if (rttMs > 3000) + { + rttMs = 3000; + } + + double filtFactor = 0; + if (_filtFactCount > 1) + { + filtFactor = static_cast<double>(_filtFactCount - 1) / _filtFactCount; + } + _filtFactCount++; + if (_filtFactCount > _filtFactMax) + { + // This prevents filtFactor from going above + // (_filtFactMax - 1) / _filtFactMax, + // e.g., _filtFactMax = 50 => filtFactor = 49/50 = 0.98 + _filtFactCount = _filtFactMax; + } + double oldAvg = _avgRtt; + double oldVar = _varRtt; + _avgRtt = filtFactor * _avgRtt + (1 - filtFactor) * rttMs; + _varRtt = filtFactor * _varRtt + (1 - filtFactor) * + (rttMs - _avgRtt) * (rttMs - _avgRtt); + _maxRtt = VCM_MAX(rttMs, _maxRtt); + if (!JumpDetection(rttMs) || !DriftDetection(rttMs)) + { + // In some cases we don't want to update the statistics + _avgRtt = oldAvg; + _varRtt = oldVar; + } +} + +bool +VCMRttFilter::JumpDetection(int64_t rttMs) +{ + double diffFromAvg = _avgRtt - rttMs; + if (fabs(diffFromAvg) > _jumpStdDevs * sqrt(_varRtt)) + { + int diffSign = (diffFromAvg >= 0) ? 1 : -1; + int jumpCountSign = (_jumpCount >= 0) ? 1 : -1; + if (diffSign != jumpCountSign) + { + // Since the signs differ the samples currently + // in the buffer is useless as they represent a + // jump in a different direction. + _jumpCount = 0; + } + if (abs(_jumpCount) < kMaxDriftJumpCount) + { + // Update the buffer used for the short time + // statistics. + // The sign of the diff is used for updating the counter since + // we want to use the same buffer for keeping track of when + // the RTT jumps down and up. + _jumpBuf[abs(_jumpCount)] = rttMs; + _jumpCount += diffSign; + } + if (abs(_jumpCount) >= _detectThreshold) + { + // Detected an RTT jump + ShortRttFilter(_jumpBuf, abs(_jumpCount)); + _filtFactCount = _detectThreshold + 1; + _jumpCount = 0; + } + else + { + return false; + } + } + else + { + _jumpCount = 0; + } + return true; +} + +bool +VCMRttFilter::DriftDetection(int64_t rttMs) +{ + if (_maxRtt - _avgRtt > _driftStdDevs * sqrt(_varRtt)) + { + if (_driftCount < kMaxDriftJumpCount) + { + // Update the buffer used for the short time + // statistics. + _driftBuf[_driftCount] = rttMs; + _driftCount++; + } + if (_driftCount >= _detectThreshold) + { + // Detected an RTT drift + ShortRttFilter(_driftBuf, _driftCount); + _filtFactCount = _detectThreshold + 1; + _driftCount = 0; + } + } + else + { + _driftCount = 0; + } + return true; +} + +void +VCMRttFilter::ShortRttFilter(int64_t* buf, uint32_t length) +{ + if (length == 0) + { + return; + } + _maxRtt = 0; + _avgRtt = 0; + for (uint32_t i=0; i < length; i++) + { + if (buf[i] > _maxRtt) + { + _maxRtt = buf[i]; + } + _avgRtt += buf[i]; + } + _avgRtt = _avgRtt / static_cast<double>(length); +} + +int64_t +VCMRttFilter::RttMs() const +{ + return static_cast<int64_t>(_maxRtt + 0.5); +} + +} |