Raw packet loss rate reported by RTP_RTCP module may vary too drastically over time. This CL is to add a filter to the value in VoE before lending it to audio coding module.

The filter is an exponential filter borrowed from video coding module.

The method is written in a new class called PacketLossProtector (not sure if the name is nice), which can be used in the future for more sophisticated logic.

BUG=
R=henrika@webrtc.org, stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/20809004

git-svn-id: http://webrtc.googlecode.com/svn/trunk/webrtc@6709 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/base/base.gyp b/base/base.gyp
index f9ba404..6a0c359 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -85,6 +85,8 @@
         'diskcache_win32.h',
         'event.cc',
         'event.h',
+        'exp_filter.cc',
+        'exp_filter.h',
         'filelock.cc',
         'filelock.h',
         'fileutils.cc',
diff --git a/base/base_tests.gyp b/base/base_tests.gyp
index ca0d72a..3cef102 100644
--- a/base/base_tests.gyp
+++ b/base/base_tests.gyp
@@ -57,6 +57,7 @@
         'crc32_unittest.cc',
         'criticalsection_unittest.cc',
         'event_unittest.cc',
+        'exp_filter_unittest.cc',
         'filelock_unittest.cc',
         'fileutils_unittest.cc',
         'helpers_unittest.cc',
diff --git a/base/exp_filter.cc b/base/exp_filter.cc
new file mode 100644
index 0000000..9529480
--- /dev/null
+++ b/base/exp_filter.cc
@@ -0,0 +1,43 @@
+/*
+ *  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/base/exp_filter.h"
+
+#include <math.h>
+
+namespace rtc {
+
+const float ExpFilter::kValueUndefined = -1.0f;
+
+void ExpFilter::Reset(float alpha) {
+  alpha_ = alpha;
+  filtered_ = kValueUndefined;
+}
+
+float ExpFilter::Apply(float exp, float sample) {
+  if (filtered_ == kValueUndefined) {
+    // Initialize filtered value.
+    filtered_ = sample;
+  } else if (exp == 1.0) {
+    filtered_ = alpha_ * filtered_ + (1 - alpha_) * sample;
+  } else {
+    float alpha = pow(alpha_, exp);
+    filtered_ = alpha * filtered_ + (1 - alpha) * sample;
+  }
+  if (max_ != kValueUndefined && filtered_ > max_) {
+    filtered_ = max_;
+  }
+  return filtered_;
+}
+
+void ExpFilter::UpdateBase(float alpha) {
+  alpha_ = alpha;
+}
+}  // namespace rtc
diff --git a/base/exp_filter.h b/base/exp_filter.h
new file mode 100644
index 0000000..174159b
--- /dev/null
+++ b/base/exp_filter.h
@@ -0,0 +1,49 @@
+/*
+ *  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.
+ */
+
+#ifndef WEBRTC_BASE_EXP_FILTER_H_
+#define WEBRTC_BASE_EXP_FILTER_H_
+
+namespace rtc {
+
+// This class can be used, for example, for smoothing the result of bandwidth
+// estimation and packet loss estimation.
+
+class ExpFilter {
+ public:
+  static const float kValueUndefined;
+
+  explicit ExpFilter(float alpha, float max = kValueUndefined)
+      : max_(max) {
+    Reset(alpha);
+  }
+
+  // Resets the filter to its initial state, and resets filter factor base to
+  // the given value |alpha|.
+  void Reset(float alpha);
+
+  // Applies the filter with a given exponent on the provided sample:
+  // y(k) = min(alpha_^ exp * y(k-1) + (1 - alpha_^ exp) * sample, max_).
+  float Apply(float exp, float sample);
+
+  // Returns current filtered value.
+  float filtered() const { return filtered_; }
+
+  // Changes the filter factor base to the given value |alpha|.
+  void UpdateBase(float alpha);
+
+ private:
+  float alpha_;  // Filter factor base.
+  float filtered_;  // Current filter output.
+  const float max_;
+};
+}  // namespace rtc
+
+#endif  // WEBRTC_BASE_EXP_FILTER_H_
diff --git a/base/exp_filter_unittest.cc b/base/exp_filter_unittest.cc
new file mode 100644
index 0000000..f027808
--- /dev/null
+++ b/base/exp_filter_unittest.cc
@@ -0,0 +1,71 @@
+/*
+ *  Copyright 2014 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 <math.h>
+
+#include "webrtc/base/gunit.h"
+#include "webrtc/base/exp_filter.h"
+
+namespace rtc {
+
+TEST(ExpFilterTest, FirstTimeOutputEqualInput) {
+  // No max value defined.
+  ExpFilter filter = ExpFilter(0.9f);
+  filter.Apply(100.0f, 10.0f);
+
+  // First time, first argument no effect.
+  double value = 10.0f;
+  EXPECT_FLOAT_EQ(value, filter.filtered());
+}
+
+TEST(ExpFilterTest, SecondTime) {
+  double value;
+
+  ExpFilter filter = ExpFilter(0.9f);
+  filter.Apply(100.0f, 10.0f);
+
+  // First time, first argument no effect.
+  value = 10.0f;
+
+  filter.Apply(10.0f, 20.0f);
+  double alpha = pow(0.9f, 10.0f);
+  value = alpha * value + (1.0f - alpha) * 20.0f;
+  EXPECT_FLOAT_EQ(value, filter.filtered());
+}
+
+TEST(ExpFilterTest, Reset) {
+  ExpFilter filter = ExpFilter(0.9f);
+  filter.Apply(100.0f, 10.0f);
+
+  filter.Reset(0.8f);
+  filter.Apply(100.0f, 1.0f);
+
+  // Become first time after a reset.
+  double value = 1.0f;
+  EXPECT_FLOAT_EQ(value, filter.filtered());
+}
+
+TEST(ExpfilterTest, OutputLimitedByMax) {
+  double value;
+
+  // Max value defined.
+  ExpFilter filter = ExpFilter(0.9f, 1.0f);
+  filter.Apply(100.0f, 10.0f);
+
+  // Limited to max value.
+  value = 1.0f;
+  EXPECT_EQ(value, filter.filtered());
+
+  filter.Apply(1.0f, 0.0f);
+  value = 0.9f * value;
+  EXPECT_FLOAT_EQ(value, filter.filtered());
+}
+
+}  // namespace rtc
diff --git a/modules/video_coding/main/source/media_opt_util.cc b/modules/video_coding/main/source/media_opt_util.cc
index ba86575..b506a5b 100644
--- a/modules/video_coding/main/source/media_opt_util.cc
+++ b/modules/video_coding/main/source/media_opt_util.cc
@@ -837,7 +837,7 @@
     case kNoFilter:
       break;
     case kAvgFilter:
-      filtered_loss = static_cast<uint8_t> (_lossPr255.Value() + 0.5);
+      filtered_loss = static_cast<uint8_t>(_lossPr255.filtered() + 0.5);
       break;
     case kMaxFilter:
       filtered_loss = MaxFilteredLossPr(nowMs);
@@ -907,8 +907,8 @@
     _currentParameters.keyFrameSize = _keyFrameSize;
     _currentParameters.fecRateDelta = _fecRateDelta;
     _currentParameters.fecRateKey = _fecRateKey;
-    _currentParameters.packetsPerFrame = _packetsPerFrame.Value();
-    _currentParameters.packetsPerFrameKey = _packetsPerFrameKey.Value();
+    _currentParameters.packetsPerFrame = _packetsPerFrame.filtered();
+    _currentParameters.packetsPerFrameKey = _packetsPerFrameKey.filtered();
     _currentParameters.residualPacketLossFec = _residualPacketLossFec;
     _currentParameters.codecWidth = _codecWidth;
     _currentParameters.codecHeight = _codecHeight;
diff --git a/modules/video_coding/main/source/media_opt_util.h b/modules/video_coding/main/source/media_opt_util.h
index f39a578..d421d9e 100644
--- a/modules/video_coding/main/source/media_opt_util.h
+++ b/modules/video_coding/main/source/media_opt_util.h
@@ -14,9 +14,9 @@
 #include <math.h>
 #include <stdlib.h>
 
+#include "webrtc/base/exp_filter.h"
 #include "webrtc/modules/video_coding/main/source/internal_defines.h"
 #include "webrtc/modules/video_coding/main/source/qm_select.h"
-#include "webrtc/modules/video_coding/utility/include/exp_filter.h"
 #include "webrtc/system_wrappers/interface/trace.h"
 #include "webrtc/typedefs.h"
 
@@ -367,27 +367,27 @@
     // Sets the available loss protection methods.
     void UpdateMaxLossHistory(uint8_t lossPr255, int64_t now);
     uint8_t MaxFilteredLossPr(int64_t nowMs) const;
-    VCMProtectionMethod*      _selectedMethod;
-    VCMProtectionParameters   _currentParameters;
-    uint32_t            _rtt;
-    float                     _lossPr;
-    float                     _bitRate;
-    float                     _frameRate;
-    float                     _keyFrameSize;
-    uint8_t             _fecRateKey;
-    uint8_t             _fecRateDelta;
-    int64_t             _lastPrUpdateT;
-    int64_t             _lastPacketPerFrameUpdateT;
-    int64_t             _lastPacketPerFrameUpdateTKey;
-    VCMExpFilter              _lossPr255;
-    VCMLossProbabilitySample  _lossPrHistory[kLossPrHistorySize];
-    uint8_t             _shortMaxLossPr255;
-    VCMExpFilter              _packetsPerFrame;
-    VCMExpFilter              _packetsPerFrameKey;
-    float                     _residualPacketLossFec;
-    uint16_t            _codecWidth;
-    uint16_t            _codecHeight;
-    int                       _numLayers;
+    VCMProtectionMethod* _selectedMethod;
+    VCMProtectionParameters _currentParameters;
+    uint32_t _rtt;
+    float _lossPr;
+    float _bitRate;
+    float _frameRate;
+    float _keyFrameSize;
+    uint8_t _fecRateKey;
+    uint8_t _fecRateDelta;
+    int64_t _lastPrUpdateT;
+    int64_t _lastPacketPerFrameUpdateT;
+    int64_t _lastPacketPerFrameUpdateTKey;
+    rtc::ExpFilter _lossPr255;
+    VCMLossProbabilitySample _lossPrHistory[kLossPrHistorySize];
+    uint8_t _shortMaxLossPr255;
+    rtc::ExpFilter _packetsPerFrame;
+    rtc::ExpFilter _packetsPerFrameKey;
+    float _residualPacketLossFec;
+    uint16_t _codecWidth;
+    uint16_t _codecHeight;
+    int _numLayers;
 };
 
 }  // namespace media_optimization
diff --git a/modules/video_coding/utility/exp_filter.cc b/modules/video_coding/utility/exp_filter.cc
deleted file mode 100644
index 44f280b..0000000
--- a/modules/video_coding/utility/exp_filter.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *  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/utility/include/exp_filter.h"
-
-#include <math.h>
-
-namespace webrtc {
-
-void
-VCMExpFilter::Reset(float alpha)
-{
-    _alpha = alpha;
-    _filtered = -1.0;
-}
-
-float
-VCMExpFilter::Apply(float exp, float sample)
-{
-    if (_filtered == -1.0)
-    {
-        // Initialize filtered bit rates
-        _filtered = sample;
-    }
-    else if (exp == 1.0)
-    {
-        _filtered = _alpha * _filtered + (1 - _alpha) * sample;
-    }
-    else
-    {
-        float alpha = pow(_alpha, exp);
-        _filtered = alpha * _filtered + (1 - alpha) * sample;
-    }
-    if (_max != -1 && _filtered > _max)
-    {
-        _filtered = _max;
-    }
-    return _filtered;
-}
-
-void
-VCMExpFilter::UpdateBase(float alpha)
-{
-    _alpha = alpha;
-}
-
-float
-VCMExpFilter::Value() const
-{
-    return _filtered;
-}
-
-}
diff --git a/modules/video_coding/utility/frame_dropper.cc b/modules/video_coding/utility/frame_dropper.cc
index d3c25fb..54c8cb8 100644
--- a/modules/video_coding/utility/frame_dropper.cc
+++ b/modules/video_coding/utility/frame_dropper.cc
@@ -86,25 +86,27 @@
     {
         _keyFrameSizeAvgKbits.Apply(1, frameSizeKbits);
         _keyFrameRatio.Apply(1.0, 1.0);
-        if (frameSizeKbits > _keyFrameSizeAvgKbits.Value())
+        if (frameSizeKbits > _keyFrameSizeAvgKbits.filtered())
         {
             // Remove the average key frame size since we
             // compensate for key frames when adding delta
             // frames.
-            frameSizeKbits -= _keyFrameSizeAvgKbits.Value();
+            frameSizeKbits -= _keyFrameSizeAvgKbits.filtered();
         }
         else
         {
             // Shouldn't be negative, so zero is the lower bound.
             frameSizeKbits = 0;
         }
-        if (_keyFrameRatio.Value() > 1e-5 && 1 / _keyFrameRatio.Value() < _keyFrameSpreadFrames)
+        if (_keyFrameRatio.filtered() > 1e-5 &&
+            1 / _keyFrameRatio.filtered() < _keyFrameSpreadFrames)
         {
             // We are sending key frames more often than our upper bound for
             // how much we allow the key frame compensation to be spread
             // out in time. Therefor we must use the key frame ratio rather
             // than keyFrameSpreadFrames.
-            _keyFrameCount = static_cast<int32_t>(1 / _keyFrameRatio.Value() + 0.5);
+            _keyFrameCount =
+                static_cast<int32_t>(1 / _keyFrameRatio.filtered() + 0.5);
         }
         else
         {
@@ -145,13 +147,14 @@
     if (_keyFrameCount > 0)
     {
         // Perform the key frame compensation
-        if (_keyFrameRatio.Value() > 0 && 1 / _keyFrameRatio.Value() < _keyFrameSpreadFrames)
+        if (_keyFrameRatio.filtered() > 0 &&
+            1 / _keyFrameRatio.filtered() < _keyFrameSpreadFrames)
         {
-            T -= _keyFrameSizeAvgKbits.Value() * _keyFrameRatio.Value();
+            T -= _keyFrameSizeAvgKbits.filtered() * _keyFrameRatio.filtered();
         }
         else
         {
-            T -= _keyFrameSizeAvgKbits.Value() / _keyFrameSpreadFrames;
+            T -= _keyFrameSizeAvgKbits.filtered() / _keyFrameSpreadFrames;
         }
         _keyFrameCount--;
     }
@@ -232,11 +235,11 @@
         _dropCount = 0;
     }
 
-    if (_dropRatio.Value() >= 0.5f) // Drops per keep
+    if (_dropRatio.filtered() >= 0.5f) // Drops per keep
     {
         // limit is the number of frames we should drop between each kept frame
         // to keep our drop ratio. limit is positive in this case.
-        float denom = 1.0f - _dropRatio.Value();
+        float denom = 1.0f - _dropRatio.filtered();
         if (denom < 1e-5)
         {
             denom = (float)1e-5;
@@ -252,7 +255,7 @@
         if (_dropCount < 0)
         {
             // Reset the _dropCount since it was negative and should be positive.
-            if (_dropRatio.Value() > 0.4f)
+            if (_dropRatio.filtered() > 0.4f)
             {
                 _dropCount = -_dropCount;
             }
@@ -274,12 +277,13 @@
             return false;
         }
     }
-    else if (_dropRatio.Value() > 0.0f && _dropRatio.Value() < 0.5f) // Keeps per drop
+    else if (_dropRatio.filtered() > 0.0f &&
+        _dropRatio.filtered() < 0.5f) // Keeps per drop
     {
         // limit is the number of frames we should keep between each drop
         // in order to keep the drop ratio. limit is negative in this case,
         // and the _dropCount is also negative.
-        float denom = _dropRatio.Value();
+        float denom = _dropRatio.filtered();
         if (denom < 1e-5)
         {
             denom = (float)1e-5;
@@ -289,7 +293,7 @@
         {
             // Reset the _dropCount since we have a positive
             // _dropCount, and it should be negative.
-            if (_dropRatio.Value() < 0.6f)
+            if (_dropRatio.filtered() < 0.6f)
             {
                 _dropCount = -_dropCount;
             }
@@ -350,7 +354,7 @@
     {
         return static_cast<float>(inputFrameRate);
     }
-    return inputFrameRate * (1.0f - _dropRatio.Value());
+    return inputFrameRate * (1.0f - _dropRatio.filtered());
 }
 
 // Put a cap on the accumulator, i.e., don't let it grow beyond some level.
diff --git a/modules/video_coding/utility/include/exp_filter.h b/modules/video_coding/utility/include/exp_filter.h
deleted file mode 100644
index d8c37a3..0000000
--- a/modules/video_coding/utility/include/exp_filter.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *  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.
- */
-
-#ifndef WEBRTC_MODULES_VIDEO_CODING_UTILITY_INCLUDE_EXP_FILTER_H_
-#define WEBRTC_MODULES_VIDEO_CODING_UTILITY_INCLUDE_EXP_FILTER_H_
-
-namespace webrtc
-{
-
-/**********************/
-/* ExpFilter class    */
-/**********************/
-
-class VCMExpFilter
-{
-public:
-    VCMExpFilter(float alpha, float max = -1.0) : _alpha(alpha), _filtered(-1.0), _max(max) {}
-
-    // Resets the filter to its initial state, and resets alpha to the given value
-    //
-    // Input:
-    //          - alpha     : the new value of the filter factor base.
-    void Reset(float alpha);
-
-    // Applies the filter with the given exponent on the provided sample
-    //
-    // Input:
-    //          - exp       : Exponent T in y(k) = alpha^T * y(k-1) + (1 - alpha^T) * x(k)
-    //          - sample    : x(k) in the above filter equation
-    float Apply(float exp, float sample);
-
-    // Return current filtered value: y(k)
-    //
-    // Return value         : The current filter output
-    float Value() const;
-
-    // Change the filter factor base
-    //
-    // Input:
-    //          - alpha     : The new filter factor base.
-    void UpdateBase(float alpha);
-
-private:
-    float          _alpha;     // Filter factor base
-    float          _filtered;  // Current filter output
-    const float    _max;
-}; // end of ExpFilter class
-
-}  // namespace webrtc
-
-#endif // WEBRTC_MODULES_VIDEO_CODING_UTILITY_INCLUDE_EXP_FILTER_H_
diff --git a/modules/video_coding/utility/include/frame_dropper.h b/modules/video_coding/utility/include/frame_dropper.h
index 4c1c168..8eebd78 100644
--- a/modules/video_coding/utility/include/frame_dropper.h
+++ b/modules/video_coding/utility/include/frame_dropper.h
@@ -11,7 +11,7 @@
 #ifndef WEBRTC_MODULES_VIDEO_CODING_UTILITY_INCLUDE_FRAME_DROPPER_H_
 #define WEBRTC_MODULES_VIDEO_CODING_UTILITY_INCLUDE_FRAME_DROPPER_H_
 
