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
This commit is contained in:
minyue@webrtc.org 2014-07-16 21:28:26 +00:00
parent 4c3e9917e7
commit 74aaf29a0f
20 changed files with 391 additions and 204 deletions

View File

@ -85,6 +85,8 @@
'diskcache_win32.h', 'diskcache_win32.h',
'event.cc', 'event.cc',
'event.h', 'event.h',
'exp_filter.cc',
'exp_filter.h',
'filelock.cc', 'filelock.cc',
'filelock.h', 'filelock.h',
'fileutils.cc', 'fileutils.cc',

View File

@ -57,6 +57,7 @@
'crc32_unittest.cc', 'crc32_unittest.cc',
'criticalsection_unittest.cc', 'criticalsection_unittest.cc',
'event_unittest.cc', 'event_unittest.cc',
'exp_filter_unittest.cc',
'filelock_unittest.cc', 'filelock_unittest.cc',
'fileutils_unittest.cc', 'fileutils_unittest.cc',
'helpers_unittest.cc', 'helpers_unittest.cc',

43
webrtc/base/exp_filter.cc Normal file
View File

@ -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

49
webrtc/base/exp_filter.h Normal file
View File

@ -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_

View File

@ -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

View File

@ -837,7 +837,7 @@ uint8_t VCMLossProtectionLogic::FilteredLoss(
case kNoFilter: case kNoFilter:
break; break;
case kAvgFilter: case kAvgFilter:
filtered_loss = static_cast<uint8_t> (_lossPr255.Value() + 0.5); filtered_loss = static_cast<uint8_t>(_lossPr255.filtered() + 0.5);
break; break;
case kMaxFilter: case kMaxFilter:
filtered_loss = MaxFilteredLossPr(nowMs); filtered_loss = MaxFilteredLossPr(nowMs);
@ -907,8 +907,8 @@ VCMLossProtectionLogic::UpdateMethod()
_currentParameters.keyFrameSize = _keyFrameSize; _currentParameters.keyFrameSize = _keyFrameSize;
_currentParameters.fecRateDelta = _fecRateDelta; _currentParameters.fecRateDelta = _fecRateDelta;
_currentParameters.fecRateKey = _fecRateKey; _currentParameters.fecRateKey = _fecRateKey;
_currentParameters.packetsPerFrame = _packetsPerFrame.Value(); _currentParameters.packetsPerFrame = _packetsPerFrame.filtered();
_currentParameters.packetsPerFrameKey = _packetsPerFrameKey.Value(); _currentParameters.packetsPerFrameKey = _packetsPerFrameKey.filtered();
_currentParameters.residualPacketLossFec = _residualPacketLossFec; _currentParameters.residualPacketLossFec = _residualPacketLossFec;
_currentParameters.codecWidth = _codecWidth; _currentParameters.codecWidth = _codecWidth;
_currentParameters.codecHeight = _codecHeight; _currentParameters.codecHeight = _codecHeight;

View File

@ -14,9 +14,9 @@
#include <math.h> #include <math.h>
#include <stdlib.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/internal_defines.h"
#include "webrtc/modules/video_coding/main/source/qm_select.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/system_wrappers/interface/trace.h"
#include "webrtc/typedefs.h" #include "webrtc/typedefs.h"
@ -367,27 +367,27 @@ private:
// Sets the available loss protection methods. // Sets the available loss protection methods.
void UpdateMaxLossHistory(uint8_t lossPr255, int64_t now); void UpdateMaxLossHistory(uint8_t lossPr255, int64_t now);
uint8_t MaxFilteredLossPr(int64_t nowMs) const; uint8_t MaxFilteredLossPr(int64_t nowMs) const;
VCMProtectionMethod* _selectedMethod; VCMProtectionMethod* _selectedMethod;
VCMProtectionParameters _currentParameters; VCMProtectionParameters _currentParameters;
uint32_t _rtt; uint32_t _rtt;
float _lossPr; float _lossPr;
float _bitRate; float _bitRate;
float _frameRate; float _frameRate;
float _keyFrameSize; float _keyFrameSize;
uint8_t _fecRateKey; uint8_t _fecRateKey;
uint8_t _fecRateDelta; uint8_t _fecRateDelta;
int64_t _lastPrUpdateT; int64_t _lastPrUpdateT;
int64_t _lastPacketPerFrameUpdateT; int64_t _lastPacketPerFrameUpdateT;
int64_t _lastPacketPerFrameUpdateTKey; int64_t _lastPacketPerFrameUpdateTKey;
VCMExpFilter _lossPr255; rtc::ExpFilter _lossPr255;
VCMLossProbabilitySample _lossPrHistory[kLossPrHistorySize]; VCMLossProbabilitySample _lossPrHistory[kLossPrHistorySize];
uint8_t _shortMaxLossPr255; uint8_t _shortMaxLossPr255;
VCMExpFilter _packetsPerFrame; rtc::ExpFilter _packetsPerFrame;
VCMExpFilter _packetsPerFrameKey; rtc::ExpFilter _packetsPerFrameKey;
float _residualPacketLossFec; float _residualPacketLossFec;
uint16_t _codecWidth; uint16_t _codecWidth;
uint16_t _codecHeight; uint16_t _codecHeight;
int _numLayers; int _numLayers;
}; };
} // namespace media_optimization } // namespace media_optimization

