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