| /* |
| * 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 <algorithm> |
| |
| #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<int64_t>(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::kbps(kInitialBandwidthKbps)), |
| bandwidth_estimate_(default_bandwidth_), |
| rtt_tracker_(TimeDelta::ms(kInitialRttMs), kAlphaForRtt), |
| monitor_interval_timeout_(TimeDelta::ms(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::ms(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<DataRate>(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::bps(std::max<double>( |
| bandwidth_estimate_.bps() + sign * kMinRateChangeBps, 0)), |
| DataRate::bps(std::max<double>( |
| 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 |