View File

@ -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;
}
}

View File

@ -86,25 +86,27 @@ FrameDropper::Fill(uint32_t frameSizeBytes, bool deltaFrame)
{ {
_keyFrameSizeAvgKbits.Apply(1, frameSizeKbits); _keyFrameSizeAvgKbits.Apply(1, frameSizeKbits);
_keyFrameRatio.Apply(1.0, 1.0); _keyFrameRatio.Apply(1.0, 1.0);
if (frameSizeKbits > _keyFrameSizeAvgKbits.Value()) if (frameSizeKbits > _keyFrameSizeAvgKbits.filtered())
{ {
// Remove the average key frame size since we // Remove the average key frame size since we
// compensate for key frames when adding delta // compensate for key frames when adding delta
// frames. // frames.
frameSizeKbits -= _keyFrameSizeAvgKbits.Value(); frameSizeKbits -= _keyFrameSizeAvgKbits.filtered();
} }
else else
{ {
// Shouldn't be negative, so zero is the lower bound. // Shouldn't be negative, so zero is the lower bound.
frameSizeKbits = 0; 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 // We are sending key frames more often than our upper bound for
// how much we allow the key frame compensation to be spread // how much we allow the key frame compensation to be spread
// out in time. Therefor we must use the key frame ratio rather // out in time. Therefor we must use the key frame ratio rather
// than keyFrameSpreadFrames. // than keyFrameSpreadFrames.
_keyFrameCount = static_cast<int32_t>(1 / _keyFrameRatio.Value() + 0.5); _keyFrameCount =
static_cast<int32_t>(1 / _keyFrameRatio.filtered() + 0.5);
} }
else else
{ {
@ -145,13 +147,14 @@ FrameDropper::Leak(uint32_t inputFrameRate)
if (_keyFrameCount > 0) if (_keyFrameCount > 0)
{ {
// Perform the key frame compensation // 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 else
{ {
T -= _keyFrameSizeAvgKbits.Value() / _keyFrameSpreadFrames; T -= _keyFrameSizeAvgKbits.filtered() / _keyFrameSpreadFrames;
} }
_keyFrameCount--; _keyFrameCount--;
} }
@ -232,11 +235,11 @@ FrameDropper::DropFrame()
_dropCount = 0; _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 // limit is the number of frames we should drop between each kept frame
// to keep our drop ratio. limit is positive in this case. // 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) if (denom < 1e-5)
{ {
denom = (float)1e-5; denom = (float)1e-5;
@ -252,7 +255,7 @@ FrameDropper::DropFrame()
if (_dropCount < 0) if (_dropCount < 0)
{ {
// Reset the _dropCount since it was negative and should be positive. // Reset the _dropCount since it was negative and should be positive.
if (_dropRatio.Value() > 0.4f) if (_dropRatio.filtered() > 0.4f)
{ {
_dropCount = -_dropCount; _dropCount = -_dropCount;
} }
@ -274,12 +277,13 @@ FrameDropper::DropFrame()
return false; 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 // 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, // in order to keep the drop ratio. limit is negative in this case,
// and the _dropCount is also negative. // and the _dropCount is also negative.
float denom = _dropRatio.Value(); float denom = _dropRatio.filtered();
if (denom < 1e-5) if (denom < 1e-5)
{ {
denom = (float)1e-5; denom = (float)1e-5;
@ -289,7 +293,7 @@ FrameDropper::DropFrame()
{ {
// Reset the _dropCount since we have a positive // Reset the _dropCount since we have a positive
// _dropCount, and it should be negative. // _dropCount, and it should be negative.
if (_dropRatio.Value() < 0.6f) if (_dropRatio.filtered() < 0.6f)
{ {
_dropCount = -_dropCount; _dropCount = -_dropCount;
} }
@ -350,7 +354,7 @@ FrameDropper::ActualFrameRate(uint32_t inputFrameRate) const
{ {
return static_cast<float>(inputFrameRate); 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. // Put a cap on the accumulator, i.e., don't let it grow beyond some level.

View File

@ -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_

View File

@ -11,7 +11,7 @@
#ifndef WEBRTC_MODULES_VIDEO_CODING_UTILITY_INCLUDE_FRAME_DROPPER_H_ #ifndef WEBRTC_MODULES_VIDEO_CODING_UTILITY_INCLUDE_FRAME_DROPPER_H_
#define 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" #include "webrtc/typedefs.h"
namespace webrtc namespace webrtc
@ -72,23 +72,23 @@ private:
void UpdateRatio(); void UpdateRatio();
void CapAccumulator(); void CapAccumulator();
VCMExpFilter _keyFrameSizeAvgKbits; rtc::ExpFilter _keyFrameSizeAvgKbits;
VCMExpFilter _keyFrameRatio; rtc::ExpFilter _keyFrameRatio;
float _keyFrameSpreadFrames; float _keyFrameSpreadFrames;
int32_t _keyFrameCount; int32_t _keyFrameCount;
float _accumulator; float _accumulator;
float _accumulatorMax; float _accumulatorMax;
float _targetBitRate; float _targetBitRate;
bool _dropNext; bool _dropNext;
VCMExpFilter _dropRatio; rtc::ExpFilter _dropRatio;
int32_t _dropCount; int32_t _dropCount;
float _windowSize; float _windowSize;
float _incoming_frame_rate; float _incoming_frame_rate;
bool _wasBelowMax; bool _wasBelowMax;
bool _enabled; bool _enabled;
bool _fastMode; bool _fastMode;
float _cap_buffer_size; float _cap_buffer_size;
float _max_time_drops; float _max_time_drops;
}; // end of VCMFrameDropper class }; // end of VCMFrameDropper class
} // namespace webrtc } // namespace webrtc

View File

@ -18,9 +18,7 @@
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers', '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
], ],
'sources': [ 'sources': [
'include/exp_filter.h',
'include/frame_dropper.h', 'include/frame_dropper.h',
'exp_filter.cc',
'frame_dropper.cc', 'frame_dropper.cc',
], ],
}, },

View File

@ -17,7 +17,7 @@
#include <list> #include <list>
#include <map> #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/clock.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/logging.h" #include "webrtc/system_wrappers/interface/logging.h"
@ -54,8 +54,8 @@ const float kMaxExp = 7.0f;
Statistics::Statistics() : Statistics::Statistics() :
sum_(0.0), sum_(0.0),
count_(0), count_(0),
filtered_samples_(new VCMExpFilter(kWeightFactorMean)), filtered_samples_(new rtc::ExpFilter(kWeightFactorMean)),
filtered_variance_(new VCMExpFilter(kWeightFactor)) { filtered_variance_(new rtc::ExpFilter(kWeightFactor)) {
Reset(); Reset();
} }
@ -84,8 +84,8 @@ void Statistics::AddSample(float sample_ms) {
float exp = sample_ms / kSampleDiffMs; float exp = sample_ms / kSampleDiffMs;
exp = std::min(exp, kMaxExp); exp = std::min(exp, kMaxExp);
filtered_samples_->Apply(exp, sample_ms); filtered_samples_->Apply(exp, sample_ms);
filtered_variance_->Apply(exp, (sample_ms - filtered_samples_->Value()) * filtered_variance_->Apply(exp, (sample_ms - filtered_samples_->filtered()) *
(sample_ms - filtered_samples_->Value())); (sample_ms - filtered_samples_->filtered()));
} }
float Statistics::InitialMean() const { float Statistics::InitialMean() const {
@ -101,10 +101,10 @@ float Statistics::InitialVariance() const {
return average_stddev * average_stddev; 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 { 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_; } uint64_t Statistics::Count() const { return count_; }
@ -116,7 +116,7 @@ class OveruseFrameDetector::EncodeTimeAvg {
EncodeTimeAvg() EncodeTimeAvg()
: kWeightFactor(0.5f), : kWeightFactor(0.5f),
kInitialAvgEncodeTimeMs(5.0f), 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); filtered_encode_time_ms_->Apply(1.0f, kInitialAvgEncodeTimeMs);
} }
~EncodeTimeAvg() {} ~EncodeTimeAvg() {}
@ -128,13 +128,13 @@ class OveruseFrameDetector::EncodeTimeAvg {
} }
int Value() const { 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: private:
const float kWeightFactor; const float kWeightFactor;
const float kInitialAvgEncodeTimeMs; const float kInitialAvgEncodeTimeMs;
scoped_ptr<VCMExpFilter> filtered_encode_time_ms_; scoped_ptr<rtc::ExpFilter> filtered_encode_time_ms_;
}; };
// Class for calculating the encode usage. // Class for calculating the encode usage.
@ -146,8 +146,8 @@ class OveruseFrameDetector::EncodeUsage {
kInitialSampleDiffMs(40.0f), kInitialSampleDiffMs(40.0f),
kMaxSampleDiffMs(45.0f), kMaxSampleDiffMs(45.0f),
count_(0), count_(0),
filtered_encode_time_ms_(new VCMExpFilter(kWeightFactorEncodeTime)), filtered_encode_time_ms_(new rtc::ExpFilter(kWeightFactorEncodeTime)),
filtered_frame_diff_ms_(new VCMExpFilter(kWeightFactorFrameDiff)) { filtered_frame_diff_ms_(new rtc::ExpFilter(kWeightFactorFrameDiff)) {
Reset(); Reset();
} }
~EncodeUsage() {} ~EncodeUsage() {}
@ -181,10 +181,10 @@ class OveruseFrameDetector::EncodeUsage {
if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) { if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) {
return static_cast<int>(InitialUsageInPercent() + 0.5f); 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); frame_diff_ms = std::min(frame_diff_ms, kMaxSampleDiffMs);
float encode_usage_percent = 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); return static_cast<int>(encode_usage_percent + 0.5);
} }
@ -205,8 +205,8 @@ class OveruseFrameDetector::EncodeUsage {
const float kMaxSampleDiffMs; const float kMaxSampleDiffMs;
uint64_t count_; uint64_t count_;
CpuOveruseOptions options_; CpuOveruseOptions options_;
scoped_ptr<VCMExpFilter> filtered_encode_time_ms_; scoped_ptr<rtc::ExpFilter> filtered_encode_time_ms_;
scoped_ptr<VCMExpFilter> filtered_frame_diff_ms_; scoped_ptr<rtc::ExpFilter> filtered_frame_diff_ms_;
}; };
// Class for calculating the relative standard deviation of encode times. // Class for calculating the relative standard deviation of encode times.
@ -215,7 +215,7 @@ class OveruseFrameDetector::EncodeTimeRsd {
EncodeTimeRsd(Clock* clock) EncodeTimeRsd(Clock* clock)
: kWeightFactor(0.6f), : kWeightFactor(0.6f),
count_(0), count_(0),
filtered_rsd_(new VCMExpFilter(kWeightFactor)), filtered_rsd_(new rtc::ExpFilter(kWeightFactor)),
hist_samples_(0), hist_samples_(0),
hist_sum_(0.0f), hist_sum_(0.0f),
last_process_time_ms_(clock->TimeInMilliseconds()) { last_process_time_ms_(clock->TimeInMilliseconds()) {
@ -294,7 +294,7 @@ class OveruseFrameDetector::EncodeTimeRsd {
} }
int Value() const { int Value() const {
return static_cast<int>(filtered_rsd_->Value() + 0.5); return static_cast<int>(filtered_rsd_->filtered() + 0.5);
} }
private: private:
@ -307,7 +307,7 @@ class OveruseFrameDetector::EncodeTimeRsd {
const float kWeightFactor; const float kWeightFactor;
uint32_t count_; // Number of encode samples since last reset. uint32_t count_; // Number of encode samples since last reset.
CpuOveruseOptions options_; CpuOveruseOptions options_;
scoped_ptr<VCMExpFilter> filtered_rsd_; scoped_ptr<rtc::ExpFilter> filtered_rsd_;
int hist_samples_; int hist_samples_;
float hist_sum_; float hist_sum_;
std::map<int,int> hist_; // Histogram of encode time of frames. std::map<int,int> hist_; // Histogram of encode time of frames.
@ -320,7 +320,7 @@ class OveruseFrameDetector::CaptureQueueDelay {
CaptureQueueDelay() CaptureQueueDelay()
: kWeightFactor(0.5f), : kWeightFactor(0.5f),
delay_ms_(0), 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); filtered_delay_ms_per_s_->Apply(1.0f, 0.0f);
} }
~CaptureQueueDelay() {} ~CaptureQueueDelay() {}
@ -361,14 +361,14 @@ class OveruseFrameDetector::CaptureQueueDelay {
} }
int Value() const { 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: private:
const float kWeightFactor; const float kWeightFactor;
std::list<int64_t> frames_; std::list<int64_t> frames_;
int delay_ms_; int delay_ms_;
scoped_ptr<VCMExpFilter> filtered_delay_ms_per_s_; scoped_ptr<rtc::ExpFilter> filtered_delay_ms_per_s_;
}; };
OveruseFrameDetector::OveruseFrameDetector(Clock* clock) OveruseFrameDetector::OveruseFrameDetector(Clock* clock)

View File

@ -12,6 +12,7 @@
#define WEBRTC_VIDEO_ENGINE_OVERUSE_FRAME_DETECTOR_H_ #define WEBRTC_VIDEO_ENGINE_OVERUSE_FRAME_DETECTOR_H_
#include "webrtc/base/constructormagic.h" #include "webrtc/base/constructormagic.h"
#include "webrtc/base/exp_filter.h"
#include "webrtc/modules/interface/module.h" #include "webrtc/modules/interface/module.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h" #include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/video_engine/include/vie_base.h" #include "webrtc/video_engine/include/vie_base.h"
@ -21,7 +22,6 @@ namespace webrtc {
class Clock; class Clock;
class CpuOveruseObserver; class CpuOveruseObserver;
class CriticalSectionWrapper; class CriticalSectionWrapper;
class VCMExpFilter;
// TODO(pbos): Move this somewhere appropriate. // TODO(pbos): Move this somewhere appropriate.
class Statistics { class Statistics {
@ -43,8 +43,8 @@ class Statistics {
float sum_; float sum_;
uint64_t count_; uint64_t count_;
CpuOveruseOptions options_; CpuOveruseOptions options_;
scoped_ptr<VCMExpFilter> filtered_samples_; scoped_ptr<rtc::ExpFilter> filtered_samples_;
scoped_ptr<VCMExpFilter> filtered_variance_; scoped_ptr<rtc::ExpFilter> filtered_variance_;
}; };
// Use to detect system overuse based on jitter in incoming frames. // Use to detect system overuse based on jitter in incoming frames.

View File

@ -934,7 +934,8 @@ Channel::Channel(int32_t channelId,
true)), true)),
rtcp_bandwidth_observer_( rtcp_bandwidth_observer_(
bitrate_controller_->CreateRtcpBandwidthObserver()), 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), WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
"Channel::Channel() - ctor"); "Channel::Channel() - ctor");
@ -1537,8 +1538,13 @@ Channel::OnNetworkChanged(const uint32_t bitrate_bps,
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId), WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
"Channel::OnNetworkChanged(bitrate_bps=%d, fration_lost=%d, rtt=%d)", "Channel::OnNetworkChanged(bitrate_bps=%d, fration_lost=%d, rtt=%d)",
bitrate_bps, fraction_lost, rtt); 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. // 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, _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
kTraceError, "OnNetworkChanged() failed to set packet loss rate"); kTraceError, "OnNetworkChanged() failed to set packet loss rate");
assert(false); // This should not happen. assert(false); // This should not happen.

