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',
'event.cc',
'event.h',
'exp_filter.cc',
'exp_filter.h',
'filelock.cc',
'filelock.h',
'fileutils.cc',

View File

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

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:
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 @@ VCMLossProtectionLogic::UpdateMethod()
_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;

View File

@ -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 @@ private:
// 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

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);
_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 @@ FrameDropper::Leak(uint32_t inputFrameRate)
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 @@ FrameDropper::DropFrame()
_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 @@ FrameDropper::DropFrame()
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 @@ FrameDropper::DropFrame()
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 @@ FrameDropper::DropFrame()
{
// 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 @@ FrameDropper::ActualFrameRate(uint32_t inputFrameRate) const
{
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.

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_
#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 @@ private:
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

View File

@ -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',
],
},

View File

@ -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 @@ const float kMaxExp = 7.0f;
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 @@ void Statistics::AddSample(float sample_ms) {
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 @@ float Statistics::InitialVariance() const {
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 @@ class OveruseFrameDetector::EncodeTimeAvg {
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 @@ class OveruseFrameDetector::EncodeTimeAvg {
}
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 @@ class OveruseFrameDetector::EncodeUsage {
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 @@ class OveruseFrameDetector::EncodeUsage {
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 @@ class OveruseFrameDetector::EncodeUsage {
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 @@ class OveruseFrameDetector::EncodeTimeRsd {
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 @@ class OveruseFrameDetector::EncodeTimeRsd {
}
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 @@ class OveruseFrameDetector::EncodeTimeRsd {
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 @@ class OveruseFrameDetector::CaptureQueueDelay {
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 @@ class OveruseFrameDetector::CaptureQueueDelay {
}
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)

View File

@ -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 @@ namespace webrtc {
class Clock;
class CpuOveruseObserver;
class CriticalSectionWrapper;
class VCMExpFilter;
// TODO(pbos): Move this somewhere appropriate.
class Statistics {
@ -43,8 +43,8 @@ class Statistics {
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.

View File

@ -934,7 +934,8 @@ Channel::Channel(int32_t channelId,
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 @@ Channel::OnNetworkChanged(const uint32_t bitrate_bps,
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.

View File

@ -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 @@ private:
scoped_ptr<BitrateController> bitrate_controller_;
scoped_ptr<RtcpBandwidthObserver> rtcp_bandwidth_observer_;
scoped_ptr<BitrateObserver> send_bitrate_observer_;
scoped_ptr<NetworkPredictor> network_predictor_;
};
} // 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',
'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',