Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(161)

Side by Side Diff: webrtc/modules/congestion_controller/delay_based_bwe.cc

Issue 2512693002: Implement Theil-Sen's method for fitting a line to noisy data (used in bandwidth estimation). (Closed)
Patch Set: Remove PercentileFilter::Clear since no longer used. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 kDefaultMedianSlopeWindowSize = 20;
50 constexpr double kDefaultMedianSlopeThresholdGain = 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 kBweMedianSlopeFilterExperiment[] = "WebRTC-BweMedianSlopeFilter";
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
61 bool ReadTrendlineFilterExperimentParameters(size_t* window_points, 68 bool MedianSlopeFilterExperimentIsEnabled() {
69 std::string experiment_string =
70 webrtc::field_trial::FindFullName(kBweMedianSlopeFilterExperiment);
71 // The experiment is enabled iff the field trial string begins with "Enabled".
72 return experiment_string.find("Enabled") == 0;
73 }
74
75 bool ReadTrendlineFilterExperimentParameters(size_t* window_size,
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(!MedianSlopeFilterExperimentIsEnabled());
80 RTC_DCHECK(window_size != 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_size, 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_size, 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_size = 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 ReadMedianSlopeFilterExperimentParameters(size_t* window_size,
103 double* threshold_gain) {
104 RTC_DCHECK(!TrendlineFilterExperimentIsEnabled());
105 RTC_DCHECK(MedianSlopeFilterExperimentIsEnabled());
106 RTC_DCHECK(window_size != nullptr);
107 RTC_DCHECK(threshold_gain != nullptr);
108 std::string experiment_string =
109 webrtc::field_trial::FindFullName(kBweMedianSlopeFilterExperiment);
110 int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%zu,%lf",
111 window_size, threshold_gain);
112 if (parsed_values == 2) {
113 RTC_CHECK_GT(*window_size, 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 BweMedianSlopeFilter "
118 "experiment from field trial string. Using default.";
119 *window_size = kDefaultMedianSlopeWindowSize;
120 *threshold_gain = kDefaultMedianSlopeThresholdGain;
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
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_median_slope_experiment_(MedianSlopeFilterExperimentIsEnabled()),
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 probing_interval_estimator_(&rate_control_),
184 probing_interval_estimator_(&rate_control_) { 225 median_slope_window_size_(kDefaultMedianSlopeWindowSize),
226 median_slope_threshold_gain_(kDefaultMedianSlopeThresholdGain) {
185 if (in_trendline_experiment_) { 227 if (in_trendline_experiment_) {
186 ReadTrendlineFilterExperimentParameters(&trendline_window_size_, 228 ReadTrendlineFilterExperimentParameters(&trendline_window_size_,
187 &trendline_smoothing_coeff_, 229 &trendline_smoothing_coeff_,
188 &trendline_threshold_gain_); 230 &trendline_threshold_gain_);
189 } 231 }
232 if (in_median_slope_experiment_) {
233 ReadMedianSlopeFilterExperimentParameters(&trendline_window_size_,
234 &trendline_threshold_gain_);
235 }
236
190 network_thread_.DetachFromThread(); 237 network_thread_.DetachFromThread();
191 } 238 }
192 239
193 DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector( 240 DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
194 const std::vector<PacketInfo>& packet_feedback_vector) { 241 const std::vector<PacketInfo>& packet_feedback_vector) {
195 RTC_DCHECK(network_thread_.CalledOnValidThread()); 242 RTC_DCHECK(network_thread_.CalledOnValidThread());
196 if (!uma_recorded_) { 243 if (!uma_recorded_) {
197 RTC_HISTOGRAM_ENUMERATION(kBweTypeHistogram, 244 RTC_HISTOGRAM_ENUMERATION(kBweTypeHistogram,
198 BweNames::kSendSideTransportSeqNum, 245 BweNames::kSendSideTransportSeqNum,
199 BweNames::kBweNamesMax); 246 BweNames::kBweNamesMax);
(...skipping 17 matching lines...) Expand all
217 // Reset if the stream has timed out. 264 // Reset if the stream has timed out.
218 if (last_seen_packet_ms_ == -1 || 265 if (last_seen_packet_ms_ == -1 ||
219 now_ms - last_seen_packet_ms_ > kStreamTimeOutMs) { 266 now_ms - last_seen_packet_ms_ > kStreamTimeOutMs) {
220 inter_arrival_.reset( 267 inter_arrival_.reset(
221 new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000, 268 new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000,
222 kTimestampToMs, true)); 269 kTimestampToMs, true));
223 kalman_estimator_.reset(new OveruseEstimator(OverUseDetectorOptions())); 270 kalman_estimator_.reset(new OveruseEstimator(OverUseDetectorOptions()));
224 trendline_estimator_.reset(new TrendlineEstimator( 271 trendline_estimator_.reset(new TrendlineEstimator(
225 trendline_window_size_, trendline_smoothing_coeff_, 272 trendline_window_size_, trendline_smoothing_coeff_,
226 trendline_threshold_gain_)); 273 trendline_threshold_gain_));
274 median_slope_estimator_.reset(new MedianSlopeEstimator(
275 median_slope_window_size_, median_slope_threshold_gain_));
227 } 276 }
228 last_seen_packet_ms_ = now_ms; 277 last_seen_packet_ms_ = now_ms;
229 278
230 uint32_t send_time_24bits = 279 uint32_t send_time_24bits =
231 static_cast<uint32_t>( 280 static_cast<uint32_t>(
232 ((static_cast<uint64_t>(info.send_time_ms) << kAbsSendTimeFraction) + 281 ((static_cast<uint64_t>(info.send_time_ms) << kAbsSendTimeFraction) +
233 500) / 282 500) /
234 1000) & 283 1000) &
235 0x00FFFFFF; 284 0x00FFFFFF;
236 // Shift up send time to use the full 32 bits that inter_arrival works with, 285 // Shift up send time to use the full 32 bits that inter_arrival works with,
237 // so wrapping works properly. 286 // so wrapping works properly.
238 uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift; 287 uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
239 288
240 uint32_t ts_delta = 0; 289 uint32_t ts_delta = 0;
241 int64_t t_delta = 0; 290 int64_t t_delta = 0;
242 int size_delta = 0; 291 int size_delta = 0;
243 if (inter_arrival_->ComputeDeltas(timestamp, info.arrival_time_ms, now_ms, 292 if (inter_arrival_->ComputeDeltas(timestamp, info.arrival_time_ms, now_ms,
244 info.payload_size, &ts_delta, &t_delta, 293 info.payload_size, &ts_delta, &t_delta,
245 &size_delta)) { 294 &size_delta)) {
246 double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift); 295 double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
247 if (in_trendline_experiment_) { 296 if (in_trendline_experiment_) {
248 trendline_estimator_->Update(t_delta, ts_delta_ms, info.arrival_time_ms); 297 trendline_estimator_->Update(t_delta, ts_delta_ms, info.arrival_time_ms);
249 detector_.Detect(trendline_estimator_->trendline_slope(), ts_delta_ms, 298 detector_.Detect(trendline_estimator_->trendline_slope(), ts_delta_ms,
250 trendline_estimator_->num_of_deltas(), 299 trendline_estimator_->num_of_deltas(),
251 info.arrival_time_ms); 300 info.arrival_time_ms);
252 301 } else if (in_median_slope_experiment_) {
302 median_slope_estimator_->Update(t_delta, ts_delta_ms,
303 info.arrival_time_ms);
304 detector_.Detect(median_slope_estimator_->trendline_slope(), ts_delta_ms,
305 median_slope_estimator_->num_of_deltas(),
306 info.arrival_time_ms);
253 } else { 307 } else {
254 kalman_estimator_->Update(t_delta, ts_delta_ms, size_delta, 308 kalman_estimator_->Update(t_delta, ts_delta_ms, size_delta,
255 detector_.State(), info.arrival_time_ms); 309 detector_.State(), info.arrival_time_ms);
256 detector_.Detect(kalman_estimator_->offset(), ts_delta_ms, 310 detector_.Detect(kalman_estimator_->offset(), ts_delta_ms,
257 kalman_estimator_->num_of_deltas(), 311 kalman_estimator_->num_of_deltas(),
258 info.arrival_time_ms); 312 info.arrival_time_ms);
259 } 313 }
260 } 314 }
261 315
262 int probing_bps = 0; 316 int probing_bps = 0;
(...skipping 18 matching lines...) Expand all
281 UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps, 335 UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps,
282 &result.target_bitrate_bps); 336 &result.target_bitrate_bps);
283 } 337 }
284 if (!result.updated && 338 if (!result.updated &&
285 (last_update_ms_ == -1 || 339 (last_update_ms_ == -1 ||
286 now_ms - last_update_ms_ > rate_control_.GetFeedbackInterval())) { 340 now_ms - last_update_ms_ > rate_control_.GetFeedbackInterval())) {
287 result.updated = 341 result.updated =
288 UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps, 342 UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps,
289 &result.target_bitrate_bps); 343 &result.target_bitrate_bps);
290 } 344 }
291 if (result.updated) 345 if (result.updated) {
292 last_update_ms_ = now_ms; 346 last_update_ms_ = now_ms;
347 BWE_TEST_LOGGING_PLOT(1, "target_bitrate_bps", now_ms,
348 result.target_bitrate_bps);
349 }
293 350
294 return result; 351 return result;
295 } 352 }
296 353
297 bool DelayBasedBwe::UpdateEstimate(int64_t arrival_time_ms, 354 bool DelayBasedBwe::UpdateEstimate(int64_t arrival_time_ms,
298 int64_t now_ms, 355 int64_t now_ms,
299 rtc::Optional<uint32_t> acked_bitrate_bps, 356 rtc::Optional<uint32_t> acked_bitrate_bps,
300 uint32_t* target_bitrate_bps) { 357 uint32_t* target_bitrate_bps) {
301 // TODO(terelius): RateControlInput::noise_var is deprecated and will be 358 // TODO(terelius): RateControlInput::noise_var is deprecated and will be
302 // removed. In the meantime, we set it to zero. 359 // removed. In the meantime, we set it to zero.
(...skipping 26 matching lines...) Expand all
329 void DelayBasedBwe::SetMinBitrate(int min_bitrate_bps) { 386 void DelayBasedBwe::SetMinBitrate(int min_bitrate_bps) {
330 // Called from both the configuration thread and the network thread. Shouldn't 387 // Called from both the configuration thread and the network thread. Shouldn't
331 // be called from the network thread in the future. 388 // be called from the network thread in the future.
332 rate_control_.SetMinBitrate(min_bitrate_bps); 389 rate_control_.SetMinBitrate(min_bitrate_bps);
333 } 390 }
334 391
335 int64_t DelayBasedBwe::GetProbingIntervalMs() const { 392 int64_t DelayBasedBwe::GetProbingIntervalMs() const {
336 return probing_interval_estimator_.GetIntervalMs(); 393 return probing_interval_estimator_.GetIntervalMs();
337 } 394 }
338 } // namespace webrtc 395 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698