View File

@ -27,6 +27,7 @@
#include "webrtc/voice_engine/include/voe_audio_processing.h" #include "webrtc/voice_engine/include/voe_audio_processing.h"
#include "webrtc/voice_engine/include/voe_network.h" #include "webrtc/voice_engine/include/voe_network.h"
#include "webrtc/voice_engine/level_indicator.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/shared_data.h"
#include "webrtc/voice_engine/voice_engine_defines.h" #include "webrtc/voice_engine/voice_engine_defines.h"
@ -621,6 +622,7 @@ private:
scoped_ptr<BitrateController> bitrate_controller_; scoped_ptr<BitrateController> bitrate_controller_;
scoped_ptr<RtcpBandwidthObserver> rtcp_bandwidth_observer_; scoped_ptr<RtcpBandwidthObserver> rtcp_bandwidth_observer_;
scoped_ptr<BitrateObserver> send_bitrate_observer_; scoped_ptr<BitrateObserver> send_bitrate_observer_;
scoped_ptr<NetworkPredictor> network_predictor_;
}; };
} // namespace voe } // namespace voe

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -55,6 +55,8 @@
'level_indicator.h', 'level_indicator.h',
'monitor_module.cc', 'monitor_module.cc',
'monitor_module.h', 'monitor_module.h',
'network_predictor.cc',
'network_predictor.h',
'output_mixer.cc', 'output_mixer.cc',
'output_mixer.h', 'output_mixer.h',
'shared_data.cc', 'shared_data.cc',
@ -122,6 +124,7 @@
], ],
'sources': [ 'sources': [
'channel_unittest.cc', 'channel_unittest.cc',
'network_predictor_unittest.cc',
'transmit_mixer_unittest.cc', 'transmit_mixer_unittest.cc',
'utility_unittest.cc', 'utility_unittest.cc',
'voe_audio_processing_unittest.cc', 'voe_audio_processing_unittest.cc',