diff --git a/src/common_types.h b/src/common_types.h index 54821a287a..681a1d29fb 100644 --- a/src/common_types.h +++ b/src/common_types.h @@ -571,5 +571,32 @@ struct VideoCodec unsigned char numberOfSimulcastStreams; 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 #endif // WEBRTC_COMMON_TYPES_H diff --git a/src/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h b/src/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h index 990b383b3a..d5678e439c 100644 --- a/src/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h +++ b/src/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h @@ -39,7 +39,8 @@ class RemoteBitrateObserver { class RemoteBitrateEstimator { public: - explicit RemoteBitrateEstimator(RemoteBitrateObserver* observer); + RemoteBitrateEstimator(RemoteBitrateObserver* observer, + const OverUseDetectorOptions& options); // Called for each incoming packet. If this is a new SSRC, a new // BitrateControl will be created. @@ -65,6 +66,16 @@ class RemoteBitrateEstimator { private: 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; OverUseDetector overuse_detector; BitRateStats incoming_bitrate; @@ -72,6 +83,7 @@ class RemoteBitrateEstimator { typedef std::map SsrcBitrateControlsMap; + const OverUseDetectorOptions& options_; SsrcBitrateControlsMap bitrate_controls_; RemoteBitrateObserver* observer_; scoped_ptr crit_sect_; diff --git a/src/modules/remote_bitrate_estimator/overuse_detector.cc b/src/modules/remote_bitrate_estimator/overuse_detector.cc index 2cd03ec768..2668111f2d 100644 --- a/src/modules/remote_bitrate_estimator/overuse_detector.cc +++ b/src/modules/remote_bitrate_estimator/overuse_detector.cc @@ -23,163 +23,128 @@ 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), +OverUseDetector::OverUseDetector(const OverUseDetectorOptions& options) + : options_(options), + first_packet_(true), + current_frame_(), + prev_frame_(), + num_of_deltas_(0), + slope_(options_.initial_slope), + offset_(options_.initial_offset), 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; + process_noise_(), + avg_noise_(options_.initial_avg_noise), + var_noise_(options_.initial_var_noise), + threshold_(options_.initial_threshold), + ts_delta_hist_(), + prev_offset_(0.0), + time_over_using_(-1), + over_use_counter_(0), + hypothesis_(kBwNormal), + plots_() { + memcpy(E_, options_.initial_e, sizeof(E_)); + memcpy(process_noise_, options_.initial_process_noise, + sizeof(process_noise_)); } OverUseDetector::~OverUseDetector() { #ifdef WEBRTC_BWE_MATLAB - if (plot1_) { - eng.DeletePlot(plot1_); - plot1_ = NULL; + if (plots_.plot1_) { + eng.DeletePlot(plots_.plot1_); + plots_.plot1_ = NULL; } - if (plot2_) { - eng.DeletePlot(plot2_); - plot2_ = NULL; + if (plots_.plot2_) { + eng.DeletePlot(plots_.plot2_); + plots_.plot2_ = NULL; } - if (plot3_) { - eng.DeletePlot(plot3_); - plot3_ = NULL; + if (plots_.plot3_) { + eng.DeletePlot(plots_.plot3_); + plots_.plot3_ = NULL; } - if (plot4_) { - eng.DeletePlot(plot4_); - plot4_ = NULL; + if (plots_.plot4_) { + eng.DeletePlot(plots_.plot4_); + plots_.plot4_ = NULL; } #endif - tsDeltaHist_.clear(); + ts_delta_hist_.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) { +void OverUseDetector::Update(uint16_t packet_size, + uint32_t timestamp, + const int64_t now_ms) { #ifdef WEBRTC_BWE_MATLAB // Create plots - const WebRtc_Word64 startTimeMs = nowMS; - if (plot1_ == NULL) { - plot1_ = eng.NewPlot(new MatlabPlot()); - plot1_->AddLine(1000, "b.", "scatter"); + const int64_t startTimeMs = nowMS; + if (plots_.plot1_ == NULL) { + plots_.plot1_ = eng.NewPlot(new MatlabPlot()); + plots_.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 (plots_.plot2_ == NULL) { + plots_.plot2_ = eng.NewPlot(new MatlabPlot()); + plots_.plot2_->AddTimeLine(30, "b", "offset", startTimeMs); + plots_.plot2_->AddTimeLine(30, "r--", "limitPos", startTimeMs); + plots_.plot2_->AddTimeLine(30, "k.", "trigger", startTimeMs); + plots_.plot2_->AddTimeLine(30, "ko", "detection", startTimeMs); + // plots_.plot2_->AddTimeLine(30, "g", "slowMean", startTimeMs); } - if (plot3_ == NULL) { - plot3_ = eng.NewPlot(new MatlabPlot()); - plot3_->AddTimeLine(30, "b", "noiseVar", startTimeMs); + if (plots_.plot3_ == NULL) { + plots_.plot3_ = eng.NewPlot(new MatlabPlot()); + plots_.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); + if (plots_.plot4_ == NULL) { + plots_.plot4_ = eng.NewPlot(new MatlabPlot()); + // plots_.plot4_->AddTimeLine(60, "b", "p11", startTimeMs); + // plots_.plot4_->AddTimeLine(60, "r", "p12", startTimeMs); + plots_.plot4_->AddTimeLine(60, "g", "p22", startTimeMs); + // plots_.plot4_->AddTimeLine(60, "g--", "p22_hat", startTimeMs); + // plots_.plot4_->AddTimeLine(30, "b.-", "deltaFs", startTimeMs); } #endif bool wrapped = false; bool completeFrame = false; - if (currentFrame_.timestamp_ == -1) { - currentFrame_.timestamp_ = timestamp; + if (current_frame_.timestamp_ == -1) { + current_frame_.timestamp_ = timestamp; } else if (OldTimestamp( timestamp, - static_cast(currentFrame_.timestamp_), + static_cast(current_frame_.timestamp_), &wrapped)) { // Don't update with old data return; - } else if (timestamp != currentFrame_.timestamp_) { + } else if (timestamp != current_frame_.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; + "Frame complete at %I64i", current_frame_.completeTimeMs_); + if (prev_frame_.completeTimeMs_ >= 0) { // This is our second frame + int64_t t_delta = 0; + double ts_delta = 0; // Check for wrap OldTimestamp( - static_cast(prevFrame_.timestamp_), - static_cast(currentFrame_.timestamp_), + static_cast(prev_frame_.timestamp_), + static_cast(current_frame_.timestamp_), &wrapped); - CompensatedTimeDelta(currentFrame_, prevFrame_, tDelta, tsDelta, + CompensatedTimeDelta(current_frame_, prev_frame_, t_delta, ts_delta, wrapped); - UpdateKalman(tDelta, tsDelta, currentFrame_.size_, - prevFrame_.size_); + UpdateKalman(t_delta, ts_delta, current_frame_.size_, + prev_frame_.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; + prev_frame_ = current_frame_; + current_frame_.timestamp_ = timestamp; + current_frame_.size_ = 0; + current_frame_.completeTimeMs_ = -1; completeFrame = true; } // Accumulate the frame size - currentFrame_.size_ += packetSize; - currentFrame_.completeTimeMs_ = nowMS; + current_frame_.size_ += packet_size; + current_frame_.completeTimeMs_ = now_ms; } BandwidthUsage OverUseDetector::State() const { @@ -187,18 +152,18 @@ BandwidthUsage OverUseDetector::State() const { } double OverUseDetector::NoiseVar() const { - return varNoise_; + return var_noise_; } void OverUseDetector::SetRateControlRegion(RateControlRegion region) { switch (region) { case kRcMaxUnknown: { - threshold_ = DETECTOR_THRESHOLD; + threshold_ = options_.initial_threshold; break; } case kRcAboveMax: case kRcNearMax: { - threshold_ = DETECTOR_THRESHOLD / 2; + threshold_ = options_.initial_threshold / 2; break; } } @@ -206,47 +171,47 @@ void OverUseDetector::SetRateControlRegion(RateControlRegion region) { void OverUseDetector::CompensatedTimeDelta(const FrameSample& currentFrame, const FrameSample& prevFrame, - WebRtc_Word64& tDelta, - double& tsDelta, + int64_t& t_delta, + double& ts_delta, bool wrapped) { - numOfDeltas_++; - if (numOfDeltas_ > 1000) { - numOfDeltas_ = 1000; + num_of_deltas_++; + if (num_of_deltas_ > 1000) { + num_of_deltas_ = 1000; } // Add wrap-around compensation - WebRtc_Word64 wrapCompensation = 0; + int64_t wrapCompensation = 0; if (wrapped) { - wrapCompensation = static_cast(1)<<32; + wrapCompensation = static_cast(1)<<32; } - tsDelta = (currentFrame.timestamp_ + ts_delta = (currentFrame.timestamp_ + wrapCompensation - prevFrame.timestamp_) / 90.0; - tDelta = currentFrame.completeTimeMs_ - prevFrame.completeTimeMs_; - assert(tsDelta > 0); + t_delta = currentFrame.completeTimeMs_ - prevFrame.completeTimeMs_; + assert(ts_delta > 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); +void OverUseDetector::UpdateKalman(int64_t t_delta, + double ts_delta, + uint32_t frame_size, + uint32_t prev_frame_size) { + const double minFramePeriod = UpdateMinFramePeriod(ts_delta); const double drift = CurrentDrift(); // Compensate for drift - const double tTsDelta = tDelta - tsDelta / drift; - double fsDelta = static_cast(frameSize) - prevFrameSize; + const double tTsDelta = t_delta - ts_delta / drift; + double fsDelta = static_cast(frame_size) - prev_frame_size; // Update the Kalman filter const double scaleFactor = minFramePeriod / (1000.0 / 30.0); - E_[0][0] += processNoise_[0] * scaleFactor; - E_[1][1] += processNoise_[1] * scaleFactor; + E_[0][0] += process_noise_[0] * scaleFactor; + E_[1][1] += process_noise_[1] * scaleFactor; - if ((hypothesis_ == kBwOverusing && offset_ < prevOffset_) || - (hypothesis_ == kBwUnderUsing && offset_ > prevOffset_)) { - E_[1][1] += 10 * processNoise_[1] * scaleFactor; + if ((hypothesis_ == kBwOverusing && offset_ < prev_offset_) || + (hypothesis_ == kBwUnderUsing && offset_ > prev_offset_)) { + E_[1][1] += 10 * process_noise_[1] * scaleFactor; } 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 bool stableState = - (BWE_MIN(numOfDeltas_, 60) * fabsf(offset_) < threshold_); + const bool stable_state = + (BWE_MIN(num_of_deltas_, 60) * fabsf(offset_) < threshold_); // We try to filter out very late frames. For instance periodic key // frames doesn't fit the Gaussian model well. - if (fabsf(residual) < 3 * sqrt(varNoise_)) { - UpdateNoiseEstimate(residual, minFramePeriod, stableState); + if (fabsf(residual) < 3 * sqrt(var_noise_)) { + UpdateNoiseEstimate(residual, minFramePeriod, stable_state); } 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, Eh[1] / denom}; @@ -287,114 +252,114 @@ void OverUseDetector::UpdateKalman(WebRtc_Word64 tDelta, 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(); + // plots_.plot4_->Append("p11",E_[0][0]); + // plots_.plot4_->Append("p12",E_[0][1]); + plots_.plot4_->Append("p22", E_[1][1]); + // plots_.plot4_->Append("p22_hat", 0.5*(process_noise_[1] + + // sqrt(process_noise_[1]*(process_noise_[1] + 4*var_noise_)))); + // plots_.plot4_->Append("deltaFs", fsDelta); + plots_.plot4_->Plot(); #endif slope_ = slope_ + K[0] * residual; - prevOffset_ = offset_; + prev_offset_ = offset_; offset_ = offset_ + K[1] * residual; - Detect(tsDelta); + Detect(ts_delta); #ifdef WEBRTC_BWE_MATLAB - plot1_->Append("scatter", - static_cast(currentFrame_.size_) - prevFrame_.size_, - static_cast(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(); + plots_.plot1_->Append("scatter", + static_cast(current_frame_.size_) - prev_frame_.size_, + static_cast(t_delta - ts_delta)); + plots_.plot1_->MakeTrend("scatter", "slope", slope_, offset_, "k-"); + plots_.plot1_->MakeTrend("scatter", "thresholdPos", + slope_, offset_ + 2 * sqrt(var_noise_), "r-"); + plots_.plot1_->MakeTrend("scatter", "thresholdNeg", + slope_, offset_ - 2 * sqrt(var_noise_), "r-"); + plots_.plot1_->Plot(); - plot2_->Append("offset", offset_); - plot2_->Append("limitPos", threshold_/BWE_MIN(numOfDeltas_, 60)); - plot2_->Plot(); + plots_.plot2_->Append("offset", offset_); + plots_.plot2_->Append("limitPos", threshold_/BWE_MIN(num_of_deltas_, 60)); + plots_.plot2_->Plot(); - plot3_->Append("noiseVar", varNoise_); - plot3_->Plot(); + plots_.plot3_->Append("noiseVar", var_noise_); + plots_.plot3_->Plot(); #endif } -double OverUseDetector::UpdateMinFramePeriod(double tsDelta) { - double minFramePeriod = tsDelta; - if (tsDeltaHist_.size() >= MIN_FRAME_PERIOD_HISTORY_LEN) { - std::list::iterator firstItem = tsDeltaHist_.begin(); - tsDeltaHist_.erase(firstItem); +double OverUseDetector::UpdateMinFramePeriod(double ts_delta) { + double minFramePeriod = ts_delta; + if (ts_delta_hist_.size() >= MIN_FRAME_PERIOD_HISTORY_LEN) { + std::list::iterator firstItem = ts_delta_hist_.begin(); + ts_delta_hist_.erase(firstItem); } - std::list::iterator it = tsDeltaHist_.begin(); - for (; it != tsDeltaHist_.end(); it++) { + std::list::iterator it = ts_delta_hist_.begin(); + for (; it != ts_delta_hist_.end(); it++) { minFramePeriod = BWE_MIN(*it, minFramePeriod); } - tsDeltaHist_.push_back(tsDelta); + ts_delta_hist_.push_back(ts_delta); return minFramePeriod; } void OverUseDetector::UpdateNoiseEstimate(double residual, - double tsDelta, - bool stableState) { - if (!stableState) { + double ts_delta, + bool stable_state) { + if (!stable_state) { 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) { + if (num_of_deltas_ > 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_ + const double beta = pow(1 - alpha, ts_delta * 30.0 / 1000.0); + avg_noise_ = beta * avg_noise_ + (1 - beta) * residual; - varNoise_ = beta * varNoise_ - + (1 - beta) * (avgNoise_ - residual) * (avgNoise_ - residual); - if (varNoise_ < 1e-7) { - varNoise_ = 1e-7; + var_noise_ = beta * var_noise_ + + (1 - beta) * (avg_noise_ - residual) * (avg_noise_ - residual); + if (var_noise_ < 1e-7) { + var_noise_ = 1e-7; } } -BandwidthUsage OverUseDetector::Detect(double tsDelta) { - if (numOfDeltas_ < 2) { +BandwidthUsage OverUseDetector::Detect(double ts_delta) { + if (num_of_deltas_ < 2) { 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 (offset_ > 0) { - if (timeOverUsing_ == -1) { + if (time_over_using_ == -1) { // Initialize the timer. Assume that we've been // over-using half of the time since the previous // sample. - timeOverUsing_ = tsDelta / 2; + time_over_using_ = ts_delta / 2; } else { // Increment timer - timeOverUsing_ += tsDelta; + time_over_using_ += ts_delta; } - overUseCounter_++; - if (timeOverUsing_ > OVER_USING_TIME_THRESHOLD - && overUseCounter_ > 1) { - if (offset_ >= prevOffset_) { + over_use_counter_++; + if (time_over_using_ > OVER_USING_TIME_THRESHOLD + && over_use_counter_ > 1) { + if (offset_ >= prev_offset_) { #ifdef _DEBUG if (hypothesis_ != kBwOverusing) { WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwOverusing"); } #endif - timeOverUsing_ = 0; - overUseCounter_ = 0; + time_over_using_ = 0; + over_use_counter_ = 0; hypothesis_ = kBwOverusing; #ifdef WEBRTC_BWE_MATLAB - plot2_->Append("detection", offset_); // plot it later + plots_.plot2_->Append("detection", offset_); // plot it later #endif } } #ifdef WEBRTC_BWE_MATLAB - plot2_->Append("trigger", offset_); // plot it later + plots_.plot2_->Append("trigger", offset_); // plot it later #endif } else { #ifdef _DEBUG @@ -402,8 +367,8 @@ BandwidthUsage OverUseDetector::Detect(double tsDelta) { WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwUnderUsing"); } #endif - timeOverUsing_ = -1; - overUseCounter_ = 0; + time_over_using_ = -1; + over_use_counter_ = 0; hypothesis_ = kBwUnderUsing; } } else { @@ -412,25 +377,25 @@ BandwidthUsage OverUseDetector::Detect(double tsDelta) { WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1, "BWE: kBwNormal"); } #endif - timeOverUsing_ = -1; - overUseCounter_ = 0; + time_over_using_ = -1; + over_use_counter_ = 0; hypothesis_ = kBwNormal; } return hypothesis_; } -bool OverUseDetector::OldTimestamp(uint32_t newTimestamp, - uint32_t existingTimestamp, +bool OverUseDetector::OldTimestamp(uint32_t new_timestamp, + uint32_t existing_timestamp, bool* wrapped) { bool tmpWrapped = - (newTimestamp < 0x0000ffff && existingTimestamp > 0xffff0000) || - (newTimestamp > 0xffff0000 && existingTimestamp < 0x0000ffff); + (new_timestamp < 0x0000ffff && existing_timestamp > 0xffff0000) || + (new_timestamp > 0xffff0000 && existing_timestamp < 0x0000ffff); *wrapped = tmpWrapped; - if (existingTimestamp > newTimestamp && !tmpWrapped) { + if (existing_timestamp > new_timestamp && !tmpWrapped) { return true; - } else if (existingTimestamp <= newTimestamp && !tmpWrapped) { + } else if (existing_timestamp <= new_timestamp && !tmpWrapped) { return false; - } else if (existingTimestamp < newTimestamp && tmpWrapped) { + } else if (existing_timestamp < new_timestamp && tmpWrapped) { return true; } else { return false; diff --git a/src/modules/remote_bitrate_estimator/overuse_detector.h b/src/modules/remote_bitrate_estimator/overuse_detector.h index e4b4c68eb5..c3a5a3c877 100644 --- a/src/modules/remote_bitrate_estimator/overuse_detector.h +++ b/src/modules/remote_bitrate_estimator/overuse_detector.h @@ -25,13 +25,12 @@ enum RateControlRegion; class OverUseDetector { public: - OverUseDetector(); + explicit OverUseDetector(const OverUseDetectorOptions& options); ~OverUseDetector(); - void Update(const WebRtc_UWord16 packetSize, - const WebRtc_UWord32 timestamp, - const WebRtc_Word64 nowMS); + void Update(const WebRtc_UWord16 packet_size, + const uint32_t timestamp, + const int64_t now_ms); BandwidthUsage State() const; - void Reset(); double NoiseVar() const; void SetRateControlRegion(RateControlRegion region); @@ -39,52 +38,59 @@ class OverUseDetector { struct FrameSample { FrameSample() : size_(0), completeTimeMs_(-1), timestamp_(-1) {} - WebRtc_UWord32 size_; - WebRtc_Word64 completeTimeMs_; - WebRtc_Word64 timestamp_; + uint32_t size_; + int64_t completeTimeMs_; + int64_t timestamp_; }; - static bool OldTimestamp(uint32_t newTimestamp, - uint32_t existingTimestamp, + struct DebugPlots { +#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); - void CompensatedTimeDelta(const FrameSample& currentFrame, - const FrameSample& prevFrame, - WebRtc_Word64& tDelta, - double& tsDelta, + void CompensatedTimeDelta(const FrameSample& current_frame, + const FrameSample& prev_frame, + int64_t& t_delta, + double& ts_delta, 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); + void UpdateKalman(int64_t t_delta, + double ts_elta, + uint32_t frame_size, + uint32_t prev_frame_size); + double UpdateMinFramePeriod(double ts_delta); + void UpdateNoiseEstimate(double residual, double ts_delta, bool stable_state); + BandwidthUsage Detect(double ts_delta); double CurrentDrift(); - bool firstPacket_; - FrameSample currentFrame_; - FrameSample prevFrame_; - WebRtc_UWord16 numOfDeltas_; + OverUseDetectorOptions options_; // Must be first member + // variable. Cannot be const + // because we need to be copyable. + bool first_packet_; + FrameSample current_frame_; + FrameSample prev_frame_; + uint16_t num_of_deltas_; double slope_; double offset_; double E_[2][2]; - double processNoise_[2]; - double avgNoise_; - double varNoise_; + double process_noise_[2]; + double avg_noise_; + double var_noise_; double threshold_; - std::list tsDeltaHist_; - double prevOffset_; - double timeOverUsing_; - WebRtc_UWord16 overUseCounter_; + std::list ts_delta_hist_; + double prev_offset_; + double time_over_using_; + uint16_t over_use_counter_; BandwidthUsage hypothesis_; - -#ifdef WEBRTC_BWE_MATLAB - MatlabPlot* plot1_; - MatlabPlot* plot2_; - MatlabPlot* plot3_; - MatlabPlot* plot4_; -#endif + DebugPlots plots_; }; } // namespace webrtc diff --git a/src/modules/remote_bitrate_estimator/remote_bitrate_estimator.cc b/src/modules/remote_bitrate_estimator/remote_bitrate_estimator.cc index a0239f8d25..70713d56f8 100644 --- a/src/modules/remote_bitrate_estimator/remote_bitrate_estimator.cc +++ b/src/modules/remote_bitrate_estimator/remote_bitrate_estimator.cc @@ -15,8 +15,10 @@ namespace webrtc { RemoteBitrateEstimator::RemoteBitrateEstimator( - RemoteBitrateObserver* observer) - : observer_(observer), + RemoteBitrateObserver* observer, + const OverUseDetectorOptions& options) + : options_(options), + observer_(observer), crit_sect_(CriticalSectionWrapper::CreateCriticalSection()) { 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 // automatically cleaned up when we have one RemoteBitrateEstimator per REMB // group. - bitrate_controls_[ssrc] = BitrateControls(); + bitrate_controls_.insert(std::make_pair(ssrc, BitrateControls(options_))); it = bitrate_controls_.find(ssrc); } - OverUseDetector* overuse_detector = - &bitrate_controls_[ssrc].overuse_detector; - bitrate_controls_[ssrc].incoming_bitrate.Update(packet_size, arrival_time); + OverUseDetector* overuse_detector = &it->second.overuse_detector; + it->second.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() && diff --git a/src/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest.cc b/src/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest.cc index 2365b1f0e6..2f16ab8a4d 100644 --- a/src/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest.cc +++ b/src/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest.cc @@ -123,7 +123,7 @@ class RemoteBitrateEstimatorTest : public ::testing::Test { virtual void SetUp() { bitrate_observer_.reset(new TestBitrateObserver); 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, // Start time: 0. stream_generator_.reset(new StreamGenerator(30, 3e5, 1e6, 0)); @@ -196,6 +196,7 @@ class RemoteBitrateEstimatorTest : public ::testing::Test { return bitrate_bps; } + OverUseDetectorOptions over_use_detector_options_; scoped_ptr bitrate_estimator_; scoped_ptr bitrate_observer_; scoped_ptr stream_generator_; diff --git a/src/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc b/src/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc index 96d1d2f2ed..466fccd3dc 100644 --- a/src/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc +++ b/src/modules/rtp_rtcp/source/rtcp_format_remb_unittest.cc @@ -59,11 +59,14 @@ class TestTransport : public Transport { class RtcpFormatRembTest : public ::testing::Test { protected: RtcpFormatRembTest() - : remote_bitrate_observer_(), - remote_bitrate_estimator_(&remote_bitrate_observer_) {} + : over_use_detector_options_(), + remote_bitrate_observer_(), + remote_bitrate_estimator_(&remote_bitrate_observer_, + over_use_detector_options_) {} virtual void SetUp(); virtual void TearDown(); + OverUseDetectorOptions over_use_detector_options_; RtpRtcpClock* system_clock_; ModuleRtpRtcpImpl* dummy_rtp_rtcp_impl_; RTCPSender* rtcp_sender_; diff --git a/src/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/src/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc index b511c4e9c5..0e94e6409d 100644 --- a/src/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc +++ b/src/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc @@ -183,8 +183,10 @@ class TestTransport : public Transport, class RtcpReceiverTest : public ::testing::Test { protected: RtcpReceiverTest() - : remote_bitrate_observer_(), - remote_bitrate_estimator_(&remote_bitrate_observer_) { + : over_use_detector_options_(), + remote_bitrate_observer_(), + remote_bitrate_estimator_(&remote_bitrate_observer_, + over_use_detector_options_) { // system_clock_ = ModuleRTPUtility::GetSystemClock(); system_clock_ = new FakeSystemClock(); test_transport_ = new TestTransport(); @@ -221,6 +223,7 @@ class RtcpReceiverTest : public ::testing::Test { return result; } + OverUseDetectorOptions over_use_detector_options_; FakeSystemClock* system_clock_; ModuleRtpRtcpImpl* rtp_rtcp_impl_; RTCPReceiver* rtcp_receiver_; diff --git a/src/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/src/modules/rtp_rtcp/source/rtcp_sender_unittest.cc index 0b14547b7d..1d14f271cb 100644 --- a/src/modules/rtp_rtcp/source/rtcp_sender_unittest.cc +++ b/src/modules/rtp_rtcp/source/rtcp_sender_unittest.cc @@ -98,8 +98,10 @@ class TestTransport : public Transport, class RtcpSenderTest : public ::testing::Test { protected: RtcpSenderTest() - : remote_bitrate_observer_(), - remote_bitrate_estimator_(&remote_bitrate_observer_) { + : over_use_detector_options_(), + remote_bitrate_observer_(), + remote_bitrate_estimator_(&remote_bitrate_observer_, + over_use_detector_options_) { system_clock_ = ModuleRTPUtility::GetSystemClock(); test_transport_ = new TestTransport(); @@ -133,6 +135,7 @@ class RtcpSenderTest : public ::testing::Test { packet_type) != 0U; } + OverUseDetectorOptions over_use_detector_options_; RtpRtcpClock* system_clock_; ModuleRtpRtcpImpl* rtp_rtcp_impl_; RTCPSender* rtcp_sender_; diff --git a/src/video_engine/vie_channel_group.cc b/src/video_engine/vie_channel_group.cc index e26e19c1c7..8d0e429968 100644 --- a/src/video_engine/vie_channel_group.cc +++ b/src/video_engine/vie_channel_group.cc @@ -19,10 +19,12 @@ namespace webrtc { -ChannelGroup::ChannelGroup(ProcessThread* process_thread) +ChannelGroup::ChannelGroup(ProcessThread* process_thread, + const OverUseDetectorOptions& options) : remb_(new VieRemb(process_thread)), bitrate_controller_(BitrateController::CreateBitrateController()), - remote_bitrate_estimator_(new RemoteBitrateEstimator(remb_.get())) { + remote_bitrate_estimator_(new RemoteBitrateEstimator(remb_.get(), + options)) { } ChannelGroup::~ChannelGroup() { diff --git a/src/video_engine/vie_channel_group.h b/src/video_engine/vie_channel_group.h index 0fb777cd2d..bcd58b2b27 100644 --- a/src/video_engine/vie_channel_group.h +++ b/src/video_engine/vie_channel_group.h @@ -18,6 +18,7 @@ namespace webrtc { class BitrateController; +struct OverUseDetectorOptions; class ProcessThread; class RemoteBitrateEstimator; class RemoteBitrateObserver; @@ -29,7 +30,8 @@ class VieRemb; // group are assumed to send/receive data to the same end-point. class ChannelGroup { public: - explicit ChannelGroup(ProcessThread* process_thread); + ChannelGroup(ProcessThread* process_thread, + const OverUseDetectorOptions& options); ~ChannelGroup(); void AddChannel(int channel_id); diff --git a/src/video_engine/vie_channel_manager.cc b/src/video_engine/vie_channel_manager.cc index 5eb4863693..5087668e67 100644 --- a/src/video_engine/vie_channel_manager.cc +++ b/src/video_engine/vie_channel_manager.cc @@ -27,7 +27,8 @@ namespace webrtc { ViEChannelManager::ViEChannelManager( int engine_id, int number_of_cores, - ViEPerformanceMonitor& vie_performance_monitor) + ViEPerformanceMonitor& vie_performance_monitor, + const OverUseDetectorOptions& options) : channel_id_critsect_(CriticalSectionWrapper::CreateCriticalSection()), engine_id_(engine_id), number_of_cores_(number_of_cores), @@ -35,7 +36,8 @@ ViEChannelManager::ViEChannelManager( free_channel_ids_size_(kViEMaxNumberOfChannels), voice_sync_interface_(NULL), voice_engine_(NULL), - module_process_thread_(NULL) { + module_process_thread_(NULL), + over_use_detector_options_(options) { WEBRTC_TRACE(kTraceMemory, kTraceVideo, ViEId(engine_id), "ViEChannelManager::ViEChannelManager(engine_id: %d)", engine_id); @@ -87,7 +89,8 @@ int ViEChannelManager::CreateChannel(int& channel_id) { } // 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(); ViEEncoder* vie_encoder = new ViEEncoder(engine_id_, new_channel_id, number_of_cores_, diff --git a/src/video_engine/vie_channel_manager.h b/src/video_engine/vie_channel_manager.h index ec241eee03..c2a06507aa 100644 --- a/src/video_engine/vie_channel_manager.h +++ b/src/video_engine/vie_channel_manager.h @@ -43,7 +43,8 @@ class ViEChannelManager: private ViEManagerBase { public: ViEChannelManager(int engine_id, int number_of_cores, - ViEPerformanceMonitor& vie_performance_monitor); + ViEPerformanceMonitor& vie_performance_monitor, + const OverUseDetectorOptions& options); ~ViEChannelManager(); void SetModuleProcessThread(ProcessThread& module_process_thread); @@ -125,6 +126,7 @@ class ViEChannelManager: private ViEManagerBase { VoiceEngine* voice_engine_; ProcessThread* module_process_thread_; + const OverUseDetectorOptions& over_use_detector_options_; }; class ViEChannelManagerScoped: private ViEManagerScopedBase { diff --git a/src/video_engine/vie_shared_data.cc b/src/video_engine/vie_shared_data.cc index 1399641c0f..6dd610bb9c 100644 --- a/src/video_engine/vie_shared_data.cc +++ b/src/video_engine/vie_shared_data.cc @@ -26,9 +26,11 @@ ViESharedData::ViESharedData() : instance_id_(++instance_counter_), initialized_(false), number_cores_(CpuInfo::DetectNumberOfCores()), + over_use_detector_options_(), vie_performance_monitor_(ViEPerformanceMonitor(instance_id_)), channel_manager_(*new ViEChannelManager(instance_id_, number_cores_, - vie_performance_monitor_)), + vie_performance_monitor_, + over_use_detector_options_)), input_manager_(*new ViEInputManager(instance_id_)), render_manager_(*new ViERenderManager(instance_id_)), module_process_thread_(ProcessThread::CreateProcessThread()), diff --git a/src/video_engine/vie_shared_data.h b/src/video_engine/vie_shared_data.h index 7f755fa019..6621e4bb64 100644 --- a/src/video_engine/vie_shared_data.h +++ b/src/video_engine/vie_shared_data.h @@ -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 * that can be found in the LICENSE file in the root of the source @@ -50,6 +50,7 @@ class ViESharedData { bool initialized_; const int number_cores_; + OverUseDetectorOptions over_use_detector_options_; ViEPerformanceMonitor vie_performance_monitor_; ViEChannelManager& channel_manager_; ViEInputManager& input_manager_;