-#include "webrtc/modules/video_coding/utility/include/exp_filter.h"
+#include "webrtc/base/exp_filter.h"
 #include "webrtc/typedefs.h"
 
 namespace webrtc
@@ -72,23 +72,23 @@
     void UpdateRatio();
     void CapAccumulator();
 
-    VCMExpFilter       _keyFrameSizeAvgKbits;
-    VCMExpFilter       _keyFrameRatio;
-    float           _keyFrameSpreadFrames;
-    int32_t     _keyFrameCount;
-    float           _accumulator;
-    float           _accumulatorMax;
-    float           _targetBitRate;
-    bool            _dropNext;
-    VCMExpFilter       _dropRatio;
-    int32_t     _dropCount;
-    float           _windowSize;
-    float           _incoming_frame_rate;
-    bool            _wasBelowMax;
-    bool            _enabled;
-    bool            _fastMode;
-    float           _cap_buffer_size;
-    float           _max_time_drops;
+    rtc::ExpFilter _keyFrameSizeAvgKbits;
+    rtc::ExpFilter _keyFrameRatio;
+    float _keyFrameSpreadFrames;
+    int32_t _keyFrameCount;
+    float _accumulator;
+    float _accumulatorMax;
+    float _targetBitRate;
+    bool _dropNext;
+    rtc::ExpFilter _dropRatio;
+    int32_t _dropCount;
+    float _windowSize;
+    float _incoming_frame_rate;
+    bool _wasBelowMax;
+    bool _enabled;
+    bool _fastMode;
+    float _cap_buffer_size;
+    float _max_time_drops;
 }; // end of VCMFrameDropper class
 
 }  // namespace webrtc
