1 /*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/congestion_controller/pcc/bitrate_controller.h"
12
13 #include <algorithm>
14 #include <cmath>
15 #include <cstdlib>
16 #include <memory>
17 #include <utility>
18 #include <vector>
19
20
21 namespace webrtc {
22 namespace pcc {
23
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)24 PccBitrateController::PccBitrateController(double initial_conversion_factor,
25 double initial_dynamic_boundary,
26 double dynamic_boundary_increment,
27 double rtt_gradient_coefficient,
28 double loss_coefficient,
29 double throughput_coefficient,
30 double throughput_power,
31 double rtt_gradient_threshold,
32 double delay_gradient_negative_bound)
33 : PccBitrateController(initial_conversion_factor,
34 initial_dynamic_boundary,
35 dynamic_boundary_increment,
36 std::make_unique<ModifiedVivaceUtilityFunction>(
37 rtt_gradient_coefficient,
38 loss_coefficient,
39 throughput_coefficient,
40 throughput_power,
41 rtt_gradient_threshold,
42 delay_gradient_negative_bound)) {}
43
PccBitrateController(double initial_conversion_factor,double initial_dynamic_boundary,double dynamic_boundary_increment,std::unique_ptr<PccUtilityFunctionInterface> utility_function)44 PccBitrateController::PccBitrateController(
45 double initial_conversion_factor,
46 double initial_dynamic_boundary,
47 double dynamic_boundary_increment,
48 std::unique_ptr<PccUtilityFunctionInterface> utility_function)
49 : consecutive_boundary_adjustments_number_(0),
50 initial_dynamic_boundary_(initial_dynamic_boundary),
51 dynamic_boundary_increment_(dynamic_boundary_increment),
52 utility_function_(std::move(utility_function)),
53 step_size_adjustments_number_(0),
54 initial_conversion_factor_(initial_conversion_factor) {}
55
56 PccBitrateController::~PccBitrateController() = default;
57
ComputeStepSize(double utility_gradient)58 double PccBitrateController::ComputeStepSize(double utility_gradient) {
59 // Computes number of consecutive step size adjustments.
60 if (utility_gradient > 0) {
61 step_size_adjustments_number_ =
62 std::max<int64_t>(step_size_adjustments_number_ + 1, 1);
63 } else if (utility_gradient < 0) {
64 step_size_adjustments_number_ =
65 std::min<int64_t>(step_size_adjustments_number_ - 1, -1);
66 } else {
67 step_size_adjustments_number_ = 0;
68 }
69 // Computes step size amplifier.
70 int64_t step_size_amplifier = 1;
71 if (std::abs(step_size_adjustments_number_) <= 3) {
72 step_size_amplifier =
73 std::max<int64_t>(std::abs(step_size_adjustments_number_), 1);
74 } else {
75 step_size_amplifier = 2 * std::abs(step_size_adjustments_number_) - 3;
76 }
77 return step_size_amplifier * initial_conversion_factor_;
78 }
79
ApplyDynamicBoundary(double rate_change,double bitrate)80 double PccBitrateController::ApplyDynamicBoundary(double rate_change,
81 double bitrate) {
82 double rate_change_abs = std::abs(rate_change);
83 int64_t rate_change_sign = (rate_change > 0) ? 1 : -1;
84 if (consecutive_boundary_adjustments_number_ * rate_change_sign < 0) {
85 consecutive_boundary_adjustments_number_ = 0;
86 }
87 double dynamic_change_boundary =
88 initial_dynamic_boundary_ +
89 std::abs(consecutive_boundary_adjustments_number_) *
90 dynamic_boundary_increment_;
91 double boundary = bitrate * dynamic_change_boundary;
92 if (rate_change_abs > boundary) {
93 consecutive_boundary_adjustments_number_ += rate_change_sign;
94 return boundary * rate_change_sign;
95 }
96 // Rate change smaller than boundary. Reset boundary to the smallest possible
97 // that would allow the change.
98 while (rate_change_abs <= boundary &&
99 consecutive_boundary_adjustments_number_ * rate_change_sign > 0) {
100 consecutive_boundary_adjustments_number_ -= rate_change_sign;
101 dynamic_change_boundary =
102 initial_dynamic_boundary_ +
103 std::abs(consecutive_boundary_adjustments_number_) *
104 dynamic_boundary_increment_;
105 boundary = bitrate * dynamic_change_boundary;
106 }
107 consecutive_boundary_adjustments_number_ += rate_change_sign;
108 return rate_change;
109 }
110
111 absl::optional<DataRate>
ComputeRateUpdateForSlowStartMode(const PccMonitorInterval & monitor_interval)112 PccBitrateController::ComputeRateUpdateForSlowStartMode(
113 const PccMonitorInterval& monitor_interval) {
114 double utility_value = utility_function_->Compute(monitor_interval);
115 if (previous_utility_.has_value() && utility_value <= previous_utility_) {
116 return absl::nullopt;
117 }
118 previous_utility_ = utility_value;
119 return monitor_interval.GetTargetSendingRate();
120 }
121
ComputeRateUpdateForOnlineLearningMode(const std::vector<PccMonitorInterval> & intervals,DataRate bandwith_estimate)122 DataRate PccBitrateController::ComputeRateUpdateForOnlineLearningMode(
123 const std::vector<PccMonitorInterval>& intervals,
124 DataRate bandwith_estimate) {
125 double first_utility = utility_function_->Compute(intervals[0]);
126 double second_utility = utility_function_->Compute(intervals[1]);
127 double first_bitrate_bps = intervals[0].GetTargetSendingRate().bps();
128 double second_bitrate_bps = intervals[1].GetTargetSendingRate().bps();
129 double gradient = (first_utility - second_utility) /
130 (first_bitrate_bps - second_bitrate_bps);
131 double rate_change_bps = gradient * ComputeStepSize(gradient); // delta_r
132 rate_change_bps =
133 ApplyDynamicBoundary(rate_change_bps, bandwith_estimate.bps());
134 return DataRate::BitsPerSec(
135 std::max(0.0, bandwith_estimate.bps() + rate_change_bps));
136 }
137
138 } // namespace pcc
139 } // namespace webrtc
140