diff --git a/modules/bitrate_controller/BUILD.gn b/modules/bitrate_controller/BUILD.gn index 72046f0a01..5bf57f623c 100644 --- a/modules/bitrate_controller/BUILD.gn +++ b/modules/bitrate_controller/BUILD.gn @@ -35,6 +35,7 @@ rtc_static_library("bitrate_controller") { "../../logging:rtc_event_log_api", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", + "../../rtc_base/experiments:field_trial_parser", "../../system_wrappers", "../../system_wrappers:field_trial", "../../system_wrappers:metrics", diff --git a/modules/bitrate_controller/send_side_bandwidth_estimation.cc b/modules/bitrate_controller/send_side_bandwidth_estimation.cc index cc108a95b0..f90ccce549 100644 --- a/modules/bitrate_controller/send_side_bandwidth_estimation.cc +++ b/modules/bitrate_controller/send_side_bandwidth_estimation.cc @@ -104,8 +104,21 @@ bool ReadBweLossExperimentParameters(float* low_loss_threshold, } } // namespace +RttBasedBackoffConfig::RttBasedBackoffConfig() + : rtt_limit("limit", TimeDelta::PlusInfinity()), + drop_fraction("fraction", 0.5), + drop_interval("interval", TimeDelta::ms(300)) { + std::string trial_string = + field_trial::FindFullName("WebRTC-Bwe-MaxRttLimit"); + ParseFieldTrial({&rtt_limit, &drop_fraction, &drop_interval}, trial_string); +} +RttBasedBackoffConfig::RttBasedBackoffConfig(const RttBasedBackoffConfig&) = + default; +RttBasedBackoffConfig::~RttBasedBackoffConfig() = default; + SendSideBandwidthEstimation::SendSideBandwidthEstimation(RtcEventLog* event_log) - : lost_packets_since_last_loss_update_(0), + : rtt_backoff_config_(RttBasedBackoffConfig()), + lost_packets_since_last_loss_update_(0), expected_packets_since_last_loss_update_(0), current_bitrate_(DataRate::Zero()), min_bitrate_configured_( @@ -119,6 +132,10 @@ SendSideBandwidthEstimation::SendSideBandwidthEstimation(RtcEventLog* event_log) last_fraction_loss_(0), last_logged_fraction_loss_(0), last_round_trip_time_(TimeDelta::Zero()), + // By initializing this to plus infinity, we make sure that we never + // trigger rtt backoff unless packet feedback is enabled. + last_propagation_rtt_update_(Timestamp::PlusInfinity()), + last_propagation_rtt_(TimeDelta::Zero()), bwe_incoming_(DataRate::Zero()), delay_based_bitrate_(DataRate::Zero()), time_last_decrease_(Timestamp::MinusInfinity()), @@ -295,6 +312,16 @@ void SendSideBandwidthEstimation::UpdateRtt(TimeDelta rtt, Timestamp at_time) { void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) { DataRate new_bitrate = current_bitrate_; + TimeDelta time_since_rtt = at_time - last_propagation_rtt_update_; + if (time_since_rtt + last_propagation_rtt_ > rtt_backoff_config_.rtt_limit) { + if (at_time - time_last_decrease_ >= rtt_backoff_config_.drop_interval) { + time_last_decrease_ = at_time; + new_bitrate = current_bitrate_ * rtt_backoff_config_.drop_fraction; + } + CapBitrateToThresholds(at_time, new_bitrate); + return; + } + // We trust the REMB and/or delay-based estimate during the first 2 seconds if // we haven't had any packet loss reported, to allow startup bitrate probing. if (last_fraction_loss_ == 0 && IsInStartPhase(at_time)) { @@ -382,6 +409,13 @@ void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) { CapBitrateToThresholds(at_time, new_bitrate); } +void SendSideBandwidthEstimation::UpdatePropagationRtt( + Timestamp at_time, + TimeDelta propagation_rtt) { + last_propagation_rtt_update_ = at_time; + last_propagation_rtt_ = propagation_rtt; +} + bool SendSideBandwidthEstimation::IsInStartPhase(Timestamp at_time) const { return first_report_time_.IsInfinite() || at_time - first_report_time_ < kStartPhase; diff --git a/modules/bitrate_controller/send_side_bandwidth_estimation.h b/modules/bitrate_controller/send_side_bandwidth_estimation.h index 2c8b4ee3d5..25ee7cf97b 100644 --- a/modules/bitrate_controller/send_side_bandwidth_estimation.h +++ b/modules/bitrate_controller/send_side_bandwidth_estimation.h @@ -19,21 +19,35 @@ #include "absl/types/optional.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/experiments/field_trial_units.h" namespace webrtc { class RtcEventLog; +struct RttBasedBackoffConfig { + RttBasedBackoffConfig(); + RttBasedBackoffConfig(const RttBasedBackoffConfig&); + RttBasedBackoffConfig& operator=(const RttBasedBackoffConfig&) = default; + ~RttBasedBackoffConfig(); + FieldTrialParameter rtt_limit; + FieldTrialParameter drop_fraction; + FieldTrialParameter drop_interval; +}; + class SendSideBandwidthEstimation { public: SendSideBandwidthEstimation() = delete; explicit SendSideBandwidthEstimation(RtcEventLog* event_log); - virtual ~SendSideBandwidthEstimation(); + ~SendSideBandwidthEstimation(); void CurrentEstimate(int* bitrate, uint8_t* loss, int64_t* rtt) const; // Call periodically to update estimate. void UpdateEstimate(Timestamp at_time); + void OnSentPacket(SentPacket sent_packet); + void UpdatePropagationRtt(Timestamp at_time, TimeDelta feedback_rtt); // Call when we receive a RTCP message with TMMBR or REMB. void UpdateReceiverEstimate(Timestamp at_time, DataRate bandwidth); @@ -79,6 +93,8 @@ class SendSideBandwidthEstimation { // set |current_bitrate_| to the capped value and updates the event log. void CapBitrateToThresholds(Timestamp at_time, DataRate bitrate); + RttBasedBackoffConfig rtt_backoff_config_; + std::deque > min_bitrate_history_; // incoming filters @@ -98,6 +114,9 @@ class SendSideBandwidthEstimation { uint8_t last_logged_fraction_loss_; TimeDelta last_round_trip_time_; + Timestamp last_propagation_rtt_update_; + TimeDelta last_propagation_rtt_; + DataRate bwe_incoming_; DataRate delay_based_bitrate_; Timestamp time_last_decrease_; diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc index 4ab9694f37..b095c2c1c4 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.cc @@ -250,6 +250,13 @@ NetworkControlUpdate GoogCcNetworkController::OnSentPacket( SentPacket sent_packet) { alr_detector_->OnBytesSent(sent_packet.size.bytes(), sent_packet.send_time.ms()); + 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()); + } return NetworkControlUpdate(); } @@ -331,24 +338,30 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportLossReport( NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( TransportPacketsFeedback report) { - TimeDelta feedback_max_rtt = TimeDelta::MinusInfinity(); + TimeDelta max_feedback_rtt = TimeDelta::MinusInfinity(); + TimeDelta min_propagation_rtt = TimeDelta::PlusInfinity(); Timestamp max_recv_time = Timestamp::MinusInfinity(); - for (const auto& packet_feedback : report.ReceivedWithSendInfo()) { - TimeDelta rtt = - report.feedback_time - packet_feedback.sent_packet->send_time; - // max() is used to account for feedback being delayed by the - // receiver. - feedback_max_rtt = std::max(feedback_max_rtt, rtt); - max_recv_time = std::max(max_recv_time, packet_feedback.receive_time); + + 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 = feedback.receive_time - max_recv_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); } - absl::optional min_feedback_max_rtt_ms; - if (feedback_max_rtt.IsFinite()) { - feedback_max_rtts_.push_back(feedback_max_rtt.ms()); + + 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(); - min_feedback_max_rtt_ms.emplace(*std::min_element( - feedback_max_rtts_.begin(), feedback_max_rtts_.end())); + bandwidth_estimation_->UpdatePropagationRtt(report.feedback_time, + min_propagation_rtt); } if (packet_feedback_only_) { if (!feedback_max_rtts_.empty()) { @@ -359,7 +372,7 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( } TimeDelta feedback_min_rtt = TimeDelta::PlusInfinity(); - for (const auto& packet_feedback : report.ReceivedWithSendInfo()) { + for (const auto& packet_feedback : feedbacks) { TimeDelta pending_time = packet_feedback.receive_time - max_recv_time; TimeDelta rtt = report.feedback_time - packet_feedback.sent_packet->send_time - pending_time; @@ -428,10 +441,13 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( // 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 (in_cwnd_experiment_ && min_feedback_max_rtt_ms) { + if (in_cwnd_experiment_ && max_feedback_rtt.IsFinite()) { + int64_t min_feedback_max_rtt_ms = + *std::min_element(feedback_max_rtts_.begin(), feedback_max_rtts_.end()); + const DataSize kMinCwnd = DataSize::bytes(2 * 1500); TimeDelta time_window = - TimeDelta::ms(*min_feedback_max_rtt_ms + accepted_queue_ms_); + TimeDelta::ms(min_feedback_max_rtt_ms + accepted_queue_ms_); DataSize data_window = last_bandwidth_ * time_window; if (current_data_window_) { data_window = @@ -440,7 +456,7 @@ NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback( data_window = std::max(kMinCwnd, data_window); } current_data_window_ = data_window; - RTC_LOG(LS_INFO) << "Feedback rtt: " << *min_feedback_max_rtt_ms + RTC_LOG(LS_INFO) << "Feedback rtt: " << min_feedback_max_rtt_ms << " Bitrate: " << last_bandwidth_.bps(); } update.congestion_window = current_data_window_; diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control.h b/modules/congestion_controller/goog_cc/goog_cc_network_control.h index f7efda3962..64401a7fcf 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control.h +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control.h @@ -73,6 +73,8 @@ class GoogCcNetworkController : public NetworkControllerInterface { absl::optional initial_config_; + bool first_packet_sent_ = false; + Timestamp next_loss_update_ = Timestamp::MinusInfinity(); int lost_packets_since_last_loss_update_ = 0; int expected_packets_since_last_loss_update_ = 0;