Home | History | Annotate | Download | only in video_coding
      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