Expose a set of options to the OveruseDetector supporting experiments

Updated overuse_detector.* to use google style naming convention
Removed OveruseDetector::Reset
Review URL: https://webrtc-codereview.appspot.com/666005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2443 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
astor@webrtc.org
2012-06-26 10:47:04 +00:00
parent f494fd0954
commit bd7aeba8fb
15 changed files with 304 additions and 271 deletions

View File

@ -571,5 +571,32 @@ struct VideoCodec
unsigned char numberOfSimulcastStreams; unsigned char numberOfSimulcastStreams;
SimulcastStream simulcastStream[kMaxSimulcastStreams]; SimulcastStream simulcastStream[kMaxSimulcastStreams];
}; };
// Bandwidth over-use detector options. These are used to drive
// experimentation with bandwidth estimation parameters.
// See modules/remote_bitrate_estimator/overuse_detector.h
struct OverUseDetectorOptions {
OverUseDetectorOptions()
: initial_slope(8.0/512.0),
initial_offset(0),
initial_e(),
initial_process_noise(),
initial_avg_noise(0.0),
initial_var_noise(500),
initial_threshold(25.0) {
initial_e[0][0] = 100;
initial_e[1][1] = 1e-1;
initial_e[0][1] = initial_e[1][0] = 0;
initial_process_noise[0] = 1e-10;
initial_process_noise[1] = 1e-2;
}
double initial_slope;
double initial_offset;
double initial_e[2][2];
double initial_process_noise[2];
double initial_avg_noise;
double initial_var_noise;
double initial_threshold;
};
} // namespace webrtc } // namespace webrtc
#endif // WEBRTC_COMMON_TYPES_H #endif // WEBRTC_COMMON_TYPES_H

View File

