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

View File

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

View File

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

View File

@ -16,6 +16,9 @@
#include "absl/types/optional.h"
#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
#include "api/units/data_rate.h"
#include "api/units/timestamp.h"
namespace webrtc {
// 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
// we have measured a throughput.
bool ValidEstimate() const;
void SetStartBitrate(int start_bitrate_bps);
void SetMinBitrate(int min_bitrate_bps);
int64_t GetFeedbackInterval() const;
void SetStartBitrate(DataRate start_bitrate);
void SetMinBitrate(DataRate min_bitrate);
TimeDelta GetFeedbackInterval() const;
// 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
// estimate. Should be used to decide if we should reduce the rate further
// when over-using.
bool TimeToReduceFurther(int64_t now_ms,
uint32_t estimated_throughput_bps) const;
bool TimeToReduceFurther(Timestamp at_time,
DataRate estimated_throughput) const;
// 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;
void SetRtt(int64_t rtt);
uint32_t Update(const RateControlInput* input, int64_t now_ms);
void SetEstimate(int bitrate_bps, int64_t now_ms);
DataRate LatestEstimate() const;
void SetRtt(TimeDelta rtt);
DataRate Update(const RateControlInput* input, Timestamp at_time);
void SetEstimate(DataRate bitrate, Timestamp at_time);
// 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).
int GetExpectedBandwidthPeriodMs() const;
TimeDelta GetExpectedBandwidthPeriod() const;
private:
friend class GoogCcStatePrinter;
@ -64,41 +67,41 @@ class AimdRateControl {
// 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
// constant to allow built up queues to drain.
uint32_t ChangeBitrate(uint32_t current_bitrate,
DataRate ChangeBitrate(DataRate current_bitrate,
const RateControlInput& input,
int64_t now_ms);
// Clamps new_bitrate_bps to within the configured min bitrate and a linear
Timestamp at_time);
// 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
// large compared to the bitrate actually being received by the other end.
uint32_t ClampBitrate(uint32_t new_bitrate_bps,
uint32_t estimated_throughput_bps) const;
uint32_t MultiplicativeRateIncrease(int64_t now_ms,
int64_t last_ms,
uint32_t current_bitrate_bps) const;
uint32_t AdditiveRateIncrease(int64_t now_ms, int64_t last_ms) const;
void UpdateChangePeriod(int64_t now_ms);
DataRate ClampBitrate(DataRate new_bitrate,
DataRate estimated_throughput) const;
DataRate MultiplicativeRateIncrease(Timestamp at_time,
Timestamp last_ms,
DataRate current_bitrate) const;
DataRate AdditiveRateIncrease(Timestamp at_time, Timestamp last_time) const;
void UpdateChangePeriod(Timestamp at_time);
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_;
uint32_t max_configured_bitrate_bps_;
uint32_t current_bitrate_bps_;
uint32_t latest_estimated_throughput_bps_;
DataRate min_configured_bitrate_;
DataRate max_configured_bitrate_;
DataRate current_bitrate_;
DataRate latest_estimated_throughput_;
float avg_max_bitrate_kbps_;
float var_max_bitrate_kbps_;
RateControlState rate_control_state_;
RateControlRegion rate_control_region_;
int64_t time_last_bitrate_change_;
int64_t time_last_bitrate_decrease_;
int64_t time_first_throughput_estimate_;
Timestamp time_last_bitrate_change_;
Timestamp time_last_bitrate_decrease_;
Timestamp time_first_throughput_estimate_;
bool bitrate_is_initialized_;
float beta_;
int64_t rtt_;
TimeDelta rtt_;
const bool in_experiment_;
const bool smoothing_experiment_;
const bool in_initial_backoff_interval_experiment_;
int64_t initial_backoff_interval_ms_;
absl::optional<int> last_decrease_;
TimeDelta initial_backoff_interval_;
absl::optional<DataRate> last_decrease_;
};
} // namespace webrtc

View File

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

View File

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

View File

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

View File