diff --git a/modules/video_coding/utility/video_coding_utility.gyp b/modules/video_coding/utility/video_coding_utility.gyp
index 24f8880..2f0202b 100644
--- a/modules/video_coding/utility/video_coding_utility.gyp
+++ b/modules/video_coding/utility/video_coding_utility.gyp
@@ -18,9 +18,7 @@
         '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
       ],
       'sources': [
-        'include/exp_filter.h',
         'include/frame_dropper.h',
-        'exp_filter.cc',
         'frame_dropper.cc',
       ],
     },
diff --git a/video_engine/overuse_frame_detector.cc b/video_engine/overuse_frame_detector.cc
index 764c258..6efb4be 100644
--- a/video_engine/overuse_frame_detector.cc
+++ b/video_engine/overuse_frame_detector.cc
@@ -17,7 +17,7 @@
 #include <list>
 #include <map>
 
-#include "webrtc/modules/video_coding/utility/include/exp_filter.h"
+#include "webrtc/base/exp_filter.h"
 #include "webrtc/system_wrappers/interface/clock.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
 #include "webrtc/system_wrappers/interface/logging.h"
@@ -54,8 +54,8 @@
 Statistics::Statistics() :
     sum_(0.0),
     count_(0),
-    filtered_samples_(new VCMExpFilter(kWeightFactorMean)),
-    filtered_variance_(new VCMExpFilter(kWeightFactor)) {
+    filtered_samples_(new rtc::ExpFilter(kWeightFactorMean)),
+    filtered_variance_(new rtc::ExpFilter(kWeightFactor)) {
   Reset();
 }
 
@@ -84,8 +84,8 @@
   float exp = sample_ms / kSampleDiffMs;
   exp = std::min(exp, kMaxExp);
   filtered_samples_->Apply(exp, sample_ms);
-  filtered_variance_->Apply(exp, (sample_ms - filtered_samples_->Value()) *
-                                 (sample_ms - filtered_samples_->Value()));
+  filtered_variance_->Apply(exp, (sample_ms - filtered_samples_->filtered()) *
+                                 (sample_ms - filtered_samples_->filtered()));
 }
 
 float Statistics::InitialMean() const {
@@ -101,10 +101,10 @@
   return average_stddev * average_stddev;
 }
 
