OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/congestion_controller/delay_based_bwe.h" | 11 #include "webrtc/modules/congestion_controller/delay_based_bwe.h" |
12 | 12 |
13 #include <algorithm> | 13 #include <algorithm> |
14 #include <cmath> | 14 #include <cmath> |
15 #include <string> | 15 #include <string> |
16 | 16 |
17 #include "webrtc/base/checks.h" | 17 #include "webrtc/base/checks.h" |
18 #include "webrtc/base/constructormagic.h" | 18 #include "webrtc/base/constructormagic.h" |
19 #include "webrtc/base/logging.h" | 19 #include "webrtc/base/logging.h" |
20 #include "webrtc/base/thread_annotations.h" | 20 #include "webrtc/base/thread_annotations.h" |
21 #include "webrtc/modules/congestion_controller/include/congestion_controller.h" | 21 #include "webrtc/modules/congestion_controller/include/congestion_controller.h" |
22 #include "webrtc/modules/pacing/paced_sender.h" | 22 #include "webrtc/modules/pacing/paced_sender.h" |
23 #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimat or.h" | 23 #include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimat or.h" |
24 #include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h" | |
24 #include "webrtc/system_wrappers/include/field_trial.h" | 25 #include "webrtc/system_wrappers/include/field_trial.h" |
25 #include "webrtc/system_wrappers/include/metrics.h" | 26 #include "webrtc/system_wrappers/include/metrics.h" |
26 #include "webrtc/typedefs.h" | 27 #include "webrtc/typedefs.h" |
27 | 28 |
28 namespace { | 29 namespace { |
29 constexpr int kTimestampGroupLengthMs = 5; | 30 constexpr int kTimestampGroupLengthMs = 5; |
30 constexpr int kAbsSendTimeFraction = 18; | 31 constexpr int kAbsSendTimeFraction = 18; |
31 constexpr int kAbsSendTimeInterArrivalUpshift = 8; | 32 constexpr int kAbsSendTimeInterArrivalUpshift = 8; |
32 constexpr int kInterArrivalShift = | 33 constexpr int kInterArrivalShift = |
33 kAbsSendTimeFraction + kAbsSendTimeInterArrivalUpshift; | 34 kAbsSendTimeFraction + kAbsSendTimeInterArrivalUpshift; |
34 constexpr double kTimestampToMs = | 35 constexpr double kTimestampToMs = |
35 1000.0 / static_cast<double>(1 << kInterArrivalShift); | 36 1000.0 / static_cast<double>(1 << kInterArrivalShift); |
36 // This ssrc is used to fulfill the current API but will be removed | 37 // This ssrc is used to fulfill the current API but will be removed |
37 // after the API has been changed. | 38 // after the API has been changed. |
38 constexpr uint32_t kFixedSsrc = 0; | 39 constexpr uint32_t kFixedSsrc = 0; |
39 constexpr int kInitialRateWindowMs = 500; | 40 constexpr int kInitialRateWindowMs = 500; |
40 constexpr int kRateWindowMs = 150; | 41 constexpr int kRateWindowMs = 150; |
41 | 42 |
43 // Parameters for linear least squares fit of regression line to noisy data. | |
42 constexpr size_t kDefaultTrendlineWindowSize = 15; | 44 constexpr size_t kDefaultTrendlineWindowSize = 15; |
43 constexpr double kDefaultTrendlineSmoothingCoeff = 0.9; | 45 constexpr double kDefaultTrendlineSmoothingCoeff = 0.9; |
44 constexpr double kDefaultTrendlineThresholdGain = 4.0; | 46 constexpr double kDefaultTrendlineThresholdGain = 4.0; |
45 | 47 |
48 // Parameters for Theil-Sen robust fitting of line to noisy data. | |
49 constexpr size_t kDefaultTheilSenWindowSize = 20; | |
50 constexpr double kDefaultTheilSenThresholdGain = 4.0; | |
51 | |
46 const char kBitrateEstimateExperiment[] = "WebRTC-ImprovedBitrateEstimate"; | 52 const char kBitrateEstimateExperiment[] = "WebRTC-ImprovedBitrateEstimate"; |
47 const char kBweTrendlineFilterExperiment[] = "WebRTC-BweTrendlineFilter"; | 53 const char kBweTrendlineFilterExperiment[] = "WebRTC-BweTrendlineFilter"; |
54 const char kBweTheilSenFilterExperiment[] = "WebRTC-BweTheilSenFilter"; | |
48 | 55 |
49 bool BitrateEstimateExperimentIsEnabled() { | 56 bool BitrateEstimateExperimentIsEnabled() { |
50 return webrtc::field_trial::FindFullName(kBitrateEstimateExperiment) == | 57 return webrtc::field_trial::FindFullName(kBitrateEstimateExperiment) == |
51 "Enabled"; | 58 "Enabled"; |
52 } | 59 } |
53 | 60 |
54 bool TrendlineFilterExperimentIsEnabled() { | 61 bool TrendlineFilterExperimentIsEnabled() { |
55 std::string experiment_string = | 62 std::string experiment_string = |
56 webrtc::field_trial::FindFullName(kBweTrendlineFilterExperiment); | 63 webrtc::field_trial::FindFullName(kBweTrendlineFilterExperiment); |
57 // The experiment is enabled iff the field trial string begins with "Enabled". | 64 // The experiment is enabled iff the field trial string begins with "Enabled". |
58 return experiment_string.find("Enabled") == 0; | 65 return experiment_string.find("Enabled") == 0; |
59 } | 66 } |
60 | 67 |
68 bool TheilSenFilterExperimentIsEnabled() { | |
69 std::string experiment_string = | |
70 webrtc::field_trial::FindFullName(kBweTheilSenFilterExperiment); | |
71 // The experiment is enabled iff the field trial string begins with "Enabled". | |
72 return experiment_string.find("Enabled") == 0; | |
73 } | |
74 | |
61 bool ReadTrendlineFilterExperimentParameters(size_t* window_points, | 75 bool ReadTrendlineFilterExperimentParameters(size_t* window_points, |
brandtr
2016/11/28 16:27:19
window_size? Here and in function below.
terelius
2016/12/02 16:45:52
Done.
| |
62 double* smoothing_coef, | 76 double* smoothing_coef, |
63 double* threshold_gain) { | 77 double* threshold_gain) { |
64 RTC_DCHECK(TrendlineFilterExperimentIsEnabled()); | 78 RTC_DCHECK(TrendlineFilterExperimentIsEnabled()); |
79 RTC_DCHECK(!TheilSenFilterExperimentIsEnabled()); | |
80 RTC_DCHECK(window_points != nullptr); | |
81 RTC_DCHECK(smoothing_coef != nullptr); | |
82 RTC_DCHECK(threshold_gain != nullptr); | |
65 std::string experiment_string = | 83 std::string experiment_string = |
66 webrtc::field_trial::FindFullName(kBweTrendlineFilterExperiment); | 84 webrtc::field_trial::FindFullName(kBweTrendlineFilterExperiment); |
67 int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%zu,%lf,%lf", | 85 int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%zu,%lf,%lf", |
68 window_points, smoothing_coef, threshold_gain); | 86 window_points, smoothing_coef, threshold_gain); |
69 if (parsed_values == 3) { | 87 if (parsed_values == 3) { |
70 RTC_CHECK_GT(*window_points, 1) << "Need at least 2 points to fit a line."; | 88 RTC_CHECK_GT(*window_points, 1) << "Need at least 2 points to fit a line."; |
71 RTC_CHECK(0 <= *smoothing_coef && *smoothing_coef <= 1) | 89 RTC_CHECK(0 <= *smoothing_coef && *smoothing_coef <= 1) |
72 << "Coefficient needs to be between 0 and 1 for weighted average."; | 90 << "Coefficient needs to be between 0 and 1 for weighted average."; |
73 RTC_CHECK_GT(*threshold_gain, 0) << "Threshold gain needs to be positive."; | 91 RTC_CHECK_GT(*threshold_gain, 0) << "Threshold gain needs to be positive."; |
74 return true; | 92 return true; |
75 } | 93 } |
76 LOG(LS_WARNING) << "Failed to parse parameters for BweTrendlineFilter " | 94 LOG(LS_WARNING) << "Failed to parse parameters for BweTrendlineFilter " |
77 "experiment from field trial string. Using default."; | 95 "experiment from field trial string. Using default."; |
78 *window_points = kDefaultTrendlineWindowSize; | 96 *window_points = kDefaultTrendlineWindowSize; |
79 *smoothing_coef = kDefaultTrendlineSmoothingCoeff; | 97 *smoothing_coef = kDefaultTrendlineSmoothingCoeff; |
80 *threshold_gain = kDefaultTrendlineThresholdGain; | 98 *threshold_gain = kDefaultTrendlineThresholdGain; |
81 return false; | 99 return false; |
82 } | 100 } |
83 | 101 |
102 bool ReadTheilSenFilterExperimentParameters(size_t* window_points, | |
103 double* threshold_gain) { | |
104 RTC_DCHECK(!TrendlineFilterExperimentIsEnabled()); | |
105 RTC_DCHECK(TheilSenFilterExperimentIsEnabled()); | |
106 RTC_DCHECK(window_points != nullptr); | |
107 RTC_DCHECK(threshold_gain != nullptr); | |
108 std::string experiment_string = | |
109 webrtc::field_trial::FindFullName(kBweTheilSenFilterExperiment); | |
110 int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%zu,%lf", | |
111 window_points, threshold_gain); | |
112 if (parsed_values == 2) { | |
113 RTC_CHECK_GT(*window_points, 1) << "Need at least 2 points to fit a line."; | |
114 RTC_CHECK_GT(*threshold_gain, 0) << "Threshold gain needs to be positive."; | |
115 return true; | |
116 } | |
117 LOG(LS_WARNING) << "Failed to parse parameters for BweTheilSenFilter " | |
118 "experiment from field trial string. Using default."; | |
119 *window_points = kDefaultTheilSenWindowSize; | |
120 *threshold_gain = kDefaultTheilSenThresholdGain; | |
121 return false; | |
122 } | |
84 } // namespace | 123 } // namespace |
85 | 124 |
86 namespace webrtc { | 125 namespace webrtc { |
87 | 126 |
88 DelayBasedBwe::BitrateEstimator::BitrateEstimator() | 127 DelayBasedBwe::BitrateEstimator::BitrateEstimator() |
89 : sum_(0), | 128 : sum_(0), |
90 current_win_ms_(0), | 129 current_win_ms_(0), |
91 prev_time_ms_(-1), | 130 prev_time_ms_(-1), |
92 bitrate_estimate_(-1.0f), | 131 bitrate_estimate_(-1.0f), |
93 bitrate_estimate_var_(50.0f), | 132 bitrate_estimate_var_(50.0f), |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
161 return bitrate_sample; | 200 return bitrate_sample; |
162 } | 201 } |
163 | 202 |
164 rtc::Optional<uint32_t> DelayBasedBwe::BitrateEstimator::bitrate_bps() const { | 203 rtc::Optional<uint32_t> DelayBasedBwe::BitrateEstimator::bitrate_bps() const { |
165 if (bitrate_estimate_ < 0.f) | 204 if (bitrate_estimate_ < 0.f) |
166 return rtc::Optional<uint32_t>(); | 205 return rtc::Optional<uint32_t>(); |
167 return rtc::Optional<uint32_t>(bitrate_estimate_ * 1000); | 206 return rtc::Optional<uint32_t>(bitrate_estimate_ * 1000); |
168 } | 207 } |
169 | 208 |
170 DelayBasedBwe::DelayBasedBwe(Clock* clock) | 209 DelayBasedBwe::DelayBasedBwe(Clock* clock) |
171 : clock_(clock), | 210 : in_trendline_experiment_(TrendlineFilterExperimentIsEnabled()), |
211 in_theil_sen_experiment_(TheilSenFilterExperimentIsEnabled()), | |
212 clock_(clock), | |
172 inter_arrival_(), | 213 inter_arrival_(), |
173 kalman_estimator_(), | 214 kalman_estimator_(), |
174 trendline_estimator_(), | 215 trendline_estimator_(), |
175 detector_(OverUseDetectorOptions()), | 216 detector_(OverUseDetectorOptions()), |
176 receiver_incoming_bitrate_(), | 217 receiver_incoming_bitrate_(), |
177 last_update_ms_(-1), | 218 last_update_ms_(-1), |
178 last_seen_packet_ms_(-1), | 219 last_seen_packet_ms_(-1), |
179 uma_recorded_(false), | 220 uma_recorded_(false), |
180 trendline_window_size_(kDefaultTrendlineWindowSize), | 221 trendline_window_size_(kDefaultTrendlineWindowSize), |
181 trendline_smoothing_coeff_(kDefaultTrendlineSmoothingCoeff), | 222 trendline_smoothing_coeff_(kDefaultTrendlineSmoothingCoeff), |
182 trendline_threshold_gain_(kDefaultTrendlineThresholdGain), | 223 trendline_threshold_gain_(kDefaultTrendlineThresholdGain), |
183 in_trendline_experiment_(TrendlineFilterExperimentIsEnabled()) { | 224 theil_sen_window_size_(kDefaultTheilSenWindowSize), |
225 theil_sen_threshold_gain_(kDefaultTheilSenThresholdGain) { | |
184 if (in_trendline_experiment_) { | 226 if (in_trendline_experiment_) { |
185 ReadTrendlineFilterExperimentParameters(&trendline_window_size_, | 227 ReadTrendlineFilterExperimentParameters(&trendline_window_size_, |
186 &trendline_smoothing_coeff_, | 228 &trendline_smoothing_coeff_, |
187 &trendline_threshold_gain_); | 229 &trendline_threshold_gain_); |
188 } | 230 } |
231 if (in_theil_sen_experiment_) { | |
232 ReadTheilSenFilterExperimentParameters(&trendline_window_size_, | |
233 &trendline_threshold_gain_); | |
234 } | |
235 | |
189 network_thread_.DetachFromThread(); | 236 network_thread_.DetachFromThread(); |
190 } | 237 } |
191 | 238 |
192 DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector( | 239 DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector( |
193 const std::vector<PacketInfo>& packet_feedback_vector) { | 240 const std::vector<PacketInfo>& packet_feedback_vector) { |
194 RTC_DCHECK(network_thread_.CalledOnValidThread()); | 241 RTC_DCHECK(network_thread_.CalledOnValidThread()); |
195 if (!uma_recorded_) { | 242 if (!uma_recorded_) { |
196 RTC_HISTOGRAM_ENUMERATION(kBweTypeHistogram, | 243 RTC_HISTOGRAM_ENUMERATION(kBweTypeHistogram, |
197 BweNames::kSendSideTransportSeqNum, | 244 BweNames::kSendSideTransportSeqNum, |
198 BweNames::kBweNamesMax); | 245 BweNames::kBweNamesMax); |
(...skipping 17 matching lines...) Expand all Loading... | |
216 // Reset if the stream has timed out. | 263 // Reset if the stream has timed out. |
217 if (last_seen_packet_ms_ == -1 || | 264 if (last_seen_packet_ms_ == -1 || |
218 now_ms - last_seen_packet_ms_ > kStreamTimeOutMs) { | 265 now_ms - last_seen_packet_ms_ > kStreamTimeOutMs) { |
219 inter_arrival_.reset( | 266 inter_arrival_.reset( |
220 new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000, | 267 new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000, |
221 kTimestampToMs, true)); | 268 kTimestampToMs, true)); |
222 kalman_estimator_.reset(new OveruseEstimator(OverUseDetectorOptions())); | 269 kalman_estimator_.reset(new OveruseEstimator(OverUseDetectorOptions())); |
223 trendline_estimator_.reset(new TrendlineEstimator( | 270 trendline_estimator_.reset(new TrendlineEstimator( |
224 trendline_window_size_, trendline_smoothing_coeff_, | 271 trendline_window_size_, trendline_smoothing_coeff_, |
225 trendline_threshold_gain_)); | 272 trendline_threshold_gain_)); |
273 theil_sen_estimator_.reset(new TheilSenEstimator( | |
274 theil_sen_window_size_, theil_sen_threshold_gain_)); | |
226 } | 275 } |
227 last_seen_packet_ms_ = now_ms; | 276 last_seen_packet_ms_ = now_ms; |
228 | 277 |
229 uint32_t send_time_24bits = | 278 uint32_t send_time_24bits = |
230 static_cast<uint32_t>( | 279 static_cast<uint32_t>( |
231 ((static_cast<uint64_t>(info.send_time_ms) << kAbsSendTimeFraction) + | 280 ((static_cast<uint64_t>(info.send_time_ms) << kAbsSendTimeFraction) + |
232 500) / | 281 500) / |
233 1000) & | 282 1000) & |
234 0x00FFFFFF; | 283 0x00FFFFFF; |
235 // Shift up send time to use the full 32 bits that inter_arrival works with, | 284 // Shift up send time to use the full 32 bits that inter_arrival works with, |
236 // so wrapping works properly. | 285 // so wrapping works properly. |
237 uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift; | 286 uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift; |
238 | 287 |
239 uint32_t ts_delta = 0; | 288 uint32_t ts_delta = 0; |
240 int64_t t_delta = 0; | 289 int64_t t_delta = 0; |
241 int size_delta = 0; | 290 int size_delta = 0; |
242 if (inter_arrival_->ComputeDeltas(timestamp, info.arrival_time_ms, now_ms, | 291 if (inter_arrival_->ComputeDeltas(timestamp, info.arrival_time_ms, now_ms, |
243 info.payload_size, &ts_delta, &t_delta, | 292 info.payload_size, &ts_delta, &t_delta, |
244 &size_delta)) { | 293 &size_delta)) { |
245 double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift); | 294 double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift); |
246 if (in_trendline_experiment_) { | 295 if (in_trendline_experiment_) { |
247 trendline_estimator_->Update(t_delta, ts_delta_ms, info.arrival_time_ms); | 296 trendline_estimator_->Update(t_delta, ts_delta_ms, info.arrival_time_ms); |
248 detector_.Detect(trendline_estimator_->trendline_slope(), ts_delta_ms, | 297 detector_.Detect(trendline_estimator_->trendline_slope(), ts_delta_ms, |
249 trendline_estimator_->num_of_deltas(), | 298 trendline_estimator_->num_of_deltas(), |
250 info.arrival_time_ms); | 299 info.arrival_time_ms); |
251 | 300 } else if (in_theil_sen_experiment_) { |
301 theil_sen_estimator_->Update(t_delta, ts_delta_ms, info.arrival_time_ms); | |
302 detector_.Detect(theil_sen_estimator_->trendline_slope(), ts_delta_ms, | |
303 theil_sen_estimator_->num_of_deltas(), | |
304 info.arrival_time_ms); | |
252 } else { | 305 } else { |
253 kalman_estimator_->Update(t_delta, ts_delta_ms, size_delta, | 306 kalman_estimator_->Update(t_delta, ts_delta_ms, size_delta, |
254 detector_.State(), info.arrival_time_ms); | 307 detector_.State(), info.arrival_time_ms); |
255 detector_.Detect(kalman_estimator_->offset(), ts_delta_ms, | 308 detector_.Detect(kalman_estimator_->offset(), ts_delta_ms, |
256 kalman_estimator_->num_of_deltas(), | 309 kalman_estimator_->num_of_deltas(), |
257 info.arrival_time_ms); | 310 info.arrival_time_ms); |
258 } | 311 } |
259 } | 312 } |
260 | 313 |
261 int probing_bps = 0; | 314 int probing_bps = 0; |
(...skipping 18 matching lines...) Expand all Loading... | |
280 UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps, | 333 UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps, |
281 &result.target_bitrate_bps); | 334 &result.target_bitrate_bps); |
282 } | 335 } |
283 if (!result.updated && | 336 if (!result.updated && |
284 (last_update_ms_ == -1 || | 337 (last_update_ms_ == -1 || |
285 now_ms - last_update_ms_ > rate_control_.GetFeedbackInterval())) { | 338 now_ms - last_update_ms_ > rate_control_.GetFeedbackInterval())) { |
286 result.updated = | 339 result.updated = |
287 UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps, | 340 UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps, |
288 &result.target_bitrate_bps); | 341 &result.target_bitrate_bps); |
289 } | 342 } |
290 if (result.updated) | 343 if (result.updated) { |
291 last_update_ms_ = now_ms; | 344 last_update_ms_ = now_ms; |
345 BWE_TEST_LOGGING_PLOT(1, "target_bitrate_bps", now_ms, | |
346 result.target_bitrate_bps); | |
347 } | |
292 | 348 |
293 return result; | 349 return result; |
294 } | 350 } |
295 | 351 |
296 bool DelayBasedBwe::UpdateEstimate(int64_t arrival_time_ms, | 352 bool DelayBasedBwe::UpdateEstimate(int64_t arrival_time_ms, |
297 int64_t now_ms, | 353 int64_t now_ms, |
298 rtc::Optional<uint32_t> acked_bitrate_bps, | 354 rtc::Optional<uint32_t> acked_bitrate_bps, |
299 uint32_t* target_bitrate_bps) { | 355 uint32_t* target_bitrate_bps) { |
300 // TODO(terelius): RateControlInput::noise_var is deprecated and will be | 356 // TODO(terelius): RateControlInput::noise_var is deprecated and will be |
301 // removed. In the meantime, we set it to zero. | 357 // removed. In the meantime, we set it to zero. |
(...skipping 22 matching lines...) Expand all Loading... | |
324 *bitrate_bps = rate_control_.LatestEstimate(); | 380 *bitrate_bps = rate_control_.LatestEstimate(); |
325 return true; | 381 return true; |
326 } | 382 } |
327 | 383 |
328 void DelayBasedBwe::SetMinBitrate(int min_bitrate_bps) { | 384 void DelayBasedBwe::SetMinBitrate(int min_bitrate_bps) { |
329 // Called from both the configuration thread and the network thread. Shouldn't | 385 // Called from both the configuration thread and the network thread. Shouldn't |
330 // be called from the network thread in the future. | 386 // be called from the network thread in the future. |
331 rate_control_.SetMinBitrate(min_bitrate_bps); | 387 rate_control_.SetMinBitrate(min_bitrate_bps); |
332 } | 388 } |
333 } // namespace webrtc | 389 } // namespace webrtc |
OLD | NEW |