New attempt to revert r2362, since drover failed.
TBR=stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/640005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@2368 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
cb89c6f914
commit
20e13edede
@ -1,5 +0,0 @@
|
|||||||
pwestin@webrtc.org
|
|
||||||
stefan@webrtc.org
|
|
||||||
henrik.lundin@webrtc.org
|
|
||||||
mflodman@webrtc.org
|
|
||||||
asapersson@webrtc.org
|
|
@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 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 "bitrate_estimator.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
enum { kBitrateAverageWindow = 2000 };
|
|
||||||
|
|
||||||
BitRateStats::BitRateStats()
|
|
||||||
:_dataSamples(), _accumulatedBytes(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
BitRateStats::~BitRateStats()
|
|
||||||
{
|
|
||||||
while (_dataSamples.size() > 0)
|
|
||||||
{
|
|
||||||
delete _dataSamples.front();
|
|
||||||
_dataSamples.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BitRateStats::Init()
|
|
||||||
{
|
|
||||||
_accumulatedBytes = 0;
|
|
||||||
while (_dataSamples.size() > 0)
|
|
||||||
{
|
|
||||||
delete _dataSamples.front();
|
|
||||||
_dataSamples.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BitRateStats::Update(WebRtc_UWord32 packetSizeBytes, WebRtc_Word64 nowMs)
|
|
||||||
{
|
|
||||||
// Find an empty slot for storing the new sample and at the same time
|
|
||||||
// accumulate the history.
|
|
||||||
_dataSamples.push_back(new DataTimeSizeTuple(packetSizeBytes, nowMs));
|
|
||||||
_accumulatedBytes += packetSizeBytes;
|
|
||||||
EraseOld(nowMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BitRateStats::EraseOld(WebRtc_Word64 nowMs)
|
|
||||||
{
|
|
||||||
while (_dataSamples.size() > 0)
|
|
||||||
{
|
|
||||||
if (nowMs - _dataSamples.front()->_timeCompleteMs >
|
|
||||||
kBitrateAverageWindow)
|
|
||||||
{
|
|
||||||
// Delete old sample
|
|
||||||
_accumulatedBytes -= _dataSamples.front()->_sizeBytes;
|
|
||||||
delete _dataSamples.front();
|
|
||||||
_dataSamples.pop_front();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WebRtc_UWord32 BitRateStats::BitRate(WebRtc_Word64 nowMs)
|
|
||||||
{
|
|
||||||
// Calculate the average bit rate the past BITRATE_AVERAGE_WINDOW ms.
|
|
||||||
// Removes any old samples from the list.
|
|
||||||
EraseOld(nowMs);
|
|
||||||
WebRtc_Word64 timeOldest = nowMs;
|
|
||||||
if (_dataSamples.size() > 0)
|
|
||||||
{
|
|
||||||
timeOldest = _dataSamples.front()->_timeCompleteMs;
|
|
||||||
}
|
|
||||||
// Update average bit rate
|
|
||||||
float denom = static_cast<float>(nowMs - timeOldest);
|
|
||||||
if (nowMs == timeOldest)
|
|
||||||
{
|
|
||||||
// Calculate with a one second window when we haven't
|
|
||||||
// received more than one packet.
|
|
||||||
denom = 1000.0;
|
|
||||||
}
|
|
||||||
return static_cast<WebRtc_UWord32>(_accumulatedBytes * 8.0f * 1000.0f /
|
|
||||||
denom + 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 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_REMOTE_BITRATE_ESTIMATOR_BITRATE_ESTIMATOR_H_
|
|
||||||
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_BITRATE_ESTIMATOR_H_
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "typedefs.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
class BitRateStats
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BitRateStats();
|
|
||||||
~BitRateStats();
|
|
||||||
|
|
||||||
void Init();
|
|
||||||
void Update(WebRtc_UWord32 packetSizeBytes, WebRtc_Word64 nowMs);
|
|
||||||
WebRtc_UWord32 BitRate(WebRtc_Word64 nowMs);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct DataTimeSizeTuple
|
|
||||||
{
|
|
||||||
DataTimeSizeTuple(uint32_t sizeBytes, int64_t timeCompleteMs)
|
|
||||||
:
|
|
||||||
_sizeBytes(sizeBytes),
|
|
||||||
_timeCompleteMs(timeCompleteMs) {}
|
|
||||||
|
|
||||||
WebRtc_UWord32 _sizeBytes;
|
|
||||||
WebRtc_Word64 _timeCompleteMs;
|
|
||||||
};
|
|
||||||
|
|
||||||
void EraseOld(WebRtc_Word64 nowMs);
|
|
||||||
|
|
||||||
std::list<DataTimeSizeTuple*> _dataSamples;
|
|
||||||
WebRtc_UWord32 _accumulatedBytes;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_BITRATE_ESTIMATOR_H_
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 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_RTP_RTCP_SOURCE_BWE_DEFINES_H_
|
|
||||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_BWE_DEFINES_H_
|
|
||||||
|
|
||||||
#include "typedefs.h"
|
|
||||||
|
|
||||||
#define BWE_MAX(a,b) ((a)>(b)?(a):(b))
|
|
||||||
#define BWE_MIN(a,b) ((a)<(b)?(a):(b))
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
enum BandwidthUsage
|
|
||||||
{
|
|
||||||
kBwNormal,
|
|
||||||
kBwOverusing,
|
|
||||||
kBwUnderUsing
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RateControlState
|
|
||||||
{
|
|
||||||
kRcHold,
|
|
||||||
kRcIncrease,
|
|
||||||
kRcDecrease
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RateControlRegion
|
|
||||||
{
|
|
||||||
kRcNearMax,
|
|
||||||
kRcAboveMax,
|
|
||||||
kRcMaxUnknown
|
|
||||||
};
|
|
||||||
|
|
||||||
class RateControlInput
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RateControlInput(BandwidthUsage bwState,
|
|
||||||
WebRtc_UWord32 incomingBitRate,
|
|
||||||
double noiseVar)
|
|
||||||
: _bwState(bwState),
|
|
||||||
_incomingBitRate(incomingBitRate),
|
|
||||||
_noiseVar(noiseVar) {}
|
|
||||||
|
|
||||||
BandwidthUsage _bwState;
|
|
||||||
WebRtc_UWord32 _incomingBitRate;
|
|
||||||
double _noiseVar;
|
|
||||||
};
|
|
||||||
} //namespace webrtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_BWE_DEFINES_H_
|
|
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 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_REMOTE_BITRATE_ESTIMATOR_INCLUDE_MOCK_MOCK_REMOTE_BITRATE_ESTIMATOR_H_
|
|
||||||
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_MOCK_MOCK_REMOTE_BITRATE_ESTIMATOR_H_
|
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
|
||||||
|
|
||||||
#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
class MockRemoteBitrateObserver : public RemoteBitrateObserver {
|
|
||||||
public:
|
|
||||||
MOCK_METHOD2(OnReceiveBitrateChanged,
|
|
||||||
void(unsigned int ssrc, unsigned int bitrate));
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_MOCK_MOCK_REMOTE_BITRATE_ESTIMATOR_H_
|
|
@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// RemoteBitrateEstimator
|
|
||||||
// This class estimates the incoming bitrate capacity.
|
|
||||||
|
|
||||||
#ifndef WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_REMOTE_BITRATE_ESTIMATOR_H_
|
|
||||||
#define WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_REMOTE_BITRATE_ESTIMATOR_H_
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "modules/remote_bitrate_estimator/bitrate_estimator.h"
|
|
||||||
#include "modules/remote_bitrate_estimator/overuse_detector.h"
|
|
||||||
#include "modules/remote_bitrate_estimator/remote_rate_control.h"
|
|
||||||
#include "system_wrappers/interface/critical_section_wrapper.h"
|
|
||||||
#include "system_wrappers/interface/scoped_ptr.h"
|
|
||||||
#include "typedefs.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
// RemoteBitrateObserver is used to signal changes in bitrate estimates for
|
|
||||||
// the incoming stream.
|
|
||||||
class RemoteBitrateObserver {
|
|
||||||
public:
|
|
||||||
// Called when a receive channel has a new bitrate estimate for the incoming
|
|
||||||
// stream.
|
|
||||||
virtual void OnReceiveBitrateChanged(unsigned int ssrc,
|
|
||||||
unsigned int bitrate) = 0;
|
|
||||||
|
|
||||||
virtual ~RemoteBitrateObserver() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class RemoteBitrateEstimator {
|
|
||||||
public:
|
|
||||||
explicit RemoteBitrateEstimator(RemoteBitrateObserver* observer);
|
|
||||||
|
|
||||||
// Called for each incoming packet. If this is a new SSRC, a new
|
|
||||||
// BitrateControl will be created.
|
|
||||||
void IncomingPacket(unsigned int ssrc,
|
|
||||||
int packet_size,
|
|
||||||
int64_t arrival_time,
|
|
||||||
uint32_t rtp_timestamp,
|
|
||||||
int64_t packet_send_time);
|
|
||||||
|
|
||||||
// Triggers a new estimate calculation for the stream identified by |ssrc|.
|
|
||||||
void UpdateEstimate(unsigned int ssrc, int64_t time_now);
|
|
||||||
|
|
||||||
// Set the current round-trip time experienced by the stream identified by
|
|
||||||
// |ssrc|.
|
|
||||||
void SetRtt(unsigned int ssrc);
|
|
||||||
|
|
||||||
// Removes all data for |ssrc|.
|
|
||||||
void RemoveStream(unsigned int ssrc);
|
|
||||||
|
|
||||||
// Returns true if a valid estimate exists for a stream identified by |ssrc|
|
|
||||||
// and sets |bitrate_bps| to the estimated bitrate in bits per second.
|
|
||||||
bool LatestEstimate(unsigned int ssrc, unsigned int* bitrate_bps) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct BitrateControls {
|
|
||||||
RemoteRateControl remote_rate;
|
|
||||||
OverUseDetector overuse_detector;
|
|
||||||
BitRateStats incoming_bitrate;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::map<unsigned int, BitrateControls> SsrcBitrateControlsMap;
|
|
||||||
|
|
||||||
SsrcBitrateControlsMap bitrate_controls_;
|
|
||||||
RemoteBitrateObserver* observer_;
|
|
||||||
scoped_ptr<CriticalSectionWrapper> crit_sect_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_REMOTE_BITRATE_ESTIMATOR_INCLUDE_REMOTE_BITRATE_ESTIMATOR_H_
|
|
@ -1,440 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 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 <stdlib.h> // abs
|
|
||||||
#if _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "modules/remote_bitrate_estimator/overuse_detector.h"
|
|
||||||
#include "modules/remote_bitrate_estimator/remote_rate_control.h"
|
|
||||||
#include "modules/rtp_rtcp/source/rtp_utility.h"
|
|
||||||
#include "system_wrappers/interface/trace.h"
|
|
||||||
|
|
||||||
#ifdef WEBRTC_BWE_MATLAB
|
|
||||||
extern MatlabEngine eng; // global variable defined elsewhere
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define INIT_CAPACITY_SLOPE 8.0/512.0
|
|
||||||
#define DETECTOR_THRESHOLD 25.0
|
|
||||||
#define OVER_USING_TIME_THRESHOLD 100
|
|
||||||
#define MIN_FRAME_PERIOD_HISTORY_LEN 60
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
OverUseDetector::OverUseDetector()
|
|
||||||
: firstPacket_(true),
|
|
||||||
currentFrame_(),
|
|
||||||
prevFrame_(),
|
|
||||||
numOfDeltas_(0),
|
|
||||||
slope_(INIT_CAPACITY_SLOPE),
|
|
||||||
offset_(0),
|
|
||||||
E_(),
|
|
||||||
processNoise_(),
|
|
||||||
avgNoise_(0.0),
|
|
||||||
varNoise_(500),
|
|
||||||
threshold_(DETECTOR_THRESHOLD),
|
|
||||||
tsDeltaHist_(),
|
|
||||||
prevOffset_(0.0),
|
|
||||||
timeOverUsing_(-1),
|
|
||||||
overUseCounter_(0),
|
|
||||||
#ifndef WEBRTC_BWE_MATLAB
|
|
||||||
hypothesis_(kBwNormal) {
|
|
||||||
#else
|
|
||||||
plot1_(NULL),
|
|
||||||
plot2_(NULL),
|
|
||||||
plot3_(NULL),
|
|
||||||
plot4_(NULL) {
|
|
||||||
#endif
|
|
||||||
E_[0][0] = 100;
|
|
||||||
E_[1][1] = 1e-1;
|
|
||||||
E_[0][1] = E_[1][0] = 0;
|
|
||||||
processNoise_[0] = 1e-10;
|
|
||||||
processNoise_[1] = 1e-2;
|
|
||||||
}
|
|
||||||
|
|
||||||
OverUseDetector::~OverUseDetector() {
|
|
||||||
#ifdef WEBRTC_BWE_MATLAB
|
|
||||||
if (plot1_) {
|
|
||||||
eng.DeletePlot(plot1_);
|
|
||||||
plot1_ = NULL;
|
|
||||||
}
|
|
||||||
if (plot2_) {
|
|
||||||
eng.DeletePlot(plot2_);
|
|
||||||
plot2_ = NULL;
|
|
||||||
}
|
|
||||||
if (plot3_) {
|
|
||||||
eng.DeletePlot(plot3_);
|
|
||||||
plot3_ = NULL;
|
|
||||||
}
|
|
||||||
if (plot4_) {
|
|
||||||
eng.DeletePlot(plot4_);
|
|
||||||
plot4_ = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tsDeltaHist_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverUseDetector::Reset() {
|
|
||||||
firstPacket_ = true;
|
|
||||||
currentFrame_.size_ = 0;
|
|
||||||
currentFrame_.completeTimeMs_ = -1;
|
|
||||||
currentFrame_.timestamp_ = -1;
|
|
||||||
prevFrame_.size_ = 0;
|
|
||||||
prevFrame_.completeTimeMs_ = -1;
|
|
||||||
prevFrame_.timestamp_ = -1;
|
|
||||||
numOfDeltas_ = 0;
|
|
||||||
slope_ = INIT_CAPACITY_SLOPE;
|
|
||||||
offset_ = 0;
|
|
||||||
E_[0][0] = 100;
|
|
||||||
E_[1][1] = 1e-1;
|
|
||||||
E_[0][1] = E_[1][0] = 0;
|
|
||||||
processNoise_[0] = 1e-10;
|
|
||||||
processNoise_[1] = 1e-2;
|
|
||||||
avgNoise_ = 0.0;
|
|
||||||
varNoise_ = 500;
|
|
||||||
threshold_ = DETECTOR_THRESHOLD;
|
|
||||||
prevOffset_ = 0.0;
|
|
||||||
timeOverUsing_ = -1;
|
|
||||||
overUseCounter_ = 0;
|
|
||||||
hypothesis_ = kBwNormal;
|
|
||||||
tsDeltaHist_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverUseDetector::Update(WebRtc_UWord16 packetSize,
|
|
||||||
WebRtc_UWord32 timestamp,
|
|
||||||
const WebRtc_Word64 nowMS) {
|
|
||||||
#ifdef WEBRTC_BWE_MATLAB
|
|
||||||
// Create plots
|
|
||||||
const WebRtc_Word64 startTimeMs = nowMS;
|
|
||||||
if (plot1_ == NULL) {
|
|
||||||
plot1_ = eng.NewPlot(new MatlabPlot());
|
|
||||||
plot1_->AddLine(1000, "b.", "scatter");
|
|
||||||
}
|
|
||||||
if (plot2_ == NULL) {
|
|
||||||
plot2_ = eng.NewPlot(new MatlabPlot());
|
|
||||||
plot2_->AddTimeLine(30, "b", "offset", startTimeMs);
|
|
||||||
plot2_->AddTimeLine(30, "r--", "limitPos", startTimeMs);
|
|
||||||
plot2_->AddTimeLine(30, "k.", "trigger", startTimeMs);
|
|
||||||
plot2_->AddTimeLine(30, "ko", "detection", startTimeMs);
|
|
||||||
// plot2_->AddTimeLine(30, "g", "slowMean", startTimeMs);
|
|
||||||
}
|
|
||||||
if (plot3_ == NULL) {
|
|
||||||
plot3_ = eng.NewPlot(new MatlabPlot());
|
|
||||||
plot3_->AddTimeLine(30, "b", "noiseVar", startTimeMs);
|
|
||||||
}
|
|
||||||
if (plot4_ == NULL) {
|
|
||||||
plot4_ = eng.NewPlot(new MatlabPlot());
|
|
||||||
// plot4_->AddTimeLine(60, "b", "p11", startTimeMs);
|
|
||||||
// plot4_->AddTimeLine(60, "r", "p12", startTimeMs);
|
|
||||||
plot4_->AddTimeLine(60, "g", "p22", startTimeMs);
|
|
||||||
// plot4_->AddTimeLine(60, "g--", "p22_hat", startTimeMs);
|
|
||||||
// plot4_->AddTimeLine(30, "b.-", "deltaFs", startTimeMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool wrapped = false;
|
|
||||||
bool completeFrame = false;
|
|
||||||
if (currentFrame_.timestamp_ == -1) {
|
|
||||||
currentFrame_.timestamp_ = timestamp;
|
|
||||||
} else if (OldTimestamp(
|
|
||||||
timestamp,
|
|
||||||
static_cast<WebRtc_UWord32>(currentFrame_.timestamp_),
|
|
||||||
&wrapped)) {
|
|
||||||
// Don't update with old data
|
|
||||||
return;
|
|
||||||
} else if (timestamp != currentFrame_.timestamp_) {
|
|
||||||
// First packet of a later frame, the previous frame sample is ready
|
|
||||||
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
|
|
||||||
"Frame complete at %I64i", currentFrame_.completeTimeMs_);
|
|
||||||
if (prevFrame_.completeTimeMs_ >= 0) { // This is our second frame
|
|
||||||
WebRtc_Word64 tDelta = 0;
|
|
||||||
double tsDelta = 0;
|
|
||||||
// Check for wrap
|
|
||||||
OldTimestamp(
|
|
||||||
static_cast<WebRtc_UWord32>(prevFrame_.timestamp_),
|
|
||||||
static_cast<WebRtc_UWord32>(currentFrame_.timestamp_),
|
|
||||||
&wrapped);
|
|
||||||
CompensatedTimeDelta(currentFrame_, prevFrame_, tDelta, tsDelta,
|
|
||||||
wrapped);
|
|
||||||
UpdateKalman(tDelta, tsDelta, currentFrame_.size_,
|
|
||||||
prevFrame_.size_);
|
|
||||||
}
|
|
||||||
// The new timestamp is now the current frame,
|
|
||||||
// and the old timestamp becomes the previous frame.
|
|
||||||
prevFrame_ = currentFrame_;
|
|
||||||
currentFrame_.timestamp_ = timestamp;
|
|
||||||
currentFrame_.size_ = 0;
|
|
||||||
currentFrame_.completeTimeMs_ = -1;
|
|
||||||
completeFrame = true;
|
|
||||||
}
|
|
||||||
// Accumulate the frame size
|
|
||||||
currentFrame_.size_ += packetSize;
|
|
||||||
currentFrame_.completeTimeMs_ = nowMS;
|
|
||||||
}
|
|
||||||
|
|
||||||
BandwidthUsage OverUseDetector::State() const {
|
|
||||||
return hypothesis_;
|
|
||||||
}
|
|
||||||
|
|
||||||
double OverUseDetector::NoiseVar() const {
|
|
||||||
return varNoise_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverUseDetector::SetRateControlRegion(RateControlRegion region) {
|
|
||||||
switch (region) {
|
|
||||||
case kRcMaxUnknown: {
|
|
||||||
threshold_ = DETECTOR_THRESHOLD;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kRcAboveMax:
|
|
||||||
case kRcNearMax: {
|
|
||||||
threshold_ = DETECTOR_THRESHOLD / 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverUseDetector::CompensatedTimeDelta(const FrameSample& currentFrame,
|
|
||||||
const FrameSample& prevFrame,
|
|
||||||
WebRtc_Word64& tDelta,
|
|
||||||
double& tsDelta,
|
|
||||||
bool wrapped) {
|
|
||||||
numOfDeltas_++;
|
|
||||||
if (numOfDeltas_ > 1000) {
|
|
||||||
numOfDeltas_ = 1000;
|
|
||||||
}
|
|
||||||
// Add wrap-around compensation
|
|
||||||
WebRtc_Word64 wrapCompensation = 0;
|
|
||||||
if (wrapped) {
|
|
||||||
wrapCompensation = static_cast<WebRtc_Word64>(1)<<32;
|
|
||||||
}
|
|
||||||
tsDelta = (currentFrame.timestamp_
|
|
||||||
+ wrapCompensation
|
|
||||||
- prevFrame.timestamp_) / 90.0;
|
|
||||||
tDelta = currentFrame.completeTimeMs_ - prevFrame.completeTimeMs_;
|
|
||||||
assert(tsDelta > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
double OverUseDetector::CurrentDrift() {
|
|
||||||
return 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverUseDetector::UpdateKalman(WebRtc_Word64 tDelta,
|
|
||||||
double tsDelta,
|
|
||||||
WebRtc_UWord32 frameSize,
|
|
||||||
WebRtc_UWord32 prevFrameSize) {
|
|
||||||
const double minFramePeriod = UpdateMinFramePeriod(tsDelta);
|
|
||||||
const double drift = CurrentDrift();
|
|
||||||
// Compensate for drift
|
|
||||||
const double tTsDelta = tDelta - tsDelta / drift;
|
|
||||||
double fsDelta = static_cast<double>(frameSize) - prevFrameSize;
|
|
||||||
|
|
||||||
// Update the Kalman filter
|
|
||||||
const double scaleFactor = minFramePeriod / (1000.0 / 30.0);
|
|
||||||
E_[0][0] += processNoise_[0] * scaleFactor;
|
|
||||||
E_[1][1] += processNoise_[1] * scaleFactor;
|
|
||||||
|
|
||||||
if ((hypothesis_ == kBwOverusing && offset_ < prevOffset_) ||
|
|
||||||
(hypothesis_ == kBwUnderUsing && offset_ > prevOffset_)) {
|
|
||||||
E_[1][1] += 10 * processNoise_[1] * scaleFactor;
|
|
||||||
}
|
|
||||||
|
|
||||||
const double h[2] = {fsDelta, 1.0};
|
|
||||||
const double Eh[2] = {E_[0][0]*h[0] + E_[0][1]*h[1],
|
|
||||||
E_[1][0]*h[0] + E_[1][1]*h[1]};
|
|
||||||
|
|
||||||
const double residual = tTsDelta - slope_*h[0] - offset_;
|
|
||||||
|
|
||||||
const bool stableState =
|
|
||||||
(BWE_MIN(numOfDeltas_, 60) * abs(offset_) < threshold_);
|
|
||||||
// We try to filter out very late frames. For instance periodic key
|
|
||||||
// frames doesn't fit the Gaussian model well.
|
|
||||||
if (abs(residual) < 3 * sqrt(varNoise_)) {
|
|
||||||
UpdateNoiseEstimate(residual, minFramePeriod, stableState);
|
|
||||||
} else {
|
|
||||||
UpdateNoiseEstimate(3 * sqrt(varNoise_), minFramePeriod, stableState);
|
|
||||||
}
|
|
||||||
|
|
||||||
const double denom = varNoise_ + h[0]*Eh[0] + h[1]*Eh[1];
|
|
||||||
|
|
||||||
const double K[2] = {Eh[0] / denom,
|
|
||||||
Eh[1] / denom};
|
|
||||||
|
|
||||||
const double IKh[2][2] = {{1.0 - K[0]*h[0], -K[0]*h[1]},
|
|
||||||
{-K[1]*h[0], 1.0 - K[1]*h[1]}};
|
|
||||||
const double e00 = E_[0][0];
|
|
||||||
const double e01 = E_[0][1];
|
|
||||||
|
|
||||||
// Update state
|
|
||||||
E_[0][0] = e00 * IKh[0][0] + E_[1][0] * IKh[0][1];
|
|
||||||
E_[0][1] = e01 * IKh[0][0] + E_[1][1] * IKh[0][1];
|
|
||||||
E_[1][0] = e00 * IKh[1][0] + E_[1][0] * IKh[1][1];
|
|
||||||
E_[1][1] = e01 * IKh[1][0] + E_[1][1] * IKh[1][1];
|
|
||||||
|
|
||||||
// Covariance matrix, must be positive semi-definite
|
|
||||||
assert(E_[0][0] + E_[1][1] >= 0 &&
|
|
||||||
E_[0][0] * E_[1][1] - E_[0][1] * E_[1][0] >= 0 &&
|
|
||||||
E_[0][0] >= 0);
|
|
||||||
|
|
||||||
#ifdef WEBRTC_BWE_MATLAB
|
|
||||||
// plot4_->Append("p11",E_[0][0]);
|
|
||||||
// plot4_->Append("p12",E_[0][1]);
|
|
||||||
plot4_->Append("p22", E_[1][1]);
|
|
||||||
// plot4_->Append("p22_hat", 0.5*(processNoise_[1] +
|
|
||||||
// sqrt(processNoise_[1]*(processNoise_[1] + 4*varNoise_))));
|
|
||||||
// plot4_->Append("deltaFs", fsDelta);
|
|
||||||
plot4_->Plot();
|
|
||||||
#endif
|
|
||||||
slope_ = slope_ + K[0] * residual;
|
|
||||||
prevOffset_ = offset_;
|
|
||||||
offset_ = offset_ + K[1] * residual;
|
|
||||||
|
|
||||||
Detect(tsDelta);
|
|
||||||
|
|
||||||
#ifdef WEBRTC_BWE_MATLAB
|
|
||||||
plot1_->Append("scatter",
|
|
||||||
static_cast<double>(currentFrame_.size_) - prevFrame_.size_,
|
|
||||||
static_cast<double>(tDelta-tsDelta));
|
|
||||||
plot1_->MakeTrend("scatter", "slope", slope_, offset_, "k-");
|
|
||||||
plot1_->MakeTrend("scatter", "thresholdPos",
|
|
||||||
slope_, offset_ + 2 * sqrt(varNoise_), "r-");
|
|
||||||
plot1_->MakeTrend("scatter", "thresholdNeg",
|
|
||||||
slope_, offset_ - 2 * sqrt(varNoise_), "r-");
|
|
||||||
plot1_->Plot();
|
|
||||||
|
|
||||||
plot2_->Append("offset", offset_);
|
|
||||||
plot2_->Append("limitPos", threshold_/BWE_MIN(numOfDeltas_, 60));
|
|
||||||
plot2_->Plot();
|
|
||||||
|
|
||||||
plot3_->Append("noiseVar", varNoise_);
|
|
||||||
plot3_->Plot();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
double OverUseDetector::UpdateMinFramePeriod(double tsDelta) {
|
|
||||||
double minFramePeriod = tsDelta;
|
|
||||||
if (tsDeltaHist_.size() >= MIN_FRAME_PERIOD_HISTORY_LEN) {
|
|
||||||
std::list<double>::iterator firstItem = tsDeltaHist_.begin();
|
|
||||||
tsDeltaHist_.erase(firstItem);
|
|
||||||
}
|
|
||||||
std::list<double>::iterator it = tsDeltaHist_.begin();
|
|
||||||
for (; it != tsDeltaHist_.end(); it++) {
|
|
||||||
minFramePeriod = BWE_MIN(*it, minFramePeriod);
|
|
||||||
}
|
|
||||||
tsDeltaHist_.push_back(tsDelta);
|
|
||||||
return minFramePeriod;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OverUseDetector::UpdateNoiseEstimate(double residual,
|
|
||||||
double tsDelta,
|
|
||||||
bool stableState) {
|
|
||||||
if (!stableState) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Faster filter during startup to faster adapt to the jitter level
|
|
||||||
// of the network alpha is tuned for 30 frames per second, but
|
|
||||||
double alpha = 0.01;
|
|
||||||
if (numOfDeltas_ > 10*30) {
|
|
||||||
alpha = 0.002;
|
|
||||||
}
|
|
||||||
// Only update the noise estimate if we're not over-using
|
|
||||||
// beta is a function of alpha and the time delta since
|
|
||||||
// the previous update.
|
|
||||||
const double beta = pow(1 - alpha, tsDelta * 30.0 / 1000.0);
|
|
||||||
avgNoise_ = beta * avgNoise_
|
|
||||||
+ (1 - beta) * residual;
|
|
||||||
varNoise_ = beta * varNoise_
|
|
||||||
+ (1 - beta) * (avgNoise_ - residual) * (avgNoise_ - residual);
|
|
||||||
if (varNoise_ < 1e-7) {
|
|
||||||
varNoise_ = 1e-7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BandwidthUsage OverUseDetector::Detect(double tsDelta) {
|
|
||||||
if (numOfDeltas_ < 2) {
|
|
||||||
return kBwNormal;
|
|
||||||
}
|
|
||||||
const double T = BWE_MIN(numOfDeltas_, 60) * offset_;
|
|
||||||
if (abs(T) > threshold_) {
|
|
||||||
if (offset_ > 0) {
|
|
||||||
if (timeOverUsing_ == -1) {
|
|
||||||
// Initialize the timer. Assume that we've been
|
|
||||||
// over-using half of the time since the previous
|
|
||||||
// sample.
|
|
||||||
timeOverUsing_ = tsDelta / 2;
|
|
||||||
} else {
|
|
||||||
// Increment timer
|
|
||||||
timeOverUsing_ += tsDelta;
|
|
||||||
}
|
|
||||||
overUseCounter_++;
|
|
||||||
if (timeOverUsing_ > OVER_USING_TIME_THRESHOLD
|
|
||||||
&& overUseCounter_ > 1) {
|
|
||||||
if (offset_ >= prevOffset_) {
|
|
||||||
#ifdef _DEBUG
|
|
||||||
if (hypothesis_ != kBwOverusing) {
|
|
||||||
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwOverusing");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
timeOverUsing_ = 0;
|
|
||||||
overUseCounter_ = 0;
|
|
||||||
hypothesis_ = kBwOverusing;
|
|
||||||
#ifdef WEBRTC_BWE_MATLAB
|
|
||||||
plot2_->Append("detection", offset_); // plot it later
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef WEBRTC_BWE_MATLAB
|
|
||||||
plot2_->Append("trigger", offset_); // plot it later
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
#ifdef _DEBUG
|
|
||||||
if (hypothesis_ != kBwUnderUsing) {
|
|
||||||
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwUnderUsing");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
timeOverUsing_ = -1;
|
|
||||||
overUseCounter_ = 0;
|
|
||||||
hypothesis_ = kBwUnderUsing;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
#ifdef _DEBUG
|
|
||||||
if (hypothesis_ != kBwNormal) {
|
|
||||||
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwNormal");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
timeOverUsing_ = -1;
|
|
||||||
overUseCounter_ = 0;
|
|
||||||
hypothesis_ = kBwNormal;
|
|
||||||
}
|
|
||||||
return hypothesis_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool OverUseDetector::OldTimestamp(uint32_t newTimestamp,
|
|
||||||
uint32_t existingTimestamp,
|
|
||||||
bool* wrapped) {
|
|
||||||
bool tmpWrapped =
|
|
||||||
(newTimestamp < 0x0000ffff && existingTimestamp > 0xffff0000) ||
|
|
||||||
(newTimestamp > 0xffff0000 && existingTimestamp < 0x0000ffff);
|
|
||||||
*wrapped = tmpWrapped;
|
|
||||||
if (existingTimestamp > newTimestamp && !tmpWrapped) {
|
|
||||||
return true;
|
|
||||||
} else if (existingTimestamp <= newTimestamp && !tmpWrapped) {
|
|
||||||
return false;
|
|
||||||
} else if (existingTimestamp < newTimestamp && tmpWrapped) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 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_RTP_RTCP_SOURCE_OVERUSE_DETECTOR_H_
|
|
||||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_OVERUSE_DETECTOR_H_
|
|
||||||
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "modules/interface/module_common_types.h"
|
|
||||||
#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
|
|
||||||
#include "typedefs.h" // NOLINT(build/include)
|
|
||||||
|
|
||||||
#ifdef WEBRTC_BWE_MATLAB
|
|
||||||
#include "../test/BWEStandAlone/MatlabPlot.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
enum RateControlRegion;
|
|
||||||
|
|
||||||
class OverUseDetector {
|
|
||||||
public:
|
|
||||||
OverUseDetector();
|
|
||||||
~OverUseDetector();
|
|
||||||
void Update(const WebRtc_UWord16 packetSize,
|
|
||||||
const WebRtc_UWord32 timestamp,
|
|
||||||
const WebRtc_Word64 nowMS);
|
|
||||||
BandwidthUsage State() const;
|
|
||||||
void Reset();
|
|
||||||
double NoiseVar() const;
|
|
||||||
void SetRateControlRegion(RateControlRegion region);
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct FrameSample {
|
|
||||||
FrameSample() : size_(0), completeTimeMs_(-1), timestamp_(-1) {}
|
|
||||||
|
|
||||||
WebRtc_UWord32 size_;
|
|
||||||
WebRtc_Word64 completeTimeMs_;
|
|
||||||
WebRtc_Word64 timestamp_;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool OldTimestamp(uint32_t newTimestamp,
|
|
||||||
uint32_t existingTimestamp,
|
|
||||||
bool* wrapped);
|
|
||||||
|
|
||||||
void CompensatedTimeDelta(const FrameSample& currentFrame,
|
|
||||||
const FrameSample& prevFrame,
|
|
||||||
WebRtc_Word64& tDelta,
|
|
||||||
double& tsDelta,
|
|
||||||
bool wrapped);
|
|
||||||
void UpdateKalman(WebRtc_Word64 tDelta,
|
|
||||||
double tsDelta,
|
|
||||||
WebRtc_UWord32 frameSize,
|
|
||||||
WebRtc_UWord32 prevFrameSize);
|
|
||||||
double UpdateMinFramePeriod(double tsDelta);
|
|
||||||
void UpdateNoiseEstimate(double residual, double tsDelta, bool stableState);
|
|
||||||
BandwidthUsage Detect(double tsDelta);
|
|
||||||
double CurrentDrift();
|
|
||||||
|
|
||||||
bool firstPacket_;
|
|
||||||
FrameSample currentFrame_;
|
|
||||||
FrameSample prevFrame_;
|
|
||||||
WebRtc_UWord16 numOfDeltas_;
|
|
||||||
double slope_;
|
|
||||||
double offset_;
|
|
||||||
double E_[2][2];
|
|
||||||
double processNoise_[2];
|
|
||||||
double avgNoise_;
|
|
||||||
double varNoise_;
|
|
||||||
double threshold_;
|
|
||||||
std::list<double> tsDeltaHist_;
|
|
||||||
double prevOffset_;
|
|
||||||
double timeOverUsing_;
|
|
||||||
WebRtc_UWord16 overUseCounter_;
|
|
||||||
BandwidthUsage hypothesis_;
|
|
||||||
|
|
||||||
#ifdef WEBRTC_BWE_MATLAB
|
|
||||||
MatlabPlot* plot1_;
|
|
||||||
MatlabPlot* plot2_;
|
|
||||||
MatlabPlot* plot3_;
|
|
||||||
MatlabPlot* plot4_;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_OVERUSE_DETECTOR_H_
|
|
@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 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 "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
|
||||||
|
|
||||||
#include "system_wrappers/interface/tick_util.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
RemoteBitrateEstimator::RemoteBitrateEstimator(
|
|
||||||
RemoteBitrateObserver* observer)
|
|
||||||
: observer_(observer),
|
|
||||||
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()) {
|
|
||||||
assert(observer_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteBitrateEstimator::IncomingPacket(unsigned int ssrc,
|
|
||||||
int packet_size,
|
|
||||||
int64_t arrival_time,
|
|
||||||
uint32_t rtp_timestamp,
|
|
||||||
int64_t packet_send_time) {
|
|
||||||
CriticalSectionScoped cs(crit_sect_.get());
|
|
||||||
SsrcBitrateControlsMap::iterator it = bitrate_controls_.find(ssrc);
|
|
||||||
if (it == bitrate_controls_.end()) {
|
|
||||||
// This is a new SSRC. Adding to map.
|
|
||||||
// TODO(holmer): If the channel changes SSRC the old SSRC will still be
|
|
||||||
// around in this map until the channel is deleted. This is OK since the
|
|
||||||
// callback will no longer be called for the old SSRC. This will be
|
|
||||||
// automatically cleaned up when we have one RemoteBitrateEstimator per REMB
|
|
||||||
// group.
|
|
||||||
bitrate_controls_[ssrc] = BitrateControls();
|
|
||||||
it = bitrate_controls_.find(ssrc);
|
|
||||||
}
|
|
||||||
OverUseDetector* overuse_detector =
|
|
||||||
&bitrate_controls_[ssrc].overuse_detector;
|
|
||||||
bitrate_controls_[ssrc].incoming_bitrate.Update(packet_size, arrival_time);
|
|
||||||
const BandwidthUsage prior_state = overuse_detector->State();
|
|
||||||
overuse_detector->Update(packet_size, rtp_timestamp, arrival_time);
|
|
||||||
if (prior_state != overuse_detector->State() &&
|
|
||||||
overuse_detector->State() == kBwOverusing) {
|
|
||||||
// The first overuse should immediately trigger a new estimate.
|
|
||||||
UpdateEstimate(ssrc, arrival_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteBitrateEstimator::UpdateEstimate(unsigned int ssrc,
|
|
||||||
int64_t time_now) {
|
|
||||||
CriticalSectionScoped cs(crit_sect_.get());
|
|
||||||
SsrcBitrateControlsMap::iterator it = bitrate_controls_.find(ssrc);
|
|
||||||
if (it == bitrate_controls_.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
OverUseDetector* overuse_detector = &it->second.overuse_detector;
|
|
||||||
RemoteRateControl* remote_rate = &it->second.remote_rate;
|
|
||||||
const RateControlInput input(overuse_detector->State(),
|
|
||||||
it->second.incoming_bitrate.BitRate(time_now),
|
|
||||||
overuse_detector->NoiseVar());
|
|
||||||
const RateControlRegion region = remote_rate->Update(&input, time_now);
|
|
||||||
unsigned int target_bitrate = remote_rate->UpdateBandwidthEstimate(time_now);
|
|
||||||
if (remote_rate->ValidEstimate()) {
|
|
||||||
observer_->OnReceiveBitrateChanged(ssrc, target_bitrate);
|
|
||||||
}
|
|
||||||
overuse_detector->SetRateControlRegion(region);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteBitrateEstimator::SetRtt(unsigned int rtt) {
|
|
||||||
CriticalSectionScoped cs(crit_sect_.get());
|
|
||||||
for (SsrcBitrateControlsMap::iterator it = bitrate_controls_.begin();
|
|
||||||
it != bitrate_controls_.end(); ++it) {
|
|
||||||
it->second.remote_rate.SetRtt(rtt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteBitrateEstimator::RemoveStream(unsigned int ssrc) {
|
|
||||||
CriticalSectionScoped cs(crit_sect_.get());
|
|
||||||
// Ignoring the return value which is the number of elements erased.
|
|
||||||
bitrate_controls_.erase(ssrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RemoteBitrateEstimator::LatestEstimate(unsigned int ssrc,
|
|
||||||
unsigned int* bitrate_bps) const {
|
|
||||||
CriticalSectionScoped cs(crit_sect_.get());
|
|
||||||
assert(bitrate_bps != NULL);
|
|
||||||
SsrcBitrateControlsMap::const_iterator it = bitrate_controls_.find(ssrc);
|
|
||||||
if (it == bitrate_controls_.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!it->second.remote_rate.ValidEstimate()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*bitrate_bps = it->second.remote_rate.LatestEstimate();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
@ -1,71 +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.
|
|
||||||
|
|
||||||
{
|
|
||||||
'targets': [
|
|
||||||
{
|
|
||||||
'target_name': 'remote_bitrate_estimator',
|
|
||||||
'type': '<(library)',
|
|
||||||
'dependencies': [
|
|
||||||
# system_wrappers
|
|
||||||
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
|
||||||
],
|
|
||||||
'include_dirs': [
|
|
||||||
'include',
|
|
||||||
'../rtp_rtcp/interface',
|
|
||||||
'../interface',
|
|
||||||
],
|
|
||||||
'direct_dependent_settings': {
|
|
||||||
'include_dirs': [
|
|
||||||
'include',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'sources': [
|
|
||||||
# interface
|
|
||||||
'include/bwe_defines.h',
|
|
||||||
'include/remote_bitrate_estimator.h',
|
|
||||||
|
|
||||||
# source
|
|
||||||
'bitrate_estimator.cc',
|
|
||||||
'bitrate_estimator.h',
|
|
||||||
'overuse_detector.cc',
|
|
||||||
'overuse_detector.h',
|
|
||||||
'remote_bitrate_estimator.cc',
|
|
||||||
'remote_rate_control.cc',
|
|
||||||
'remote_rate_control.h',
|
|
||||||
], # source
|
|
||||||
},
|
|
||||||
], # targets
|
|
||||||
'conditions': [
|
|
||||||
['include_tests==1', {
|
|
||||||
'targets': [
|
|
||||||
{
|
|
||||||
'target_name': 'remote_bitrate_estimator_unittests',
|
|
||||||
'type': 'executable',
|
|
||||||
'dependencies': [
|
|
||||||
'remote_bitrate_estimator',
|
|
||||||
'<(webrtc_root)/../testing/gmock.gyp:gmock',
|
|
||||||
'<(webrtc_root)/../testing/gtest.gyp:gtest',
|
|
||||||
'<(webrtc_root)/../test/test.gyp:test_support_main',
|
|
||||||
],
|
|
||||||
'sources': [
|
|
||||||
'include/mock/mock_remote_bitrate_estimator.h',
|
|
||||||
'bitrate_estimator_unittest.cc',
|
|
||||||
'remote_bitrate_estimator_unittest.cc',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
], # targets
|
|
||||||
}], # build_with_chromium
|
|
||||||
], # conditions
|
|
||||||
}
|
|
||||||
|
|
||||||
# Local Variables:
|
|
||||||
# tab-width:2
|
|
||||||
# indent-tabs-mode:nil
|
|
||||||
# End:
|
|
||||||
# vim: set expandtab tabstop=2 shiftwidth=2:
|
|
@ -1,297 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// This file includes unit tests for RemoteBitrateEstimator.
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
|
||||||
#include "system_wrappers/interface/scoped_ptr.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
enum { kMtu = 1200 };
|
|
||||||
|
|
||||||
class TestBitrateObserver : public RemoteBitrateObserver {
|
|
||||||
public:
|
|
||||||
TestBitrateObserver() : updated_(false), latest_bitrate_(0) {}
|
|
||||||
|
|
||||||
void OnReceiveBitrateChanged(unsigned int ssrc, unsigned int bitrate) {
|
|
||||||
latest_bitrate_ = bitrate;
|
|
||||||
updated_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool updated() {
|
|
||||||
bool updated = updated_;
|
|
||||||
updated_ = false;
|
|
||||||
return updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int latest_bitrate() const {
|
|
||||||
return latest_bitrate_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool updated_;
|
|
||||||
unsigned int latest_bitrate_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StreamGenerator {
|
|
||||||
public:
|
|
||||||
struct Packet {
|
|
||||||
int64_t send_time;
|
|
||||||
int64_t arrival_time;
|
|
||||||
uint32_t rtp_timestamp;
|
|
||||||
unsigned int size;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::list<Packet*> PacketList;
|
|
||||||
|
|
||||||
StreamGenerator(int fps, int bitrate_bps, int capacity, int64_t time_now)
|
|
||||||
: fps_(fps),
|
|
||||||
bitrate_bps_(bitrate_bps),
|
|
||||||
capacity_(capacity),
|
|
||||||
time_now_(time_now),
|
|
||||||
prev_arrival_time_(time_now),
|
|
||||||
rtp_timestamp_offset_(0xFFFFF000) {}
|
|
||||||
|
|
||||||
void SetCapacity(int capacity_bps) {
|
|
||||||
ASSERT_GT(capacity_bps, 0);
|
|
||||||
capacity_ = capacity_bps;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetBitrate(int bitrate_bps) {
|
|
||||||
ASSERT_GE(bitrate_bps, 0);
|
|
||||||
bitrate_bps_ = bitrate_bps;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetRtpTimestampOffset(uint32_t offset) {
|
|
||||||
rtp_timestamp_offset_ = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenerateFrame(PacketList* packets) {
|
|
||||||
ASSERT_FALSE(packets == NULL);
|
|
||||||
ASSERT_TRUE(packets->empty());
|
|
||||||
ASSERT_GT(fps_, 0);
|
|
||||||
int bits_per_frame = bitrate_bps_ / fps_;
|
|
||||||
int n_packets = std::max(bits_per_frame / (8 * kMtu), 1);
|
|
||||||
int packet_size = bits_per_frame / (8 * n_packets);
|
|
||||||
ASSERT_GE(n_packets, 0);
|
|
||||||
for (int i = 0; i < n_packets; ++i) {
|
|
||||||
Packet* packet = new Packet;
|
|
||||||
packet->send_time = time_now_ + kSendSideOffsetMs;
|
|
||||||
ASSERT_GT(capacity_, 0);
|
|
||||||
packet->arrival_time = std::max(
|
|
||||||
prev_arrival_time_ + 8 * 1000 * packet_size / capacity_,
|
|
||||||
time_now_);
|
|
||||||
packet->size = packet_size;
|
|
||||||
packet->rtp_timestamp = rtp_timestamp_offset_ + 90 * packet->send_time;
|
|
||||||
prev_arrival_time_ = packet->arrival_time;
|
|
||||||
packets->push_back(packet);
|
|
||||||
}
|
|
||||||
time_now_ = time_now_ + 1000 / fps_;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t TimeNow() const {
|
|
||||||
return time_now_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum { kSendSideOffsetMs = 1000 };
|
|
||||||
|
|
||||||
int fps_;
|
|
||||||
int bitrate_bps_;
|
|
||||||
int capacity_;
|
|
||||||
int64_t time_now_;
|
|
||||||
int64_t prev_arrival_time_;
|
|
||||||
uint32_t rtp_timestamp_offset_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RemoteBitrateEstimatorTest : public ::testing::Test {
|
|
||||||
protected:
|
|
||||||
virtual void SetUp() {
|
|
||||||
bitrate_observer_.reset(new TestBitrateObserver);
|
|
||||||
bitrate_estimator_.reset(new RemoteBitrateEstimator(
|
|
||||||
bitrate_observer_.get()));
|
|
||||||
// Framerate: 30 fps; Start bitrate: 300 kbps; Link capacity: 1000 kbps,
|
|
||||||
// Start time: 0.
|
|
||||||
stream_generator_.reset(new StreamGenerator(30, 3e5, 1e6, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generates a frame of packets belonging to a stream at a given bitrate and
|
|
||||||
// with a given ssrc. The stream is pushed through a very simple simulated
|
|
||||||
// network, and is then given to the receive-side bandwidth estimator.
|
|
||||||
void GenerateAndProcessFrame(unsigned int ssrc, unsigned int bitrate_bps) {
|
|
||||||
stream_generator_->SetBitrate(bitrate_bps);
|
|
||||||
StreamGenerator::PacketList packets;
|
|
||||||
stream_generator_->GenerateFrame(&packets);
|
|
||||||
int64_t last_arrival_time = -1;
|
|
||||||
bool prev_was_decrease = false;
|
|
||||||
while (!packets.empty()) {
|
|
||||||
StreamGenerator::Packet* packet = packets.front();
|
|
||||||
bitrate_estimator_->IncomingPacket(ssrc,
|
|
||||||
packet->size,
|
|
||||||
packet->arrival_time,
|
|
||||||
packet->rtp_timestamp,
|
|
||||||
-1);
|
|
||||||
if (bitrate_observer_->updated()) {
|
|
||||||
// Verify that new estimates only are triggered by an overuse and a
|
|
||||||
// rate decrease.
|
|
||||||
EXPECT_LE(bitrate_observer_->latest_bitrate(), bitrate_bps);
|
|
||||||
EXPECT_FALSE(prev_was_decrease);
|
|
||||||
prev_was_decrease = true;
|
|
||||||
} else {
|
|
||||||
prev_was_decrease = false;
|
|
||||||
}
|
|
||||||
last_arrival_time = packet->arrival_time;
|
|
||||||
delete packet;
|
|
||||||
packets.pop_front();
|
|
||||||
}
|
|
||||||
EXPECT_GT(last_arrival_time, -1);
|
|
||||||
bitrate_estimator_->UpdateEstimate(ssrc, last_arrival_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the bandwidth estimator with a stream of |number_of_frames| frames.
|
|
||||||
// Can for instance be used to run the estimator for some time to get it
|
|
||||||
// into a steady state.
|
|
||||||
unsigned int SteadyStateRun(unsigned int ssrc,
|
|
||||||
int number_of_frames,
|
|
||||||
unsigned int start_bitrate,
|
|
||||||
unsigned int min_bitrate,
|
|
||||||
unsigned int max_bitrate) {
|
|
||||||
unsigned int bitrate_bps = start_bitrate;
|
|
||||||
bool bitrate_update_seen = false;
|
|
||||||
// Produce |number_of_frames| frames and give them to the estimator.
|
|
||||||
for (int i = 0; i < number_of_frames; ++i) {
|
|
||||||
GenerateAndProcessFrame(ssrc, bitrate_bps);
|
|
||||||
if (bitrate_observer_->updated()) {
|
|
||||||
EXPECT_LT(bitrate_observer_->latest_bitrate(), max_bitrate);
|
|
||||||
EXPECT_GT(bitrate_observer_->latest_bitrate(), min_bitrate);
|
|
||||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
|
||||||
bitrate_update_seen = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPECT_TRUE(bitrate_update_seen);
|
|
||||||
return bitrate_bps;
|
|
||||||
}
|
|
||||||
|
|
||||||
scoped_ptr<RemoteBitrateEstimator> bitrate_estimator_;
|
|
||||||
scoped_ptr<TestBitrateObserver> bitrate_observer_;
|
|
||||||
scoped_ptr<StreamGenerator> stream_generator_;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(RemoteBitrateEstimatorTest, TestInitialBehavior) {
|
|
||||||
unsigned int bitrate_bps = 0;
|
|
||||||
unsigned int ssrc = 0;
|
|
||||||
int64_t time_now = 0;
|
|
||||||
uint32_t timestamp = 0;
|
|
||||||
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(ssrc, &bitrate_bps));
|
|
||||||
bitrate_estimator_->UpdateEstimate(ssrc, time_now);
|
|
||||||
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(ssrc, &bitrate_bps));
|
|
||||||
EXPECT_FALSE(bitrate_observer_->updated());
|
|
||||||
// Inserting a packet. Still no valid estimate. We need to wait 1 second.
|
|
||||||
bitrate_estimator_->IncomingPacket(ssrc, kMtu, time_now,
|
|
||||||
timestamp, -1);
|
|
||||||
bitrate_estimator_->UpdateEstimate(ssrc, time_now);
|
|
||||||
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(ssrc, &bitrate_bps));
|
|
||||||
EXPECT_FALSE(bitrate_observer_->updated());
|
|
||||||
// Waiting more than one second gives us a valid estimate.
|
|
||||||
time_now += 1001;
|
|
||||||
bitrate_estimator_->UpdateEstimate(ssrc, time_now);
|
|
||||||
EXPECT_TRUE(bitrate_estimator_->LatestEstimate(ssrc, &bitrate_bps));
|
|
||||||
EXPECT_EQ(bitrate_bps, 10734u);
|
|
||||||
EXPECT_TRUE(bitrate_observer_->updated());
|
|
||||||
EXPECT_EQ(bitrate_observer_->latest_bitrate(), bitrate_bps);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure we initially increase the bitrate as expected.
|
|
||||||
TEST_F(RemoteBitrateEstimatorTest, TestRateIncreaseRtpTimestamps) {
|
|
||||||
const int kExpectedIterations = 323;
|
|
||||||
unsigned int bitrate_bps = 30000;
|
|
||||||
unsigned int ssrc = 0;
|
|
||||||
int iterations = 0;
|
|
||||||
// Feed the estimator with a stream of packets and verify that it reaches
|
|
||||||
// 500 kbps at the expected time.
|
|
||||||
while (bitrate_bps < 5e5) {
|
|
||||||
GenerateAndProcessFrame(ssrc, bitrate_bps);
|
|
||||||
if (bitrate_observer_->updated()) {
|
|
||||||
EXPECT_GT(bitrate_observer_->latest_bitrate(), bitrate_bps);
|
|
||||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
|
||||||
}
|
|
||||||
++iterations;
|
|
||||||
ASSERT_LE(iterations, kExpectedIterations);
|
|
||||||
}
|
|
||||||
ASSERT_EQ(iterations, kExpectedIterations);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that the time it takes for the estimator to reduce the bitrate when
|
|
||||||
// the capacity is tightened stays the same.
|
|
||||||
TEST_F(RemoteBitrateEstimatorTest, TestCapacityDropRtpTimestamps) {
|
|
||||||
const unsigned int kSsrc = 0;
|
|
||||||
const int kNumberOfFrames= 1000;
|
|
||||||
const int kStartBitrate = 900e3;
|
|
||||||
const int kMinExpectedBitrate = 800e3;
|
|
||||||
const int kMaxExpectedBitrate = 1500e3;
|
|
||||||
// Run in steady state to make the estimator converge.
|
|
||||||
unsigned int bitrate_bps = SteadyStateRun(kSsrc, kNumberOfFrames,
|
|
||||||
kStartBitrate, kMinExpectedBitrate,
|
|
||||||
kMaxExpectedBitrate);
|
|
||||||
// Reduce the capacity and verify the decrease time.
|
|
||||||
stream_generator_->SetCapacity(500e3);
|
|
||||||
int64_t bitrate_drop_time = 0;
|
|
||||||
for (int i = 0; i < 1000; ++i) {
|
|
||||||
GenerateAndProcessFrame(kSsrc, bitrate_bps);
|
|
||||||
if (bitrate_observer_->updated()) {
|
|
||||||
if (bitrate_observer_->latest_bitrate() <= 500e3) {
|
|
||||||
bitrate_drop_time = stream_generator_->TimeNow();
|
|
||||||
}
|
|
||||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPECT_EQ(66000, bitrate_drop_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that the time it takes for the estimator to reduce the bitrate when
|
|
||||||
// the capacity is tightened stays the same. This test also verifies that we
|
|
||||||
// handle wrap-arounds in this scenario.
|
|
||||||
TEST_F(RemoteBitrateEstimatorTest, TestCapacityDropRtpTimestampsWrap) {
|
|
||||||
const unsigned int kSsrc = 0;
|
|
||||||
const int kFramerate= 30;
|
|
||||||
const int kStartBitrate = 900e3;
|
|
||||||
const int kMinExpectedBitrate = 800e3;
|
|
||||||
const int kMaxExpectedBitrate = 1500e3;
|
|
||||||
const int kSteadyStateTime = 5; // Seconds.
|
|
||||||
// Trigger wrap right after the steady state run.
|
|
||||||
stream_generator_->SetRtpTimestampOffset(
|
|
||||||
std::numeric_limits<uint32_t>::max() - kSteadyStateTime * 90000);
|
|
||||||
// Run in steady state to make the estimator converge.
|
|
||||||
unsigned int bitrate_bps = SteadyStateRun(kSsrc,
|
|
||||||
kSteadyStateTime * kFramerate,
|
|
||||||
kStartBitrate,
|
|
||||||
kMinExpectedBitrate,
|
|
||||||
kMaxExpectedBitrate);
|
|
||||||
// Reduce the capacity and verify the decrease time.
|
|
||||||
stream_generator_->SetCapacity(500e3);
|
|
||||||
int64_t bitrate_drop_time = 0;
|
|
||||||
for (int i = 0; i < 1000; ++i) {
|
|
||||||
GenerateAndProcessFrame(kSsrc, bitrate_bps);
|
|
||||||
if (bitrate_observer_->updated()) {
|
|
||||||
if (bitrate_observer_->latest_bitrate() <= 500e3) {
|
|
||||||
bitrate_drop_time = stream_generator_->TimeNow();
|
|
||||||
}
|
|
||||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPECT_EQ(37356, bitrate_drop_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
@ -1,489 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 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 "modules/remote_bitrate_estimator/remote_rate_control.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <string.h>
|
|
||||||
#if _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "system_wrappers/interface/trace.h"
|
|
||||||
|
|
||||||
#ifdef MATLAB
|
|
||||||
extern MatlabEngine eng; // global variable defined elsewhere
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
RemoteRateControl::RemoteRateControl()
|
|
||||||
:
|
|
||||||
_minConfiguredBitRate(30000),
|
|
||||||
_maxConfiguredBitRate(30000000),
|
|
||||||
_currentBitRate(_maxConfiguredBitRate),
|
|
||||||
_maxHoldRate(0),
|
|
||||||
_avgMaxBitRate(-1.0f),
|
|
||||||
_varMaxBitRate(0.4f),
|
|
||||||
_rcState(kRcHold),
|
|
||||||
_cameFromState(kRcDecrease),
|
|
||||||
_rcRegion(kRcMaxUnknown),
|
|
||||||
_lastBitRateChange(-1),
|
|
||||||
_currentInput(kBwNormal, 0, 1.0),
|
|
||||||
_updated(false),
|
|
||||||
_timeFirstIncomingEstimate(-1),
|
|
||||||
_initializedBitRate(false),
|
|
||||||
_avgChangePeriod(1000.0f),
|
|
||||||
_lastChangeMs(-1),
|
|
||||||
_beta(0.9f),
|
|
||||||
_rtt(0)
|
|
||||||
#ifdef MATLAB
|
|
||||||
,_plot1(NULL),
|
|
||||||
_plot2(NULL)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoteRateControl::~RemoteRateControl()
|
|
||||||
{
|
|
||||||
#ifdef MATLAB
|
|
||||||
eng.DeletePlot(_plot1);
|
|
||||||
eng.DeletePlot(_plot2);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteRateControl::Reset()
|
|
||||||
{
|
|
||||||
_minConfiguredBitRate = 30000;
|
|
||||||
_maxConfiguredBitRate = 30000000;
|
|
||||||
_currentBitRate = _maxConfiguredBitRate;
|
|
||||||
_maxHoldRate = 0;
|
|
||||||
_avgMaxBitRate = -1.0f;
|
|
||||||
_varMaxBitRate = 0.4f;
|
|
||||||
_rcState = kRcHold;
|
|
||||||
_cameFromState = kRcHold;
|
|
||||||
_rcRegion = kRcMaxUnknown;
|
|
||||||
_lastBitRateChange = -1;
|
|
||||||
_avgChangePeriod = 1000.0f;
|
|
||||||
_lastChangeMs = -1;
|
|
||||||
_beta = 0.9f;
|
|
||||||
_currentInput._bwState = kBwNormal;
|
|
||||||
_currentInput._incomingBitRate = 0;
|
|
||||||
_currentInput._noiseVar = 1.0;
|
|
||||||
_updated = false;
|
|
||||||
_timeFirstIncomingEstimate = -1;
|
|
||||||
_initializedBitRate = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RemoteRateControl::ValidEstimate() const {
|
|
||||||
return _initializedBitRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebRtc_Word32 RemoteRateControl::SetConfiguredBitRates(
|
|
||||||
WebRtc_UWord32 minBitRateBps, WebRtc_UWord32 maxBitRateBps)
|
|
||||||
{
|
|
||||||
if (minBitRateBps > maxBitRateBps)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
_minConfiguredBitRate = minBitRateBps;
|
|
||||||
_maxConfiguredBitRate = maxBitRateBps;
|
|
||||||
_currentBitRate = BWE_MIN(BWE_MAX(minBitRateBps, _currentBitRate),
|
|
||||||
maxBitRateBps);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebRtc_UWord32 RemoteRateControl::LatestEstimate() const {
|
|
||||||
return _currentBitRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebRtc_UWord32 RemoteRateControl::UpdateBandwidthEstimate(WebRtc_Word64 nowMS)
|
|
||||||
{
|
|
||||||
_currentBitRate = ChangeBitRate(_currentBitRate,
|
|
||||||
_currentInput._incomingBitRate,
|
|
||||||
_currentInput._noiseVar,
|
|
||||||
nowMS);
|
|
||||||
return _currentBitRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteRateControl::SetRtt(unsigned int rtt) {
|
|
||||||
_rtt = rtt;
|
|
||||||
}
|
|
||||||
|
|
||||||
RateControlRegion RemoteRateControl::Update(const RateControlInput* input,
|
|
||||||
WebRtc_Word64 nowMS)
|
|
||||||
{
|
|
||||||
assert(input);
|
|
||||||
#ifdef MATLAB
|
|
||||||
// Create plots
|
|
||||||
if (_plot1 == NULL)
|
|
||||||
{
|
|
||||||
_plot1 = eng.NewPlot(new MatlabPlot());
|
|
||||||
|
|
||||||
_plot1->AddTimeLine(30, "b", "current");
|
|
||||||
_plot1->AddTimeLine(30, "r-", "avgMax");
|
|
||||||
_plot1->AddTimeLine(30, "r--", "pStdMax");
|
|
||||||
_plot1->AddTimeLine(30, "r--", "nStdMax");
|
|
||||||
_plot1->AddTimeLine(30, "r+", "max");
|
|
||||||
_plot1->AddTimeLine(30, "g", "incoming");
|
|
||||||
_plot1->AddTimeLine(30, "b+", "recovery");
|
|
||||||
}
|
|
||||||
if (_plot2 == NULL)
|
|
||||||
{
|
|
||||||
_plot2 = eng.NewPlot(new MatlabPlot());
|
|
||||||
|
|
||||||
_plot2->AddTimeLine(30, "b", "alpha");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set the initial bit rate value to what we're receiving the first second
|
|
||||||
if (!_initializedBitRate)
|
|
||||||
{
|
|
||||||
if (_timeFirstIncomingEstimate < 0)
|
|
||||||
{
|
|
||||||
if (input->_incomingBitRate > 0)
|
|
||||||
{
|
|
||||||
_timeFirstIncomingEstimate = nowMS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (nowMS - _timeFirstIncomingEstimate > 1000 &&
|
|
||||||
input->_incomingBitRate > 0)
|
|
||||||
{
|
|
||||||
_currentBitRate = input->_incomingBitRate;
|
|
||||||
_initializedBitRate = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_updated && _currentInput._bwState == kBwOverusing)
|
|
||||||
{
|
|
||||||
// Only update delay factor and incoming bit rate. We always want to react on an over-use.
|
|
||||||
_currentInput._noiseVar = input->_noiseVar;
|
|
||||||
_currentInput._incomingBitRate = input->_incomingBitRate;
|
|
||||||
return _rcRegion;
|
|
||||||
}
|
|
||||||
_updated = true;
|
|
||||||
_currentInput = *input;
|
|
||||||
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: Incoming rate = %u kbps", input->_incomingBitRate/1000);
|
|
||||||
return _rcRegion;
|
|
||||||
}
|
|
||||||
|
|
||||||
WebRtc_UWord32 RemoteRateControl::ChangeBitRate(WebRtc_UWord32 currentBitRate,
|
|
||||||
WebRtc_UWord32 incomingBitRate,
|
|
||||||
double noiseVar,
|
|
||||||
WebRtc_Word64 nowMS)
|
|
||||||
{
|
|
||||||
if (!_updated)
|
|
||||||
{
|
|
||||||
return _currentBitRate;
|
|
||||||
}
|
|
||||||
_updated = false;
|
|
||||||
UpdateChangePeriod(nowMS);
|
|
||||||
ChangeState(_currentInput, nowMS);
|
|
||||||
// calculated here because it's used in multiple places
|
|
||||||
const float incomingBitRateKbps = incomingBitRate / 1000.0f;
|
|
||||||
// Calculate the max bit rate std dev given the normalized
|
|
||||||
// variance and the current incoming bit rate.
|
|
||||||
const float stdMaxBitRate = sqrt(_varMaxBitRate * _avgMaxBitRate);
|
|
||||||
bool recovery = false;
|
|
||||||
switch (_rcState)
|
|
||||||
{
|
|
||||||
case kRcHold:
|
|
||||||
{
|
|
||||||
_maxHoldRate = BWE_MAX(_maxHoldRate, incomingBitRate);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kRcIncrease:
|
|
||||||
{
|
|
||||||
if (_avgMaxBitRate >= 0)
|
|
||||||
{
|
|
||||||
if (incomingBitRateKbps > _avgMaxBitRate + 3 * stdMaxBitRate)
|
|
||||||
{
|
|
||||||
ChangeRegion(kRcMaxUnknown);
|
|
||||||
_avgMaxBitRate = -1.0;
|
|
||||||
}
|
|
||||||
else if (incomingBitRateKbps > _avgMaxBitRate + 2.5 * stdMaxBitRate)
|
|
||||||
{
|
|
||||||
ChangeRegion(kRcAboveMax);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
|
|
||||||
"BWE: Response time: %f + %i + 10*33\n",
|
|
||||||
_avgChangePeriod, _rtt);
|
|
||||||
const WebRtc_UWord32 responseTime = static_cast<WebRtc_UWord32>(_avgChangePeriod + 0.5f) + _rtt + 300;
|
|
||||||
double alpha = RateIncreaseFactor(nowMS, _lastBitRateChange,
|
|
||||||
responseTime, noiseVar);
|
|
||||||
|
|
||||||
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
|
|
||||||
"BWE: _avgChangePeriod = %f ms; RTT = %u ms", _avgChangePeriod, _rtt);
|
|
||||||
|
|
||||||
currentBitRate = static_cast<WebRtc_UWord32>(currentBitRate * alpha) + 1000;
|
|
||||||
if (_maxHoldRate > 0 && _beta * _maxHoldRate > currentBitRate)
|
|
||||||
{
|
|
||||||
currentBitRate = static_cast<WebRtc_UWord32>(_beta * _maxHoldRate);
|
|
||||||
_avgMaxBitRate = _beta * _maxHoldRate / 1000.0f;
|
|
||||||
ChangeRegion(kRcNearMax);
|
|
||||||
recovery = true;
|
|
||||||
#ifdef MATLAB
|
|
||||||
_plot1->Append("recovery", _maxHoldRate/1000);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
_maxHoldRate = 0;
|
|
||||||
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
|
|
||||||
"BWE: Increase rate to currentBitRate = %u kbps", currentBitRate/1000);
|
|
||||||
_lastBitRateChange = nowMS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kRcDecrease:
|
|
||||||
{
|
|
||||||
if (incomingBitRate < _minConfiguredBitRate)
|
|
||||||
{
|
|
||||||
currentBitRate = _minConfiguredBitRate;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Set bit rate to something slightly lower than max
|
|
||||||
// to get rid of any self-induced delay.
|
|
||||||
currentBitRate = static_cast<WebRtc_UWord32>(_beta * incomingBitRate + 0.5);
|
|
||||||
if (currentBitRate > _currentBitRate)
|
|
||||||
{
|
|
||||||
// Avoid increasing the rate when over-using.
|
|
||||||
if (_rcRegion != kRcMaxUnknown)
|
|
||||||
{
|
|
||||||
currentBitRate = static_cast<WebRtc_UWord32>(_beta * _avgMaxBitRate * 1000 + 0.5f);
|
|
||||||
}
|
|
||||||
currentBitRate = BWE_MIN(currentBitRate, _currentBitRate);
|
|
||||||
}
|
|
||||||
ChangeRegion(kRcNearMax);
|
|
||||||
|
|
||||||
if (incomingBitRateKbps < _avgMaxBitRate - 3 * stdMaxBitRate)
|
|
||||||
{
|
|
||||||
_avgMaxBitRate = -1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateMaxBitRateEstimate(incomingBitRateKbps);
|
|
||||||
|
|
||||||
#ifdef MATLAB
|
|
||||||
_plot1->Append("max", incomingBitRateKbps);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: Decrease rate to currentBitRate = %u kbps", currentBitRate/1000);
|
|
||||||
}
|
|
||||||
// Stay on hold until the pipes are cleared.
|
|
||||||
ChangeState(kRcHold);
|
|
||||||
_lastBitRateChange = nowMS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!recovery && (incomingBitRate > 100000 || currentBitRate > 150000) &&
|
|
||||||
currentBitRate > 1.5 * incomingBitRate)
|
|
||||||
{
|
|
||||||
// Allow changing the bit rate if we are operating at very low rates
|
|
||||||
// Don't change the bit rate if the send side is too far off
|
|
||||||
currentBitRate = _currentBitRate;
|
|
||||||
_lastBitRateChange = nowMS;
|
|
||||||
}
|
|
||||||
#ifdef MATLAB
|
|
||||||
if (_avgMaxBitRate >= 0.0f)
|
|
||||||
{
|
|
||||||
_plot1->Append("avgMax", _avgMaxBitRate);
|
|
||||||
_plot1->Append("pStdMax", _avgMaxBitRate + 3*stdMaxBitRate);
|
|
||||||
_plot1->Append("nStdMax", _avgMaxBitRate - 3*stdMaxBitRate);
|
|
||||||
}
|
|
||||||
_plot1->Append("incoming", incomingBitRate/1000);
|
|
||||||
_plot1->Append("current", currentBitRate/1000);
|
|
||||||
_plot1->Plot();
|
|
||||||
#endif
|
|
||||||
return currentBitRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
double RemoteRateControl::RateIncreaseFactor(WebRtc_Word64 nowMs, WebRtc_Word64 lastMs, WebRtc_UWord32 reactionTimeMs, double noiseVar) const
|
|
||||||
{
|
|
||||||
// alpha = 1.02 + B ./ (1 + exp(b*(tr - (c1*s2 + c2))))
|
|
||||||
// Parameters
|
|
||||||
const double B = 0.0407;
|
|
||||||
const double b = 0.0025;
|
|
||||||
const double c1 = -6700.0 / (33 * 33);
|
|
||||||
const double c2 = 800.0;
|
|
||||||
const double d = 0.85;
|
|
||||||
|
|
||||||
double alpha = 1.005 + B / (1 + exp( b * (d * reactionTimeMs - (c1 * noiseVar + c2))));
|
|
||||||
|
|
||||||
if (alpha < 1.005)
|
|
||||||
{
|
|
||||||
alpha = 1.005;
|
|
||||||
}
|
|
||||||
else if (alpha > 1.3)
|
|
||||||
{
|
|
||||||
alpha = 1.3;
|
|
||||||
}
|
|
||||||
|
|
||||||
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
|
|
||||||
"BWE: alpha = %f", alpha);
|
|
||||||
#ifdef MATLAB
|
|
||||||
_plot2->Append("alpha", alpha);
|
|
||||||
_plot2->Plot();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (lastMs > -1)
|
|
||||||
{
|
|
||||||
alpha = pow(alpha, (nowMs - lastMs) / 1000.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_rcRegion == kRcNearMax)
|
|
||||||
{
|
|
||||||
// We're close to our previous maximum. Try to stabilize the
|
|
||||||
// bit rate in this region, by increasing in smaller steps.
|
|
||||||
alpha = alpha - (alpha - 1.0) / 2.0;
|
|
||||||
}
|
|
||||||
else if (_rcRegion == kRcMaxUnknown)
|
|
||||||
{
|
|
||||||
alpha = alpha + (alpha - 1.0) * 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteRateControl::UpdateChangePeriod(WebRtc_Word64 nowMs)
|
|
||||||
{
|
|
||||||
WebRtc_Word64 changePeriod = 0;
|
|
||||||
if (_lastChangeMs > -1)
|
|
||||||
{
|
|
||||||
changePeriod = nowMs - _lastChangeMs;
|
|
||||||
}
|
|
||||||
_lastChangeMs = nowMs;
|
|
||||||
_avgChangePeriod = 0.9f * _avgChangePeriod + 0.1f * changePeriod;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteRateControl::UpdateMaxBitRateEstimate(float incomingBitRateKbps)
|
|
||||||
{
|
|
||||||
const float alpha = 0.05f;
|
|
||||||
if (_avgMaxBitRate == -1.0f)
|
|
||||||
{
|
|
||||||
_avgMaxBitRate = incomingBitRateKbps;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_avgMaxBitRate = (1 - alpha) * _avgMaxBitRate +
|
|
||||||
alpha * incomingBitRateKbps;
|
|
||||||
}
|
|
||||||
// Estimate the max bit rate variance and normalize the variance
|
|
||||||
// with the average max bit rate.
|
|
||||||
const float norm = BWE_MAX(_avgMaxBitRate, 1.0f);
|
|
||||||
_varMaxBitRate = (1 - alpha) * _varMaxBitRate +
|
|
||||||
alpha * (_avgMaxBitRate - incomingBitRateKbps) *
|
|
||||||
(_avgMaxBitRate - incomingBitRateKbps) /
|
|
||||||
norm;
|
|
||||||
// 0.4 ~= 14 kbit/s at 500 kbit/s
|
|
||||||
if (_varMaxBitRate < 0.4f)
|
|
||||||
{
|
|
||||||
_varMaxBitRate = 0.4f;
|
|
||||||
}
|
|
||||||
// 2.5f ~= 35 kbit/s at 500 kbit/s
|
|
||||||
if (_varMaxBitRate > 2.5f)
|
|
||||||
{
|
|
||||||
_varMaxBitRate = 2.5f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteRateControl::ChangeState(const RateControlInput& input, WebRtc_Word64 nowMs)
|
|
||||||
{
|
|
||||||
switch (_currentInput._bwState)
|
|
||||||
{
|
|
||||||
case kBwNormal:
|
|
||||||
{
|
|
||||||
if (_rcState == kRcHold)
|
|
||||||
{
|
|
||||||
_lastBitRateChange = nowMs;
|
|
||||||
ChangeState(kRcIncrease);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kBwOverusing:
|
|
||||||
{
|
|
||||||
if (_rcState != kRcDecrease)
|
|
||||||
{
|
|
||||||
ChangeState(kRcDecrease);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kBwUnderUsing:
|
|
||||||
{
|
|
||||||
ChangeState(kRcHold);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteRateControl::ChangeRegion(RateControlRegion region)
|
|
||||||
{
|
|
||||||
_rcRegion = region;
|
|
||||||
switch (_rcRegion)
|
|
||||||
{
|
|
||||||
case kRcAboveMax:
|
|
||||||
case kRcMaxUnknown:
|
|
||||||
{
|
|
||||||
_beta = 0.9f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case kRcNearMax:
|
|
||||||
{
|
|
||||||
_beta = 0.95f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteRateControl::ChangeState(RateControlState newState)
|
|
||||||
{
|
|
||||||
_cameFromState = _rcState;
|
|
||||||
_rcState = newState;
|
|
||||||
char state1[15];
|
|
||||||
char state2[15];
|
|
||||||
char state3[15];
|
|
||||||
StateStr(_cameFromState, state1);
|
|
||||||
StateStr(_rcState, state2);
|
|
||||||
StateStr(_currentInput._bwState, state3);
|
|
||||||
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
|
|
||||||
"\t%s => %s due to %s\n", state1, state2, state3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteRateControl::StateStr(RateControlState state, char* str)
|
|
||||||
{
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case kRcDecrease:
|
|
||||||
strncpy(str, "DECREASE", 9);
|
|
||||||
break;
|
|
||||||
case kRcHold:
|
|
||||||
strncpy(str, "HOLD", 5);
|
|
||||||
break;
|
|
||||||
case kRcIncrease:
|
|
||||||
strncpy(str, "INCREASE", 9);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoteRateControl::StateStr(BandwidthUsage state, char* str)
|
|
||||||
{
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case kBwNormal:
|
|
||||||
strncpy(str, "NORMAL", 7);
|
|
||||||
break;
|
|
||||||
case kBwOverusing:
|
|
||||||
strncpy(str, "OVER USING", 11);
|
|
||||||
break;
|
|
||||||
case kBwUnderUsing:
|
|
||||||
strncpy(str, "UNDER USING", 12);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012 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_RTP_RTCP_SOURCE_REMOTE_RATE_CONTROL_H_
|
|
||||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_REMOTE_RATE_CONTROL_H_
|
|
||||||
|
|
||||||
#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
|
|
||||||
#include "typedefs.h"
|
|
||||||
|
|
||||||
#ifdef MATLAB
|
|
||||||
#include "../test/BWEStandAlone/MatlabPlot.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
class RemoteRateControl
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RemoteRateControl();
|
|
||||||
~RemoteRateControl();
|
|
||||||
WebRtc_Word32 SetConfiguredBitRates(WebRtc_UWord32 minBitRate,
|
|
||||||
WebRtc_UWord32 maxBitRate);
|
|
||||||
WebRtc_UWord32 LatestEstimate() const;
|
|
||||||
WebRtc_UWord32 UpdateBandwidthEstimate(WebRtc_Word64 nowMS);
|
|
||||||
void SetRtt(unsigned int rtt);
|
|
||||||
RateControlRegion Update(const RateControlInput* input,
|
|
||||||
WebRtc_Word64 nowMS);
|
|
||||||
void Reset();
|
|
||||||
|
|
||||||
// Returns true if there is a valid estimate of the incoming bitrate, false
|
|
||||||
// otherwise.
|
|
||||||
bool ValidEstimate() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
WebRtc_UWord32 ChangeBitRate(WebRtc_UWord32 currentBitRate,
|
|
||||||
WebRtc_UWord32 incomingBitRate,
|
|
||||||
double delayFactor,
|
|
||||||
WebRtc_Word64 nowMS);
|
|
||||||
double RateIncreaseFactor(WebRtc_Word64 nowMs,
|
|
||||||
WebRtc_Word64 lastMs,
|
|
||||||
WebRtc_UWord32 reactionTimeMs,
|
|
||||||
double noiseVar) const;
|
|
||||||
void UpdateChangePeriod(WebRtc_Word64 nowMs);
|
|
||||||
void UpdateMaxBitRateEstimate(float incomingBitRateKbps);
|
|
||||||
void ChangeState(const RateControlInput& input, WebRtc_Word64 nowMs);
|
|
||||||
void ChangeState(RateControlState newState);
|
|
||||||
void ChangeRegion(RateControlRegion region);
|
|
||||||
static void StateStr(RateControlState state, char* str);
|
|
||||||
static void StateStr(BandwidthUsage state, char* str);
|
|
||||||
|
|
||||||
WebRtc_UWord32 _minConfiguredBitRate;
|
|
||||||
WebRtc_UWord32 _maxConfiguredBitRate;
|
|
||||||
WebRtc_UWord32 _currentBitRate;
|
|
||||||
WebRtc_UWord32 _maxHoldRate;
|
|
||||||
float _avgMaxBitRate;
|
|
||||||
float _varMaxBitRate;
|
|
||||||
RateControlState _rcState;
|
|
||||||
RateControlState _cameFromState;
|
|
||||||
RateControlRegion _rcRegion;
|
|
||||||
WebRtc_Word64 _lastBitRateChange;
|
|
||||||
RateControlInput _currentInput;
|
|
||||||
bool _updated;
|
|
||||||
WebRtc_Word64 _timeFirstIncomingEstimate;
|
|
||||||
bool _initializedBitRate;
|
|
||||||
|
|
||||||
float _avgChangePeriod;
|
|
||||||
WebRtc_Word64 _lastChangeMs;
|
|
||||||
float _beta;
|
|
||||||
unsigned int _rtt;
|
|
||||||
#ifdef MATLAB
|
|
||||||
MatlabPlot *_plot1;
|
|
||||||
MatlabPlot *_plot2;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
} // namespace webrtc
|
|
||||||
|
|
||||||
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_REMOTE_RATE_CONTROL_H_
|
|
35
src/modules/rtp_rtcp/test/test_bwe/test_bwe.gypi
Normal file
35
src/modules/rtp_rtcp/test/test_bwe/test_bwe.gypi
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
{
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'test_bwe',
|
||||||
|
'type': 'executable',
|
||||||
|
'dependencies': [
|
||||||
|
'rtp_rtcp',
|
||||||
|
'<(webrtc_root)/../test/test.gyp:test_support_main',
|
||||||
|
'<(webrtc_root)/../testing/gtest.gyp:gtest',
|
||||||
|
'<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||||
|
],
|
||||||
|
'include_dirs': [
|
||||||
|
'../../source',
|
||||||
|
],
|
||||||
|
'sources': [
|
||||||
|
'unit_test.cc',
|
||||||
|
'../../source/bitrate.cc',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
# Local Variables:
|
||||||
|
# tab-width:2
|
||||||
|
# indent-tabs-mode:nil
|
||||||
|
# End:
|
||||||
|
# vim: set expandtab tabstop=2 shiftwidth=2:
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by a BSD-style license
|
* 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
|
* that can be found in the LICENSE file in the root of the source
|
||||||
@ -8,14 +8,15 @@
|
|||||||
* be found in the AUTHORS file in the root of the source tree.
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file includes unit tests for the bitrate estimator.
|
* This file includes unit tests for the bandwidth estimation and management
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include "typedefs.h"
|
#include "typedefs.h"
|
||||||
#include "bitrate_estimator.h"
|
#include "Bitrate.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
@ -106,7 +106,7 @@ NORMAL_TESTS = {
|
|||||||
'rtp_rtcp_unittests': (True, True, True),
|
'rtp_rtcp_unittests': (True, True, True),
|
||||||
'signal_processing_unittests': (True, True, True),
|
'signal_processing_unittests': (True, True, True),
|
||||||
'system_wrappers_unittests': (True, True, True),
|
'system_wrappers_unittests': (True, True, True),
|
||||||
'remote_bitrate_estimator_unittests': (True, True, True),
|
'test_bwe': (True, True, True),
|
||||||
'test_fec': (True, True, True),
|
'test_fec': (True, True, True),
|
||||||
'test_support_unittests': (True, True, True),
|
'test_support_unittests': (True, True, True),
|
||||||
'udp_transport_unittests': (True, True, True),
|
'udp_transport_unittests': (True, True, True),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user