-float Statistics::Mean() const { return filtered_samples_->Value(); }
+float Statistics::Mean() const { return filtered_samples_->filtered(); }
 
 float Statistics::StdDev() const {
-  return sqrt(std::max(filtered_variance_->Value(), 0.0f));
+  return sqrt(std::max(filtered_variance_->filtered(), 0.0f));
 }
 
 uint64_t Statistics::Count() const { return count_; }
@@ -116,7 +116,7 @@
   EncodeTimeAvg()
       : kWeightFactor(0.5f),
         kInitialAvgEncodeTimeMs(5.0f),
-        filtered_encode_time_ms_(new VCMExpFilter(kWeightFactor)) {
+        filtered_encode_time_ms_(new rtc::ExpFilter(kWeightFactor)) {
     filtered_encode_time_ms_->Apply(1.0f, kInitialAvgEncodeTimeMs);
   }
   ~EncodeTimeAvg() {}
@@ -128,13 +128,13 @@
   }
 
   int Value() const {
-    return static_cast<int>(filtered_encode_time_ms_->Value() + 0.5);
+    return static_cast<int>(filtered_encode_time_ms_->filtered() + 0.5);
   }
 
  private:
   const float kWeightFactor;
   const float kInitialAvgEncodeTimeMs;
-  scoped_ptr<VCMExpFilter> filtered_encode_time_ms_;
+  scoped_ptr<rtc::ExpFilter> filtered_encode_time_ms_;
 };
 
 // Class for calculating the encode usage.
