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:
parent
4c3e9917e7
commit
74aaf29a0f
@ -85,6 +85,8 @@
|
||||
'diskcache_win32.h',
|
||||
'event.cc',
|
||||
'event.h',
|
||||
'exp_filter.cc',
|
||||
'exp_filter.h',
|
||||
'filelock.cc',
|
||||
'filelock.h',
|
||||
'fileutils.cc',
|
||||
|
@ -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
43
webrtc/base/exp_filter.cc
Normal 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
49
webrtc/base/exp_filter.h
Normal 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_
|
71
webrtc/base/exp_filter_unittest.cc
Normal file
71
webrtc/base/exp_filter_unittest.cc
Normal 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
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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.
|
||||
|
@ -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_
|
@ -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
|
||||
|
@ -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',
|
||||
],
|
||||
},
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
37
webrtc/voice_engine/network_predictor.cc
Normal file
37
webrtc/voice_engine/network_predictor.cc
Normal 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
|
46
webrtc/voice_engine/network_predictor.h
Normal file
46
webrtc/voice_engine/network_predictor.h
Normal 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_
|
43
webrtc/voice_engine/network_predictor_unittest.cc
Normal file
43
webrtc/voice_engine/network_predictor_unittest.cc
Normal 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
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user