Source code
Revision control
Copy as Markdown
Other Tools
/*
* 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 <optional>
#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::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<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::BitsPerSec(std::max<double>(
bandwidth_estimate_.bps() + sign * kMinRateChangeBps, 0)),
DataRate::BitsPerSec(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