@@ -146,8 +146,8 @@
         kInitialSampleDiffMs(40.0f),
         kMaxSampleDiffMs(45.0f),
         count_(0),
-        filtered_encode_time_ms_(new VCMExpFilter(kWeightFactorEncodeTime)),
-        filtered_frame_diff_ms_(new VCMExpFilter(kWeightFactorFrameDiff)) {
+        filtered_encode_time_ms_(new rtc::ExpFilter(kWeightFactorEncodeTime)),
+        filtered_frame_diff_ms_(new rtc::ExpFilter(kWeightFactorFrameDiff)) {
     Reset();
   }
   ~EncodeUsage() {}
@@ -181,10 +181,10 @@
     if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) {
       return static_cast<int>(InitialUsageInPercent() + 0.5f);
     }
-    float frame_diff_ms = std::max(filtered_frame_diff_ms_->Value(), 1.0f);
+    float frame_diff_ms = std::max(filtered_frame_diff_ms_->filtered(), 1.0f);
     frame_diff_ms = std::min(frame_diff_ms, kMaxSampleDiffMs);
     float encode_usage_percent =
-        100.0f * filtered_encode_time_ms_->Value() / frame_diff_ms;
+        100.0f * filtered_encode_time_ms_->filtered() / frame_diff_ms;
     return static_cast<int>(encode_usage_percent + 0.5);
   }
 