@ -39,7 +39,8 @@ class RemoteBitrateObserver {
class RemoteBitrateEstimator { class RemoteBitrateEstimator {
public: public:
explicit RemoteBitrateEstimator(RemoteBitrateObserver* observer); RemoteBitrateEstimator(RemoteBitrateObserver* observer,
const OverUseDetectorOptions& options);
// Called for each incoming packet. If this is a new SSRC, a new // Called for each incoming packet. If this is a new SSRC, a new
// BitrateControl will be created. // BitrateControl will be created.
@ -65,6 +66,16 @@ class RemoteBitrateEstimator {
private: private:
struct BitrateControls { struct BitrateControls {
explicit BitrateControls(const OverUseDetectorOptions& options)
: remote_rate(),
overuse_detector(options),
incoming_bitrate() {
}
BitrateControls(const BitrateControls& other)
: remote_rate(other.remote_rate),
overuse_detector(other.overuse_detector),
incoming_bitrate(other.incoming_bitrate) {
}
RemoteRateControl remote_rate; RemoteRateControl remote_rate;
OverUseDetector overuse_detector; OverUseDetector overuse_detector;
BitRateStats incoming_bitrate; BitRateStats incoming_bitrate;
@ -72,6 +83,7 @@ class RemoteBitrateEstimator {
typedef std::map<unsigned int, BitrateControls> SsrcBitrateControlsMap; typedef std::map<unsigned int, BitrateControls> SsrcBitrateControlsMap;
const OverUseDetectorOptions& options_;
SsrcBitrateControlsMap bitrate_controls_; SsrcBitrateControlsMap bitrate_controls_;
RemoteBitrateObserver* observer_; RemoteBitrateObserver* observer_;
scoped_ptr<CriticalSectionWrapper> crit_sect_; scoped_ptr<CriticalSectionWrapper> crit_sect_;

View File

@ -23,163 +23,128 @@
extern MatlabEngine eng; // global variable defined elsewhere extern MatlabEngine eng; // global variable defined elsewhere
#endif #endif
#define INIT_CAPACITY_SLOPE 8.0/512.0
#define DETECTOR_THRESHOLD 25.0
#define OVER_USING_TIME_THRESHOLD 100 #define OVER_USING_TIME_THRESHOLD 100
#define MIN_FRAME_PERIOD_HISTORY_LEN 60 #define MIN_FRAME_PERIOD_HISTORY_LEN 60
namespace webrtc { namespace webrtc {
OverUseDetector::OverUseDetector() OverUseDetector::OverUseDetector(const OverUseDetectorOptions& options)
: firstPacket_(true), : options_(options),
currentFrame_(), first_packet_(true),
prevFrame_(), current_frame_(),
numOfDeltas_(0), prev_frame_(),
slope_(INIT_CAPACITY_SLOPE), num_of_deltas_(0),
offset_(0), slope_(options_.initial_slope),
offset_(options_.initial_offset),
E_(), E_(),
processNoise_(), process_noise_(),
avgNoise_(0.0), avg_noise_(options_.initial_avg_noise),
varNoise_(500), var_noise_(options_.initial_var_noise),
threshold_(DETECTOR_THRESHOLD), threshold_(options_.initial_threshold),
tsDeltaHist_(), ts_delta_hist_(),
prevOffset_(0.0), prev_offset_(0.0),
timeOverUsing_(-1), time_over_using_(-1),
overUseCounter_(0), over_use_counter_(0),
#ifndef WEBRTC_BWE_MATLAB hypothesis_(kBwNormal),
hypothesis_(kBwNormal) { plots_() {
#else memcpy(E_, options_.initial_e, sizeof(E_));
plot1_(NULL), memcpy(process_noise_, options_.initial_process_noise,
plot2_(NULL), sizeof(process_noise_));
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() { OverUseDetector::~OverUseDetector() {
#ifdef WEBRTC_BWE_MATLAB #ifdef WEBRTC_BWE_MATLAB
if (plot1_) { if (plots_.plot1_) {
eng.DeletePlot(plot1_); eng.DeletePlot(plots_.plot1_);
plot1_ = NULL; plots_.plot1_ = NULL;
} }
if (plot2_) { if (plots_.plot2_) {
eng.DeletePlot(plot2_); eng.DeletePlot(plots_.plot2_);
plot2_ = NULL; plots_.plot2_ = NULL;
} }
if (plot3_) { if (plots_.plot3_) {
eng.DeletePlot(plot3_); eng.DeletePlot(plots_.plot3_);
plot3_ = NULL; plots_.plot3_ = NULL;
} }
if (plot4_) { if (plots_.plot4_) {
eng.DeletePlot(plot4_); eng.DeletePlot(plots_.plot4_);
plot4_ = NULL; plots_.plot4_ = NULL;
} }
#endif #endif
tsDeltaHist_.clear(); ts_delta_hist_.clear();
} }
void OverUseDetector::Reset() { void OverUseDetector::Update(uint16_t packet_size,
firstPacket_ = true; uint32_t timestamp,
currentFrame_.size_ = 0; const int64_t now_ms) {
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 #ifdef WEBRTC_BWE_MATLAB
// Create plots // Create plots
const WebRtc_Word64 startTimeMs = nowMS; const int64_t startTimeMs = nowMS;
if (plot1_ == NULL) { if (plots_.plot1_ == NULL) {
plot1_ = eng.NewPlot(new MatlabPlot()); plots_.plot1_ = eng.NewPlot(new MatlabPlot());
plot1_->AddLine(1000, "b.", "scatter"); plots_.plot1_->AddLine(1000, "b.", "scatter");
} }
if (plot2_ == NULL) { if (plots_.plot2_ == NULL) {
plot2_ = eng.NewPlot(new MatlabPlot()); plots_.plot2_ = eng.NewPlot(new MatlabPlot());
plot2_->AddTimeLine(30, "b", "offset", startTimeMs); plots_.plot2_->AddTimeLine(30, "b", "offset", startTimeMs);
plot2_->AddTimeLine(30, "r--", "limitPos", startTimeMs); plots_.plot2_->AddTimeLine(30, "r--", "limitPos", startTimeMs);
plot2_->AddTimeLine(30, "k.", "trigger", startTimeMs); plots_.plot2_->AddTimeLine(30, "k.", "trigger", startTimeMs);
plot2_->AddTimeLine(30, "ko", "detection", startTimeMs); plots_.plot2_->AddTimeLine(30, "ko", "detection", startTimeMs);
// plot2_->AddTimeLine(30, "g", "slowMean", startTimeMs); // plots_.plot2_->AddTimeLine(30, "g", "slowMean", startTimeMs);
} }
if (plot3_ == NULL) { if (plots_.plot3_ == NULL) {
plot3_ = eng.NewPlot(new MatlabPlot()); plots_.plot3_ = eng.NewPlot(new MatlabPlot());
plot3_->AddTimeLine(30, "b", "noiseVar", startTimeMs); plots_.plot3_->AddTimeLine(30, "b", "noiseVar", startTimeMs);
} }
if (plot4_ == NULL) { if (plots_.plot4_ == NULL) {
plot4_ = eng.NewPlot(new MatlabPlot()); plots_.plot4_ = eng.NewPlot(new MatlabPlot());
// plot4_->AddTimeLine(60, "b", "p11", startTimeMs); // plots_.plot4_->AddTimeLine(60, "b", "p11", startTimeMs);
// plot4_->AddTimeLine(60, "r", "p12", startTimeMs); // plots_.plot4_->AddTimeLine(60, "r", "p12", startTimeMs);
plot4_->AddTimeLine(60, "g", "p22", startTimeMs); plots_.plot4_->AddTimeLine(60, "g", "p22", startTimeMs);
// plot4_->AddTimeLine(60, "g--", "p22_hat", startTimeMs); // plots_.plot4_->AddTimeLine(60, "g--", "p22_hat", startTimeMs);
// plot4_->AddTimeLine(30, "b.-", "deltaFs", startTimeMs); // plots_.plot4_->AddTimeLine(30, "b.-", "deltaFs", startTimeMs);
} }
#endif #endif
bool wrapped = false; bool wrapped = false;
bool completeFrame = false; bool completeFrame = false;
if (currentFrame_.timestamp_ == -1) { if (current_frame_.timestamp_ == -1) {
currentFrame_.timestamp_ = timestamp; current_frame_.timestamp_ = timestamp;
} else if (OldTimestamp( } else if (OldTimestamp(
timestamp, timestamp,
static_cast<WebRtc_UWord32>(currentFrame_.timestamp_), static_cast<uint32_t>(current_frame_.timestamp_),
&wrapped)) { &wrapped)) {
// Don't update with old data // Don't update with old data
return; return;
} else if (timestamp != currentFrame_.timestamp_) { } else if (timestamp != current_frame_.timestamp_) {
// First packet of a later frame, the previous frame sample is ready // First packet of a later frame, the previous frame sample is ready
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
"Frame complete at %I64i", currentFrame_.completeTimeMs_); "Frame complete at %I64i", current_frame_.completeTimeMs_);
if (prevFrame_.completeTimeMs_ >= 0) { // This is our second frame if (prev_frame_.completeTimeMs_ >= 0) { // This is our second frame
WebRtc_Word64 tDelta = 0; int64_t t_delta = 0;
double tsDelta = 0; double ts_delta = 0;
// Check for wrap // Check for wrap
OldTimestamp( OldTimestamp(
static_cast<WebRtc_UWord32>(prevFrame_.timestamp_), static_cast<uint32_t>(prev_frame_.timestamp_),
static_cast<WebRtc_UWord32>(currentFrame_.timestamp_), static_cast<uint32_t>(current_frame_.timestamp_),
&wrapped); &wrapped);
CompensatedTimeDelta(currentFrame_, prevFrame_, tDelta, tsDelta, CompensatedTimeDelta(current_frame_, prev_frame_, t_delta, ts_delta,
wrapped); wrapped);
UpdateKalman(tDelta, tsDelta, currentFrame_.size_, UpdateKalman(t_delta, ts_delta, current_frame_.size_,
prevFrame_.size_); prev_frame_.size_);
} }
// The new timestamp is now the current frame, // The new timestamp is now the current frame,
// and the old timestamp becomes the previous frame. // and the old timestamp becomes the previous frame.
prevFrame_ = currentFrame_; prev_frame_ = current_frame_;
currentFrame_.timestamp_ = timestamp; current_frame_.timestamp_ = timestamp;
currentFrame_.size_ = 0; current_frame_.size_ = 0;
currentFrame_.completeTimeMs_ = -1; current_frame_.completeTimeMs_ = -1;
completeFrame = true; completeFrame = true;
} }
// Accumulate the frame size // Accumulate the frame size
currentFrame_.size_ += packetSize; current_frame_.size_ += packet_size;
currentFrame_.completeTimeMs_ = nowMS; current_frame_.completeTimeMs_ = now_ms;
} }
BandwidthUsage OverUseDetector::State() const { BandwidthUsage OverUseDetector::State() const {
@ -187,18 +152,18 @@ BandwidthUsage OverUseDetector::State() const {
} }
double OverUseDetector::NoiseVar() const { double OverUseDetector::NoiseVar() const {
return varNoise_; return var_noise_;
} }
void OverUseDetector::SetRateControlRegion(RateControlRegion region) { void OverUseDetector::SetRateControlRegion(RateControlRegion region) {
switch (region) { switch (region) {
case kRcMaxUnknown: { case kRcMaxUnknown: {
threshold_ = DETECTOR_THRESHOLD; threshold_ = options_.initial_threshold;
break; break;
} }
case kRcAboveMax: case kRcAboveMax:
case kRcNearMax: { case kRcNearMax: {
threshold_ = DETECTOR_THRESHOLD / 2; threshold_ = options_.initial_threshold / 2;
break; break;
} }
} }
@ -206,47 +171,47 @@ void OverUseDetector::SetRateControlRegion(RateControlRegion region) {
void OverUseDetector::CompensatedTimeDelta(const FrameSample& currentFrame, void OverUseDetector::CompensatedTimeDelta(const FrameSample& currentFrame,
const FrameSample& prevFrame, const FrameSample& prevFrame,
WebRtc_Word64& tDelta, int64_t& t_delta,
double& tsDelta, double& ts_delta,
bool wrapped) { bool wrapped) {
numOfDeltas_++; num_of_deltas_++;
if (numOfDeltas_ > 1000) { if (num_of_deltas_ > 1000) {
numOfDeltas_ = 1000; num_of_deltas_ = 1000;
} }
// Add wrap-around compensation // Add wrap-around compensation
WebRtc_Word64 wrapCompensation = 0; int64_t wrapCompensation = 0;
if (wrapped) { if (wrapped) {
wrapCompensation = static_cast<WebRtc_Word64>(1)<<32; wrapCompensation = static_cast<int64_t>(1)<<32;
} }
tsDelta = (currentFrame.timestamp_ ts_delta = (currentFrame.timestamp_
+ wrapCompensation + wrapCompensation
- prevFrame.timestamp_) / 90.0; - prevFrame.timestamp_) / 90.0;
tDelta = currentFrame.completeTimeMs_ - prevFrame.completeTimeMs_; t_delta = currentFrame.completeTimeMs_ - prevFrame.completeTimeMs_;
assert(tsDelta > 0); assert(ts_delta > 0);
} }
double OverUseDetector::CurrentDrift() { double OverUseDetector::CurrentDrift() {
return 1.0; return 1.0;
} }
void OverUseDetector::UpdateKalman(WebRtc_Word64 tDelta, void OverUseDetector::UpdateKalman(int64_t t_delta,
double tsDelta, double ts_delta,
WebRtc_UWord32 frameSize, uint32_t frame_size,
WebRtc_UWord32 prevFrameSize) { uint32_t prev_frame_size) {
const double minFramePeriod = UpdateMinFramePeriod(tsDelta); const double minFramePeriod = UpdateMinFramePeriod(ts_delta);
const double drift = CurrentDrift(); const double drift = CurrentDrift();
// Compensate for drift // Compensate for drift
const double tTsDelta = tDelta - tsDelta / drift; const double tTsDelta = t_delta - ts_delta / drift;
double fsDelta = static_cast<double>(frameSize) - prevFrameSize; double fsDelta = static_cast<double>(frame_size) - prev_frame_size;
// Update the Kalman filter // Update the Kalman filter
const double scaleFactor = minFramePeriod / (1000.0 / 30.0); const double scaleFactor = minFramePeriod / (1000.0 / 30.0);
E_[0][0] += processNoise_[0] * scaleFactor; E_[0][0] += process_noise_[0] * scaleFactor;
E_[1][1] += processNoise_[1] * scaleFactor; E_[1][1] += process_noise_[1] * scaleFactor;
if ((hypothesis_ == kBwOverusing && offset_ < prevOffset_) || if ((hypothesis_ == kBwOverusing && offset_ < prev_offset_) ||
(hypothesis_ == kBwUnderUsing && offset_ > prevOffset_)) { (hypothesis_ == kBwUnderUsing && offset_ > prev_offset_)) {
E_[1][1] += 10 * processNoise_[1] * scaleFactor; E_[1][1] += 10 * process_noise_[1] * scaleFactor;
} }
const double h[2] = {fsDelta, 1.0}; const double h[2] = {fsDelta, 1.0};
@ -255,17 +220,17 @@ void OverUseDetector::UpdateKalman(WebRtc_Word64 tDelta,
const double residual = tTsDelta - slope_*h[0] - offset_; const double residual = tTsDelta - slope_*h[0] - offset_;
const bool stableState = const bool stable_state =
(BWE_MIN(numOfDeltas_, 60) * fabsf(offset_) < threshold_); (BWE_MIN(num_of_deltas_, 60) * fabsf(offset_) < threshold_);
// We try to filter out very late frames. For instance periodic key // We try to filter out very late frames. For instance periodic key
// frames doesn't fit the Gaussian model well. // frames doesn't fit the Gaussian model well.
if (fabsf(residual) < 3 * sqrt(varNoise_)) { if (fabsf(residual) < 3 * sqrt(var_noise_)) {
UpdateNoiseEstimate(residual, minFramePeriod, stableState); UpdateNoiseEstimate(residual, minFramePeriod, stable_state);
} else { } else {
UpdateNoiseEstimate(3 * sqrt(varNoise_), minFramePeriod, stableState); UpdateNoiseEstimate(3 * sqrt(var_noise_), minFramePeriod, stable_state);
} }
const double denom = varNoise_ + h[0]*Eh[0] + h[1]*Eh[1]; const double denom = var_noise_ + h[0]*Eh[0] + h[1]*Eh[1];
const double K[2] = {Eh[0] / denom, const double K[2] = {Eh[0] / denom,
Eh[1] / denom}; Eh[1] / denom};
@ -287,114 +252,114 @@ void OverUseDetector::UpdateKalman(WebRtc_Word64 tDelta,
E_[0][0] >= 0); E_[0][0] >= 0);
#ifdef WEBRTC_BWE_MATLAB #ifdef WEBRTC_BWE_MATLAB
// plot4_->Append("p11",E_[0][0]); // plots_.plot4_->Append("p11",E_[0][0]);
// plot4_->Append("p12",E_[0][1]); // plots_.plot4_->Append("p12",E_[0][1]);
plot4_->Append("p22", E_[1][1]); plots_.plot4_->Append("p22", E_[1][1]);
// plot4_->Append("p22_hat", 0.5*(processNoise_[1] + // plots_.plot4_->Append("p22_hat", 0.5*(process_noise_[1] +
// sqrt(processNoise_[1]*(processNoise_[1] + 4*varNoise_)))); // sqrt(process_noise_[1]*(process_noise_[1] + 4*var_noise_))));
// plot4_->Append("deltaFs", fsDelta); // plots_.plot4_->Append("deltaFs", fsDelta);
plot4_->Plot(); plots_.plot4_->Plot();
#endif #endif
slope_ = slope_ + K[0] * residual; slope_ = slope_ + K[0] * residual;
prevOffset_ = offset_; prev_offset_ = offset_;
offset_ = offset_ + K[1] * residual; offset_ = offset_ + K[1] * residual;
Detect(tsDelta); Detect(ts_delta);
#ifdef WEBRTC_BWE_MATLAB #ifdef WEBRTC_BWE_MATLAB
plot1_->Append("scatter", plots_.plot1_->Append("scatter",
static_cast<double>(currentFrame_.size_) - prevFrame_.size_, static_cast<double>(current_frame_.size_) - prev_frame_.size_,
static_cast<double>(tDelta-tsDelta)); static_cast<double>(t_delta - ts_delta));
plot1_->MakeTrend("scatter", "slope", slope_, offset_, "k-"); plots_.plot1_->MakeTrend("scatter", "slope", slope_, offset_, "k-");
plot1_->MakeTrend("scatter", "thresholdPos", plots_.plot1_->MakeTrend("scatter", "thresholdPos",
slope_, offset_ + 2 * sqrt(varNoise_), "r-"); slope_, offset_ + 2 * sqrt(var_noise_), "r-");
plot1_->MakeTrend("scatter", "thresholdNeg", plots_.plot1_->MakeTrend("scatter", "thresholdNeg",
slope_, offset_ - 2 * sqrt(varNoise_), "r-"); slope_, offset_ - 2 * sqrt(var_noise_), "r-");
plot1_->Plot(); plots_.plot1_->Plot();
plot2_->Append("offset", offset_); plots_.plot2_->Append("offset", offset_);
plot2_->Append("limitPos", threshold_/BWE_MIN(numOfDeltas_, 60)); plots_.plot2_->Append("limitPos", threshold_/BWE_MIN(num_of_deltas_, 60));
plot2_->Plot(); plots_.plot2_->Plot();
plot3_->Append("noiseVar", varNoise_); plots_.plot3_->Append("noiseVar", var_noise_);
plot3_->Plot(); plots_.plot3_->Plot();
#endif #endif
} }
double OverUseDetector::UpdateMinFramePeriod(double tsDelta) { double OverUseDetector::UpdateMinFramePeriod(double ts_delta) {
double minFramePeriod = tsDelta; double minFramePeriod = ts_delta;
if (tsDeltaHist_.size() >= MIN_FRAME_PERIOD_HISTORY_LEN) { if (ts_delta_hist_.size() >= MIN_FRAME_PERIOD_HISTORY_LEN) {
std::list<double>::iterator firstItem = tsDeltaHist_.begin(); std::list<double>::iterator firstItem = ts_delta_hist_.begin();
tsDeltaHist_.erase(firstItem); ts_delta_hist_.erase(firstItem);
} }
std::list<double>::iterator it = tsDeltaHist_.begin(); std::list<double>::iterator it = ts_delta_hist_.begin();
for (; it != tsDeltaHist_.end(); it++) { for (; it != ts_delta_hist_.end(); it++) {
minFramePeriod = BWE_MIN(*it, minFramePeriod); minFramePeriod = BWE_MIN(*it, minFramePeriod);
} }
tsDeltaHist_.push_back(tsDelta); ts_delta_hist_.push_back(ts_delta);
return minFramePeriod; return minFramePeriod;
} }
void OverUseDetector::UpdateNoiseEstimate(double residual, void OverUseDetector::UpdateNoiseEstimate(double residual,
double tsDelta, double ts_delta,
bool stableState) { bool stable_state) {
if (!stableState) { if (!stable_state) {
return; return;
} }
// Faster filter during startup to faster adapt to the jitter level // Faster filter during startup to faster adapt to the jitter level
// of the network alpha is tuned for 30 frames per second, but // of the network alpha is tuned for 30 frames per second, but
double alpha = 0.01; double alpha = 0.01;
if (numOfDeltas_ > 10*30) { if (num_of_deltas_ > 10*30) {
alpha = 0.002; alpha = 0.002;
} }
// Only update the noise estimate if we're not over-using // Only update the noise estimate if we're not over-using
// beta is a function of alpha and the time delta since // beta is a function of alpha and the time delta since
// the previous update. // the previous update.
const double beta = pow(1 - alpha, tsDelta * 30.0 / 1000.0); const double beta = pow(1 - alpha, ts_delta * 30.0 / 1000.0);
avgNoise_ = beta * avgNoise_ avg_noise_ = beta * avg_noise_
+ (1 - beta) * residual; + (1 - beta) * residual;
varNoise_ = beta * varNoise_ var_noise_ = beta * var_noise_
+ (1 - beta) * (avgNoise_ - residual) * (avgNoise_ - residual); + (1 - beta) * (avg_noise_ - residual) * (avg_noise_ - residual);
if (varNoise_ < 1e-7) { if (var_noise_ < 1e-7) {
varNoise_ = 1e-7; var_noise_ = 1e-7;
} }
} }
BandwidthUsage OverUseDetector::Detect(double tsDelta) { BandwidthUsage OverUseDetector::Detect(double ts_delta) {
if (numOfDeltas_ < 2) { if (num_of_deltas_ < 2) {
return kBwNormal; return kBwNormal;
} }
const double T = BWE_MIN(numOfDeltas_, 60) * offset_; const double T = BWE_MIN(num_of_deltas_, 60) * offset_;
if (fabsf(T) > threshold_) { if (fabsf(T) > threshold_) {
if (offset_ > 0) { if (offset_ > 0) {
if (timeOverUsing_ == -1) { if (time_over_using_ == -1) {
// Initialize the timer. Assume that we've been // Initialize the timer. Assume that we've been
// over-using half of the time since the previous // over-using half of the time since the previous
// sample. // sample.
timeOverUsing_ = tsDelta / 2; time_over_using_ = ts_delta / 2;
} else { } else {
// Increment timer // Increment timer
timeOverUsing_ += tsDelta; time_over_using_ += ts_delta;
} }
overUseCounter_++; over_use_counter_++;
if (timeOverUsing_ > OVER_USING_TIME_THRESHOLD if (time_over_using_ > OVER_USING_TIME_THRESHOLD
&& overUseCounter_ > 1) { && over_use_counter_ > 1) {
if (offset_ >= prevOffset_) { if (offset_ >= prev_offset_) {
#ifdef _DEBUG #ifdef _DEBUG
if (hypothesis_ != kBwOverusing) { if (hypothesis_ != kBwOverusing) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwOverusing"); WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwOverusing");
} }
#endif #endif
timeOverUsing_ = 0; time_over_using_ = 0;
overUseCounter_ = 0; over_use_counter_ = 0;
hypothesis_ = kBwOverusing; hypothesis_ = kBwOverusing;
#ifdef WEBRTC_BWE_MATLAB #ifdef WEBRTC_BWE_MATLAB
plot2_->Append("detection", offset_); // plot it later plots_.plot2_->Append("detection", offset_); // plot it later
#endif #endif
} }
} }
#ifdef WEBRTC_BWE_MATLAB #ifdef WEBRTC_BWE_MATLAB
plot2_->Append("trigger", offset_); // plot it later plots_.plot2_->Append("trigger", offset_); // plot it later
#endif #endif
} else { } else {
#ifdef _DEBUG #ifdef _DEBUG
@ -402,8 +367,8 @@ BandwidthUsage OverUseDetector::Detect(double tsDelta) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwUnderUsing"); WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwUnderUsing");
} }
#endif #endif
timeOverUsing_ = -1; time_over_using_ = -1;
overUseCounter_ = 0; over_use_counter_ = 0;
hypothesis_ = kBwUnderUsing; hypothesis_ = kBwUnderUsing;
} }
} else { } else {
@ -412,25 +377,25 @@ BandwidthUsage OverUseDetector::Detect(double tsDelta) {
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwNormal"); WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwNormal");
} }
#endif #endif
timeOverUsing_ = -1; time_over_using_ = -1;
overUseCounter_ = 0; over_use_counter_ = 0;
hypothesis_ = kBwNormal; hypothesis_ = kBwNormal;
} }
return hypothesis_; return hypothesis_;
} }
bool OverUseDetector::OldTimestamp(uint32_t newTimestamp, bool OverUseDetector::OldTimestamp(uint32_t new_timestamp,
uint32_t existingTimestamp, uint32_t existing_timestamp,
bool* wrapped) { bool* wrapped) {
bool tmpWrapped = bool tmpWrapped =
(newTimestamp < 0x0000ffff && existingTimestamp > 0xffff0000) || (new_timestamp < 0x0000ffff && existing_timestamp > 0xffff0000) ||
(newTimestamp > 0xffff0000 && existingTimestamp < 0x0000ffff); (new_timestamp > 0xffff0000 && existing_timestamp < 0x0000ffff);
*wrapped = tmpWrapped; *wrapped = tmpWrapped;
if (existingTimestamp > newTimestamp && !tmpWrapped) { if (existing_timestamp > new_timestamp && !tmpWrapped) {
return true; return true;
} else if (existingTimestamp <= newTimestamp && !tmpWrapped) { } else if (existing_timestamp <= new_timestamp && !tmpWrapped) {
return false; return false;
} else if (existingTimestamp < newTimestamp && tmpWrapped) { } else if (existing_timestamp < new_timestamp && tmpWrapped) {
return true; return true;
} else { } else {
return false; return false;

View File

@ -25,13 +25,12 @@ enum RateControlRegion;
class OverUseDetector { class OverUseDetector {
public: public:
OverUseDetector(); explicit OverUseDetector(const OverUseDetectorOptions& options);
~OverUseDetector(); ~OverUseDetector();
void Update(const WebRtc_UWord16 packetSize, void Update(const WebRtc_UWord16 packet_size,
const WebRtc_UWord32 timestamp, const uint32_t timestamp,
const WebRtc_Word64 nowMS); const int64_t now_ms);
BandwidthUsage State() const; BandwidthUsage State() const;
void Reset();
double NoiseVar() const; double NoiseVar() const;
void SetRateControlRegion(RateControlRegion region); void SetRateControlRegion(RateControlRegion region);
@ -39,52 +38,59 @@ class OverUseDetector {
struct FrameSample { struct FrameSample {
FrameSample() : size_(0), completeTimeMs_(-1), timestamp_(-1) {} FrameSample() : size_(0), completeTimeMs_(-1), timestamp_(-1) {}
WebRtc_UWord32 size_; uint32_t size_;
WebRtc_Word64 completeTimeMs_; int64_t completeTimeMs_;
WebRtc_Word64 timestamp_; int64_t timestamp_;
}; };
static bool OldTimestamp(uint32_t newTimestamp, struct DebugPlots {
uint32_t existingTimestamp, #ifdef WEBRTC_BWE_MATLAB
DebugPlots() : plot1(NULL), plot2(NULL), plot3(NULL), plot4(NULL) {}
MatlabPlot* plot1;
MatlabPlot* plot2;
MatlabPlot* plot3;
MatlabPlot* plot4;
#endif
};
static bool OldTimestamp(uint32_t new_timestamp,
uint32_t existing_timestamp,
bool* wrapped); bool* wrapped);
void CompensatedTimeDelta(const FrameSample& currentFrame, void CompensatedTimeDelta(const FrameSample& current_frame,
const FrameSample& prevFrame, const FrameSample& prev_frame,
WebRtc_Word64& tDelta, int64_t& t_delta,
double& tsDelta, double& ts_delta,
bool wrapped); bool wrapped);
void UpdateKalman(WebRtc_Word64 tDelta, void UpdateKalman(int64_t t_delta,
double tsDelta, double ts_elta,
WebRtc_UWord32 frameSize, uint32_t frame_size,
WebRtc_UWord32 prevFrameSize); uint32_t prev_frame_size);
double UpdateMinFramePeriod(double tsDelta); double UpdateMinFramePeriod(double ts_delta);
void UpdateNoiseEstimate(double residual, double tsDelta, bool stableState); void UpdateNoiseEstimate(double residual, double ts_delta, bool stable_state);
BandwidthUsage Detect(double tsDelta); BandwidthUsage Detect(double ts_delta);
double CurrentDrift(); double CurrentDrift();
bool firstPacket_; OverUseDetectorOptions options_; // Must be first member
FrameSample currentFrame_; // variable. Cannot be const
FrameSample prevFrame_; // because we need to be copyable.
WebRtc_UWord16 numOfDeltas_; bool first_packet_;
FrameSample current_frame_;
FrameSample prev_frame_;
uint16_t num_of_deltas_;
double slope_; double slope_;
double offset_; double offset_;
double E_[2][2]; double E_[2][2];
double processNoise_[2]; double process_noise_[2];
double avgNoise_; double avg_noise_;
double varNoise_; double var_noise_;
double threshold_; double threshold_;
std::list<double> tsDeltaHist_; std::list<double> ts_delta_hist_;
double prevOffset_; double prev_offset_;
double timeOverUsing_; double time_over_using_;
WebRtc_UWord16 overUseCounter_; uint16_t over_use_counter_;
BandwidthUsage hypothesis_; BandwidthUsage hypothesis_;
DebugPlots plots_;
#ifdef WEBRTC_BWE_MATLAB
MatlabPlot* plot1_;
MatlabPlot* plot2_;
MatlabPlot* plot3_;
MatlabPlot* plot4_;
#endif
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -15,8 +15,10 @@
namespace webrtc { namespace webrtc {
RemoteBitrateEstimator::RemoteBitrateEstimator( RemoteBitrateEstimator::RemoteBitrateEstimator(
RemoteBitrateObserver* observer) RemoteBitrateObserver* observer,
: observer_(observer), const OverUseDetectorOptions& options)
: options_(options),
observer_(observer),
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()) { crit_sect_(CriticalSectionWrapper::CreateCriticalSection()) {
assert(observer_); assert(observer_);
} }
@ -35,12 +37,11 @@ void RemoteBitrateEstimator::IncomingPacket(unsigned int ssrc,
// callback will no longer be called for the old SSRC. This will be // callback will no longer be called for the old SSRC. This will be
// automatically cleaned up when we have one RemoteBitrateEstimator per REMB // automatically cleaned up when we have one RemoteBitrateEstimator per REMB
// group. // group.
bitrate_controls_[ssrc] = BitrateControls(); bitrate_controls_.insert(std::make_pair(ssrc, BitrateControls(options_)));
it = bitrate_controls_.find(ssrc); it = bitrate_controls_.find(ssrc);
} }
OverUseDetector* overuse_detector = OverUseDetector* overuse_detector = &it->second.overuse_detector;
&bitrate_controls_[ssrc].overuse_detector; it->second.incoming_bitrate.Update(packet_size, arrival_time);
bitrate_controls_[ssrc].incoming_bitrate.Update(packet_size, arrival_time);
const BandwidthUsage prior_state = overuse_detector->State(); const BandwidthUsage prior_state = overuse_detector->State();
overuse_detector->Update(packet_size, rtp_timestamp, arrival_time); overuse_detector->Update(packet_size, rtp_timestamp, arrival_time);
if (prior_state != overuse_detector->State() && if (prior_state != overuse_detector->State() &&

View File

@ -123,7 +123,7 @@ class RemoteBitrateEstimatorTest : public ::testing::Test {
virtual void SetUp() { virtual void SetUp() {
bitrate_observer_.reset(new TestBitrateObserver); bitrate_observer_.reset(new TestBitrateObserver);
bitrate_estimator_.reset(new RemoteBitrateEstimator( bitrate_estimator_.reset(new RemoteBitrateEstimator(
bitrate_observer_.get())); bitrate_observer_.get(), over_use_detector_options_));
// Framerate: 30 fps; Start bitrate: 300 kbps; Link capacity: 1000 kbps, // Framerate: 30 fps; Start bitrate: 300 kbps; Link capacity: 1000 kbps,
// Start time: 0. // Start time: 0.
stream_generator_.reset(new StreamGenerator(30, 3e5, 1e6, 0)); stream_generator_.reset(new StreamGenerator(30, 3e5, 1e6, 0));
@ -196,6 +196,7 @@ class RemoteBitrateEstimatorTest : public ::testing::Test {
return bitrate_bps; return bitrate_bps;
} }
OverUseDetectorOptions over_use_detector_options_;
scoped_ptr<RemoteBitrateEstimator> bitrate_estimator_; scoped_ptr<RemoteBitrateEstimator> bitrate_estimator_;
scoped_ptr<TestBitrateObserver> bitrate_observer_; scoped_ptr<TestBitrateObserver> bitrate_observer_;
scoped_ptr<StreamGenerator> stream_generator_; scoped_ptr<StreamGenerator> stream_generator_;

View File

@ -59,11 +59,14 @@ class TestTransport : public Transport {
class RtcpFormatRembTest : public ::testing::Test { class RtcpFormatRembTest : public ::testing::Test {
protected: protected:
RtcpFormatRembTest() RtcpFormatRembTest()
: remote_bitrate_observer_(), : over_use_detector_options_(),
remote_bitrate_estimator_(&remote_bitrate_observer_) {} remote_bitrate_observer_(),
remote_bitrate_estimator_(&remote_bitrate_observer_,
over_use_detector_options_) {}
virtual void SetUp(); virtual void SetUp();
virtual void TearDown(); virtual void TearDown();
OverUseDetectorOptions over_use_detector_options_;
RtpRtcpClock* system_clock_; RtpRtcpClock* system_clock_;
ModuleRtpRtcpImpl* dummy_rtp_rtcp_impl_; ModuleRtpRtcpImpl* dummy_rtp_rtcp_impl_;
RTCPSender* rtcp_sender_; RTCPSender* rtcp_sender_;

View File

@ -183,8 +183,10 @@ class TestTransport : public Transport,
class RtcpReceiverTest : public ::testing::Test { class RtcpReceiverTest : public ::testing::Test {
protected: protected:
RtcpReceiverTest() RtcpReceiverTest()
: remote_bitrate_observer_(), : over_use_detector_options_(),
remote_bitrate_estimator_(&remote_bitrate_observer_) { remote_bitrate_observer_(),
remote_bitrate_estimator_(&remote_bitrate_observer_,
over_use_detector_options_) {
// system_clock_ = ModuleRTPUtility::GetSystemClock(); // system_clock_ = ModuleRTPUtility::GetSystemClock();
system_clock_ = new FakeSystemClock(); system_clock_ = new FakeSystemClock();
test_transport_ = new TestTransport(); test_transport_ = new TestTransport();
@ -221,6 +223,7 @@ class RtcpReceiverTest : public ::testing::Test {
return result; return result;
} }
OverUseDetectorOptions over_use_detector_options_;
FakeSystemClock* system_clock_; FakeSystemClock* system_clock_;
ModuleRtpRtcpImpl* rtp_rtcp_impl_; ModuleRtpRtcpImpl* rtp_rtcp_impl_;
RTCPReceiver* rtcp_receiver_; RTCPReceiver* rtcp_receiver_;

View File

@ -98,8 +98,10 @@ class TestTransport : public Transport,
class RtcpSenderTest : public ::testing::Test { class RtcpSenderTest : public ::testing::Test {
protected: protected:
RtcpSenderTest() RtcpSenderTest()
: remote_bitrate_observer_(), : over_use_detector_options_(),
remote_bitrate_estimator_(&remote_bitrate_observer_) { remote_bitrate_observer_(),
remote_bitrate_estimator_(&remote_bitrate_observer_,
over_use_detector_options_) {
system_clock_ = ModuleRTPUtility::GetSystemClock(); system_clock_ = ModuleRTPUtility::GetSystemClock();
test_transport_ = new TestTransport(); test_transport_ = new TestTransport();
@ -133,6 +135,7 @@ class RtcpSenderTest : public ::testing::Test {
packet_type) != 0U; packet_type) != 0U;
} }
OverUseDetectorOptions over_use_detector_options_;
RtpRtcpClock* system_clock_; RtpRtcpClock* system_clock_;
ModuleRtpRtcpImpl* rtp_rtcp_impl_; ModuleRtpRtcpImpl* rtp_rtcp_impl_;
RTCPSender* rtcp_sender_; RTCPSender* rtcp_sender_;

View File

@ -19,10 +19,12 @@
namespace webrtc { namespace webrtc {
ChannelGroup::ChannelGroup(ProcessThread* process_thread) ChannelGroup::ChannelGroup(ProcessThread* process_thread,
const OverUseDetectorOptions& options)
: remb_(new VieRemb(process_thread)), : remb_(new VieRemb(process_thread)),
bitrate_controller_(BitrateController::CreateBitrateController()), bitrate_controller_(BitrateController::CreateBitrateController()),
remote_bitrate_estimator_(new RemoteBitrateEstimator(remb_.get())) { remote_bitrate_estimator_(new RemoteBitrateEstimator(remb_.get(),
options)) {
} }
ChannelGroup::~ChannelGroup() { ChannelGroup::~ChannelGroup() {

View File

@ -18,6 +18,7 @@
namespace webrtc { namespace webrtc {
class BitrateController; class BitrateController;
struct OverUseDetectorOptions;
class ProcessThread; class ProcessThread;
class RemoteBitrateEstimator; class RemoteBitrateEstimator;
class RemoteBitrateObserver; class RemoteBitrateObserver;
@ -29,7 +30,8 @@ class VieRemb;
// group are assumed to send/receive data to the same end-point. // group are assumed to send/receive data to the same end-point.
class ChannelGroup { class ChannelGroup {
public: public:
explicit ChannelGroup(ProcessThread* process_thread); ChannelGroup(ProcessThread* process_thread,
const OverUseDetectorOptions& options);
~ChannelGroup(); ~ChannelGroup();
void AddChannel(int channel_id); void AddChannel(int channel_id);

View File

@ -27,7 +27,8 @@ namespace webrtc {
ViEChannelManager::ViEChannelManager( ViEChannelManager::ViEChannelManager(
int engine_id, int engine_id,
int number_of_cores, int number_of_cores,
ViEPerformanceMonitor& vie_performance_monitor) ViEPerformanceMonitor& vie_performance_monitor,
const OverUseDetectorOptions& options)
: channel_id_critsect_(CriticalSectionWrapper::CreateCriticalSection()), : channel_id_critsect_(CriticalSectionWrapper::CreateCriticalSection()),
engine_id_(engine_id), engine_id_(engine_id),
number_of_cores_(number_of_cores), number_of_cores_(number_of_cores),
@ -35,7 +36,8 @@ ViEChannelManager::ViEChannelManager(
free_channel_ids_size_(kViEMaxNumberOfChannels), free_channel_ids_size_(kViEMaxNumberOfChannels),
voice_sync_interface_(NULL), voice_sync_interface_(NULL),
voice_engine_(NULL), voice_engine_(NULL),
module_process_thread_(NULL) { module_process_thread_(NULL),
over_use_detector_options_(options) {
WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id), WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id),
"ViEChannelManager::ViEChannelManager(engine_id: %d)", "ViEChannelManager::ViEChannelManager(engine_id: %d)",
engine_id); engine_id);
@ -87,7 +89,8 @@ int ViEChannelManager::CreateChannel(int& channel_id) {
} }
// Create a new channel group and add this channel. // Create a new channel group and add this channel.
ChannelGroup* group = new ChannelGroup(module_process_thread_); ChannelGroup* group = new ChannelGroup(module_process_thread_,
over_use_detector_options_);
BitrateController* bitrate_controller = group->GetBitrateController(); BitrateController* bitrate_controller = group->GetBitrateController();
ViEEncoder* vie_encoder = new ViEEncoder(engine_id_, new_channel_id, ViEEncoder* vie_encoder = new ViEEncoder(engine_id_, new_channel_id,
number_of_cores_, number_of_cores_,

View File

@ -43,7 +43,8 @@ class ViEChannelManager: private ViEManagerBase {
public: public:
ViEChannelManager(int engine_id, ViEChannelManager(int engine_id,
int number_of_cores, int number_of_cores,
ViEPerformanceMonitor& vie_performance_monitor); ViEPerformanceMonitor& vie_performance_monitor,
const OverUseDetectorOptions& options);
~ViEChannelManager(); ~ViEChannelManager();
void SetModuleProcessThread(ProcessThread& module_process_thread); void SetModuleProcessThread(ProcessThread& module_process_thread);
@ -125,6 +126,7 @@ class ViEChannelManager: private ViEManagerBase {
VoiceEngine* voice_engine_; VoiceEngine* voice_engine_;
ProcessThread* module_process_thread_; ProcessThread* module_process_thread_;
const OverUseDetectorOptions& over_use_detector_options_;
}; };
class ViEChannelManagerScoped: private ViEManagerScopedBase { class ViEChannelManagerScoped: private ViEManagerScopedBase {

View File

@ -26,9 +26,11 @@ ViESharedData::ViESharedData()
: instance_id_(++instance_counter_), : instance_id_(++instance_counter_),
initialized_(false), initialized_(false),
number_cores_(CpuInfo::DetectNumberOfCores()), number_cores_(CpuInfo::DetectNumberOfCores()),
over_use_detector_options_(),
vie_performance_monitor_(ViEPerformanceMonitor(instance_id_)), vie_performance_monitor_(ViEPerformanceMonitor(instance_id_)),
channel_manager_(*new ViEChannelManager(instance_id_, number_cores_, channel_manager_(*new ViEChannelManager(instance_id_, number_cores_,
vie_performance_monitor_)), vie_performance_monitor_,
over_use_detector_options_)),
input_manager_(*new ViEInputManager(instance_id_)), input_manager_(*new ViEInputManager(instance_id_)),
render_manager_(*new ViERenderManager(instance_id_)), render_manager_(*new ViERenderManager(instance_id_)),
module_process_thread_(ProcessThread::CreateProcessThread()), module_process_thread_(ProcessThread::CreateProcessThread()),

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * Copyright (c) 2012 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
@ -50,6 +50,7 @@ class ViESharedData {
bool initialized_; bool initialized_;
const int number_cores_; const int number_cores_;
OverUseDetectorOptions over_use_detector_options_;
ViEPerformanceMonitor vie_performance_monitor_; ViEPerformanceMonitor vie_performance_monitor_;
ViEChannelManager& channel_manager_; ViEChannelManager& channel_manager_;
ViEInputManager& input_manager_; ViEInputManager& input_manager_;