blob: 04dadc489c0afac2a17e88510e2ea4397b5e9f4b [file] [log] [blame]
philipel863a8262016-06-17 09:21:34 -07001/*
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/delay_based_bwe.h"
12
philipel863a8262016-06-17 09:21:34 -070013#include <algorithm>
Stefan Holmer492ee282016-10-27 17:19:20 +020014#include <cmath>
tereliusafaef8b2016-11-17 03:48:18 -080015#include <string>
philipel863a8262016-06-17 09:21:34 -070016
17#include "webrtc/base/checks.h"
18#include "webrtc/base/constructormagic.h"
19#include "webrtc/base/logging.h"
20#include "webrtc/base/thread_annotations.h"
Irfan Sheriffb2540bb2016-09-12 12:28:54 -070021#include "webrtc/modules/congestion_controller/include/congestion_controller.h"
philipel863a8262016-06-17 09:21:34 -070022#include "webrtc/modules/pacing/paced_sender.h"
23#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
Stefan Holmer492ee282016-10-27 17:19:20 +020024#include "webrtc/system_wrappers/include/field_trial.h"
stefan64636dd2016-08-03 00:29:03 -070025#include "webrtc/system_wrappers/include/metrics.h"
philipel863a8262016-06-17 09:21:34 -070026#include "webrtc/typedefs.h"
27
28namespace {
philipel7522a282016-08-16 10:59:36 +020029constexpr int kTimestampGroupLengthMs = 5;
30constexpr int kAbsSendTimeFraction = 18;
31constexpr int kAbsSendTimeInterArrivalUpshift = 8;
32constexpr int kInterArrivalShift =
33 kAbsSendTimeFraction + kAbsSendTimeInterArrivalUpshift;
34constexpr double kTimestampToMs =
philipel863a8262016-06-17 09:21:34 -070035 1000.0 / static_cast<double>(1 << kInterArrivalShift);
philipel7522a282016-08-16 10:59:36 +020036// This ssrc is used to fulfill the current API but will be removed
37// after the API has been changed.
38constexpr uint32_t kFixedSsrc = 0;
Stefan Holmer492ee282016-10-27 17:19:20 +020039constexpr int kInitialRateWindowMs = 500;
40constexpr int kRateWindowMs = 150;
41
tereliusafaef8b2016-11-17 03:48:18 -080042constexpr size_t kDefaultTrendlineWindowSize = 15;
43constexpr double kDefaultTrendlineSmoothingCoeff = 0.9;
44constexpr double kDefaultTrendlineThresholdGain = 4.0;
45
Stefan Holmer492ee282016-10-27 17:19:20 +020046const char kBitrateEstimateExperiment[] = "WebRTC-ImprovedBitrateEstimate";
tereliusafaef8b2016-11-17 03:48:18 -080047const char kBweTrendlineFilterExperiment[] = "WebRTC-BweTrendlineFilter";
Stefan Holmer492ee282016-10-27 17:19:20 +020048
49bool BitrateEstimateExperimentIsEnabled() {
50 return webrtc::field_trial::FindFullName(kBitrateEstimateExperiment) ==
51 "Enabled";
52}
tereliusafaef8b2016-11-17 03:48:18 -080053
54bool TrendlineFilterExperimentIsEnabled() {
55 std::string experiment_string =
56 webrtc::field_trial::FindFullName(kBweTrendlineFilterExperiment);
57 // The experiment is enabled iff the field trial string begins with "Enabled".
58 return experiment_string.find("Enabled") == 0;
59}
60
61bool ReadTrendlineFilterExperimentParameters(size_t* window_points,
62 double* smoothing_coef,
63 double* threshold_gain) {
64 RTC_DCHECK(TrendlineFilterExperimentIsEnabled());
65 std::string experiment_string =
66 webrtc::field_trial::FindFullName(kBweTrendlineFilterExperiment);
67 int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%zu,%lf,%lf",
68 window_points, smoothing_coef, threshold_gain);
69 if (parsed_values == 3) {
70 RTC_CHECK_GT(*window_points, 1) << "Need at least 2 points to fit a line.";
71 RTC_CHECK(0 <= *smoothing_coef && *smoothing_coef <= 1)
72 << "Coefficient needs to be between 0 and 1 for weighted average.";
73 RTC_CHECK_GT(*threshold_gain, 0) << "Threshold gain needs to be positive.";
74 return true;
75 }
76 LOG(LS_WARNING) << "Failed to parse parameters for BweTrendlineFilter "
77 "experiment from field trial string. Using default.";
78 *window_points = kDefaultTrendlineWindowSize;
79 *smoothing_coef = kDefaultTrendlineSmoothingCoeff;
80 *threshold_gain = kDefaultTrendlineThresholdGain;
81 return false;
82}
83
philipel863a8262016-06-17 09:21:34 -070084} // namespace
85
86namespace webrtc {
tereliusafaef8b2016-11-17 03:48:18 -080087
Stefan Holmer492ee282016-10-27 17:19:20 +020088DelayBasedBwe::BitrateEstimator::BitrateEstimator()
89 : sum_(0),
90 current_win_ms_(0),
91 prev_time_ms_(-1),
92 bitrate_estimate_(-1.0f),
93 bitrate_estimate_var_(50.0f),
94 old_estimator_(kBitrateWindowMs, 8000),
95 in_experiment_(BitrateEstimateExperimentIsEnabled()) {}
96
97void DelayBasedBwe::BitrateEstimator::Update(int64_t now_ms, int bytes) {
98 if (!in_experiment_) {
99 old_estimator_.Update(bytes, now_ms);
100 rtc::Optional<uint32_t> rate = old_estimator_.Rate(now_ms);
101 bitrate_estimate_ = -1.0f;
102 if (rate)
103 bitrate_estimate_ = *rate / 1000.0f;
104 return;
105 }
106 int rate_window_ms = kRateWindowMs;
107 // We use a larger window at the beginning to get a more stable sample that
108 // we can use to initialize the estimate.
109 if (bitrate_estimate_ < 0.f)
110 rate_window_ms = kInitialRateWindowMs;
111 float bitrate_sample = UpdateWindow(now_ms, bytes, rate_window_ms);
112 if (bitrate_sample < 0.0f)
113 return;
114 if (bitrate_estimate_ < 0.0f) {
115 // This is the very first sample we get. Use it to initialize the estimate.
116 bitrate_estimate_ = bitrate_sample;
117 return;
118 }
119 // Define the sample uncertainty as a function of how far away it is from the
120 // current estimate.
121 float sample_uncertainty =
122 10.0f * std::abs(bitrate_estimate_ - bitrate_sample) / bitrate_estimate_;
123 float sample_var = sample_uncertainty * sample_uncertainty;
124 // Update a bayesian estimate of the rate, weighting it lower if the sample
125 // uncertainty is large.
126 // The bitrate estimate uncertainty is increased with each update to model
127 // that the bitrate changes over time.
128 float pred_bitrate_estimate_var = bitrate_estimate_var_ + 5.f;
129 bitrate_estimate_ = (sample_var * bitrate_estimate_ +
130 pred_bitrate_estimate_var * bitrate_sample) /
131 (sample_var + pred_bitrate_estimate_var);
132 bitrate_estimate_var_ = sample_var * pred_bitrate_estimate_var /
133 (sample_var + pred_bitrate_estimate_var);
134}
135
136float DelayBasedBwe::BitrateEstimator::UpdateWindow(int64_t now_ms,
137 int bytes,
138 int rate_window_ms) {
139 // Reset if time moves backwards.
140 if (now_ms < prev_time_ms_) {
141 prev_time_ms_ = -1;
142 sum_ = 0;
143 current_win_ms_ = 0;
144 }
145 if (prev_time_ms_ >= 0) {
146 current_win_ms_ += now_ms - prev_time_ms_;
147 // Reset if nothing has been received for more than a full window.
148 if (now_ms - prev_time_ms_ > rate_window_ms) {
149 sum_ = 0;
150 current_win_ms_ %= rate_window_ms;
151 }
152 }
153 prev_time_ms_ = now_ms;
154 float bitrate_sample = -1.0f;
155 if (current_win_ms_ >= rate_window_ms) {
156 bitrate_sample = 8.0f * sum_ / static_cast<float>(rate_window_ms);
157 current_win_ms_ -= rate_window_ms;
158 sum_ = 0;
159 }
160 sum_ += bytes;
161 return bitrate_sample;
162}
163
164rtc::Optional<uint32_t> DelayBasedBwe::BitrateEstimator::bitrate_bps() const {
165 if (bitrate_estimate_ < 0.f)
166 return rtc::Optional<uint32_t>();
167 return rtc::Optional<uint32_t>(bitrate_estimate_ * 1000);
168}
philipel863a8262016-06-17 09:21:34 -0700169
Stefan Holmer280de9e2016-09-30 10:06:51 +0200170DelayBasedBwe::DelayBasedBwe(Clock* clock)
stefan5e12d362016-07-11 01:44:02 -0700171 : clock_(clock),
philipel863a8262016-06-17 09:21:34 -0700172 inter_arrival_(),
tereliusafaef8b2016-11-17 03:48:18 -0800173 kalman_estimator_(),
174 trendline_estimator_(),
philipel863a8262016-06-17 09:21:34 -0700175 detector_(OverUseDetectorOptions()),
Stefan Holmer492ee282016-10-27 17:19:20 +0200176 receiver_incoming_bitrate_(),
philipel863a8262016-06-17 09:21:34 -0700177 last_update_ms_(-1),
philipel7522a282016-08-16 10:59:36 +0200178 last_seen_packet_ms_(-1),
tereliusafaef8b2016-11-17 03:48:18 -0800179 uma_recorded_(false),
180 trendline_window_size_(kDefaultTrendlineWindowSize),
181 trendline_smoothing_coeff_(kDefaultTrendlineSmoothingCoeff),
182 trendline_threshold_gain_(kDefaultTrendlineThresholdGain),
minyue78b4d562016-11-30 04:47:39 -0800183 in_trendline_experiment_(TrendlineFilterExperimentIsEnabled()),
184 probing_interval_estimator_(&rate_control_) {
tereliusafaef8b2016-11-17 03:48:18 -0800185 if (in_trendline_experiment_) {
186 ReadTrendlineFilterExperimentParameters(&trendline_window_size_,
187 &trendline_smoothing_coeff_,
188 &trendline_threshold_gain_);
189 }
philipel863a8262016-06-17 09:21:34 -0700190 network_thread_.DetachFromThread();
191}
192
Stefan Holmer280de9e2016-09-30 10:06:51 +0200193DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
philipel863a8262016-06-17 09:21:34 -0700194 const std::vector<PacketInfo>& packet_feedback_vector) {
195 RTC_DCHECK(network_thread_.CalledOnValidThread());
stefan64636dd2016-08-03 00:29:03 -0700196 if (!uma_recorded_) {
asapersson1d02d3e2016-09-09 22:40:25 -0700197 RTC_HISTOGRAM_ENUMERATION(kBweTypeHistogram,
198 BweNames::kSendSideTransportSeqNum,
199 BweNames::kBweNamesMax);
stefan64636dd2016-08-03 00:29:03 -0700200 uma_recorded_ = true;
201 }
Stefan Holmer280de9e2016-09-30 10:06:51 +0200202 Result aggregated_result;
philipel863a8262016-06-17 09:21:34 -0700203 for (const auto& packet_info : packet_feedback_vector) {
Stefan Holmer280de9e2016-09-30 10:06:51 +0200204 Result result = IncomingPacketInfo(packet_info);
205 if (result.updated)
206 aggregated_result = result;
philipel863a8262016-06-17 09:21:34 -0700207 }
Stefan Holmer280de9e2016-09-30 10:06:51 +0200208 return aggregated_result;
philipel863a8262016-06-17 09:21:34 -0700209}
210
Stefan Holmer280de9e2016-09-30 10:06:51 +0200211DelayBasedBwe::Result DelayBasedBwe::IncomingPacketInfo(
212 const PacketInfo& info) {
stefan5e12d362016-07-11 01:44:02 -0700213 int64_t now_ms = clock_->TimeInMilliseconds();
philipel863a8262016-06-17 09:21:34 -0700214
Stefan Holmer492ee282016-10-27 17:19:20 +0200215 receiver_incoming_bitrate_.Update(info.arrival_time_ms, info.payload_size);
Stefan Holmer280de9e2016-09-30 10:06:51 +0200216 Result result;
217 // Reset if the stream has timed out.
218 if (last_seen_packet_ms_ == -1 ||
219 now_ms - last_seen_packet_ms_ > kStreamTimeOutMs) {
220 inter_arrival_.reset(
221 new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000,
222 kTimestampToMs, true));
tereliusafaef8b2016-11-17 03:48:18 -0800223 kalman_estimator_.reset(new OveruseEstimator(OverUseDetectorOptions()));
224 trendline_estimator_.reset(new TrendlineEstimator(
225 trendline_window_size_, trendline_smoothing_coeff_,
226 trendline_threshold_gain_));
Stefan Holmer280de9e2016-09-30 10:06:51 +0200227 }
228 last_seen_packet_ms_ = now_ms;
philipel863a8262016-06-17 09:21:34 -0700229
Stefan Holmer280de9e2016-09-30 10:06:51 +0200230 uint32_t send_time_24bits =
231 static_cast<uint32_t>(
232 ((static_cast<uint64_t>(info.send_time_ms) << kAbsSendTimeFraction) +
233 500) /
234 1000) &
235 0x00FFFFFF;
236 // Shift up send time to use the full 32 bits that inter_arrival works with,
237 // so wrapping works properly.
238 uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
stefanfd0d4262016-09-29 02:44:31 -0700239
Stefan Holmer280de9e2016-09-30 10:06:51 +0200240 uint32_t ts_delta = 0;
241 int64_t t_delta = 0;
242 int size_delta = 0;
243 if (inter_arrival_->ComputeDeltas(timestamp, info.arrival_time_ms, now_ms,
244 info.payload_size, &ts_delta, &t_delta,
245 &size_delta)) {
246 double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
tereliusafaef8b2016-11-17 03:48:18 -0800247 if (in_trendline_experiment_) {
248 trendline_estimator_->Update(t_delta, ts_delta_ms, info.arrival_time_ms);
249 detector_.Detect(trendline_estimator_->trendline_slope(), ts_delta_ms,
250 trendline_estimator_->num_of_deltas(),
Stefan Holmer280de9e2016-09-30 10:06:51 +0200251 info.arrival_time_ms);
tereliusafaef8b2016-11-17 03:48:18 -0800252
253 } else {
254 kalman_estimator_->Update(t_delta, ts_delta_ms, size_delta,
255 detector_.State(), info.arrival_time_ms);
256 detector_.Detect(kalman_estimator_->offset(), ts_delta_ms,
257 kalman_estimator_->num_of_deltas(),
258 info.arrival_time_ms);
259 }
stefan5ec85fb2016-09-29 04:19:38 -0700260 }
261
Stefan Holmer280de9e2016-09-30 10:06:51 +0200262 int probing_bps = 0;
263 if (info.probe_cluster_id != PacketInfo::kNotAProbe) {
264 probing_bps = probe_bitrate_estimator_.HandleProbeAndEstimateBitrate(info);
265 }
Stefan Holmer492ee282016-10-27 17:19:20 +0200266 rtc::Optional<uint32_t> acked_bitrate_bps =
267 receiver_incoming_bitrate_.bitrate_bps();
Stefan Holmer280de9e2016-09-30 10:06:51 +0200268 // Currently overusing the bandwidth.
269 if (detector_.State() == kBwOverusing) {
Stefan Holmer492ee282016-10-27 17:19:20 +0200270 if (acked_bitrate_bps &&
271 rate_control_.TimeToReduceFurther(now_ms, *acked_bitrate_bps)) {
272 result.updated =
273 UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps,
274 &result.target_bitrate_bps);
Stefan Holmer280de9e2016-09-30 10:06:51 +0200275 }
276 } else if (probing_bps > 0) {
277 // No overuse, but probing measured a bitrate.
terelius6ed592d2016-10-18 05:55:30 -0700278 rate_control_.SetEstimate(probing_bps, info.arrival_time_ms);
Stefan Holmer280de9e2016-09-30 10:06:51 +0200279 result.probe = true;
Stefan Holmer492ee282016-10-27 17:19:20 +0200280 result.updated =
281 UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps,
282 &result.target_bitrate_bps);
Stefan Holmer280de9e2016-09-30 10:06:51 +0200283 }
Stefan Holmer280de9e2016-09-30 10:06:51 +0200284 if (!result.updated &&
285 (last_update_ms_ == -1 ||
terelius6ed592d2016-10-18 05:55:30 -0700286 now_ms - last_update_ms_ > rate_control_.GetFeedbackInterval())) {
Stefan Holmer492ee282016-10-27 17:19:20 +0200287 result.updated =
288 UpdateEstimate(info.arrival_time_ms, now_ms, acked_bitrate_bps,
289 &result.target_bitrate_bps);
Stefan Holmer280de9e2016-09-30 10:06:51 +0200290 }
291 if (result.updated)
stefan5ec85fb2016-09-29 04:19:38 -0700292 last_update_ms_ = now_ms;
Stefan Holmer280de9e2016-09-30 10:06:51 +0200293
294 return result;
philipel863a8262016-06-17 09:21:34 -0700295}
296
Irfan Sheriffb2540bb2016-09-12 12:28:54 -0700297bool DelayBasedBwe::UpdateEstimate(int64_t arrival_time_ms,
298 int64_t now_ms,
Stefan Holmer492ee282016-10-27 17:19:20 +0200299 rtc::Optional<uint32_t> acked_bitrate_bps,
Irfan Sheriffb2540bb2016-09-12 12:28:54 -0700300 uint32_t* target_bitrate_bps) {
tereliusafaef8b2016-11-17 03:48:18 -0800301 // TODO(terelius): RateControlInput::noise_var is deprecated and will be
302 // removed. In the meantime, we set it to zero.
303 const RateControlInput input(detector_.State(), acked_bitrate_bps, 0);
terelius6ed592d2016-10-18 05:55:30 -0700304 rate_control_.Update(&input, now_ms);
305 *target_bitrate_bps = rate_control_.UpdateBandwidthEstimate(now_ms);
306 return rate_control_.ValidEstimate();
Irfan Sheriffb2540bb2016-09-12 12:28:54 -0700307}
308
philipel863a8262016-06-17 09:21:34 -0700309void DelayBasedBwe::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
terelius6ed592d2016-10-18 05:55:30 -0700310 rate_control_.SetRtt(avg_rtt_ms);
philipel863a8262016-06-17 09:21:34 -0700311}
312
philipel863a8262016-06-17 09:21:34 -0700313bool DelayBasedBwe::LatestEstimate(std::vector<uint32_t>* ssrcs,
314 uint32_t* bitrate_bps) const {
315 // Currently accessed from both the process thread (see
316 // ModuleRtpRtcpImpl::Process()) and the configuration thread (see
317 // Call::GetStats()). Should in the future only be accessed from a single
318 // thread.
319 RTC_DCHECK(ssrcs);
320 RTC_DCHECK(bitrate_bps);
terelius6ed592d2016-10-18 05:55:30 -0700321 if (!rate_control_.ValidEstimate())
philipel863a8262016-06-17 09:21:34 -0700322 return false;
philipel7522a282016-08-16 10:59:36 +0200323
324 *ssrcs = {kFixedSsrc};
terelius6ed592d2016-10-18 05:55:30 -0700325 *bitrate_bps = rate_control_.LatestEstimate();
philipel863a8262016-06-17 09:21:34 -0700326 return true;
327}
328
329void DelayBasedBwe::SetMinBitrate(int min_bitrate_bps) {
330 // Called from both the configuration thread and the network thread. Shouldn't
331 // be called from the network thread in the future.
terelius6ed592d2016-10-18 05:55:30 -0700332 rate_control_.SetMinBitrate(min_bitrate_bps);
philipel863a8262016-06-17 09:21:34 -0700333}
minyue78b4d562016-11-30 04:47:39 -0800334
335int64_t DelayBasedBwe::GetProbingIntervalMs() const {
336 return probing_interval_estimator_.GetIntervalMs();
337}
philipel863a8262016-06-17 09:21:34 -0700338} // namespace webrtc