@@ -205,8 +205,8 @@
   const float kMaxSampleDiffMs;
   uint64_t count_;
   CpuOveruseOptions options_;
-  scoped_ptr<VCMExpFilter> filtered_encode_time_ms_;
-  scoped_ptr<VCMExpFilter> filtered_frame_diff_ms_;
+  scoped_ptr<rtc::ExpFilter> filtered_encode_time_ms_;
+  scoped_ptr<rtc::ExpFilter> filtered_frame_diff_ms_;
 };
 
 // Class for calculating the relative standard deviation of encode times.
@@ -215,7 +215,7 @@
   EncodeTimeRsd(Clock* clock)
       : kWeightFactor(0.6f),
         count_(0),
-        filtered_rsd_(new VCMExpFilter(kWeightFactor)),
+        filtered_rsd_(new rtc::ExpFilter(kWeightFactor)),
         hist_samples_(0),
         hist_sum_(0.0f),
         last_process_time_ms_(clock->TimeInMilliseconds()) {
@@ -294,7 +294,7 @@
   }
 
   int Value() const {
-    return static_cast<int>(filtered_rsd_->Value() + 0.5);
+    return static_cast<int>(filtered_rsd_->filtered() + 0.5);
   }
 
  private:
@@ -307,7 +307,7 @@
   const float kWeightFactor;
   uint32_t count_;  // Number of encode samples since last reset.
   CpuOveruseOptions options_;
-  scoped_ptr<VCMExpFilter> filtered_rsd_;
+  scoped_ptr<rtc::ExpFilter> filtered_rsd_;
   int hist_samples_;
   float hist_sum_;
   std::map<int,int> hist_;  // Histogram of encode time of frames.
@@ -320,7 +320,7 @@
   CaptureQueueDelay()
       : kWeightFactor(0.5f),
         delay_ms_(0),
-        filtered_delay_ms_per_s_(new VCMExpFilter(kWeightFactor)) {
+        filtered_delay_ms_per_s_(new rtc::ExpFilter(kWeightFactor)) {
     filtered_delay_ms_per_s_->Apply(1.0f, 0.0f);
   }
   ~CaptureQueueDelay() {}
@@ -361,14 +361,14 @@
   }
 
   int Value() const {
-    return static_cast<int>(filtered_delay_ms_per_s_->Value() + 0.5);
+    return static_cast<int>(filtered_delay_ms_per_s_->filtered() + 0.5);
   }
 
  private:
   const float kWeightFactor;
   std::list<int64_t> frames_;
   int delay_ms_;
