Using unit classes in AimdRateControl.

Bug: webrtc:9718
Change-Id: I1efed4e55c9d1ccec3c32ed012cb3cd82d7f4ee8
Reviewed-on: https://webrtc-review.googlesource.com/c/110788
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25705}
This commit is contained in:
Sebastian Jansson
2018-11-19 18:02:20 +01:00
committed by Commit Bot
parent 50b8426648
commit 5f00995964
10 changed files with 298 additions and 267 deletions

View File

@ -175,12 +175,11 @@ DelayBasedBwe::Result DelayBasedBwe::OnLongFeedbackDelay(
// Call constructor. An alternative would be to return an empty Result here, // Call constructor. An alternative would be to return an empty Result here,
// or to estimate the throughput based on the feedback we received. // or to estimate the throughput based on the feedback we received.
RTC_DCHECK(rate_control_.ValidEstimate()); RTC_DCHECK(rate_control_.ValidEstimate());
rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2, rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2, arrival_time);
arrival_time.ms());
Result result; Result result;
result.updated = true; result.updated = true;
result.probe = false; result.probe = false;
result.target_bitrate = DataRate::bps(rate_control_.LatestEstimate()); result.target_bitrate = rate_control_.LatestEstimate();
RTC_LOG(LS_WARNING) << "Long feedback delay detected, reducing BWE to " RTC_LOG(LS_WARNING) << "Long feedback delay detected, reducing BWE to "
<< ToString(result.target_bitrate); << ToString(result.target_bitrate);
return result; return result;
@ -239,27 +238,26 @@ DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
// Currently overusing the bandwidth. // Currently overusing the bandwidth.
if (delay_detector_->State() == BandwidthUsage::kBwOverusing) { if (delay_detector_->State() == BandwidthUsage::kBwOverusing) {
if (acked_bitrate && if (acked_bitrate &&
rate_control_.TimeToReduceFurther(at_time.ms(), acked_bitrate->bps())) { rate_control_.TimeToReduceFurther(at_time, *acked_bitrate)) {
result.updated = result.updated =
UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate); UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate);
} else if (!acked_bitrate && rate_control_.ValidEstimate() && } else if (!acked_bitrate && rate_control_.ValidEstimate() &&
rate_control_.InitialTimeToReduceFurther(at_time.ms())) { rate_control_.InitialTimeToReduceFurther(at_time)) {
// Overusing before we have a measured acknowledged bitrate. Reduce send // Overusing before we have a measured acknowledged bitrate. Reduce send
// rate by 50% every 200 ms. // rate by 50% every 200 ms.
// TODO(tschumim): Improve this and/or the acknowledged bitrate estimator // TODO(tschumim): Improve this and/or the acknowledged bitrate estimator
// so that we (almost) always have a bitrate estimate. // so that we (almost) always have a bitrate estimate.
rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2, rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2, at_time);
at_time.ms());
result.updated = true; result.updated = true;
result.probe = false; result.probe = false;
result.target_bitrate = DataRate::bps(rate_control_.LatestEstimate()); result.target_bitrate = rate_control_.LatestEstimate();
} }
} else { } else {
if (probe_bitrate) { if (probe_bitrate) {
result.probe = true; result.probe = true;
result.updated = true; result.updated = true;
result.target_bitrate = *probe_bitrate; result.target_bitrate = *probe_bitrate;
rate_control_.SetEstimate(probe_bitrate->bps(), at_time.ms()); rate_control_.SetEstimate(*probe_bitrate, at_time);
} else { } else {
result.updated = result.updated =
UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate); UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate);
@ -287,16 +285,13 @@ DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
bool DelayBasedBwe::UpdateEstimate(Timestamp at_time, bool DelayBasedBwe::UpdateEstimate(Timestamp at_time,
absl::optional<DataRate> acked_bitrate, absl::optional<DataRate> acked_bitrate,
DataRate* target_rate) { DataRate* target_rate) {
absl::optional<int> acked_bitrate_bps; const RateControlInput input(delay_detector_->State(), acked_bitrate);
if (acked_bitrate) *target_rate = rate_control_.Update(&input, at_time);
acked_bitrate_bps = acked_bitrate->bps<int>();
const RateControlInput input(delay_detector_->State(), acked_bitrate_bps);
*target_rate = DataRate::bps(rate_control_.Update(&input, at_time.ms()));
return rate_control_.ValidEstimate(); return rate_control_.ValidEstimate();
} }
void DelayBasedBwe::OnRttUpdate(TimeDelta avg_rtt) { void DelayBasedBwe::OnRttUpdate(TimeDelta avg_rtt) {
rate_control_.SetRtt(avg_rtt.ms()); rate_control_.SetRtt(avg_rtt);
} }
bool DelayBasedBwe::LatestEstimate(std::vector<uint32_t>* ssrcs, bool DelayBasedBwe::LatestEstimate(std::vector<uint32_t>* ssrcs,
@ -311,23 +306,23 @@ bool DelayBasedBwe::LatestEstimate(std::vector<uint32_t>* ssrcs,
return false; return false;
*ssrcs = {kFixedSsrc}; *ssrcs = {kFixedSsrc};
*bitrate = DataRate::bps(rate_control_.LatestEstimate()); *bitrate = rate_control_.LatestEstimate();
return true; return true;
} }
void DelayBasedBwe::SetStartBitrate(DataRate start_bitrate) { void DelayBasedBwe::SetStartBitrate(DataRate start_bitrate) {
RTC_LOG(LS_INFO) << "BWE Setting start bitrate to: " RTC_LOG(LS_INFO) << "BWE Setting start bitrate to: "
<< ToString(start_bitrate); << ToString(start_bitrate);
rate_control_.SetStartBitrate(start_bitrate.bps()); rate_control_.SetStartBitrate(start_bitrate);
} }
void DelayBasedBwe::SetMinBitrate(DataRate min_bitrate) { void DelayBasedBwe::SetMinBitrate(DataRate min_bitrate) {
// Called from both the configuration thread and the network thread. Shouldn't // Called from both the configuration thread and the network thread. Shouldn't
// be called from the network thread in the future. // be called from the network thread in the future.
rate_control_.SetMinBitrate(min_bitrate.bps()); rate_control_.SetMinBitrate(min_bitrate);
} }
TimeDelta DelayBasedBwe::GetExpectedBwePeriod() const { TimeDelta DelayBasedBwe::GetExpectedBwePeriod() const {
return TimeDelta::ms(rate_control_.GetExpectedBandwidthPeriodMs()); return rate_control_.GetExpectedBandwidthPeriod();
} }
} // namespace webrtc } // namespace webrtc

View File

@ -42,6 +42,7 @@ rtc_static_library("remote_bitrate_estimator") {
deps = [ deps = [
"../..:webrtc_common", "../..:webrtc_common",
"../../api/units:data_rate", "../../api/units:data_rate",
"../../api/units:timestamp",
"../../modules:module_api", "../../modules:module_api",
"../../modules:module_api_public", "../../modules:module_api_public",
"../../modules/rtp_rtcp:rtp_rtcp_format", "../../modules/rtp_rtcp:rtp_rtcp_format",

View File

@ -26,10 +26,9 @@
namespace webrtc { namespace webrtc {
static const int64_t kDefaultRttMs = 200; constexpr TimeDelta kDefaultRtt = TimeDelta::Millis<200>();
static const int64_t kMaxFeedbackIntervalMs = 1000; constexpr float kDefaultBackoffFactor = 0.85f;
static const float kDefaultBackoffFactor = 0.85f; constexpr TimeDelta kDefaultInitialBackOffInterval = TimeDelta::Millis<200>();
static const int64_t kDefaultInitialBackOffIntervalMs = 200;
const char kBweBackOffFactorExperiment[] = "WebRTC-BweBackOffFactor"; const char kBweBackOffFactorExperiment[] = "WebRTC-BweBackOffFactor";
const char kBweInitialBackOffIntervalExperiment[] = const char kBweInitialBackOffIntervalExperiment[] =
@ -55,7 +54,7 @@ float ReadBackoffFactor() {
return kDefaultBackoffFactor; return kDefaultBackoffFactor;
} }
int64_t ReadInitialBackoffIntervalMs() { TimeDelta ReadInitialBackoffInterval() {
std::string experiment_string = std::string experiment_string =
webrtc::field_trial::FindFullName(kBweInitialBackOffIntervalExperiment); webrtc::field_trial::FindFullName(kBweInitialBackOffIntervalExperiment);
int64_t backoff_interval; int64_t backoff_interval;
@ -63,7 +62,7 @@ int64_t ReadInitialBackoffIntervalMs() {
sscanf(experiment_string.c_str(), "Enabled-%" SCNd64, &backoff_interval); sscanf(experiment_string.c_str(), "Enabled-%" SCNd64, &backoff_interval);
if (parsed_values == 1) { if (parsed_values == 1) {
if (10 <= backoff_interval && backoff_interval <= 200) { if (10 <= backoff_interval && backoff_interval <= 200) {
return backoff_interval; return TimeDelta::ms(backoff_interval);
} }
RTC_LOG(WARNING) RTC_LOG(WARNING)
<< "Initial back-off interval must be between 10 and 200 ms."; << "Initial back-off interval must be between 10 and 200 ms.";
@ -71,188 +70,193 @@ int64_t ReadInitialBackoffIntervalMs() {
RTC_LOG(LS_WARNING) << "Failed to parse parameters for " RTC_LOG(LS_WARNING) << "Failed to parse parameters for "
<< kBweInitialBackOffIntervalExperiment << kBweInitialBackOffIntervalExperiment
<< " experiment. Using default."; << " experiment. Using default.";
return kDefaultInitialBackOffIntervalMs; return kDefaultInitialBackOffInterval;
} }
AimdRateControl::AimdRateControl() AimdRateControl::AimdRateControl()
: min_configured_bitrate_bps_(congestion_controller::GetMinBitrateBps()), : min_configured_bitrate_(congestion_controller::GetMinBitrate()),
max_configured_bitrate_bps_(30000000), max_configured_bitrate_(DataRate::kbps(30000)),
current_bitrate_bps_(max_configured_bitrate_bps_), current_bitrate_(max_configured_bitrate_),
latest_estimated_throughput_bps_(current_bitrate_bps_), latest_estimated_throughput_(current_bitrate_),
avg_max_bitrate_kbps_(-1.0f), avg_max_bitrate_kbps_(-1.0f),
var_max_bitrate_kbps_(0.4f), var_max_bitrate_kbps_(0.4f),
rate_control_state_(kRcHold), rate_control_state_(kRcHold),
rate_control_region_(kRcMaxUnknown), rate_control_region_(kRcMaxUnknown),
time_last_bitrate_change_(-1), time_last_bitrate_change_(Timestamp::MinusInfinity()),
time_last_bitrate_decrease_(-1), time_last_bitrate_decrease_(Timestamp::MinusInfinity()),
time_first_throughput_estimate_(-1), time_first_throughput_estimate_(Timestamp::MinusInfinity()),
bitrate_is_initialized_(false), bitrate_is_initialized_(false),
beta_(webrtc::field_trial::IsEnabled(kBweBackOffFactorExperiment) beta_(webrtc::field_trial::IsEnabled(kBweBackOffFactorExperiment)
? ReadBackoffFactor() ? ReadBackoffFactor()
: kDefaultBackoffFactor), : kDefaultBackoffFactor),
rtt_(kDefaultRttMs), rtt_(kDefaultRtt),
in_experiment_(!AdaptiveThresholdExperimentIsDisabled()), in_experiment_(!AdaptiveThresholdExperimentIsDisabled()),
smoothing_experiment_( smoothing_experiment_(
webrtc::field_trial::IsEnabled("WebRTC-Audio-BandwidthSmoothing")), webrtc::field_trial::IsEnabled("WebRTC-Audio-BandwidthSmoothing")),
in_initial_backoff_interval_experiment_( in_initial_backoff_interval_experiment_(
webrtc::field_trial::IsEnabled(kBweInitialBackOffIntervalExperiment)), webrtc::field_trial::IsEnabled(kBweInitialBackOffIntervalExperiment)),
initial_backoff_interval_ms_(kDefaultInitialBackOffIntervalMs) { initial_backoff_interval_(kDefaultInitialBackOffInterval) {
if (in_initial_backoff_interval_experiment_) { if (in_initial_backoff_interval_experiment_) {
initial_backoff_interval_ms_ = ReadInitialBackoffIntervalMs(); initial_backoff_interval_ = ReadInitialBackoffInterval();
RTC_LOG(LS_INFO) << "Using aimd rate control with initial back-off interval" RTC_LOG(LS_INFO) << "Using aimd rate control with initial back-off interval"
<< " " << initial_backoff_interval_ms_ << " ms."; << " " << ToString(initial_backoff_interval_) << ".";
} }
RTC_LOG(LS_INFO) << "Using aimd rate control with back off factor " << beta_; RTC_LOG(LS_INFO) << "Using aimd rate control with back off factor " << beta_;
} }
AimdRateControl::~AimdRateControl() {} AimdRateControl::~AimdRateControl() {}
void AimdRateControl::SetStartBitrate(int start_bitrate_bps) { void AimdRateControl::SetStartBitrate(DataRate start_bitrate) {
current_bitrate_bps_ = start_bitrate_bps; current_bitrate_ = start_bitrate;
latest_estimated_throughput_bps_ = current_bitrate_bps_; latest_estimated_throughput_ = current_bitrate_;
bitrate_is_initialized_ = true; bitrate_is_initialized_ = true;
} }
void AimdRateControl::SetMinBitrate(int min_bitrate_bps) { void AimdRateControl::SetMinBitrate(DataRate min_bitrate) {
min_configured_bitrate_bps_ = min_bitrate_bps; min_configured_bitrate_ = min_bitrate;
current_bitrate_bps_ = std::max<int>(min_bitrate_bps, current_bitrate_bps_); current_bitrate_ = std::max(min_bitrate, current_bitrate_);
} }
bool AimdRateControl::ValidEstimate() const { bool AimdRateControl::ValidEstimate() const {
return bitrate_is_initialized_; return bitrate_is_initialized_;
} }
int64_t AimdRateControl::GetFeedbackInterval() const { TimeDelta AimdRateControl::GetFeedbackInterval() const {
// Estimate how often we can send RTCP if we allocate up to 5% of bandwidth // Estimate how often we can send RTCP if we allocate up to 5% of bandwidth
// to feedback. // to feedback.
static const int kRtcpSize = 80; const DataSize kRtcpSize = DataSize::bytes(80);
const int64_t interval = static_cast<int64_t>( const DataRate rtcp_bitrate = current_bitrate_ * 0.05;
kRtcpSize * 8.0 * 1000.0 / (0.05 * current_bitrate_bps_) + 0.5); const TimeDelta interval = kRtcpSize / rtcp_bitrate;
const int64_t kMinFeedbackIntervalMs = 200; const TimeDelta kMinFeedbackInterval = TimeDelta::ms(200);
return rtc::SafeClamp(interval, kMinFeedbackIntervalMs, const TimeDelta kMaxFeedbackInterval = TimeDelta::ms(1000);
kMaxFeedbackIntervalMs); return interval.Clamped(kMinFeedbackInterval, kMaxFeedbackInterval);
} }
bool AimdRateControl::TimeToReduceFurther( bool AimdRateControl::TimeToReduceFurther(Timestamp at_time,
int64_t now_ms, DataRate estimated_throughput) const {
uint32_t estimated_throughput_bps) const { const TimeDelta bitrate_reduction_interval =
const int64_t bitrate_reduction_interval = rtt_.Clamped(TimeDelta::ms(10), TimeDelta::ms(200));
std::max<int64_t>(std::min<int64_t>(rtt_, 200), 10); if (at_time - time_last_bitrate_change_ >= bitrate_reduction_interval) {
if (now_ms - time_last_bitrate_change_ >= bitrate_reduction_interval) {
return true; return true;
} }
if (ValidEstimate()) { if (ValidEstimate()) {
// TODO(terelius/holmer): Investigate consequences of increasing // TODO(terelius/holmer): Investigate consequences of increasing
// the threshold to 0.95 * LatestEstimate(). // the threshold to 0.95 * LatestEstimate().
const uint32_t threshold = static_cast<uint32_t>(0.5 * LatestEstimate()); const DataRate threshold = 0.5 * LatestEstimate();
return estimated_throughput_bps < threshold; return estimated_throughput < threshold;
} }
return false; return false;
} }
bool AimdRateControl::InitialTimeToReduceFurther(int64_t now_ms) const { bool AimdRateControl::InitialTimeToReduceFurther(Timestamp at_time) const {
if (!in_initial_backoff_interval_experiment_) { if (!in_initial_backoff_interval_experiment_) {
return ValidEstimate() && return ValidEstimate() &&
TimeToReduceFurther(now_ms, LatestEstimate() / 2 - 1); TimeToReduceFurther(at_time,
LatestEstimate() / 2 - DataRate::bps(1));
} }
// TODO(terelius): We could use the RTT (clamped to suitable limits) instead // TODO(terelius): We could use the RTT (clamped to suitable limits) instead
// of a fixed bitrate_reduction_interval. // of a fixed bitrate_reduction_interval.
if (time_last_bitrate_decrease_ == -1 || if (time_last_bitrate_decrease_.IsInfinite() ||
now_ms - time_last_bitrate_decrease_ >= initial_backoff_interval_ms_) { at_time - time_last_bitrate_decrease_ >= initial_backoff_interval_) {
return true; return true;
} }
return false; return false;
} }
uint32_t AimdRateControl::LatestEstimate() const { DataRate AimdRateControl::LatestEstimate() const {
return current_bitrate_bps_; return current_bitrate_;
} }
void AimdRateControl::SetRtt(int64_t rtt) { void AimdRateControl::SetRtt(TimeDelta rtt) {
rtt_ = rtt; rtt_ = rtt;
} }
uint32_t AimdRateControl::Update(const RateControlInput* input, DataRate AimdRateControl::Update(const RateControlInput* input,
int64_t now_ms) { Timestamp at_time) {
RTC_CHECK(input); RTC_CHECK(input);
// Set the initial bit rate value to what we're receiving the first half // Set the initial bit rate value to what we're receiving the first half
// second. // second.
// TODO(bugs.webrtc.org/9379): The comment above doesn't match to the code. // TODO(bugs.webrtc.org/9379): The comment above doesn't match to the code.
if (!bitrate_is_initialized_) { if (!bitrate_is_initialized_) {
const int64_t kInitializationTimeMs = 5000; const TimeDelta kInitializationTime = TimeDelta::seconds(5);
RTC_DCHECK_LE(kBitrateWindowMs, kInitializationTimeMs); RTC_DCHECK_LE(kBitrateWindowMs, kInitializationTime.ms());
if (time_first_throughput_estimate_ < 0) { if (time_first_throughput_estimate_.IsInfinite()) {
if (input->estimated_throughput_bps) if (input->estimated_throughput)
time_first_throughput_estimate_ = now_ms; time_first_throughput_estimate_ = at_time;
} else if (now_ms - time_first_throughput_estimate_ > } else if (at_time - time_first_throughput_estimate_ >
kInitializationTimeMs && kInitializationTime &&
input->estimated_throughput_bps) { input->estimated_throughput) {
current_bitrate_bps_ = *input->estimated_throughput_bps; current_bitrate_ = *input->estimated_throughput;
bitrate_is_initialized_ = true; bitrate_is_initialized_ = true;
} }
} }
current_bitrate_bps_ = ChangeBitrate(current_bitrate_bps_, *input, now_ms); current_bitrate_ = ChangeBitrate(current_bitrate_, *input, at_time);
return current_bitrate_bps_; return current_bitrate_;
} }
void AimdRateControl::SetEstimate(int bitrate_bps, int64_t now_ms) { void AimdRateControl::SetEstimate(DataRate bitrate, Timestamp at_time) {
bitrate_is_initialized_ = true; bitrate_is_initialized_ = true;
uint32_t prev_bitrate_bps = current_bitrate_bps_; DataRate prev_bitrate = current_bitrate_;
current_bitrate_bps_ = ClampBitrate(bitrate_bps, bitrate_bps); current_bitrate_ = ClampBitrate(bitrate, bitrate);
time_last_bitrate_change_ = now_ms; time_last_bitrate_change_ = at_time;
if (current_bitrate_bps_ < prev_bitrate_bps) { if (current_bitrate_ < prev_bitrate) {
time_last_bitrate_decrease_ = now_ms; time_last_bitrate_decrease_ = at_time;
} }
} }
int AimdRateControl::GetNearMaxIncreaseRateBps() const { double AimdRateControl::GetNearMaxIncreaseRateBpsPerSecond() const {
RTC_DCHECK_GT(current_bitrate_bps_, 0); RTC_DCHECK(!current_bitrate_.IsZero());
double bits_per_frame = static_cast<double>(current_bitrate_bps_) / 30.0; const TimeDelta kFrameInterval = TimeDelta::seconds(1) / 30;
double packets_per_frame = std::ceil(bits_per_frame / (8.0 * 1200.0)); DataSize frame_size = current_bitrate_ * kFrameInterval;
double avg_packet_size_bits = bits_per_frame / packets_per_frame; const DataSize kPacketSize = DataSize::bytes(1200);
double packets_per_frame = std::ceil(frame_size / kPacketSize);
DataSize avg_packet_size = frame_size / packets_per_frame;
// Approximate the over-use estimator delay to 100 ms. // Approximate the over-use estimator delay to 100 ms.
const int64_t response_time = in_experiment_ ? (rtt_ + 100) * 2 : rtt_ + 100; TimeDelta response_time = rtt_ + TimeDelta::ms(100);
constexpr double kMinIncreaseRateBps = 4000; if (in_experiment_)
return static_cast<int>(std::max( response_time = response_time * 2;
kMinIncreaseRateBps, (avg_packet_size_bits * 1000) / response_time)); double increase_rate_bps_per_second =
(avg_packet_size / response_time).bps<double>();
double kMinIncreaseRateBpsPerSecond = 4000;
return std::max(kMinIncreaseRateBpsPerSecond, increase_rate_bps_per_second);
} }
int AimdRateControl::GetExpectedBandwidthPeriodMs() const { TimeDelta AimdRateControl::GetExpectedBandwidthPeriod() const {
const int kMinPeriodMs = smoothing_experiment_ ? 500 : 2000; const TimeDelta kMinPeriod =
constexpr int kDefaultPeriodMs = 3000; smoothing_experiment_ ? TimeDelta::ms(500) : TimeDelta::seconds(2);
constexpr int kMaxPeriodMs = 50000; const TimeDelta kDefaultPeriod = TimeDelta::seconds(3);
const TimeDelta kMaxPeriod = TimeDelta::seconds(50);
int increase_rate = GetNearMaxIncreaseRateBps(); double increase_rate_bps_per_second = GetNearMaxIncreaseRateBpsPerSecond();
if (!last_decrease_) if (!last_decrease_)
return smoothing_experiment_ ? kMinPeriodMs : kDefaultPeriodMs; return smoothing_experiment_ ? kMinPeriod : kDefaultPeriod;
double time_to_recover_decrease_seconds =
return std::min(kMaxPeriodMs, last_decrease_->bps() / increase_rate_bps_per_second;
std::max<int>(1000 * static_cast<int64_t>(*last_decrease_) / TimeDelta period = TimeDelta::seconds(time_to_recover_decrease_seconds);
increase_rate, return period.Clamped(kMinPeriod, kMaxPeriod);
kMinPeriodMs));
} }
uint32_t AimdRateControl::ChangeBitrate(uint32_t new_bitrate_bps, DataRate AimdRateControl::ChangeBitrate(DataRate new_bitrate,
const RateControlInput& input, const RateControlInput& input,
int64_t now_ms) { Timestamp at_time) {
uint32_t estimated_throughput_bps = DataRate estimated_throughput =
input.estimated_throughput_bps.value_or(latest_estimated_throughput_bps_); input.estimated_throughput.value_or(latest_estimated_throughput_);
if (input.estimated_throughput_bps) if (input.estimated_throughput)
latest_estimated_throughput_bps_ = *input.estimated_throughput_bps; latest_estimated_throughput_ = *input.estimated_throughput;
// An over-use should always trigger us to reduce the bitrate, even though // An over-use should always trigger us to reduce the bitrate, even though
// we have not yet established our first estimate. By acting on the over-use, // we have not yet established our first estimate. By acting on the over-use,
// we will end up with a valid estimate. // we will end up with a valid estimate.
if (!bitrate_is_initialized_ && if (!bitrate_is_initialized_ &&
input.bw_state != BandwidthUsage::kBwOverusing) input.bw_state != BandwidthUsage::kBwOverusing)
return current_bitrate_bps_; return current_bitrate_;
ChangeState(input, now_ms); ChangeState(input, at_time);
// Calculated here because it's used in multiple places. // Calculated here because it's used in multiple places.
const float estimated_throughput_kbps = estimated_throughput_bps / 1000.0f; const float estimated_throughput_kbps = estimated_throughput.kbps<double>();
// Calculate the max bit rate std dev given the normalized // Calculate the max bit rate std dev given the normalized
// variance and the current throughput bitrate. // variance and the current throughput bitrate.
const float std_max_bit_rate = const float std_max_bit_rate =
@ -270,45 +274,41 @@ uint32_t AimdRateControl::ChangeBitrate(uint32_t new_bitrate_bps,
avg_max_bitrate_kbps_ = -1.0; avg_max_bitrate_kbps_ = -1.0;
} }
if (rate_control_region_ == kRcNearMax) { if (rate_control_region_ == kRcNearMax) {
uint32_t additive_increase_bps = DataRate additive_increase =
AdditiveRateIncrease(now_ms, time_last_bitrate_change_); AdditiveRateIncrease(at_time, time_last_bitrate_change_);
new_bitrate_bps += additive_increase_bps; new_bitrate += additive_increase;
} else { } else {
uint32_t multiplicative_increase_bps = MultiplicativeRateIncrease( DataRate multiplicative_increase = MultiplicativeRateIncrease(
now_ms, time_last_bitrate_change_, new_bitrate_bps); at_time, time_last_bitrate_change_, new_bitrate);
new_bitrate_bps += multiplicative_increase_bps; new_bitrate += multiplicative_increase;
} }
time_last_bitrate_change_ = now_ms; time_last_bitrate_change_ = at_time;
break; break;
case kRcDecrease: case kRcDecrease:
// Set bit rate to something slightly lower than max // Set bit rate to something slightly lower than max
// to get rid of any self-induced delay. // to get rid of any self-induced delay.
new_bitrate_bps = new_bitrate = estimated_throughput * beta_;
static_cast<uint32_t>(beta_ * estimated_throughput_bps + 0.5); if (new_bitrate > current_bitrate_) {
if (new_bitrate_bps > current_bitrate_bps_) {
// Avoid increasing the rate when over-using. // Avoid increasing the rate when over-using.
if (rate_control_region_ != kRcMaxUnknown) { if (rate_control_region_ != kRcMaxUnknown) {
new_bitrate_bps = static_cast<uint32_t>( new_bitrate = DataRate::kbps(beta_ * avg_max_bitrate_kbps_);
beta_ * avg_max_bitrate_kbps_ * 1000 + 0.5f);
} }
new_bitrate_bps = std::min(new_bitrate_bps, current_bitrate_bps_); new_bitrate = std::min(new_bitrate, current_bitrate_);
} }
rate_control_region_ = kRcNearMax; rate_control_region_ = kRcNearMax;
if (bitrate_is_initialized_ && if (bitrate_is_initialized_ && estimated_throughput < current_bitrate_) {
estimated_throughput_bps < current_bitrate_bps_) {
constexpr float kDegradationFactor = 0.9f; constexpr float kDegradationFactor = 0.9f;
if (smoothing_experiment_ && if (smoothing_experiment_ &&
new_bitrate_bps < new_bitrate < kDegradationFactor * beta_ * current_bitrate_) {
kDegradationFactor * beta_ * current_bitrate_bps_) {
// If bitrate decreases more than a normal back off after overuse, it // If bitrate decreases more than a normal back off after overuse, it
// indicates a real network degradation. We do not let such a decrease // indicates a real network degradation. We do not let such a decrease
// to determine the bandwidth estimation period. // to determine the bandwidth estimation period.
last_decrease_ = absl::nullopt; last_decrease_ = absl::nullopt;
} else { } else {
last_decrease_ = current_bitrate_bps_ - new_bitrate_bps; last_decrease_ = current_bitrate_ - new_bitrate;
} }
} }
if (estimated_throughput_kbps < if (estimated_throughput_kbps <
@ -320,51 +320,49 @@ uint32_t AimdRateControl::ChangeBitrate(uint32_t new_bitrate_bps,
UpdateMaxThroughputEstimate(estimated_throughput_kbps); UpdateMaxThroughputEstimate(estimated_throughput_kbps);
// Stay on hold until the pipes are cleared. // Stay on hold until the pipes are cleared.
rate_control_state_ = kRcHold; rate_control_state_ = kRcHold;
time_last_bitrate_change_ = now_ms; time_last_bitrate_change_ = at_time;
time_last_bitrate_decrease_ = now_ms; time_last_bitrate_decrease_ = at_time;
break; break;
default: default:
assert(false); assert(false);
} }
return ClampBitrate(new_bitrate_bps, estimated_throughput_bps); return ClampBitrate(new_bitrate, estimated_throughput);
} }
uint32_t AimdRateControl::ClampBitrate( DataRate AimdRateControl::ClampBitrate(DataRate new_bitrate,
uint32_t new_bitrate_bps, DataRate estimated_throughput) const {
uint32_t estimated_throughput_bps) const {
// Don't change the bit rate if the send side is too far off. // Don't change the bit rate if the send side is too far off.
// We allow a bit more lag at very low rates to not too easily get stuck if // We allow a bit more lag at very low rates to not too easily get stuck if
// the encoder produces uneven outputs. // the encoder produces uneven outputs.
const uint32_t max_bitrate_bps = const DataRate max_bitrate = 1.5 * estimated_throughput + DataRate::kbps(10);
static_cast<uint32_t>(1.5f * estimated_throughput_bps) + 10000; if (new_bitrate > current_bitrate_ && new_bitrate > max_bitrate) {
if (new_bitrate_bps > current_bitrate_bps_ && new_bitrate = std::max(current_bitrate_, max_bitrate);
new_bitrate_bps > max_bitrate_bps) {
new_bitrate_bps = std::max(current_bitrate_bps_, max_bitrate_bps);
} }
new_bitrate_bps = std::max(new_bitrate_bps, min_configured_bitrate_bps_); new_bitrate = std::max(new_bitrate, min_configured_bitrate_);
return new_bitrate_bps; return new_bitrate;
} }
uint32_t AimdRateControl::MultiplicativeRateIncrease( DataRate AimdRateControl::MultiplicativeRateIncrease(
int64_t now_ms, Timestamp at_time,
int64_t last_ms, Timestamp last_time,
uint32_t current_bitrate_bps) const { DataRate current_bitrate) const {
double alpha = 1.08; double alpha = 1.08;
if (last_ms > -1) { if (last_time.IsFinite()) {
auto time_since_last_update_ms = auto time_since_last_update = at_time - last_time;
rtc::SafeMin<int64_t>(now_ms - last_ms, 1000); alpha = pow(alpha, std::min(time_since_last_update.seconds<double>(), 1.0));
alpha = pow(alpha, time_since_last_update_ms / 1000.0);
} }
uint32_t multiplicative_increase_bps = DataRate multiplicative_increase =
std::max(current_bitrate_bps * (alpha - 1.0), 1000.0); std::max(current_bitrate * (alpha - 1.0), DataRate::bps(1000));
return multiplicative_increase_bps; return multiplicative_increase;
} }
uint32_t AimdRateControl::AdditiveRateIncrease(int64_t now_ms, DataRate AimdRateControl::AdditiveRateIncrease(Timestamp at_time,
int64_t last_ms) const { Timestamp last_time) const {
return static_cast<uint32_t>((now_ms - last_ms) * double time_period_seconds = (at_time - last_time).seconds<double>();
GetNearMaxIncreaseRateBps() / 1000); double data_rate_increase_bps =
GetNearMaxIncreaseRateBpsPerSecond() * time_period_seconds;
return DataRate::bps(data_rate_increase_bps);
} }
void AimdRateControl::UpdateMaxThroughputEstimate( void AimdRateControl::UpdateMaxThroughputEstimate(
@ -394,11 +392,11 @@ void AimdRateControl::UpdateMaxThroughputEstimate(
} }
void AimdRateControl::ChangeState(const RateControlInput& input, void AimdRateControl::ChangeState(const RateControlInput& input,
int64_t now_ms) { Timestamp at_time) {
switch (input.bw_state) { switch (input.bw_state) {
case BandwidthUsage::kBwNormal: case BandwidthUsage::kBwNormal:
if (rate_control_state_ == kRcHold) { if (rate_control_state_ == kRcHold) {
time_last_bitrate_change_ = now_ms; time_last_bitrate_change_ = at_time;
rate_control_state_ = kRcIncrease; rate_control_state_ = kRcIncrease;
} }
break; break;

View File

@ -16,6 +16,9 @@
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
#include "api/units/data_rate.h"
#include "api/units/timestamp.h"
namespace webrtc { namespace webrtc {
// A rate control implementation based on additive increases of // A rate control implementation based on additive increases of
@ -32,28 +35,28 @@ class AimdRateControl {
// either if it has been explicitly set via SetStartBitrate/SetEstimate, or if // either if it has been explicitly set via SetStartBitrate/SetEstimate, or if
// we have measured a throughput. // we have measured a throughput.
bool ValidEstimate() const; bool ValidEstimate() const;
void SetStartBitrate(int start_bitrate_bps); void SetStartBitrate(DataRate start_bitrate);
void SetMinBitrate(int min_bitrate_bps); void SetMinBitrate(DataRate min_bitrate);
int64_t GetFeedbackInterval() const; TimeDelta GetFeedbackInterval() const;
// Returns true if the bitrate estimate hasn't been changed for more than // Returns true if the bitrate estimate hasn't been changed for more than
// an RTT, or if the estimated_throughput is less than half of the current // an RTT, or if the estimated_throughput is less than half of the current
// estimate. Should be used to decide if we should reduce the rate further // estimate. Should be used to decide if we should reduce the rate further
// when over-using. // when over-using.
bool TimeToReduceFurther(int64_t now_ms, bool TimeToReduceFurther(Timestamp at_time,
uint32_t estimated_throughput_bps) const; DataRate estimated_throughput) const;
// As above. To be used if overusing before we have measured a throughput. // As above. To be used if overusing before we have measured a throughput.
bool InitialTimeToReduceFurther(int64_t now_ms) const; bool InitialTimeToReduceFurther(Timestamp at_time) const;
uint32_t LatestEstimate() const; DataRate LatestEstimate() const;
void SetRtt(int64_t rtt); void SetRtt(TimeDelta rtt);
uint32_t Update(const RateControlInput* input, int64_t now_ms); DataRate Update(const RateControlInput* input, Timestamp at_time);
void SetEstimate(int bitrate_bps, int64_t now_ms); void SetEstimate(DataRate bitrate, Timestamp at_time);
// Returns the increase rate when used bandwidth is near the link capacity. // Returns the increase rate when used bandwidth is near the link capacity.
int GetNearMaxIncreaseRateBps() const; double GetNearMaxIncreaseRateBpsPerSecond() const;
// Returns the expected time between overuse signals (assuming steady state). // Returns the expected time between overuse signals (assuming steady state).
int GetExpectedBandwidthPeriodMs() const; TimeDelta GetExpectedBandwidthPeriod() const;
private: private:
friend class GoogCcStatePrinter; friend class GoogCcStatePrinter;
@ -64,41 +67,41 @@ class AimdRateControl {
// in the "decrease" state the bitrate will be decreased to slightly below the // in the "decrease" state the bitrate will be decreased to slightly below the
// current throughput. When in the "hold" state the bitrate will be kept // current throughput. When in the "hold" state the bitrate will be kept
// constant to allow built up queues to drain. // constant to allow built up queues to drain.
uint32_t ChangeBitrate(uint32_t current_bitrate, DataRate ChangeBitrate(DataRate current_bitrate,
const RateControlInput& input, const RateControlInput& input,
int64_t now_ms); Timestamp at_time);
// Clamps new_bitrate_bps to within the configured min bitrate and a linear // Clamps new_bitrate to within the configured min bitrate and a linear
// function of the throughput, so that the new bitrate can't grow too // function of the throughput, so that the new bitrate can't grow too
// large compared to the bitrate actually being received by the other end. // large compared to the bitrate actually being received by the other end.
uint32_t ClampBitrate(uint32_t new_bitrate_bps, DataRate ClampBitrate(DataRate new_bitrate,
uint32_t estimated_throughput_bps) const; DataRate estimated_throughput) const;
uint32_t MultiplicativeRateIncrease(int64_t now_ms, DataRate MultiplicativeRateIncrease(Timestamp at_time,
int64_t last_ms, Timestamp last_ms,
uint32_t current_bitrate_bps) const; DataRate current_bitrate) const;
uint32_t AdditiveRateIncrease(int64_t now_ms, int64_t last_ms) const; DataRate AdditiveRateIncrease(Timestamp at_time, Timestamp last_time) const;
void UpdateChangePeriod(int64_t now_ms); void UpdateChangePeriod(Timestamp at_time);
void UpdateMaxThroughputEstimate(float estimated_throughput_kbps); void UpdateMaxThroughputEstimate(float estimated_throughput_kbps);
void ChangeState(const RateControlInput& input, int64_t now_ms); void ChangeState(const RateControlInput& input, Timestamp at_time);
uint32_t min_configured_bitrate_bps_; DataRate min_configured_bitrate_;
uint32_t max_configured_bitrate_bps_; DataRate max_configured_bitrate_;
uint32_t current_bitrate_bps_; DataRate current_bitrate_;
uint32_t latest_estimated_throughput_bps_; DataRate latest_estimated_throughput_;
float avg_max_bitrate_kbps_; float avg_max_bitrate_kbps_;
float var_max_bitrate_kbps_; float var_max_bitrate_kbps_;
RateControlState rate_control_state_; RateControlState rate_control_state_;
RateControlRegion rate_control_region_; RateControlRegion rate_control_region_;
int64_t time_last_bitrate_change_; Timestamp time_last_bitrate_change_;
int64_t time_last_bitrate_decrease_; Timestamp time_last_bitrate_decrease_;
int64_t time_first_throughput_estimate_; Timestamp time_first_throughput_estimate_;
bool bitrate_is_initialized_; bool bitrate_is_initialized_;
float beta_; float beta_;
int64_t rtt_; TimeDelta rtt_;
const bool in_experiment_; const bool in_experiment_;
const bool smoothing_experiment_; const bool smoothing_experiment_;
const bool in_initial_backoff_interval_experiment_; const bool in_initial_backoff_interval_experiment_;
int64_t initial_backoff_interval_ms_; TimeDelta initial_backoff_interval_;
absl::optional<int> last_decrease_; absl::optional<DataRate> last_decrease_;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -40,13 +40,26 @@ AimdRateControlStates CreateAimdRateControlStates() {
states.simulated_clock.reset(new SimulatedClock(kClockInitialTime)); states.simulated_clock.reset(new SimulatedClock(kClockInitialTime));
return states; return states;
} }
absl::optional<DataRate> OptionalRateFromOptionalBps(
absl::optional<int> bitrate_bps) {
if (bitrate_bps) {
return DataRate::bps(*bitrate_bps);
} else {
return absl::nullopt;
}
}
void UpdateRateControl(const AimdRateControlStates& states, void UpdateRateControl(const AimdRateControlStates& states,
const BandwidthUsage& bandwidth_usage, const BandwidthUsage& bandwidth_usage,
absl::optional<uint32_t> throughput_estimate, absl::optional<uint32_t> throughput_estimate,
int64_t now_ms) { int64_t now_ms) {
RateControlInput input(bandwidth_usage, throughput_estimate); RateControlInput input(bandwidth_usage,
states.aimd_rate_control->Update(&input, now_ms); OptionalRateFromOptionalBps(throughput_estimate));
states.aimd_rate_control->Update(&input, Timestamp::ms(now_ms));
}
void SetEstimate(const AimdRateControlStates& states, int bitrate_bps) {
states.aimd_rate_control->SetEstimate(
DataRate::bps(bitrate_bps),
Timestamp::ms(states.simulated_clock->TimeInMilliseconds()));
} }
} // namespace } // namespace
@ -54,40 +67,40 @@ void UpdateRateControl(const AimdRateControlStates& states,
TEST(AimdRateControlTest, MinNearMaxIncreaseRateOnLowBandwith) { TEST(AimdRateControlTest, MinNearMaxIncreaseRateOnLowBandwith) {
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kBitrate = 30000; constexpr int kBitrate = 30000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kBitrate);
kBitrate, states.simulated_clock->TimeInMilliseconds()); EXPECT_EQ(4000,
EXPECT_EQ(4000, states.aimd_rate_control->GetNearMaxIncreaseRateBps()); states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
} }
TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn90kbpsAnd200msRtt) { TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn90kbpsAnd200msRtt) {
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kBitrate = 90000; constexpr int kBitrate = 90000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kBitrate);
kBitrate, states.simulated_clock->TimeInMilliseconds()); EXPECT_EQ(5000,
EXPECT_EQ(5000, states.aimd_rate_control->GetNearMaxIncreaseRateBps()); states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
} }
TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn60kbpsAnd100msRtt) { TEST(AimdRateControlTest, NearMaxIncreaseRateIs5kbpsOn60kbpsAnd100msRtt) {
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kBitrate = 60000; constexpr int kBitrate = 60000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kBitrate);
kBitrate, states.simulated_clock->TimeInMilliseconds()); states.aimd_rate_control->SetRtt(TimeDelta::ms(100));
states.aimd_rate_control->SetRtt(100); EXPECT_EQ(5000,
EXPECT_EQ(5000, states.aimd_rate_control->GetNearMaxIncreaseRateBps()); states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
} }
TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriod) { TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriod) {
// Smoothing experiment disabled // Smoothing experiment disabled
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kBitrate = 300000; constexpr int kBitrate = 300000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kBitrate);
kBitrate, states.simulated_clock->TimeInMilliseconds());
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kBitrate, UpdateRateControl(states, BandwidthUsage::kBwOverusing, kBitrate,
states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->TimeInMilliseconds());
EXPECT_NEAR(14000, states.aimd_rate_control->GetNearMaxIncreaseRateBps(), EXPECT_NEAR(14000,
states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond(),
1000); 1000);
EXPECT_EQ(kDefaultPeriodMsNoSmoothingExp, EXPECT_EQ(kDefaultPeriodMsNoSmoothingExp,
states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
} }
TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriodSmoothingExp) { TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriodSmoothingExp) {
@ -95,21 +108,20 @@ TEST(AimdRateControlTest, GetIncreaseRateAndBandwidthPeriodSmoothingExp) {
test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial); test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kBitrate = 300000; constexpr int kBitrate = 300000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kBitrate);
kBitrate, states.simulated_clock->TimeInMilliseconds());
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kBitrate, UpdateRateControl(states, BandwidthUsage::kBwOverusing, kBitrate,
states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->TimeInMilliseconds());
EXPECT_NEAR(14000, states.aimd_rate_control->GetNearMaxIncreaseRateBps(), EXPECT_NEAR(14000,
states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond(),
1000); 1000);
EXPECT_EQ(kMinBwePeriodMsSmoothingExp, EXPECT_EQ(kMinBwePeriodMsSmoothingExp,
states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
} }
TEST(AimdRateControlTest, BweLimitedByAckedBitrate) { TEST(AimdRateControlTest, BweLimitedByAckedBitrate) {
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kAckedBitrate = 10000; constexpr int kAckedBitrate = 10000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kAckedBitrate);
kAckedBitrate, states.simulated_clock->TimeInMilliseconds());
while (states.simulated_clock->TimeInMilliseconds() - kClockInitialTime < while (states.simulated_clock->TimeInMilliseconds() - kClockInitialTime <
20000) { 20000) {
UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate, UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate,
@ -118,14 +130,13 @@ TEST(AimdRateControlTest, BweLimitedByAckedBitrate) {
} }
ASSERT_TRUE(states.aimd_rate_control->ValidEstimate()); ASSERT_TRUE(states.aimd_rate_control->ValidEstimate());
EXPECT_EQ(static_cast<uint32_t>(1.5 * kAckedBitrate + 10000), EXPECT_EQ(static_cast<uint32_t>(1.5 * kAckedBitrate + 10000),
states.aimd_rate_control->LatestEstimate()); states.aimd_rate_control->LatestEstimate().bps());
} }
TEST(AimdRateControlTest, BweNotLimitedByDecreasingAckedBitrate) { TEST(AimdRateControlTest, BweNotLimitedByDecreasingAckedBitrate) {
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kAckedBitrate = 100000; constexpr int kAckedBitrate = 100000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kAckedBitrate);
kAckedBitrate, states.simulated_clock->TimeInMilliseconds());
while (states.simulated_clock->TimeInMilliseconds() - kClockInitialTime < while (states.simulated_clock->TimeInMilliseconds() - kClockInitialTime <
20000) { 20000) {
UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate, UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate,
@ -135,10 +146,10 @@ TEST(AimdRateControlTest, BweNotLimitedByDecreasingAckedBitrate) {
ASSERT_TRUE(states.aimd_rate_control->ValidEstimate()); ASSERT_TRUE(states.aimd_rate_control->ValidEstimate());
// If the acked bitrate decreases the BWE shouldn't be reduced to 1.5x // If the acked bitrate decreases the BWE shouldn't be reduced to 1.5x
// what's being acked, but also shouldn't get to increase more. // what's being acked, but also shouldn't get to increase more.
uint32_t prev_estimate = states.aimd_rate_control->LatestEstimate(); uint32_t prev_estimate = states.aimd_rate_control->LatestEstimate().bps();
UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate / 2, UpdateRateControl(states, BandwidthUsage::kBwNormal, kAckedBitrate / 2,
states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->TimeInMilliseconds());
uint32_t new_estimate = states.aimd_rate_control->LatestEstimate(); uint32_t new_estimate = states.aimd_rate_control->LatestEstimate().bps();
EXPECT_NEAR(new_estimate, static_cast<uint32_t>(1.5 * kAckedBitrate + 10000), EXPECT_NEAR(new_estimate, static_cast<uint32_t>(1.5 * kAckedBitrate + 10000),
2000); 2000);
EXPECT_EQ(new_estimate, prev_estimate); EXPECT_EQ(new_estimate, prev_estimate);
@ -147,35 +158,34 @@ TEST(AimdRateControlTest, BweNotLimitedByDecreasingAckedBitrate) {
TEST(AimdRateControlTest, DefaultPeriodUntilFirstOveruse) { TEST(AimdRateControlTest, DefaultPeriodUntilFirstOveruse) {
// Smoothing experiment disabled // Smoothing experiment disabled
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
states.aimd_rate_control->SetStartBitrate(300000); states.aimd_rate_control->SetStartBitrate(DataRate::kbps(300));
EXPECT_EQ(kDefaultPeriodMsNoSmoothingExp, EXPECT_EQ(kDefaultPeriodMsNoSmoothingExp,
states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
states.simulated_clock->AdvanceTimeMilliseconds(100); states.simulated_clock->AdvanceTimeMilliseconds(100);
UpdateRateControl(states, BandwidthUsage::kBwOverusing, 280000, UpdateRateControl(states, BandwidthUsage::kBwOverusing, 280000,
states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->TimeInMilliseconds());
EXPECT_NE(kDefaultPeriodMsNoSmoothingExp, EXPECT_NE(kDefaultPeriodMsNoSmoothingExp,
states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
} }
TEST(AimdRateControlTest, MinPeriodUntilFirstOveruseSmoothingExp) { TEST(AimdRateControlTest, MinPeriodUntilFirstOveruseSmoothingExp) {
// Smoothing experiment enabled // Smoothing experiment enabled
test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial); test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
states.aimd_rate_control->SetStartBitrate(300000); states.aimd_rate_control->SetStartBitrate(DataRate::kbps(300));
EXPECT_EQ(kMinBwePeriodMsSmoothingExp, EXPECT_EQ(kMinBwePeriodMsSmoothingExp,
states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
states.simulated_clock->AdvanceTimeMilliseconds(100); states.simulated_clock->AdvanceTimeMilliseconds(100);
UpdateRateControl(states, BandwidthUsage::kBwOverusing, 280000, UpdateRateControl(states, BandwidthUsage::kBwOverusing, 280000,
states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->TimeInMilliseconds());
EXPECT_NE(kMinBwePeriodMsSmoothingExp, EXPECT_NE(kMinBwePeriodMsSmoothingExp,
states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
} }
TEST(AimdRateControlTest, ExpectedPeriodAfter20kbpsDropAnd5kbpsIncrease) { TEST(AimdRateControlTest, ExpectedPeriodAfter20kbpsDropAnd5kbpsIncrease) {
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kInitialBitrate = 110000; constexpr int kInitialBitrate = 110000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kInitialBitrate);
kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
states.simulated_clock->AdvanceTimeMilliseconds(100); states.simulated_clock->AdvanceTimeMilliseconds(100);
// Make the bitrate drop by 20 kbps to get to 90 kbps. // Make the bitrate drop by 20 kbps to get to 90 kbps.
// The rate increase at 90 kbps should be 5 kbps, so the period should be 4 s. // The rate increase at 90 kbps should be 5 kbps, so the period should be 4 s.
@ -183,8 +193,9 @@ TEST(AimdRateControlTest, ExpectedPeriodAfter20kbpsDropAnd5kbpsIncrease) {
(kInitialBitrate - 20000) / kFractionAfterOveruse; (kInitialBitrate - 20000) / kFractionAfterOveruse;
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate, UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate,
states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->TimeInMilliseconds());
EXPECT_EQ(5000, states.aimd_rate_control->GetNearMaxIncreaseRateBps()); EXPECT_EQ(5000,
EXPECT_EQ(4000, states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.aimd_rate_control->GetNearMaxIncreaseRateBpsPerSecond());
EXPECT_EQ(4000, states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
} }
TEST(AimdRateControlTest, MinPeriodAfterLargeBitrateDecreaseSmoothingExp) { TEST(AimdRateControlTest, MinPeriodAfterLargeBitrateDecreaseSmoothingExp) {
@ -192,8 +203,7 @@ TEST(AimdRateControlTest, MinPeriodAfterLargeBitrateDecreaseSmoothingExp) {
test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial); test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kInitialBitrate = 110000; constexpr int kInitialBitrate = 110000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kInitialBitrate);
kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
states.simulated_clock->AdvanceTimeMilliseconds(100); states.simulated_clock->AdvanceTimeMilliseconds(100);
// Make such a large drop in bitrate that should be treated as network // Make such a large drop in bitrate that should be treated as network
// degradation. // degradation.
@ -201,20 +211,19 @@ TEST(AimdRateControlTest, MinPeriodAfterLargeBitrateDecreaseSmoothingExp) {
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate, UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate,
states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->TimeInMilliseconds());
EXPECT_EQ(kMinBwePeriodMsSmoothingExp, EXPECT_EQ(kMinBwePeriodMsSmoothingExp,
states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
} }
TEST(AimdRateControlTest, BandwidthPeriodIsNotBelowMin) { TEST(AimdRateControlTest, BandwidthPeriodIsNotBelowMin) {
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kInitialBitrate = 10000; constexpr int kInitialBitrate = 10000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kInitialBitrate);
kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
states.simulated_clock->AdvanceTimeMilliseconds(100); states.simulated_clock->AdvanceTimeMilliseconds(100);
// Make a small (1.5 kbps) bitrate drop to 8.5 kbps. // Make a small (1.5 kbps) bitrate drop to 8.5 kbps.
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kInitialBitrate - 1, UpdateRateControl(states, BandwidthUsage::kBwOverusing, kInitialBitrate - 1,
states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->TimeInMilliseconds());
EXPECT_EQ(kMinBwePeriodMsNoSmoothingExp, EXPECT_EQ(kMinBwePeriodMsNoSmoothingExp,
states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
} }
TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxSmoothingExp) { TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxSmoothingExp) {
@ -222,29 +231,27 @@ TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxSmoothingExp) {
test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial); test::ScopedFieldTrials override_field_trials(kSmoothingExpFieldTrial);
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kInitialBitrate = 50000000; constexpr int kInitialBitrate = 50000000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kInitialBitrate);
kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
states.simulated_clock->AdvanceTimeMilliseconds(100); states.simulated_clock->AdvanceTimeMilliseconds(100);
// Make a large (10 Mbps) bitrate drop to 10 kbps. // Make a large (10 Mbps) bitrate drop to 10 kbps.
constexpr int kAckedBitrate = 40000000 / kFractionAfterOveruse; constexpr int kAckedBitrate = 40000000 / kFractionAfterOveruse;
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate, UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate,
states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->TimeInMilliseconds());
EXPECT_EQ(kMaxBwePeriodMs, EXPECT_EQ(kMaxBwePeriodMs,
states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
} }
TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxNoSmoothingExp) { TEST(AimdRateControlTest, BandwidthPeriodIsNotAboveMaxNoSmoothingExp) {
auto states = CreateAimdRateControlStates(); auto states = CreateAimdRateControlStates();
constexpr int kInitialBitrate = 10010000; constexpr int kInitialBitrate = 10010000;
states.aimd_rate_control->SetEstimate( SetEstimate(states, kInitialBitrate);
kInitialBitrate, states.simulated_clock->TimeInMilliseconds());
states.simulated_clock->AdvanceTimeMilliseconds(100); states.simulated_clock->AdvanceTimeMilliseconds(100);
// Make a large (10 Mbps) bitrate drop to 10 kbps. // Make a large (10 Mbps) bitrate drop to 10 kbps.
constexpr int kAckedBitrate = 10000 / kFractionAfterOveruse; constexpr int kAckedBitrate = 10000 / kFractionAfterOveruse;
UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate, UpdateRateControl(states, BandwidthUsage::kBwOverusing, kAckedBitrate,
states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->TimeInMilliseconds());
EXPECT_EQ(kMaxBwePeriodMs, EXPECT_EQ(kMaxBwePeriodMs,
states.aimd_rate_control->GetExpectedBandwidthPeriodMs()); states.aimd_rate_control->GetExpectedBandwidthPeriod().ms());
} }
TEST(AimdRateControlTest, SendingRateBoundedWhenThroughputNotEstimated) { TEST(AimdRateControlTest, SendingRateBoundedWhenThroughputNotEstimated) {
@ -265,7 +272,7 @@ TEST(AimdRateControlTest, SendingRateBoundedWhenThroughputNotEstimated) {
states.simulated_clock->TimeInMilliseconds()); states.simulated_clock->TimeInMilliseconds());
states.simulated_clock->AdvanceTimeMilliseconds(100); states.simulated_clock->AdvanceTimeMilliseconds(100);
} }
EXPECT_LE(states.aimd_rate_control->LatestEstimate(), EXPECT_LE(states.aimd_rate_control->LatestEstimate().bps(),
kInitialBitrateBps * 1.5 + 10000); kInitialBitrateBps * 1.5 + 10000);
} }

View File

@ -34,8 +34,8 @@ DataRate GetMinBitrate() {
RateControlInput::RateControlInput( RateControlInput::RateControlInput(
BandwidthUsage bw_state, BandwidthUsage bw_state,
const absl::optional<uint32_t>& estimated_throughput_bps) const absl::optional<DataRate>& estimated_throughput)
: bw_state(bw_state), estimated_throughput_bps(estimated_throughput_bps) {} : bw_state(bw_state), estimated_throughput(estimated_throughput) {}
RateControlInput::~RateControlInput() = default; RateControlInput::~RateControlInput() = default;

View File

@ -51,11 +51,11 @@ enum RateControlRegion { kRcNearMax, kRcAboveMax, kRcMaxUnknown };
struct RateControlInput { struct RateControlInput {
RateControlInput(BandwidthUsage bw_state, RateControlInput(BandwidthUsage bw_state,
const absl::optional<uint32_t>& estimated_throughput_bps); const absl::optional<DataRate>& estimated_throughput);
~RateControlInput(); ~RateControlInput();
BandwidthUsage bw_state; BandwidthUsage bw_state;
absl::optional<uint32_t> estimated_throughput_bps; absl::optional<DataRate> estimated_throughput;
}; };
} // namespace webrtc } // namespace webrtc

View File

@ -22,6 +22,16 @@
#include "system_wrappers/include/metrics.h" #include "system_wrappers/include/metrics.h"
namespace webrtc { namespace webrtc {
namespace {
absl::optional<DataRate> OptionalRateFromOptionalBps(
absl::optional<int> bitrate_bps) {
if (bitrate_bps) {
return DataRate::bps(*bitrate_bps);
} else {
return absl::nullopt;
}
}
} // namespace
enum { enum {
kTimestampGroupLengthMs = 5, kTimestampGroupLengthMs = 5,
@ -188,7 +198,8 @@ RemoteBitrateEstimatorAbsSendTime::ProcessClusters(int64_t now_ms) {
<< " bps. Mean send delta: " << best_it->send_mean_ms << " bps. Mean send delta: " << best_it->send_mean_ms
<< " ms, mean recv delta: " << best_it->recv_mean_ms << " ms, mean recv delta: " << best_it->recv_mean_ms
<< " ms, num probes: " << best_it->count; << " ms, num probes: " << best_it->count;
remote_rate_.SetEstimate(probe_bitrate_bps, now_ms); remote_rate_.SetEstimate(DataRate::bps(probe_bitrate_bps),
Timestamp::ms(now_ms));
return ProbeResult::kBitrateUpdated; return ProbeResult::kBitrateUpdated;
} }
} }
@ -205,7 +216,7 @@ bool RemoteBitrateEstimatorAbsSendTime::IsBitrateImproving(
bool initial_probe = !remote_rate_.ValidEstimate() && new_bitrate_bps > 0; bool initial_probe = !remote_rate_.ValidEstimate() && new_bitrate_bps > 0;
bool bitrate_above_estimate = bool bitrate_above_estimate =
remote_rate_.ValidEstimate() && remote_rate_.ValidEstimate() &&
new_bitrate_bps > static_cast<int>(remote_rate_.LatestEstimate()); new_bitrate_bps > remote_rate_.LatestEstimate().bps<int>();
return initial_probe || bitrate_above_estimate; return initial_probe || bitrate_above_estimate;
} }
@ -316,13 +327,14 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
// Check if it's time for a periodic update or if we should update because // Check if it's time for a periodic update or if we should update because
// of an over-use. // of an over-use.
if (last_update_ms_ == -1 || if (last_update_ms_ == -1 ||
now_ms - last_update_ms_ > remote_rate_.GetFeedbackInterval()) { now_ms - last_update_ms_ > remote_rate_.GetFeedbackInterval().ms()) {
update_estimate = true; update_estimate = true;
} else if (detector_.State() == BandwidthUsage::kBwOverusing) { } else if (detector_.State() == BandwidthUsage::kBwOverusing) {
absl::optional<uint32_t> incoming_rate = absl::optional<uint32_t> incoming_rate =
incoming_bitrate_.Rate(arrival_time_ms); incoming_bitrate_.Rate(arrival_time_ms);
if (incoming_rate && if (incoming_rate &&
remote_rate_.TimeToReduceFurther(now_ms, *incoming_rate)) { remote_rate_.TimeToReduceFurther(Timestamp::ms(now_ms),
DataRate::bps(*incoming_rate))) {
update_estimate = true; update_estimate = true;
} }
} }
@ -332,9 +344,11 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
// The first overuse should immediately trigger a new estimate. // The first overuse should immediately trigger a new estimate.
// We also have to update the estimate immediately if we are overusing // We also have to update the estimate immediately if we are overusing
// and the target bitrate is too high compared to what we are receiving. // and the target bitrate is too high compared to what we are receiving.
const RateControlInput input(detector_.State(), const RateControlInput input(
incoming_bitrate_.Rate(arrival_time_ms)); detector_.State(),
target_bitrate_bps = remote_rate_.Update(&input, now_ms); OptionalRateFromOptionalBps(incoming_bitrate_.Rate(arrival_time_ms)));
target_bitrate_bps =
remote_rate_.Update(&input, Timestamp::ms(now_ms)).bps<uint32_t>();
update_estimate = remote_rate_.ValidEstimate(); update_estimate = remote_rate_.ValidEstimate();
ssrcs = Keys(ssrcs_); ssrcs = Keys(ssrcs_);
} }
@ -374,7 +388,7 @@ void RemoteBitrateEstimatorAbsSendTime::TimeoutStreams(int64_t now_ms) {
void RemoteBitrateEstimatorAbsSendTime::OnRttUpdate(int64_t avg_rtt_ms, void RemoteBitrateEstimatorAbsSendTime::OnRttUpdate(int64_t avg_rtt_ms,
int64_t max_rtt_ms) { int64_t max_rtt_ms) {
rtc::CritScope lock(&crit_); rtc::CritScope lock(&crit_);
remote_rate_.SetRtt(avg_rtt_ms); remote_rate_.SetRtt(TimeDelta::ms(avg_rtt_ms));
} }
void RemoteBitrateEstimatorAbsSendTime::RemoveStream(uint32_t ssrc) { void RemoteBitrateEstimatorAbsSendTime::RemoveStream(uint32_t ssrc) {
@ -399,7 +413,7 @@ bool RemoteBitrateEstimatorAbsSendTime::LatestEstimate(
if (ssrcs_.empty()) { if (ssrcs_.empty()) {
*bitrate_bps = 0; *bitrate_bps = 0;
} else { } else {
*bitrate_bps = remote_rate_.LatestEstimate(); *bitrate_bps = remote_rate_.LatestEstimate().bps<uint32_t>();
} }
return true; return true;
} }
@ -408,6 +422,6 @@ void RemoteBitrateEstimatorAbsSendTime::SetMinBitrate(int min_bitrate_bps) {
// Called from both the configuration thread and the network thread. Shouldn't // Called from both the configuration thread and the network thread. Shouldn't
// be called from the network thread in the future. // be called from the network thread in the future.
rtc::CritScope lock(&crit_); rtc::CritScope lock(&crit_);
remote_rate_.SetMinBitrate(min_bitrate_bps); remote_rate_.SetMinBitrate(DataRate::bps(min_bitrate_bps));
} }
} // namespace webrtc } // namespace webrtc

View File

@ -27,6 +27,16 @@
#include "system_wrappers/include/metrics.h" #include "system_wrappers/include/metrics.h"
namespace webrtc { namespace webrtc {
namespace {
absl::optional<DataRate> OptionalRateFromOptionalBps(
absl::optional<int> bitrate_bps) {
if (bitrate_bps) {
return DataRate::bps(*bitrate_bps);
} else {
return absl::nullopt;
}
}
} // namespace
enum { kTimestampGroupLengthMs = 5 }; enum { kTimestampGroupLengthMs = 5 };
static const double kTimestampToMs = 1.0 / 90.0; static const double kTimestampToMs = 1.0 / 90.0;
@ -133,7 +143,8 @@ void RemoteBitrateEstimatorSingleStream::IncomingPacket(
incoming_bitrate_.Rate(now_ms); incoming_bitrate_.Rate(now_ms);
if (incoming_bitrate_bps && if (incoming_bitrate_bps &&
(prior_state != BandwidthUsage::kBwOverusing || (prior_state != BandwidthUsage::kBwOverusing ||
GetRemoteRate()->TimeToReduceFurther(now_ms, *incoming_bitrate_bps))) { GetRemoteRate()->TimeToReduceFurther(
Timestamp::ms(now_ms), DataRate::bps(*incoming_bitrate_bps)))) {
// The first overuse should immediately trigger a new estimate. // The first overuse should immediately trigger a new estimate.
// We also have to update the estimate immediately if we are overusing // We also have to update the estimate immediately if we are overusing
// and the target bitrate is too high compared to what we are receiving. // and the target bitrate is too high compared to what we are receiving.
@ -187,10 +198,12 @@ void RemoteBitrateEstimatorSingleStream::UpdateEstimate(int64_t now_ms) {
} }
AimdRateControl* remote_rate = GetRemoteRate(); AimdRateControl* remote_rate = GetRemoteRate();
const RateControlInput input(bw_state, incoming_bitrate_.Rate(now_ms)); const RateControlInput input(
uint32_t target_bitrate = remote_rate->Update(&input, now_ms); bw_state, OptionalRateFromOptionalBps(incoming_bitrate_.Rate(now_ms)));
uint32_t target_bitrate =
remote_rate->Update(&input, Timestamp::ms(now_ms)).bps<uint32_t>();
if (remote_rate->ValidEstimate()) { if (remote_rate->ValidEstimate()) {
process_interval_ms_ = remote_rate->GetFeedbackInterval(); process_interval_ms_ = remote_rate->GetFeedbackInterval().ms();
RTC_DCHECK_GT(process_interval_ms_, 0); RTC_DCHECK_GT(process_interval_ms_, 0);
std::vector<uint32_t> ssrcs; std::vector<uint32_t> ssrcs;
GetSsrcs(&ssrcs); GetSsrcs(&ssrcs);
@ -202,7 +215,7 @@ void RemoteBitrateEstimatorSingleStream::UpdateEstimate(int64_t now_ms) {
void RemoteBitrateEstimatorSingleStream::OnRttUpdate(int64_t avg_rtt_ms, void RemoteBitrateEstimatorSingleStream::OnRttUpdate(int64_t avg_rtt_ms,
int64_t max_rtt_ms) { int64_t max_rtt_ms) {
rtc::CritScope cs(&crit_sect_); rtc::CritScope cs(&crit_sect_);
GetRemoteRate()->SetRtt(avg_rtt_ms); GetRemoteRate()->SetRtt(TimeDelta::ms(avg_rtt_ms));
} }
void RemoteBitrateEstimatorSingleStream::RemoveStream(unsigned int ssrc) { void RemoteBitrateEstimatorSingleStream::RemoveStream(unsigned int ssrc) {
@ -226,7 +239,7 @@ bool RemoteBitrateEstimatorSingleStream::LatestEstimate(
if (ssrcs->empty()) if (ssrcs->empty())
*bitrate_bps = 0; *bitrate_bps = 0;
else else
*bitrate_bps = remote_rate_->LatestEstimate(); *bitrate_bps = remote_rate_->LatestEstimate().bps<uint32_t>();
return true; return true;
} }
@ -249,7 +262,7 @@ AimdRateControl* RemoteBitrateEstimatorSingleStream::GetRemoteRate() {
void RemoteBitrateEstimatorSingleStream::SetMinBitrate(int min_bitrate_bps) { void RemoteBitrateEstimatorSingleStream::SetMinBitrate(int min_bitrate_bps) {
rtc::CritScope cs(&crit_sect_); rtc::CritScope cs(&crit_sect_);
remote_rate_->SetMinBitrate(min_bitrate_bps); remote_rate_->SetMinBitrate(DataRate::bps(min_bitrate_bps));
} }
} // namespace webrtc } // namespace webrtc

View File

@ -55,7 +55,7 @@ TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThreeStreamsWrap) {
} }
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirteenStreamsWrap) { TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirteenStreamsWrap) {
CapacityDropTestHelper(13, true, 733, 0); CapacityDropTestHelper(13, true, 567, 0);
} }
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropNineteenStreamsWrap) { TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropNineteenStreamsWrap) {