Home | History | Annotate | Download | only in source
      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 
     20 VCMRttFilter::VCMRttFilter()
     21     : _filtFactMax(35),
     22       _jumpStdDevs(2.5),
     23       _driftStdDevs(3.5),
     24       _detectThreshold(kMaxDriftJumpCount) {
     25     Reset();
     26 }
     27 
     28 VCMRttFilter&
     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
     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
     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
    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
    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
    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
    197 VCMRttFilter::RttMs() const
    198 {
    199     return static_cast<uint32_t>(_maxRtt + 0.5);
    200 }
    201 
    202 }
    203