-  scoped_ptr<VCMExpFilter> filtered_delay_ms_per_s_;
+  scoped_ptr<rtc::ExpFilter> filtered_delay_ms_per_s_;
 };
 
 OveruseFrameDetector::OveruseFrameDetector(Clock* clock)
diff --git a/video_engine/overuse_frame_detector.h b/video_engine/overuse_frame_detector.h
index efd23dc..df3c1a0 100644
--- a/video_engine/overuse_frame_detector.h
+++ b/video_engine/overuse_frame_detector.h
@@ -12,6 +12,7 @@
 #define WEBRTC_VIDEO_ENGINE_OVERUSE_FRAME_DETECTOR_H_
 
 #include "webrtc/base/constructormagic.h"
+#include "webrtc/base/exp_filter.h"
 #include "webrtc/modules/interface/module.h"
 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
 #include "webrtc/video_engine/include/vie_base.h"
@@ -21,7 +22,6 @@
 class Clock;
 class CpuOveruseObserver;
 class CriticalSectionWrapper;
-class VCMExpFilter;
 
 // TODO(pbos): Move this somewhere appropriate.
 class Statistics {
@@ -43,8 +43,8 @@
   float sum_;
   uint64_t count_;
   CpuOveruseOptions options_;
-  scoped_ptr<VCMExpFilter> filtered_samples_;
-  scoped_ptr<VCMExpFilter> filtered_variance_;
+  scoped_ptr<rtc::ExpFilter> filtered_samples_;
+  scoped_ptr<rtc::ExpFilter> filtered_variance_;
 };
 
 // Use to detect system overuse based on jitter in incoming frames.
diff --git a/voice_engine/channel.cc b/voice_engine/channel.cc
index 2d4ba57..af773e7 100644
--- a/voice_engine/channel.cc
+++ b/voice_engine/channel.cc
@@ -934,7 +934,8 @@
                                                    true)),
     rtcp_bandwidth_observer_(
         bitrate_controller_->CreateRtcpBandwidthObserver()),
-    send_bitrate_observer_(new VoEBitrateObserver(this))
+    send_bitrate_observer_(new VoEBitrateObserver(this)),
+    network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock()))
 {
     WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
                  "Channel::Channel() - ctor");
@@ -1537,8 +1538,13 @@
   WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
       "Channel::OnNetworkChanged(bitrate_bps=%d, fration_lost=%d, rtt=%d)",
       bitrate_bps, fraction_lost, rtt);
+  // |fraction_lost| from BitrateObserver is short time observation of packet
+  // loss rate from past. We use network predictor to make a more reasonable
+  // loss rate estimation.
+  network_predictor_->UpdatePacketLossRate(fraction_lost);
+  uint8_t loss_rate = network_predictor_->GetLossRate();
   // Normalizes rate to 0 - 100.
-  if (audio_coding_->SetPacketLossRate(100 * fraction_lost / 255) != 0) {
+  if (audio_coding_->SetPacketLossRate(100 * loss_rate / 255) != 0) {
     _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
         kTraceError, "OnNetworkChanged() failed to set packet loss rate");
     assert(false);  // This should not happen.
diff --git a/voice_engine/channel.h b/voice_engine/channel.h
index 5cb2b9c..8385ccc 100644
--- a/voice_engine/channel.h
+++ b/voice_engine/channel.h
@@ -27,6 +27,7 @@
 #include "webrtc/voice_engine/include/voe_audio_processing.h"
 #include "webrtc/voice_engine/include/voe_network.h"
 #include "webrtc/voice_engine/level_indicator.h"
+#include "webrtc/voice_engine/network_predictor.h"
 #include "webrtc/voice_engine/shared_data.h"
 #include "webrtc/voice_engine/voice_engine_defines.h"
 
@@ -621,6 +622,7 @@
     scoped_ptr<BitrateController> bitrate_controller_;
     scoped_ptr<RtcpBandwidthObserver> rtcp_bandwidth_observer_;
     scoped_ptr<BitrateObserver> send_bitrate_observer_;
+    scoped_ptr<NetworkPredictor> network_predictor_;
 };
 
 }  // namespace voe