@ -22,6 +22,16 @@
#include "system_wrappers/include/metrics.h"
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,
@ -188,7 +198,8 @@ RemoteBitrateEstimatorAbsSendTime::ProcessClusters(int64_t now_ms) {
<< " bps. Mean send delta: " << best_it->send_mean_ms
<< " ms, mean recv delta: " << best_it->recv_mean_ms
<< " 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;
}
}
@ -205,7 +216,7 @@ bool RemoteBitrateEstimatorAbsSendTime::IsBitrateImproving(
bool initial_probe = !remote_rate_.ValidEstimate() && new_bitrate_bps > 0;
bool bitrate_above_estimate =
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;
}
@ -316,13 +327,14 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
// Check if it's time for a periodic update or if we should update because
// of an over-use.
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;
} else if (detector_.State() == BandwidthUsage::kBwOverusing) {
absl::optional<uint32_t> incoming_rate =
incoming_bitrate_.Rate(arrival_time_ms);
if (incoming_rate &&
remote_rate_.TimeToReduceFurther(now_ms, *incoming_rate)) {
remote_rate_.TimeToReduceFurther(Timestamp::ms(now_ms),
DataRate::bps(*incoming_rate))) {
update_estimate = true;
}
}
@ -332,9 +344,11 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
// The first overuse should immediately trigger a new estimate.
// 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.
const RateControlInput input(detector_.State(),
incoming_bitrate_.Rate(arrival_time_ms));
target_bitrate_bps = remote_rate_.Update(&input, now_ms);
const RateControlInput input(
detector_.State(),
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();
ssrcs = Keys(ssrcs_);
}
@ -374,7 +388,7 @@ void RemoteBitrateEstimatorAbsSendTime::TimeoutStreams(int64_t now_ms) {
void RemoteBitrateEstimatorAbsSendTime::OnRttUpdate(int64_t avg_rtt_ms,
int64_t max_rtt_ms) {
rtc::CritScope lock(&crit_);
remote_rate_.SetRtt(avg_rtt_ms);
remote_rate_.SetRtt(TimeDelta::ms(avg_rtt_ms));
}
void RemoteBitrateEstimatorAbsSendTime::RemoveStream(uint32_t ssrc) {
@ -399,7 +413,7 @@ bool RemoteBitrateEstimatorAbsSendTime::LatestEstimate(
if (ssrcs_.empty()) {
*bitrate_bps = 0;
} else {
*bitrate_bps = remote_rate_.LatestEstimate();
*bitrate_bps = remote_rate_.LatestEstimate().bps<uint32_t>();
}
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
// be called from the network thread in the future.
rtc::CritScope lock(&crit_);
remote_rate_.SetMinBitrate(min_bitrate_bps);
remote_rate_.SetMinBitrate(DataRate::bps(min_bitrate_bps));
}
} // namespace webrtc

View File

@ -27,6 +27,16 @@
#include "system_wrappers/include/metrics.h"
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 };
static const double kTimestampToMs = 1.0 / 90.0;
@ -133,7 +143,8 @@ void RemoteBitrateEstimatorSingleStream::IncomingPacket(
incoming_bitrate_.Rate(now_ms);
if (incoming_bitrate_bps &&
(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.
// 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.
@ -187,10 +198,12 @@ void RemoteBitrateEstimatorSingleStream::UpdateEstimate(int64_t now_ms) {
}
AimdRateControl* remote_rate = GetRemoteRate();
const RateControlInput input(bw_state, incoming_bitrate_.Rate(now_ms));
uint32_t target_bitrate = remote_rate->Update(&input, now_ms);
const RateControlInput input(
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()) {
process_interval_ms_ = remote_rate->GetFeedbackInterval();
process_interval_ms_ = remote_rate->GetFeedbackInterval().ms();
RTC_DCHECK_GT(process_interval_ms_, 0);
std::vector<uint32_t> ssrcs;
GetSsrcs(&ssrcs);
@ -202,7 +215,7 @@ void RemoteBitrateEstimatorSingleStream::UpdateEstimate(int64_t now_ms) {
void RemoteBitrateEstimatorSingleStream::OnRttUpdate(int64_t avg_rtt_ms,
int64_t max_rtt_ms) {
rtc::CritScope cs(&crit_sect_);
GetRemoteRate()->SetRtt(avg_rtt_ms);
GetRemoteRate()->SetRtt(TimeDelta::ms(avg_rtt_ms));
}
void RemoteBitrateEstimatorSingleStream::RemoveStream(unsigned int ssrc) {
@ -226,7 +239,7 @@ bool RemoteBitrateEstimatorSingleStream::LatestEstimate(
if (ssrcs->empty())
*bitrate_bps = 0;
else
*bitrate_bps = remote_rate_->LatestEstimate();
*bitrate_bps = remote_rate_->LatestEstimate().bps<uint32_t>();
return true;
}
@ -249,7 +262,7 @@ AimdRateControl* RemoteBitrateEstimatorSingleStream::GetRemoteRate() {
void RemoteBitrateEstimatorSingleStream::SetMinBitrate(int min_bitrate_bps) {
rtc::CritScope cs(&crit_sect_);
remote_rate_->SetMinBitrate(min_bitrate_bps);
remote_rate_->SetMinBitrate(DataRate::bps(min_bitrate_bps));
}
} // namespace webrtc

View File

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