Line data Source code
1 : /*
2 : * Copyright (c) 2016 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 "webrtc/modules/congestion_controller/probe_controller.h"
12 :
13 : #include <algorithm>
14 : #include <initializer_list>
15 :
16 : #include "webrtc/base/logging.h"
17 : #include "webrtc/base/safe_conversions.h"
18 : #include "webrtc/system_wrappers/include/metrics.h"
19 :
20 : namespace webrtc {
21 :
22 : namespace {
23 : // Maximum waiting time from the time of initiating probing to getting
24 : // the measured results back.
25 : constexpr int64_t kMaxWaitingTimeForProbingResultMs = 1000;
26 :
27 : // Value of |min_bitrate_to_probe_further_bps_| that indicates
28 : // further probing is disabled.
29 : constexpr int kExponentialProbingDisabled = 0;
30 :
31 : // Default probing bitrate limit. Applied only when the application didn't
32 : // specify max bitrate.
33 : constexpr int64_t kDefaultMaxProbingBitrateBps = 5000000;
34 :
35 : // This is a limit on how often probing can be done when there is a BW
36 : // drop detected in ALR.
37 : constexpr int64_t kAlrProbingIntervalMinMs = 5000;
38 :
39 : // Interval between probes when ALR periodic probing is enabled.
40 : constexpr int64_t kAlrPeriodicProbingIntervalMs = 5000;
41 :
42 : // Minimum probe bitrate percentage to probe further for repeated probes,
43 : // relative to the previous probe. For example, if 1Mbps probe results in
44 : // 80kbps, then we'll probe again at 1.6Mbps. In that case second probe won't be
45 : // sent if we get 600kbps from the first one.
46 : constexpr int kRepeatedProbeMinPercentage = 70;
47 :
48 : } // namespace
49 :
50 0 : ProbeController::ProbeController(PacedSender* pacer, Clock* clock)
51 : : pacer_(pacer),
52 : clock_(clock),
53 : network_state_(kNetworkUp),
54 : state_(State::kInit),
55 : min_bitrate_to_probe_further_bps_(kExponentialProbingDisabled),
56 : time_last_probing_initiated_ms_(0),
57 : estimated_bitrate_bps_(0),
58 : start_bitrate_bps_(0),
59 : max_bitrate_bps_(0),
60 0 : last_alr_probing_time_(clock_->TimeInMilliseconds()),
61 : enable_periodic_alr_probing_(false),
62 0 : mid_call_probing_waiting_for_result_(false) {}
63 :
64 0 : void ProbeController::SetBitrates(int64_t min_bitrate_bps,
65 : int64_t start_bitrate_bps,
66 : int64_t max_bitrate_bps) {
67 0 : rtc::CritScope cs(&critsect_);
68 :
69 0 : if (start_bitrate_bps > 0) {
70 0 : start_bitrate_bps_ = start_bitrate_bps;
71 0 : } else if (start_bitrate_bps_ == 0) {
72 0 : start_bitrate_bps_ = min_bitrate_bps;
73 : }
74 :
75 : // The reason we use the variable |old_max_bitrate_pbs| is because we
76 : // need to set |max_bitrate_bps_| before we call InitiateProbing.
77 0 : int64_t old_max_bitrate_bps = max_bitrate_bps_;
78 0 : max_bitrate_bps_ = max_bitrate_bps;
79 :
80 0 : switch (state_) {
81 : case State::kInit:
82 0 : if (network_state_ == kNetworkUp)
83 0 : InitiateExponentialProbing();
84 0 : break;
85 :
86 : case State::kWaitingForProbingResult:
87 0 : break;
88 :
89 : case State::kProbingComplete:
90 : // If the new max bitrate is higher than the old max bitrate and the
91 : // estimate is lower than the new max bitrate then initiate probing.
92 0 : if (estimated_bitrate_bps_ != 0 &&
93 0 : old_max_bitrate_bps < max_bitrate_bps_ &&
94 0 : estimated_bitrate_bps_ < max_bitrate_bps_) {
95 : // The assumption is that if we jump more than 20% in the bandwidth
96 : // estimate or if the bandwidth estimate is within 90% of the new
97 : // max bitrate then the probing attempt was successful.
98 0 : mid_call_probing_succcess_threshold_ =
99 0 : std::min(estimated_bitrate_bps_ * 1.2, max_bitrate_bps_ * 0.9);
100 0 : mid_call_probing_waiting_for_result_ = true;
101 0 : mid_call_probing_bitrate_bps_ = max_bitrate_bps_;
102 :
103 0 : RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Initiated",
104 : max_bitrate_bps_ / 1000);
105 :
106 0 : InitiateProbing(clock_->TimeInMilliseconds(), {max_bitrate_bps}, false);
107 : }
108 0 : break;
109 : }
110 0 : }
111 :
112 0 : void ProbeController::OnNetworkStateChanged(NetworkState network_state) {
113 0 : rtc::CritScope cs(&critsect_);
114 0 : network_state_ = network_state;
115 0 : if (network_state_ == kNetworkUp && state_ == State::kInit)
116 0 : InitiateExponentialProbing();
117 0 : }
118 :
119 0 : void ProbeController::InitiateExponentialProbing() {
120 0 : RTC_DCHECK(network_state_ == kNetworkUp);
121 0 : RTC_DCHECK(state_ == State::kInit);
122 0 : RTC_DCHECK_GT(start_bitrate_bps_, 0);
123 :
124 : // When probing at 1.8 Mbps ( 6x 300), this represents a threshold of
125 : // 1.2 Mbps to continue probing.
126 0 : InitiateProbing(clock_->TimeInMilliseconds(),
127 0 : {3 * start_bitrate_bps_, 6 * start_bitrate_bps_}, true);
128 0 : }
129 :
130 0 : void ProbeController::SetEstimatedBitrate(int64_t bitrate_bps) {
131 0 : rtc::CritScope cs(&critsect_);
132 0 : int64_t now_ms = clock_->TimeInMilliseconds();
133 :
134 0 : if (mid_call_probing_waiting_for_result_ &&
135 0 : bitrate_bps >= mid_call_probing_succcess_threshold_) {
136 0 : RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Success",
137 : mid_call_probing_bitrate_bps_ / 1000);
138 0 : RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.ProbedKbps",
139 : bitrate_bps / 1000);
140 0 : mid_call_probing_waiting_for_result_ = false;
141 : }
142 :
143 0 : if (state_ == State::kWaitingForProbingResult) {
144 : // Continue probing if probing results indicate channel has greater
145 : // capacity.
146 0 : LOG(LS_INFO) << "Measured bitrate: " << bitrate_bps
147 0 : << " Minimum to probe further: "
148 0 : << min_bitrate_to_probe_further_bps_;
149 :
150 0 : if (min_bitrate_to_probe_further_bps_ != kExponentialProbingDisabled &&
151 0 : bitrate_bps > min_bitrate_to_probe_further_bps_) {
152 : // Double the probing bitrate.
153 0 : InitiateProbing(now_ms, {2 * bitrate_bps}, true);
154 : }
155 : }
156 :
157 : // Detect a drop in estimated BW when operating in ALR and not already
158 : // probing. The current response is to initiate a single probe session at the
159 : // previous bitrate and immediately use the reported bitrate as the new
160 : // bitrate.
161 : //
162 : // If the probe session fails, the assumption is that this drop was a
163 : // real one from a competing flow or something else on the network and
164 : // it ramps up from bitrate_bps.
165 0 : if (state_ == State::kProbingComplete &&
166 0 : pacer_->GetApplicationLimitedRegionStartTime() &&
167 0 : bitrate_bps < estimated_bitrate_bps_ / 2 &&
168 0 : (now_ms - last_alr_probing_time_) > kAlrProbingIntervalMinMs) {
169 0 : LOG(LS_INFO) << "Detected big BW drop in ALR, start probe.";
170 : // Track how often we probe in response to BW drop in ALR.
171 0 : RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.AlrProbingIntervalInS",
172 : (now_ms - last_alr_probing_time_) / 1000);
173 0 : InitiateProbing(now_ms, {estimated_bitrate_bps_}, false);
174 0 : last_alr_probing_time_ = now_ms;
175 :
176 : // TODO(isheriff): May want to track when we did ALR probing in order
177 : // to reset |last_alr_probing_time_| if we validate that it was a
178 : // drop due to exogenous event.
179 : }
180 :
181 0 : estimated_bitrate_bps_ = bitrate_bps;
182 0 : }
183 :
184 0 : void ProbeController::EnablePeriodicAlrProbing(bool enable) {
185 0 : rtc::CritScope cs(&critsect_);
186 0 : enable_periodic_alr_probing_ = enable;
187 0 : }
188 :
189 0 : void ProbeController::Process() {
190 0 : rtc::CritScope cs(&critsect_);
191 :
192 0 : int64_t now_ms = clock_->TimeInMilliseconds();
193 :
194 0 : if (now_ms - time_last_probing_initiated_ms_ >
195 : kMaxWaitingTimeForProbingResultMs) {
196 0 : mid_call_probing_waiting_for_result_ = false;
197 :
198 0 : if (state_ == State::kWaitingForProbingResult) {
199 0 : LOG(LS_INFO) << "kWaitingForProbingResult: timeout";
200 0 : state_ = State::kProbingComplete;
201 0 : min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled;
202 : }
203 : }
204 :
205 0 : if (state_ != State::kProbingComplete || !enable_periodic_alr_probing_)
206 0 : return;
207 :
208 : // Probe bandwidth periodically when in ALR state.
209 : rtc::Optional<int64_t> alr_start_time =
210 0 : pacer_->GetApplicationLimitedRegionStartTime();
211 0 : if (alr_start_time) {
212 : int64_t next_probe_time_ms =
213 0 : std::max(*alr_start_time, time_last_probing_initiated_ms_) +
214 0 : kAlrPeriodicProbingIntervalMs;
215 0 : if (now_ms >= next_probe_time_ms) {
216 0 : InitiateProbing(now_ms, {estimated_bitrate_bps_ * 2}, true);
217 : }
218 : }
219 : }
220 :
221 0 : void ProbeController::InitiateProbing(
222 : int64_t now_ms,
223 : std::initializer_list<int64_t> bitrates_to_probe,
224 : bool probe_further) {
225 0 : for (int64_t bitrate : bitrates_to_probe) {
226 : int64_t max_probe_bitrate_bps =
227 0 : max_bitrate_bps_ > 0 ? max_bitrate_bps_ : kDefaultMaxProbingBitrateBps;
228 0 : if (bitrate > max_probe_bitrate_bps) {
229 0 : bitrate = max_probe_bitrate_bps;
230 0 : probe_further = false;
231 : }
232 0 : pacer_->CreateProbeCluster(rtc::checked_cast<int>(bitrate));
233 : }
234 0 : time_last_probing_initiated_ms_ = now_ms;
235 0 : if (probe_further) {
236 0 : state_ = State::kWaitingForProbingResult;
237 0 : min_bitrate_to_probe_further_bps_ =
238 0 : (*(bitrates_to_probe.end() - 1)) * kRepeatedProbeMinPercentage / 100;
239 : } else {
240 0 : state_ = State::kProbingComplete;
241 0 : min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled;
242 : }
243 0 : }
244 :
245 : } // namespace webrtc
|