diff --git a/voice_engine/network_predictor.cc b/voice_engine/network_predictor.cc
new file mode 100644
index 0000000..4093877
--- /dev/null
+++ b/voice_engine/network_predictor.cc
@@ -0,0 +1,37 @@
+/*
+ *  Copyright (c) 2014 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/voice_engine/network_predictor.h"
+
+namespace webrtc {
+namespace voe {
+
+NetworkPredictor::NetworkPredictor(Clock* clock)
+    : clock_(clock),
+      last_loss_rate_update_time_ms_(clock_->TimeInMilliseconds()),
+      loss_rate_filter_(new rtc::ExpFilter(0.9999f)) {
+}
+
+void NetworkPredictor::UpdatePacketLossRate(uint8_t loss_rate) {
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  // Update the recursive average filter.
+  loss_rate_filter_->Apply(
+      static_cast<float>(now_ms - last_loss_rate_update_time_ms_),
+      static_cast<float>(loss_rate));
+  last_loss_rate_update_time_ms_ = now_ms;
+}
+
+uint8_t NetworkPredictor::GetLossRate() {
+  float value = loss_rate_filter_->filtered();
+  return (value == rtc::ExpFilter::kValueUndefined) ? 0 :
+      static_cast<uint8_t>(value + 0.5);
+}
+}  // namespace voe
+}  // namespace webrtc
diff --git a/voice_engine/network_predictor.h b/voice_engine/network_predictor.h
new file mode 100644
index 0000000..d9f0b7b
--- /dev/null
+++ b/voice_engine/network_predictor.h
@@ -0,0 +1,46 @@
+/*
+ *  Copyright (c) 2014 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.
+ */
+
+#ifndef WEBRTC_VOICE_ENGINE_NETWORK_PREDICTOR_H_
+#define WEBRTC_VOICE_ENGINE_NETWORK_PREDICTOR_H_
+
+#include "webrtc/base/exp_filter.h"
+#include "webrtc/system_wrappers/interface/clock.h"
+
+namespace webrtc {
+
+namespace voe {
+
+// NetworkPredictor is to predict network conditions e.g., packet loss rate, for
+// sender and/or receiver to cope with changes in the network condition.
+class NetworkPredictor {
+ public:
+  explicit NetworkPredictor(Clock* clock);
+  ~NetworkPredictor() {}
+
+  // Gets the predicted packet loss rate.
+  uint8_t GetLossRate();
+
+  // Updates the packet loss rate predictor, on receiving a new observation of
+  // packet loss rate from past. Input packet loss rate should be in the
+  // interval [0, 255].
+  void UpdatePacketLossRate(uint8_t loss_rate);
+
+ private:
+  Clock* clock_;
+  int64_t last_loss_rate_update_time_ms_;
+
+  // An exponential filter is used to predict packet loss rate.
+  scoped_ptr<rtc::ExpFilter> loss_rate_filter_;
+};
+
+}  // namespace voe
+}  // namespace webrtc
+#endif  // WEBRTC_VOICE_ENGINE_NETWORK_PREDICTOR_H_
diff --git a/voice_engine/network_predictor_unittest.cc b/voice_engine/network_predictor_unittest.cc
new file mode 100644
index 0000000..e399f68
--- /dev/null
+++ b/voice_engine/network_predictor_unittest.cc
@@ -0,0 +1,43 @@
+/*
+ *  Copyright (c) 2014 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 <math.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/voice_engine/network_predictor.h"
+#include "webrtc/system_wrappers/interface/clock.h"
+
+namespace webrtc {
+namespace voe {
+
+class TestNetworkPredictor : public ::testing::Test {
+ protected:
+  TestNetworkPredictor()
+      : clock_(0),
+        network_predictor_(new NetworkPredictor(&clock_)) {}
+  SimulatedClock clock_;
+  scoped_ptr<NetworkPredictor> network_predictor_;
+};
+
+TEST_F(TestNetworkPredictor, TestPacketLossRateFilter) {
+  // Test initial packet loss rate estimate is 0.
+  EXPECT_EQ(0, network_predictor_->GetLossRate());
+  network_predictor_->UpdatePacketLossRate(32);
+  // First time, no filtering.
+  EXPECT_EQ(32, network_predictor_->GetLossRate());
+  clock_.AdvanceTimeMilliseconds(1000);
+  network_predictor_->UpdatePacketLossRate(40);
+  float exp = pow(0.9999f, 1000);
+  float value = 32.0f * exp + (1 - exp) * 40.0f;
+  EXPECT_EQ(static_cast<uint8_t>(value + 0.5f),
+            network_predictor_->GetLossRate());
+}
+}  // namespace voe
+}  // namespace webrtc
diff --git a/voice_engine/voice_engine.gyp b/voice_engine/voice_engine.gyp
index 19342c3..43296ff 100644
--- a/voice_engine/voice_engine.gyp
+++ b/voice_engine/voice_engine.gyp
@@ -55,6 +55,8 @@
         'level_indicator.h',
         'monitor_module.cc',
         'monitor_module.h',
+        'network_predictor.cc',
+        'network_predictor.h',
         'output_mixer.cc',
         'output_mixer.h',
         'shared_data.cc',
@@ -122,6 +124,7 @@
           ],
           'sources': [
             'channel_unittest.cc',
+            'network_predictor_unittest.cc',
             'transmit_mixer_unittest.cc',
             'utility_unittest.cc',
             'voe_audio_processing_unittest.cc',