/* * 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 #include #include #include #include #include #include #include "absl/strings/match.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "api/field_trials_view.h" #include "api/network_state_predictor.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 "modules/remote_bitrate_estimator/test/bwe_test_logging.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; bool IsEnabled(const FieldTrialsView* config, absl::string_view key) { return absl::StartsWith(config->Lookup(key), "Enabled"); } bool IsNotDisabled(const FieldTrialsView* config, absl::string_view key) { return !absl::StartsWith(config->Lookup(key), "Disabled"); } 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) : key_value_config_(config.key_value_config ? config.key_value_config : &trial_based_config_), event_log_(config.event_log), 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_( IsNotDisabled(key_value_config_, "WebRTC-Bwe-MinAllocAsLowerBound")), ignore_probes_lower_than_network_estimate_(IsNotDisabled( key_value_config_, "WebRTC-Bwe-IgnoreProbesLowerThanNetworkStateEstimate")), limit_probes_lower_than_throughput_estimate_( IsNotDisabled(key_value_config_, "WebRTC-Bwe-LimitProbesLowerThanThroughputEstimate")), rate_control_settings_( RateControlSettings::ParseFromKeyValueConfig(key_value_config_)), pace_at_max_of_bwe_and_lower_link_capacity_( IsEnabled(key_value_config_, "WebRTC-Bwe-PaceAtMaxOfBweAndLowerLinkCapacity")), probe_controller_( new ProbeController(key_value_config_, config.event_log)), congestion_window_pushback_controller_( rate_control_settings_.UseCongestionWindowPushback() ? std::make_unique( key_value_config_) : nullptr), bandwidth_estimation_( std::make_unique(key_value_config_, event_log_)), alr_detector_( std::make_unique(key_value_config_, config.event_log)), probe_bitrate_estimator_(new ProbeBitrateEstimator(config.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(key_value_config_, event_log_, network_state_predictor_.get())), acknowledged_bitrate_estimator_( AcknowledgedBitrateEstimatorInterface::Create(key_value_config_)), 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_}, key_value_config_->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_) { absl::optional 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(key_value_config_); probe_bitrate_estimator_.reset(new ProbeBitrateEstimator(event_log_)); if (network_estimator_) network_estimator_->OnRouteChange(msg); delay_based_bwe_.reset(new DelayBasedBwe(key_value_config_, 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); } absl::optional 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); absl::optional 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); BWE_TEST_LOGGING_PLOT(1, "REMB_kbps", msg.receive_time.ms(), msg.bandwidth.bps() / 1000); 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 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 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(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; } } absl::optional 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); auto prev_estimate = estimate_; estimate_ = network_estimator_->GetCurrentEstimate(); // TODO(srte): Make OnTransportPacketsFeedback signal whether the state // changed to avoid the need for this check. if (estimate_ && (!prev_estimate || estimate_->last_feed_time != prev_estimate->last_feed_time)) { event_log_->Log(std::make_unique( estimate_->link_capacity_lower, estimate_->link_capacity_upper)); probe_controller_->SetNetworkStateEstimate(*estimate_); } } absl::optional 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) { estimate_ = msg; return NetworkControlUpdate(); } 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; BWE_TEST_LOGGING_PLOT(1, "fraction_loss_%", at_time.ms(), (fraction_loss * 100) / 256); BWE_TEST_LOGGING_PLOT(1, "rtt_ms", at_time.ms(), round_trip_time.ms()); BWE_TEST_LOGGING_PLOT(1, "Target_bitrate_kbps", at_time.ms(), loss_based_target_rate.kbps()); 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(bandwidth_estimation_->GetMinBitrate(), pushback_rate); pushback_target_rate = DataRate::BitsPerSec(pushback_rate); if (rate_control_settings_.UseCongestionWindowDropFrameOnly()) { cwnd_reduce_ratio = static_cast(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_; } 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