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@6709 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/base/base.gyp b/webrtc/base/base.gyp
index f9ba404..6a0c359 100644
--- a/webrtc/base/base.gyp
+++ b/webrtc/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/webrtc/base/base_tests.gyp b/webrtc/base/base_tests.gyp
index ca0d72a..3cef1028 100644
--- a/webrtc/base/base_tests.gyp
+++ b/webrtc/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/webrtc/base/exp_filter.cc b/webrtc/base/exp_filter.cc
new file mode 100644
index 0000000..9529480
--- /dev/null
+++ b/webrtc/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/webrtc/base/exp_filter.h b/webrtc/base/exp_filter.h
new file mode 100644
index 0000000..174159b
--- /dev/null
+++ b/webrtc/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/webrtc/base/exp_filter_unittest.cc b/webrtc/base/exp_filter_unittest.cc
new file mode 100644
index 0000000..f027808
--- /dev/null
+++ b/webrtc/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/webrtc/modules/video_coding/main/source/media_opt_util.cc b/webrtc/modules/video_coding/main/source/media_opt_util.cc
index ba86575..b506a5b 100644
--- a/webrtc/modules/video_coding/main/source/media_opt_util.cc
+++ b/webrtc/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/webrtc/modules/video_coding/main/source/media_opt_util.h b/webrtc/modules/video_coding/main/source/media_opt_util.h
index f39a578..d421d9e 100644
--- a/webrtc/modules/video_coding/main/source/media_opt_util.h
+++ b/webrtc/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/webrtc/modules/video_coding/utility/exp_filter.cc b/webrtc/modules/video_coding/utility/exp_filter.cc
deleted file mode 100644
index 44f280bc..0000000
--- a/webrtc/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/webrtc/modules/video_coding/utility/frame_dropper.cc b/webrtc/modules/video_coding/utility/frame_dropper.cc
index d3c25fb..54c8cb8 100644
--- a/webrtc/modules/video_coding/utility/frame_dropper.cc
+++ b/webrtc/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/webrtc/modules/video_coding/utility/include/exp_filter.h b/webrtc/modules/video_coding/utility/include/exp_filter.h
deleted file mode 100644
index d8c37a3..0000000
--- a/webrtc/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/webrtc/modules/video_coding/utility/include/frame_dropper.h b/webrtc/modules/video_coding/utility/include/frame_dropper.h
index 4c1c168..8eebd78 100644
--- a/webrtc/modules/video_coding/utility/include/frame_dropper.h
+++ b/webrtc/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/webrtc/modules/video_coding/utility/video_coding_utility.gyp b/webrtc/modules/video_coding/utility/video_coding_utility.gyp
index 24f8880..2f0202b 100644
--- a/webrtc/modules/video_coding/utility/video_coding_utility.gyp
+++ b/webrtc/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/webrtc/video_engine/overuse_frame_detector.cc b/webrtc/video_engine/overuse_frame_detector.cc
index 764c258..6efb4be 100644
--- a/webrtc/video_engine/overuse_frame_detector.cc
+++ b/webrtc/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/webrtc/video_engine/overuse_frame_detector.h b/webrtc/video_engine/overuse_frame_detector.h
index efd23dc..df3c1a0 100644
--- a/webrtc/video_engine/overuse_frame_detector.h
+++ b/webrtc/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/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc
index 2d4ba57..af773e7 100644
--- a/webrtc/voice_engine/channel.cc
+++ b/webrtc/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/webrtc/voice_engine/channel.h b/webrtc/voice_engine/channel.h
index 5cb2b9c..8385ccc 100644
--- a/webrtc/voice_engine/channel.h
+++ b/webrtc/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/webrtc/voice_engine/network_predictor.cc b/webrtc/voice_engine/network_predictor.cc
new file mode 100644
index 0000000..40938773
--- /dev/null
+++ b/webrtc/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/webrtc/voice_engine/network_predictor.h b/webrtc/voice_engine/network_predictor.h
new file mode 100644
index 0000000..d9f0b7b
--- /dev/null
+++ b/webrtc/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/webrtc/voice_engine/network_predictor_unittest.cc b/webrtc/voice_engine/network_predictor_unittest.cc
new file mode 100644
index 0000000..e399f68
--- /dev/null
+++ b/webrtc/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/webrtc/voice_engine/voice_engine.gyp b/webrtc/voice_engine/voice_engine.gyp
index 19342c3..43296ff 100644
--- a/webrtc/voice_engine/voice_engine.gyp
+++ b/webrtc/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',