| /* |
| * 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 |