/* * 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/pcc/pcc_network_controller.h" #include #include "absl/types/optional.h" #include "api/units/data_size.h" #include "rtc_base/checks.h" namespace webrtc { namespace pcc { namespace { constexpr int64_t kInitialRttMs = 200; constexpr int64_t kInitialBandwidthKbps = 300; constexpr double kMonitorIntervalDurationRatio = 1; constexpr double kDefaultSamplingStep = 0.05; constexpr double kTimeoutRatio = 2; constexpr double kAlphaForRtt = 0.9; constexpr double kSlowStartModeIncrease = 1.5; constexpr double kAlphaForPacketInterval = 0.9; constexpr int64_t kMinPacketsNumberPerInterval = 20; const TimeDelta kMinDurationOfMonitorInterval = TimeDelta::Millis(50); const TimeDelta kStartupDuration = TimeDelta::Millis(500); constexpr double kMinRateChangeBps = 4000; constexpr DataRate kMinRateHaveMultiplicativeRateChange = DataRate::BitsPerSec( static_cast(kMinRateChangeBps / kDefaultSamplingStep)); // Bitrate controller constants. constexpr double kInitialConversionFactor = 5; constexpr double kInitialDynamicBoundary = 0.1; constexpr double kDynamicBoundaryIncrement = 0.1; // Utility function parameters. constexpr double kRttGradientCoefficientBps = 0.005; constexpr double kLossCoefficientBps = 10; constexpr double kThroughputCoefficient = 0.001; constexpr double kThroughputPower = 0.9; constexpr double kRttGradientThreshold = 0.01; constexpr double kDelayGradientNegativeBound = 0.1; constexpr int64_t kNumberOfPacketsToKeep = 20; const uint64_t kRandomSeed = 100; } // namespace PccNetworkController::PccNetworkController(NetworkControllerConfig config) : start_time_(Timestamp::PlusInfinity()), last_sent_packet_time_(Timestamp::PlusInfinity()), smoothed_packets_sending_interval_(TimeDelta::Zero()), mode_(Mode::kStartup), default_bandwidth_(DataRate::KilobitsPerSec(kInitialBandwidthKbps)), bandwidth_estimate_(default_bandwidth_), rtt_tracker_(TimeDelta::Millis(kInitialRttMs), kAlphaForRtt), monitor_interval_timeout_(TimeDelta::Millis(kInitialRttMs) * kTimeoutRatio), monitor_interval_length_strategy_(MonitorIntervalLengthStrategy::kFixed), monitor_interval_duration_ratio_(kMonitorIntervalDurationRatio), sampling_step_(kDefaultSamplingStep), monitor_interval_timeout_ratio_(kTimeoutRatio), min_packets_number_per_interval_(kMinPacketsNumberPerInterval), bitrate_controller_(kInitialConversionFactor, kInitialDynamicBoundary, kDynamicBoundaryIncrement, kRttGradientCoefficientBps, kLossCoefficientBps, kThroughputCoefficient, kThroughputPower, kRttGradientThreshold, kDelayGradientNegativeBound), monitor_intervals_duration_(TimeDelta::Zero()), complete_feedback_monitor_interval_number_(0), random_generator_(kRandomSeed) { if (config.constraints.starting_rate) { default_bandwidth_ = *config.constraints.starting_rate; bandwidth_estimate_ = default_bandwidth_; } } PccNetworkController::~PccNetworkController() {} NetworkControlUpdate PccNetworkController::CreateRateUpdate( Timestamp at_time) const { DataRate sending_rate = DataRate::Zero(); if (monitor_intervals_.empty() || (monitor_intervals_.size() >= monitor_intervals_bitrates_.size() && at_time >= monitor_intervals_.back().GetEndTime())) { sending_rate = bandwidth_estimate_; } else { sending_rate = monitor_intervals_.back().GetTargetSendingRate(); } // Set up config when sending rate is computed. NetworkControlUpdate update; // Set up target rate to encoder. TargetTransferRate target_rate_msg; target_rate_msg.at_time = at_time; target_rate_msg.network_estimate.at_time = at_time; target_rate_msg.network_estimate.round_trip_time = rtt_tracker_.GetRtt(); // TODO(koloskova): Add correct estimate. target_rate_msg.network_estimate.loss_rate_ratio = 0; target_rate_msg.network_estimate.bwe_period = monitor_interval_duration_ratio_ * rtt_tracker_.GetRtt(); target_rate_msg.target_rate = sending_rate; update.target_rate = target_rate_msg; // Set up pacing/padding target rate. PacerConfig pacer_config; pacer_config.at_time = at_time; pacer_config.time_window = TimeDelta::Millis(1); pacer_config.data_window = sending_rate * pacer_config.time_window; pacer_config.pad_window = sending_rate * pacer_config.time_window; update.pacer_config = pacer_config; return update; } NetworkControlUpdate PccNetworkController::OnSentPacket(SentPacket msg) { // Start new monitor interval if previous has finished. // Monitor interval is initialized in OnProcessInterval function. if (start_time_.IsInfinite()) { start_time_ = msg.send_time; monitor_intervals_duration_ = kStartupDuration; monitor_intervals_bitrates_ = {bandwidth_estimate_}; monitor_intervals_.emplace_back(bandwidth_estimate_, msg.send_time, monitor_intervals_duration_); complete_feedback_monitor_interval_number_ = 0; } if (last_sent_packet_time_.IsFinite()) { smoothed_packets_sending_interval_ = (msg.send_time - last_sent_packet_time_) * kAlphaForPacketInterval + (1 - kAlphaForPacketInterval) * smoothed_packets_sending_interval_; } last_sent_packet_time_ = msg.send_time; if (!monitor_intervals_.empty() && msg.send_time >= monitor_intervals_.back().GetEndTime() && monitor_intervals_bitrates_.size() > monitor_intervals_.size()) { // Start new monitor interval. monitor_intervals_.emplace_back( monitor_intervals_bitrates_[monitor_intervals_.size()], msg.send_time, monitor_intervals_duration_); } if (IsTimeoutExpired(msg.send_time)) { DataSize received_size = DataSize::Zero(); for (size_t i = 1; i < last_received_packets_.size(); ++i) { received_size += last_received_packets_[i].sent_packet.size; } TimeDelta sending_time = TimeDelta::Zero(); if (last_received_packets_.size() > 0) sending_time = last_received_packets_.back().receive_time - last_received_packets_.front().receive_time; DataRate receiving_rate = bandwidth_estimate_; if (sending_time > TimeDelta::Zero()) receiving_rate = received_size / sending_time; bandwidth_estimate_ = std::min(bandwidth_estimate_ * 0.5, receiving_rate); if (mode_ == Mode::kSlowStart) mode_ = Mode::kOnlineLearning; } if (mode_ == Mode::kStartup && msg.send_time - start_time_ >= kStartupDuration) { DataSize received_size = DataSize::Zero(); for (size_t i = 1; i < last_received_packets_.size(); ++i) { received_size += last_received_packets_[i].sent_packet.size; } TimeDelta sending_time = TimeDelta::Zero(); if (last_received_packets_.size() > 0) sending_time = last_received_packets_.back().receive_time - last_received_packets_.front().receive_time; DataRate receiving_rate = bandwidth_estimate_; if (sending_time > TimeDelta::Zero()) receiving_rate = received_size / sending_time; bandwidth_estimate_ = receiving_rate; monitor_intervals_.clear(); mode_ = Mode::kSlowStart; monitor_intervals_duration_ = ComputeMonitorIntervalsDuration(); monitor_intervals_bitrates_ = {bandwidth_estimate_}; monitor_intervals_.emplace_back(bandwidth_estimate_, msg.send_time, monitor_intervals_duration_); bandwidth_estimate_ = bandwidth_estimate_ * (1 / kSlowStartModeIncrease); complete_feedback_monitor_interval_number_ = 0; return CreateRateUpdate(msg.send_time); } if (IsFeedbackCollectionDone() || IsTimeoutExpired(msg.send_time)) { // Creating new monitor intervals. monitor_intervals_.clear(); monitor_interval_timeout_ = rtt_tracker_.GetRtt() * monitor_interval_timeout_ratio_; monitor_intervals_duration_ = ComputeMonitorIntervalsDuration(); complete_feedback_monitor_interval_number_ = 0; // Compute bitrates and start first monitor interval. if (mode_ == Mode::kSlowStart) { monitor_intervals_bitrates_ = {kSlowStartModeIncrease * bandwidth_estimate_}; monitor_intervals_.emplace_back( kSlowStartModeIncrease * bandwidth_estimate_, msg.send_time, monitor_intervals_duration_); } else { RTC_DCHECK(mode_ == Mode::kOnlineLearning || mode_ == Mode::kDoubleCheck); monitor_intervals_.clear(); int64_t sign = 2 * (random_generator_.Rand(0, 1) % 2) - 1; RTC_DCHECK_GE(sign, -1); RTC_DCHECK_LE(sign, 1); if (bandwidth_estimate_ >= kMinRateHaveMultiplicativeRateChange) { monitor_intervals_bitrates_ = { bandwidth_estimate_ * (1 + sign * sampling_step_), bandwidth_estimate_ * (1 - sign * sampling_step_)}; } else { monitor_intervals_bitrates_ = { DataRate::BitsPerSec(std::max( bandwidth_estimate_.bps() + sign * kMinRateChangeBps, 0)), DataRate::BitsPerSec(std::max( bandwidth_estimate_.bps() - sign * kMinRateChangeBps, 0))}; } monitor_intervals_.emplace_back(monitor_intervals_bitrates_[0], msg.send_time, monitor_intervals_duration_); } } return CreateRateUpdate(msg.send_time); } TimeDelta PccNetworkController::ComputeMonitorIntervalsDuration() const { TimeDelta monitor_intervals_duration = TimeDelta::Zero(); if (monitor_interval_length_strategy_ == MonitorIntervalLengthStrategy::kAdaptive) { monitor_intervals_duration = std::max( rtt_tracker_.GetRtt() * monitor_interval_duration_ratio_, smoothed_packets_sending_interval_ * min_packets_number_per_interval_); } else { RTC_DCHECK(monitor_interval_length_strategy_ == MonitorIntervalLengthStrategy::kFixed); monitor_intervals_duration = smoothed_packets_sending_interval_ * min_packets_number_per_interval_; } monitor_intervals_duration = std::max(kMinDurationOfMonitorInterval, monitor_intervals_duration); return monitor_intervals_duration; } bool PccNetworkController::IsTimeoutExpired(Timestamp current_time) const { if (complete_feedback_monitor_interval_number_ >= monitor_intervals_.size()) { return false; } return current_time - monitor_intervals_[complete_feedback_monitor_interval_number_] .GetEndTime() >= monitor_interval_timeout_; } bool PccNetworkController::IsFeedbackCollectionDone() const { return complete_feedback_monitor_interval_number_ >= monitor_intervals_bitrates_.size(); } NetworkControlUpdate PccNetworkController::OnTransportPacketsFeedback( TransportPacketsFeedback msg) { if (msg.packet_feedbacks.empty()) return NetworkControlUpdate(); // Save packets to last_received_packets_ array. for (const PacketResult& packet_result : msg.ReceivedWithSendInfo()) { last_received_packets_.push_back(packet_result); } while (last_received_packets_.size() > kNumberOfPacketsToKeep) { last_received_packets_.pop_front(); } rtt_tracker_.OnPacketsFeedback(msg.PacketsWithFeedback(), msg.feedback_time); // Skip rate update in case when online learning mode just started, but // corresponding monitor intervals were not started yet. if (mode_ == Mode::kOnlineLearning && monitor_intervals_bitrates_.size() < 2) { return NetworkControlUpdate(); } if (!IsFeedbackCollectionDone() && !monitor_intervals_.empty()) { while (complete_feedback_monitor_interval_number_ < monitor_intervals_.size()) { monitor_intervals_[complete_feedback_monitor_interval_number_] .OnPacketsFeedback(msg.PacketsWithFeedback()); if (!monitor_intervals_[complete_feedback_monitor_interval_number_] .IsFeedbackCollectionDone()) break; ++complete_feedback_monitor_interval_number_; } } if (IsFeedbackCollectionDone()) { if (mode_ == Mode::kDoubleCheck) { mode_ = Mode::kOnlineLearning; } else if (NeedDoubleCheckMeasurments()) { mode_ = Mode::kDoubleCheck; } if (mode_ != Mode::kDoubleCheck) UpdateSendingRateAndMode(); } return NetworkControlUpdate(); } bool PccNetworkController::NeedDoubleCheckMeasurments() const { if (mode_ == Mode::kSlowStart) { return false; } double first_loss_rate = monitor_intervals_[0].GetLossRate(); double second_loss_rate = monitor_intervals_[1].GetLossRate(); DataRate first_bitrate = monitor_intervals_[0].GetTargetSendingRate(); DataRate second_bitrate = monitor_intervals_[1].GetTargetSendingRate(); if ((first_bitrate.bps() - second_bitrate.bps()) * (first_loss_rate - second_loss_rate) < 0) { return true; } return false; } void PccNetworkController::UpdateSendingRateAndMode() { if (monitor_intervals_.empty() || !IsFeedbackCollectionDone()) { return; } if (mode_ == Mode::kSlowStart) { DataRate old_bandwidth_estimate = bandwidth_estimate_; bandwidth_estimate_ = bitrate_controller_ .ComputeRateUpdateForSlowStartMode(monitor_intervals_[0]) .value_or(bandwidth_estimate_); if (bandwidth_estimate_ <= old_bandwidth_estimate) mode_ = Mode::kOnlineLearning; } else { RTC_DCHECK(mode_ == Mode::kOnlineLearning); bandwidth_estimate_ = bitrate_controller_.ComputeRateUpdateForOnlineLearningMode( monitor_intervals_, bandwidth_estimate_); } } NetworkControlUpdate PccNetworkController::OnNetworkAvailability( NetworkAvailability msg) { return NetworkControlUpdate(); } NetworkControlUpdate PccNetworkController::OnNetworkRouteChange( NetworkRouteChange msg) { return NetworkControlUpdate(); } NetworkControlUpdate PccNetworkController::OnProcessInterval( ProcessInterval msg) { return CreateRateUpdate(msg.at_time); } NetworkControlUpdate PccNetworkController::OnTargetRateConstraints( TargetRateConstraints msg) { return NetworkControlUpdate(); } NetworkControlUpdate PccNetworkController::OnRemoteBitrateReport( RemoteBitrateReport) { return NetworkControlUpdate(); } NetworkControlUpdate PccNetworkController::OnRoundTripTimeUpdate( RoundTripTimeUpdate) { return NetworkControlUpdate(); } NetworkControlUpdate PccNetworkController::OnTransportLossReport( TransportLossReport) { return NetworkControlUpdate(); } NetworkControlUpdate PccNetworkController::OnStreamsConfig(StreamsConfig msg) { return NetworkControlUpdate(); } NetworkControlUpdate PccNetworkController::OnReceivedPacket( ReceivedPacket msg) { return NetworkControlUpdate(); } NetworkControlUpdate PccNetworkController::OnNetworkStateEstimate( NetworkStateEstimate msg) { return NetworkControlUpdate(); } } // namespace pcc } // namespace webrtc