blob: 9b005118e9c27b83795ed2bfc9fcf7364a5b0b83 [file] [log] [blame]
/*
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/congestion_controller/goog_cc/goog_cc_network_control.h"
#include <stdio.h>
#include <algorithm>
#include <cstdint>
#include <memory>
#include <numeric>
#include <optional>
#include <utility>
#include <vector>
#include "absl/strings/string_view.h"
#include "api/environment/environment.h"
#include "api/field_trials_view.h"
#include "api/transport/bandwidth_usage.h"
#include "api/transport/network_control.h"
#include "api/transport/network_types.h"
#include "api/units/data_rate.h"
#include "api/units/data_size.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "logging/rtc_event_log/events/rtc_event_remote_estimate.h"
#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h"
#include "modules/congestion_controller/goog_cc/alr_detector.h"
#include "modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h"
#include "modules/congestion_controller/goog_cc/delay_based_bwe.h"
#include "modules/congestion_controller/goog_cc/loss_based_bwe_v2.h"
#include "modules/congestion_controller/goog_cc/probe_bitrate_estimator.h"
#include "modules/congestion_controller/goog_cc/probe_controller.h"
#include "modules/congestion_controller/goog_cc/send_side_bandwidth_estimation.h"
#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
#include "rtc_base/checks.h"
#include "rtc_base/experiments/field_trial_parser.h"
#include "rtc_base/experiments/rate_control_settings.h"
#include "rtc_base/logging.h"
namespace webrtc {
namespace {
// From RTCPSender video report interval.
constexpr TimeDelta kLossUpdateInterval = TimeDelta::Millis(1000);
// Pacing-rate relative to our target send rate.
// Multiplicative factor that is applied to the target bitrate to calculate
// the number of bytes that can be transmitted per interval.
// Increasing this factor will result in lower delays in cases of bitrate
// overshoots from the encoder.
constexpr float kDefaultPaceMultiplier = 2.5f;
// If the probe result is far below the current throughput estimate
// it's unlikely that the probe is accurate, so we don't want to drop too far.
// However, if we actually are overusing, we want to drop to something slightly
// below the current throughput estimate to drain the network queues.
constexpr double kProbeDropThroughputFraction = 0.85;
BandwidthLimitedCause GetBandwidthLimitedCause(LossBasedState loss_based_state,
bool is_rtt_above_limit,
BandwidthUsage bandwidth_usage) {
if (bandwidth_usage == BandwidthUsage::kBwOverusing ||
bandwidth_usage == BandwidthUsage::kBwUnderusing) {
return BandwidthLimitedCause::kDelayBasedLimitedDelayIncreased;
} else if (is_rtt_above_limit) {
return BandwidthLimitedCause::kRttBasedBackOffHighRtt;
}
switch (loss_based_state) {
case LossBasedState::kDecreasing:
// Probes may not be sent in this state.
return BandwidthLimitedCause::kLossLimitedBwe;
case webrtc::LossBasedState::kIncreaseUsingPadding:
// Probes may not be sent in this state.
return BandwidthLimitedCause::kLossLimitedBwe;
case LossBasedState::kIncreasing:
// Probes may be sent in this state.
return BandwidthLimitedCause::kLossLimitedBweIncreasing;
case LossBasedState::kDelayBasedEstimate:
return BandwidthLimitedCause::kDelayBasedLimited;
}
}
} // namespace
GoogCcNetworkController::GoogCcNetworkController(NetworkControllerConfig config,
GoogCcConfig goog_cc_config)
: env_(config.env),
packet_feedback_only_(goog_cc_config.feedback_only),
safe_reset_on_route_change_("Enabled"),
safe_reset_acknowledged_rate_("ack"),
use_min_allocatable_as_lower_bound_(
!env_.field_trials().IsDisabled("WebRTC-Bwe-MinAllocAsLowerBound")),
ignore_probes_lower_than_network_estimate_(
!env_.field_trials().IsDisabled(
"WebRTC-Bwe-IgnoreProbesLowerThanNetworkStateEstimate")),
limit_probes_lower_than_throughput_estimate_(
!env_.field_trials().IsDisabled(
"WebRTC-Bwe-LimitProbesLowerThanThroughputEstimate")),
rate_control_settings_(env_.field_trials()),
pace_at_max_of_bwe_and_lower_link_capacity_(env_.field_trials().IsEnabled(
"WebRTC-Bwe-PaceAtMaxOfBweAndLowerLinkCapacity")),
limit_pacingfactor_by_upper_link_capacity_estimate_(
env_.field_trials().IsEnabled(
"WebRTC-Bwe-LimitPacingFactorByUpperLinkCapacityEstimate")),
probe_controller_(
new ProbeController(&env_.field_trials(), &env_.event_log())),
congestion_window_pushback_controller_(
rate_control_settings_.UseCongestionWindowPushback()
? std::make_unique<CongestionWindowPushbackController>(
env_.field_trials())
: nullptr),
bandwidth_estimation_(
std::make_unique<SendSideBandwidthEstimation>(&env_.field_trials(),
&env_.event_log())),
alr_detector_(std::make_unique<AlrDetector>(&env_.field_trials(),
&env_.event_log())),
probe_bitrate_estimator_(new ProbeBitrateEstimator(&env_.event_log())),
network_estimator_(std::move(goog_cc_config.network_state_estimator)),
network_state_predictor_(
std::move(goog_cc_config.network_state_predictor)),
delay_based_bwe_(new DelayBasedBwe(&env_.field_trials(),
&env_.event_log(),
network_state_predictor_.get())),
acknowledged_bitrate_estimator_(
AcknowledgedBitrateEstimatorInterface::Create(&env_.field_trials())),
initial_config_(config),
last_loss_based_target_rate_(*config.constraints.starting_rate),
last_pushback_target_rate_(last_loss_based_target_rate_),
last_stable_target_rate_(last_loss_based_target_rate_),
last_loss_base_state_(LossBasedState::kDelayBasedEstimate),
pacing_factor_(config.stream_based_config.pacing_factor.value_or(
kDefaultPaceMultiplier)),
min_total_allocated_bitrate_(
config.stream_based_config.min_total_allocated_bitrate.value_or(
DataRate::Zero())),
max_padding_rate_(config.stream_based_config.max_padding_rate.value_or(
DataRate::Zero())) {
RTC_DCHECK(config.constraints.at_time.IsFinite());
ParseFieldTrial(
{&safe_reset_on_route_change_, &safe_reset_acknowledged_rate_},
env_.field_trials().Lookup("WebRTC-Bwe-SafeResetOnRouteChange"));
if (delay_based_bwe_)
delay_based_bwe_->SetMinBitrate(kCongestionControllerMinBitrate);
}
GoogCcNetworkController::~GoogCcNetworkController() {}
NetworkControlUpdate GoogCcNetworkController::OnNetworkAvailability(
NetworkAvailability msg) {
NetworkControlUpdate update;
update.probe_cluster_configs = probe_controller_->OnNetworkAvailability(msg);
return update;
}
NetworkControlUpdate GoogCcNetworkController::OnNetworkRouteChange(
NetworkRouteChange msg) {
if (safe_reset_on_route_change_) {
std::optional<DataRate> estimated_bitrate;
if (safe_reset_acknowledged_rate_) {
estimated_bitrate = acknowledged_bitrate_estimator_->bitrate();
if (!estimated_bitrate)
estimated_bitrate = acknowledged_bitrate_estimator_->PeekRate();
} else {
estimated_bitrate = bandwidth_estimation_->target_rate();
}
if (estimated_bitrate) {
if (msg.constraints.starting_rate) {
msg.constraints.starting_rate =
std::min(*msg.constraints.starting_rate, *estimated_bitrate);
} else {
msg.constraints.starting_rate = estimated_bitrate;
}
}
}
acknowledged_bitrate_estimator_ =
AcknowledgedBitrateEstimatorInterface::Create(&env_.field_trials());
probe_bitrate_estimator_.reset(new ProbeBitrateEstimator(&env_.event_log()));
if (network_estimator_)
network_estimator_->OnRouteChange(msg);
delay_based_bwe_.reset(new DelayBasedBwe(
&env_.field_trials(), &env_.event_log(), network_state_predictor_.get()));
bandwidth_estimation_->OnRouteChange();
probe_controller_->Reset(msg.at_time);
NetworkControlUpdate update;
update.probe_cluster_configs = ResetConstraints(msg.constraints);
MaybeTriggerOnNetworkChanged(&update, msg.at_time);
return update;
}
NetworkControlUpdate GoogCcNetworkController::OnProcessInterval(
ProcessInterval msg) {
NetworkControlUpdate update;
if (initial_config_) {
update.probe_cluster_configs =
ResetConstraints(initial_config_->constraints);
update.pacer_config = GetPacingRates(msg.at_time);
if (initial_config_->stream_based_config.requests_alr_probing) {
probe_controller_->EnablePeriodicAlrProbing(
*initial_config_->stream_based_config.requests_alr_probing);
}
if (initial_config_->stream_based_config.enable_repeated_initial_probing) {
probe_controller_->EnableRepeatedInitialProbing(
*initial_config_->stream_based_config
.enable_repeated_initial_probing);
}
std::optional<DataRate> total_bitrate =
initial_config_->stream_based_config.max_total_allocated_bitrate;
if (total_bitrate) {
auto probes = probe_controller_->OnMaxTotalAllocatedBitrate(
*total_bitrate, msg.at_time);
update.probe_cluster_configs.insert(update.probe_cluster_configs.end(),
probes.begin(), probes.end());
}
initial_config_.reset();
}
if (congestion_window_pushback_controller_ && msg.pacer_queue) {
congestion_window_pushback_controller_->UpdatePacingQueue(
msg.pacer_queue->bytes());
}
bandwidth_estimation_->UpdateEstimate(msg.at_time);
std::optional<int64_t> start_time_ms =
alr_detector_->GetApplicationLimitedRegionStartTime();
probe_controller_->SetAlrStartTimeMs(start_time_ms);
auto probes = probe_controller_->Process(msg.at_time);
update.probe_cluster_configs.insert(update.probe_cluster_configs.end(),
probes.begin(), probes.end());
if (rate_control_settings_.UseCongestionWindow() &&
!feedback_max_rtts_.empty()) {
UpdateCongestionWindowSize();
}
if (congestion_window_pushback_controller_ && current_data_window_) {
congestion_window_pushback_controller_->SetDataWindow(
*current_data_window_);
} else {
update.congestion_window = current_data_window_;
}
MaybeTriggerOnNetworkChanged(&update, msg.at_time);
return update;
}
NetworkControlUpdate GoogCcNetworkController::OnRemoteBitrateReport(
RemoteBitrateReport msg) {
if (packet_feedback_only_) {
RTC_LOG(LS_ERROR) << "Received REMB for packet feedback only GoogCC";
return NetworkControlUpdate();
}
bandwidth_estimation_->UpdateReceiverEstimate(msg.receive_time,
msg.bandwidth);
return NetworkControlUpdate();
}
NetworkControlUpdate GoogCcNetworkController::OnRoundTripTimeUpdate(
RoundTripTimeUpdate msg) {
if (packet_feedback_only_ || msg.smoothed)
return NetworkControlUpdate();
RTC_DCHECK(!msg.round_trip_time.IsZero());
if (delay_based_bwe_)
delay_based_bwe_->OnRttUpdate(msg.round_trip_time);
bandwidth_estimation_->UpdateRtt(msg.round_trip_time, msg.receive_time);
return NetworkControlUpdate();
}
NetworkControlUpdate GoogCcNetworkController::OnSentPacket(
SentPacket sent_packet) {
alr_detector_->OnBytesSent(sent_packet.size.bytes(),
sent_packet.send_time.ms());
acknowledged_bitrate_estimator_->SetAlr(
alr_detector_->GetApplicationLimitedRegionStartTime().has_value());
if (!first_packet_sent_) {
first_packet_sent_ = true;
// Initialize feedback time to send time to allow estimation of RTT until
// first feedback is received.
bandwidth_estimation_->UpdatePropagationRtt(sent_packet.send_time,
TimeDelta::Zero());
}
bandwidth_estimation_->OnSentPacket(sent_packet);
if (congestion_window_pushback_controller_) {
congestion_window_pushback_controller_->UpdateOutstandingData(
sent_packet.data_in_flight.bytes());
NetworkControlUpdate update;
MaybeTriggerOnNetworkChanged(&update, sent_packet.send_time);
return update;
} else {
return NetworkControlUpdate();
}
}
NetworkControlUpdate GoogCcNetworkController::OnReceivedPacket(
ReceivedPacket received_packet) {
return NetworkControlUpdate();
}
NetworkControlUpdate GoogCcNetworkController::OnStreamsConfig(
StreamsConfig msg) {
NetworkControlUpdate update;
if (msg.requests_alr_probing) {
probe_controller_->EnablePeriodicAlrProbing(*msg.requests_alr_probing);
}
if (msg.max_total_allocated_bitrate) {
update.probe_cluster_configs =
probe_controller_->OnMaxTotalAllocatedBitrate(
*msg.max_total_allocated_bitrate, msg.at_time);
}
bool pacing_changed = false;
if (msg.pacing_factor && *msg.pacing_factor != pacing_factor_) {
pacing_factor_ = *msg.pacing_factor;
pacing_changed = true;
}
if (msg.min_total_allocated_bitrate &&
*msg.min_total_allocated_bitrate != min_total_allocated_bitrate_) {
min_total_allocated_bitrate_ = *msg.min_total_allocated_bitrate;
pacing_changed = true;
if (use_min_allocatable_as_lower_bound_) {
ClampConstraints();
delay_based_bwe_->SetMinBitrate(min_data_rate_);
bandwidth_estimation_->SetMinMaxBitrate(min_data_rate_, max_data_rate_);
}
}
if (msg.max_padding_rate && *msg.max_padding_rate != max_padding_rate_) {
max_padding_rate_ = *msg.max_padding_rate;
pacing_changed = true;
}
if (pacing_changed)
update.pacer_config = GetPacingRates(msg.at_time);
return update;
}
NetworkControlUpdate GoogCcNetworkController::OnTargetRateConstraints(
TargetRateConstraints constraints) {
NetworkControlUpdate update;
update.probe_cluster_configs = ResetConstraints(constraints);
MaybeTriggerOnNetworkChanged(&update, constraints.at_time);
return update;
}
void GoogCcNetworkController::ClampConstraints() {
// TODO(holmer): We should make sure the default bitrates are set to 10 kbps,
// and that we don't try to set the min bitrate to 0 from any applications.
// The congestion controller should allow a min bitrate of 0.
min_data_rate_ = std::max(min_target_rate_, kCongestionControllerMinBitrate);
if (use_min_allocatable_as_lower_bound_) {
min_data_rate_ = std::max(min_data_rate_, min_total_allocated_bitrate_);
}
if (max_data_rate_ < min_data_rate_) {
RTC_LOG(LS_WARNING) << "max bitrate smaller than min bitrate";
max_data_rate_ = min_data_rate_;
}
if (starting_rate_ && starting_rate_ < min_data_rate_) {
RTC_LOG(LS_WARNING) << "start bitrate smaller than min bitrate";
starting_rate_ = min_data_rate_;
}
}
std::vector<ProbeClusterConfig> GoogCcNetworkController::ResetConstraints(
TargetRateConstraints new_constraints) {
min_target_rate_ = new_constraints.min_data_rate.value_or(DataRate::Zero());
max_data_rate_ =
new_constraints.max_data_rate.value_or(DataRate::PlusInfinity());
starting_rate_ = new_constraints.starting_rate;
ClampConstraints();
bandwidth_estimation_->SetBitrates(starting_rate_, min_data_rate_,
max_data_rate_, new_constraints.at_time);
if (starting_rate_)
delay_based_bwe_->SetStartBitrate(*starting_rate_);
delay_based_bwe_->SetMinBitrate(min_data_rate_);
return probe_controller_->SetBitrates(
min_data_rate_, starting_rate_.value_or(DataRate::Zero()), max_data_rate_,
new_constraints.at_time);
}
NetworkControlUpdate GoogCcNetworkController::OnTransportLossReport(
TransportLossReport msg) {
if (packet_feedback_only_)
return NetworkControlUpdate();
int64_t total_packets_delta =
msg.packets_received_delta + msg.packets_lost_delta;
bandwidth_estimation_->UpdatePacketsLost(
msg.packets_lost_delta, total_packets_delta, msg.receive_time);
return NetworkControlUpdate();
}
void GoogCcNetworkController::UpdateCongestionWindowSize() {
TimeDelta min_feedback_max_rtt = TimeDelta::Millis(
*std::min_element(feedback_max_rtts_.begin(), feedback_max_rtts_.end()));
const DataSize kMinCwnd = DataSize::Bytes(2 * 1500);
TimeDelta time_window =
min_feedback_max_rtt +
TimeDelta::Millis(
rate_control_settings_.GetCongestionWindowAdditionalTimeMs());
DataSize data_window = last_loss_based_target_rate_ * time_window;
if (current_data_window_) {
data_window =
std::max(kMinCwnd, (data_window + current_data_window_.value()) / 2);
} else {
data_window = std::max(kMinCwnd, data_window);
}
current_data_window_ = data_window;
}
NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(
TransportPacketsFeedback report) {
if (report.packet_feedbacks.empty()) {
// TODO(bugs.webrtc.org/10125): Design a better mechanism to safe-guard
// against building very large network queues.
return NetworkControlUpdate();
}
if (congestion_window_pushback_controller_) {
congestion_window_pushback_controller_->UpdateOutstandingData(
report.data_in_flight.bytes());
}
TimeDelta max_feedback_rtt = TimeDelta::MinusInfinity();
TimeDelta min_propagation_rtt = TimeDelta::PlusInfinity();
Timestamp max_recv_time = Timestamp::MinusInfinity();
std::vector<PacketResult> feedbacks = report.ReceivedWithSendInfo();
for (const auto& feedback : feedbacks)
max_recv_time = std::max(max_recv_time, feedback.receive_time);
for (const auto& feedback : feedbacks) {
TimeDelta feedback_rtt =
report.feedback_time - feedback.sent_packet.send_time;
TimeDelta min_pending_time = max_recv_time - feedback.receive_time;
TimeDelta propagation_rtt = feedback_rtt - min_pending_time;
max_feedback_rtt = std::max(max_feedback_rtt, feedback_rtt);
min_propagation_rtt = std::min(min_propagation_rtt, propagation_rtt);
}
if (max_feedback_rtt.IsFinite()) {
feedback_max_rtts_.push_back(max_feedback_rtt.ms());
const size_t kMaxFeedbackRttWindow = 32;
if (feedback_max_rtts_.size() > kMaxFeedbackRttWindow)
feedback_max_rtts_.pop_front();
// TODO(srte): Use time since last unacknowledged packet.
bandwidth_estimation_->UpdatePropagationRtt(report.feedback_time,
min_propagation_rtt);
}
if (packet_feedback_only_) {
if (!feedback_max_rtts_.empty()) {
int64_t sum_rtt_ms =
std::accumulate(feedback_max_rtts_.begin(), feedback_max_rtts_.end(),
static_cast<int64_t>(0));
int64_t mean_rtt_ms = sum_rtt_ms / feedback_max_rtts_.size();
if (delay_based_bwe_)
delay_based_bwe_->OnRttUpdate(TimeDelta::Millis(mean_rtt_ms));
}
TimeDelta feedback_min_rtt = TimeDelta::PlusInfinity();
for (const auto& packet_feedback : feedbacks) {
TimeDelta pending_time = max_recv_time - packet_feedback.receive_time;
TimeDelta rtt = report.feedback_time -
packet_feedback.sent_packet.send_time - pending_time;
// Value used for predicting NACK round trip time in FEC controller.
feedback_min_rtt = std::min(rtt, feedback_min_rtt);
}
if (feedback_min_rtt.IsFinite()) {
bandwidth_estimation_->UpdateRtt(feedback_min_rtt, report.feedback_time);
}
expected_packets_since_last_loss_update_ +=
report.PacketsWithFeedback().size();
for (const auto& packet_feedback : report.PacketsWithFeedback()) {
if (!packet_feedback.IsReceived())
lost_packets_since_last_loss_update_ += 1;
}
if (report.feedback_time > next_loss_update_) {
next_loss_update_ = report.feedback_time + kLossUpdateInterval;
bandwidth_estimation_->UpdatePacketsLost(
lost_packets_since_last_loss_update_,
expected_packets_since_last_loss_update_, report.feedback_time);
expected_packets_since_last_loss_update_ = 0;
lost_packets_since_last_loss_update_ = 0;
}
}
std::optional<int64_t> alr_start_time =
alr_detector_->GetApplicationLimitedRegionStartTime();
if (previously_in_alr_ && !alr_start_time.has_value()) {
int64_t now_ms = report.feedback_time.ms();
acknowledged_bitrate_estimator_->SetAlrEndedTime(report.feedback_time);
probe_controller_->SetAlrEndedTimeMs(now_ms);
}
previously_in_alr_ = alr_start_time.has_value();
acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(
report.SortedByReceiveTime());
auto acknowledged_bitrate = acknowledged_bitrate_estimator_->bitrate();
bandwidth_estimation_->SetAcknowledgedRate(acknowledged_bitrate,
report.feedback_time);
for (const auto& feedback : report.SortedByReceiveTime()) {
if (feedback.sent_packet.pacing_info.probe_cluster_id !=
PacedPacketInfo::kNotAProbe) {
probe_bitrate_estimator_->HandleProbeAndEstimateBitrate(feedback);
}
}
if (network_estimator_) {
network_estimator_->OnTransportPacketsFeedback(report);
SetNetworkStateEstimate(network_estimator_->GetCurrentEstimate());
}
std::optional<DataRate> probe_bitrate =
probe_bitrate_estimator_->FetchAndResetLastEstimatedBitrate();
if (ignore_probes_lower_than_network_estimate_ && probe_bitrate &&
estimate_ && *probe_bitrate < delay_based_bwe_->last_estimate() &&
*probe_bitrate < estimate_->link_capacity_lower) {
probe_bitrate.reset();
}
if (limit_probes_lower_than_throughput_estimate_ && probe_bitrate &&
acknowledged_bitrate) {
// Limit the backoff to something slightly below the acknowledged
// bitrate. ("Slightly below" because we want to drain the queues
// if we are actually overusing.)
// The acknowledged bitrate shouldn't normally be higher than the delay
// based estimate, but it could happen e.g. due to packet bursts or
// encoder overshoot. We use std::min to ensure that a probe result
// below the current BWE never causes an increase.
DataRate limit =
std::min(delay_based_bwe_->last_estimate(),
*acknowledged_bitrate * kProbeDropThroughputFraction);
probe_bitrate = std::max(*probe_bitrate, limit);
}
NetworkControlUpdate update;
bool recovered_from_overuse = false;
DelayBasedBwe::Result result;
result = delay_based_bwe_->IncomingPacketFeedbackVector(
report, acknowledged_bitrate, probe_bitrate, estimate_,
alr_start_time.has_value());
if (result.updated) {
if (result.probe) {
bandwidth_estimation_->SetSendBitrate(result.target_bitrate,
report.feedback_time);
}
// Since SetSendBitrate now resets the delay-based estimate, we have to
// call UpdateDelayBasedEstimate after SetSendBitrate.
bandwidth_estimation_->UpdateDelayBasedEstimate(report.feedback_time,
result.target_bitrate);
}
bandwidth_estimation_->UpdateLossBasedEstimator(
report, result.delay_detector_state, probe_bitrate,
alr_start_time.has_value());
if (result.updated) {
// Update the estimate in the ProbeController, in case we want to probe.
MaybeTriggerOnNetworkChanged(&update, report.feedback_time);
}
recovered_from_overuse = result.recovered_from_overuse;
if (recovered_from_overuse) {
probe_controller_->SetAlrStartTimeMs(alr_start_time);
auto probes = probe_controller_->RequestProbe(report.feedback_time);
update.probe_cluster_configs.insert(update.probe_cluster_configs.end(),
probes.begin(), probes.end());
}
// No valid RTT could be because send-side BWE isn't used, in which case
// we don't try to limit the outstanding packets.
if (rate_control_settings_.UseCongestionWindow() &&
max_feedback_rtt.IsFinite()) {
UpdateCongestionWindowSize();
}
if (congestion_window_pushback_controller_ && current_data_window_) {
congestion_window_pushback_controller_->SetDataWindow(
*current_data_window_);
} else {
update.congestion_window = current_data_window_;
}
return update;
}
NetworkControlUpdate GoogCcNetworkController::OnNetworkStateEstimate(
NetworkStateEstimate msg) {
if (!network_estimator_) {
SetNetworkStateEstimate(msg);
}
return NetworkControlUpdate();
}
void GoogCcNetworkController::SetNetworkStateEstimate(
std::optional<NetworkStateEstimate> estimate) {
auto prev_estimate = estimate_;
estimate_ = estimate;
if (estimate_ && (!prev_estimate ||
estimate_->update_time != prev_estimate->update_time)) {
env_.event_log().Log(std::make_unique<RtcEventRemoteEstimate>(
estimate_->link_capacity_lower, estimate_->link_capacity_upper));
probe_controller_->SetNetworkStateEstimate(*estimate_);
}
}
NetworkControlUpdate GoogCcNetworkController::GetNetworkState(
Timestamp at_time) const {
NetworkControlUpdate update;
update.target_rate = TargetTransferRate();
update.target_rate->network_estimate.at_time = at_time;
update.target_rate->network_estimate.loss_rate_ratio =
last_estimated_fraction_loss_.value_or(0) / 255.0;
update.target_rate->network_estimate.round_trip_time =
last_estimated_round_trip_time_;
update.target_rate->network_estimate.bwe_period =
delay_based_bwe_->GetExpectedBwePeriod();
update.target_rate->at_time = at_time;
update.target_rate->target_rate = last_pushback_target_rate_;
update.target_rate->stable_target_rate =
bandwidth_estimation_->GetEstimatedLinkCapacity();
update.pacer_config = GetPacingRates(at_time);
update.congestion_window = current_data_window_;
return update;
}
void GoogCcNetworkController::MaybeTriggerOnNetworkChanged(
NetworkControlUpdate* update,
Timestamp at_time) {
uint8_t fraction_loss = bandwidth_estimation_->fraction_loss();
TimeDelta round_trip_time = bandwidth_estimation_->round_trip_time();
DataRate loss_based_target_rate = bandwidth_estimation_->target_rate();
LossBasedState loss_based_state = bandwidth_estimation_->loss_based_state();
DataRate pushback_target_rate = loss_based_target_rate;
double cwnd_reduce_ratio = 0.0;
if (congestion_window_pushback_controller_) {
int64_t pushback_rate =
congestion_window_pushback_controller_->UpdateTargetBitrate(
loss_based_target_rate.bps());
pushback_rate = std::max<int64_t>(bandwidth_estimation_->GetMinBitrate(),
pushback_rate);
pushback_target_rate = DataRate::BitsPerSec(pushback_rate);
if (rate_control_settings_.UseCongestionWindowDropFrameOnly()) {
cwnd_reduce_ratio = static_cast<double>(loss_based_target_rate.bps() -
pushback_target_rate.bps()) /
loss_based_target_rate.bps();
}
}
DataRate stable_target_rate =
bandwidth_estimation_->GetEstimatedLinkCapacity();
stable_target_rate = std::min(stable_target_rate, pushback_target_rate);
if ((loss_based_target_rate != last_loss_based_target_rate_) ||
(loss_based_state != last_loss_base_state_) ||
(fraction_loss != last_estimated_fraction_loss_) ||
(round_trip_time != last_estimated_round_trip_time_) ||
(pushback_target_rate != last_pushback_target_rate_) ||
(stable_target_rate != last_stable_target_rate_)) {
last_loss_based_target_rate_ = loss_based_target_rate;
last_pushback_target_rate_ = pushback_target_rate;
last_estimated_fraction_loss_ = fraction_loss;
last_estimated_round_trip_time_ = round_trip_time;
last_stable_target_rate_ = stable_target_rate;
last_loss_base_state_ = loss_based_state;
alr_detector_->SetEstimatedBitrate(loss_based_target_rate.bps());
TimeDelta bwe_period = delay_based_bwe_->GetExpectedBwePeriod();
TargetTransferRate target_rate_msg;
target_rate_msg.at_time = at_time;
if (rate_control_settings_.UseCongestionWindowDropFrameOnly()) {
target_rate_msg.target_rate = loss_based_target_rate;
target_rate_msg.cwnd_reduce_ratio = cwnd_reduce_ratio;
} else {
target_rate_msg.target_rate = pushback_target_rate;
}
target_rate_msg.stable_target_rate = stable_target_rate;
target_rate_msg.network_estimate.at_time = at_time;
target_rate_msg.network_estimate.round_trip_time = round_trip_time;
target_rate_msg.network_estimate.loss_rate_ratio = fraction_loss / 255.0f;
target_rate_msg.network_estimate.bwe_period = bwe_period;
update->target_rate = target_rate_msg;
auto probes = probe_controller_->SetEstimatedBitrate(
loss_based_target_rate,
GetBandwidthLimitedCause(bandwidth_estimation_->loss_based_state(),
bandwidth_estimation_->IsRttAboveLimit(),
delay_based_bwe_->last_state()),
at_time);
update->probe_cluster_configs.insert(update->probe_cluster_configs.end(),
probes.begin(), probes.end());
update->pacer_config = GetPacingRates(at_time);
RTC_LOG(LS_VERBOSE) << "bwe " << at_time.ms() << " pushback_target_bps="
<< last_pushback_target_rate_.bps()
<< " estimate_bps=" << loss_based_target_rate.bps();
}
}
PacerConfig GoogCcNetworkController::GetPacingRates(Timestamp at_time) const {
// Pacing rate is based on target rate before congestion window pushback,
// because we don't want to build queues in the pacer when pushback occurs.
DataRate pacing_rate = DataRate::Zero();
if (pace_at_max_of_bwe_and_lower_link_capacity_ && estimate_ &&
!bandwidth_estimation_->PaceAtLossBasedEstimate()) {
pacing_rate =
std::max({min_total_allocated_bitrate_, estimate_->link_capacity_lower,
last_loss_based_target_rate_}) *
pacing_factor_;
} else {
pacing_rate =
std::max(min_total_allocated_bitrate_, last_loss_based_target_rate_) *
pacing_factor_;
}
if (limit_pacingfactor_by_upper_link_capacity_estimate_ && estimate_ &&
estimate_->link_capacity_upper.IsFinite() &&
pacing_rate > estimate_->link_capacity_upper) {
pacing_rate =
std::max({estimate_->link_capacity_upper, min_total_allocated_bitrate_,
last_loss_based_target_rate_});
}
DataRate padding_rate =
(last_loss_base_state_ == LossBasedState::kIncreaseUsingPadding)
? std::max(max_padding_rate_, last_loss_based_target_rate_)
: max_padding_rate_;
padding_rate = std::min(padding_rate, last_pushback_target_rate_);
PacerConfig msg;
msg.at_time = at_time;
msg.time_window = TimeDelta::Seconds(1);
msg.data_window = pacing_rate * msg.time_window;
msg.pad_window = padding_rate * msg.time_window;
return msg;
}
} // namespace webrtc