140 lines
5.8 KiB
C++
140 lines
5.8 KiB
C++
|
/*
|
||
|
* 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/bitrate_controller.h"
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <cmath>
|
||
|
#include <cstdlib>
|
||
|
#include <memory>
|
||
|
#include <utility>
|
||
|
#include <vector>
|
||
|
|
||
|
|
||
|
namespace webrtc {
|
||
|
namespace pcc {
|
||
|
|
||
|
PccBitrateController::PccBitrateController(double initial_conversion_factor,
|
||
|
double initial_dynamic_boundary,
|
||
|
double dynamic_boundary_increment,
|
||
|
double rtt_gradient_coefficient,
|
||
|
double loss_coefficient,
|
||
|
double throughput_coefficient,
|
||
|
double throughput_power,
|
||
|
double rtt_gradient_threshold,
|
||
|
double delay_gradient_negative_bound)
|
||
|
: PccBitrateController(initial_conversion_factor,
|
||
|
initial_dynamic_boundary,
|
||
|
dynamic_boundary_increment,
|
||
|
std::make_unique<ModifiedVivaceUtilityFunction>(
|
||
|
rtt_gradient_coefficient,
|
||
|
loss_coefficient,
|
||
|
throughput_coefficient,
|
||
|
throughput_power,
|
||
|
rtt_gradient_threshold,
|
||
|
delay_gradient_negative_bound)) {}
|
||
|
|
||
|
PccBitrateController::PccBitrateController(
|
||
|
double initial_conversion_factor,
|
||
|
double initial_dynamic_boundary,
|
||
|
double dynamic_boundary_increment,
|
||
|
std::unique_ptr<PccUtilityFunctionInterface> utility_function)
|
||
|
: consecutive_boundary_adjustments_number_(0),
|
||
|
initial_dynamic_boundary_(initial_dynamic_boundary),
|
||
|
dynamic_boundary_increment_(dynamic_boundary_increment),
|
||
|
utility_function_(std::move(utility_function)),
|
||
|
step_size_adjustments_number_(0),
|
||
|
initial_conversion_factor_(initial_conversion_factor) {}
|
||
|
|
||
|
PccBitrateController::~PccBitrateController() = default;
|
||
|
|
||
|
double PccBitrateController::ComputeStepSize(double utility_gradient) {
|
||
|
// Computes number of consecutive step size adjustments.
|
||
|
if (utility_gradient > 0) {
|
||
|
step_size_adjustments_number_ =
|
||
|
std::max<int64_t>(step_size_adjustments_number_ + 1, 1);
|
||
|
} else if (utility_gradient < 0) {
|
||
|
step_size_adjustments_number_ =
|
||
|
std::min<int64_t>(step_size_adjustments_number_ - 1, -1);
|
||
|
} else {
|
||
|
step_size_adjustments_number_ = 0;
|
||
|
}
|
||
|
// Computes step size amplifier.
|
||
|
int64_t step_size_amplifier = 1;
|
||
|
if (std::abs(step_size_adjustments_number_) <= 3) {
|
||
|
step_size_amplifier =
|
||
|
std::max<int64_t>(std::abs(step_size_adjustments_number_), 1);
|
||
|
} else {
|
||
|
step_size_amplifier = 2 * std::abs(step_size_adjustments_number_) - 3;
|
||
|
}
|
||
|
return step_size_amplifier * initial_conversion_factor_;
|
||
|
}
|
||
|
|
||
|
double PccBitrateController::ApplyDynamicBoundary(double rate_change,
|
||
|
double bitrate) {
|
||
|
double rate_change_abs = std::abs(rate_change);
|
||
|
int64_t rate_change_sign = (rate_change > 0) ? 1 : -1;
|
||
|
if (consecutive_boundary_adjustments_number_ * rate_change_sign < 0) {
|
||
|
consecutive_boundary_adjustments_number_ = 0;
|
||
|
}
|
||
|
double dynamic_change_boundary =
|
||
|
initial_dynamic_boundary_ +
|
||
|
std::abs(consecutive_boundary_adjustments_number_) *
|
||
|
dynamic_boundary_increment_;
|
||
|
double boundary = bitrate * dynamic_change_boundary;
|
||
|
if (rate_change_abs > boundary) {
|
||
|
consecutive_boundary_adjustments_number_ += rate_change_sign;
|
||
|
return boundary * rate_change_sign;
|
||
|
}
|
||
|
// Rate change smaller than boundary. Reset boundary to the smallest possible
|
||
|
// that would allow the change.
|
||
|
while (rate_change_abs <= boundary &&
|
||
|
consecutive_boundary_adjustments_number_ * rate_change_sign > 0) {
|
||
|
consecutive_boundary_adjustments_number_ -= rate_change_sign;
|
||
|
dynamic_change_boundary =
|
||
|
initial_dynamic_boundary_ +
|
||
|
std::abs(consecutive_boundary_adjustments_number_) *
|
||
|
dynamic_boundary_increment_;
|
||
|
boundary = bitrate * dynamic_change_boundary;
|
||
|
}
|
||
|
consecutive_boundary_adjustments_number_ += rate_change_sign;
|
||
|
return rate_change;
|
||
|
}
|
||
|
|
||
|
absl::optional<DataRate>
|
||
|
PccBitrateController::ComputeRateUpdateForSlowStartMode(
|
||
|
const PccMonitorInterval& monitor_interval) {
|
||
|
double utility_value = utility_function_->Compute(monitor_interval);
|
||
|
if (previous_utility_.has_value() && utility_value <= previous_utility_) {
|
||
|
return absl::nullopt;
|
||
|
}
|
||
|
previous_utility_ = utility_value;
|
||
|
return monitor_interval.GetTargetSendingRate();
|
||
|
}
|
||
|
|
||
|
DataRate PccBitrateController::ComputeRateUpdateForOnlineLearningMode(
|
||
|
const std::vector<PccMonitorInterval>& intervals,
|
||
|
DataRate bandwith_estimate) {
|
||
|
double first_utility = utility_function_->Compute(intervals[0]);
|
||
|
double second_utility = utility_function_->Compute(intervals[1]);
|
||
|
double first_bitrate_bps = intervals[0].GetTargetSendingRate().bps();
|
||
|
double second_bitrate_bps = intervals[1].GetTargetSendingRate().bps();
|
||
|
double gradient = (first_utility - second_utility) /
|
||
|
(first_bitrate_bps - second_bitrate_bps);
|
||
|
double rate_change_bps = gradient * ComputeStepSize(gradient); // delta_r
|
||
|
rate_change_bps =
|
||
|
ApplyDynamicBoundary(rate_change_bps, bandwith_estimate.bps());
|
||
|
return DataRate::BitsPerSec(
|
||
|
std::max(0.0, bandwith_estimate.bps() + rate_change_bps));
|
||
|
}
|
||
|
|
||
|
} // namespace pcc
|
||
|
} // namespace webrtc
|