blob: c81a18c3b4cea53cd7f03b0a54a6ae86a4606a4d [file] [log] [blame]
stefan@webrtc.org82462aa2014-10-23 11:57:05 +00001/*
2 * Copyright (c) 2014 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/pacing/bitrate_prober.h"
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000012
Stefan Holmer01b48882015-05-05 10:21:24 +020013#include <algorithm>
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000014
Karl Wiberg918f50c2018-07-05 11:40:33 +020015#include "absl/memory/memory.h"
Yves Gerey988cc082018-10-23 12:03:01 +020016#include "logging/rtc_event_log/events/rtc_event.h"
Elad Alon4a87e1c2017-10-03 16:11:34 +020017#include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "logging/rtc_event_log/rtc_event_log.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/checks.h"
20#include "rtc_base/logging.h"
Jonas Olsson8f433842019-03-25 10:10:31 +010021#include "system_wrappers/include/metrics.h"
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000022
23namespace webrtc {
24
25namespace {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070026
isheriffcc5903e2016-10-04 08:29:38 -070027// A minimum interval between probes to allow scheduling to be feasible.
28constexpr int kMinProbeDeltaMs = 1;
29
philipelfd58b612017-01-04 07:05:25 -080030// The minimum number probing packets used.
31constexpr int kMinProbePacketsSent = 5;
32
33// The minimum probing duration in ms.
34constexpr int kMinProbeDurationMs = 15;
35
sergeyu6dbbd892017-01-17 15:07:59 -080036// Maximum amount of time each probe can be delayed. Probe cluster is reset and
37// retried from the start when this limit is reached.
38constexpr int kMaxProbeDelayMs = 3;
39
stefanf00497c2017-01-27 02:27:33 -080040// The min probe packet size is scaled with the bitrate we're probing at.
41// This defines the max min probe packet size, meaning that on high bitrates
42// we have a min probe packet size of 200 bytes.
43constexpr size_t kMinProbePacketSize = 200;
44
Stefan Holmer0e3213a2017-02-08 15:19:05 +010045constexpr int64_t kProbeClusterTimeoutMs = 5000;
46
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000047} // namespace
48
philipelc3b3f7a2017-03-29 01:23:13 -070049BitrateProber::BitrateProber() : BitrateProber(nullptr) {}
50
Jonas Olsson8f433842019-03-25 10:10:31 +010051BitrateProber::~BitrateProber() {
52 RTC_HISTOGRAM_COUNTS_1000("WebRTC.BWE.Probing.TotalProbeClustersRequested",
53 total_probe_count_);
54 RTC_HISTOGRAM_COUNTS_1000("WebRTC.BWE.Probing.TotalFailedProbeClusters",
55 total_failed_probe_count_);
56}
Mirko Bonadeib471c902018-07-18 14:11:27 +020057
Piotr (Peter) Slatalac39f4622019-02-15 07:38:04 -080058// TODO(psla): Remove this constructor in a follow up change.
philipelc3b3f7a2017-03-29 01:23:13 -070059BitrateProber::BitrateProber(RtcEventLog* event_log)
Jonas Olsson8f433842019-03-25 10:10:31 +010060 : probing_state_(ProbingState::kDisabled),
61 next_probe_time_ms_(-1),
62 total_probe_count_(0),
63 total_failed_probe_count_(0) {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070064 SetEnabled(true);
65}
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000066
67void BitrateProber::SetEnabled(bool enable) {
68 if (enable) {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070069 if (probing_state_ == ProbingState::kDisabled) {
70 probing_state_ = ProbingState::kInactive;
Mirko Bonadei675513b2017-11-09 11:09:25 +010071 RTC_LOG(LS_INFO) << "Bandwidth probing enabled, set to inactive";
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000072 }
73 } else {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070074 probing_state_ = ProbingState::kDisabled;
Mirko Bonadei675513b2017-11-09 11:09:25 +010075 RTC_LOG(LS_INFO) << "Bandwidth probing disabled";
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000076 }
77}
78
79bool BitrateProber::IsProbing() const {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070080 return probing_state_ == ProbingState::kActive;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000081}
82
philipel4a1ec1e2016-08-15 11:51:06 -070083void BitrateProber::OnIncomingPacket(size_t packet_size) {
Peter Boström0453ef82016-02-16 16:23:08 +010084 // Don't initialize probing unless we have something large enough to start
85 // probing.
stefanf00497c2017-01-27 02:27:33 -080086 if (probing_state_ == ProbingState::kInactive && !clusters_.empty() &&
87 packet_size >=
88 std::min<size_t>(RecommendedMinProbeSize(), kMinProbePacketSize)) {
sergeyu6dbbd892017-01-17 15:07:59 -080089 // Send next probe right away.
90 next_probe_time_ms_ = -1;
philipel4a1ec1e2016-08-15 11:51:06 -070091 probing_state_ = ProbingState::kActive;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000092 }
philipel4a1ec1e2016-08-15 11:51:06 -070093}
94
Piotr (Peter) Slatalac39f4622019-02-15 07:38:04 -080095void BitrateProber::CreateProbeCluster(int bitrate_bps,
96 int64_t now_ms,
97 int cluster_id) {
Irfan Sheriffb2540bb2016-09-12 12:28:54 -070098 RTC_DCHECK(probing_state_ != ProbingState::kDisabled);
philipeld1d247f2017-05-04 08:35:52 -070099 RTC_DCHECK_GT(bitrate_bps, 0);
Jonas Olsson8f433842019-03-25 10:10:31 +0100100
101 total_probe_count_++;
Stefan Holmer0e3213a2017-02-08 15:19:05 +0100102 while (!clusters_.empty() &&
103 now_ms - clusters_.front().time_created_ms > kProbeClusterTimeoutMs) {
104 clusters_.pop();
Jonas Olsson8f433842019-03-25 10:10:31 +0100105 total_failed_probe_count_++;
Stefan Holmer0e3213a2017-02-08 15:19:05 +0100106 }
107
philipel4a1ec1e2016-08-15 11:51:06 -0700108 ProbeCluster cluster;
Stefan Holmer0e3213a2017-02-08 15:19:05 +0100109 cluster.time_created_ms = now_ms;
philipelc7bf32a2017-02-17 03:59:43 -0800110 cluster.pace_info.probe_cluster_min_probes = kMinProbePacketsSent;
Johannes Kron85846672018-11-09 12:39:38 +0100111 cluster.pace_info.probe_cluster_min_bytes = static_cast<int32_t>(
112 static_cast<int64_t>(bitrate_bps) * kMinProbeDurationMs / 8000);
113 RTC_DCHECK_GE(cluster.pace_info.probe_cluster_min_bytes, 0);
philipelc7bf32a2017-02-17 03:59:43 -0800114 cluster.pace_info.send_bitrate_bps = bitrate_bps;
Piotr (Peter) Slatalac39f4622019-02-15 07:38:04 -0800115 cluster.pace_info.probe_cluster_id = cluster_id;
philipel4a1ec1e2016-08-15 11:51:06 -0700116 clusters_.push(cluster);
philipelfd58b612017-01-04 07:05:25 -0800117
Mirko Bonadei675513b2017-11-09 11:09:25 +0100118 RTC_LOG(LS_INFO) << "Probe cluster (bitrate:min bytes:min packets): ("
119 << cluster.pace_info.send_bitrate_bps << ":"
120 << cluster.pace_info.probe_cluster_min_bytes << ":"
121 << cluster.pace_info.probe_cluster_min_probes << ")";
philipelfd58b612017-01-04 07:05:25 -0800122 // If we are already probing, continue to do so. Otherwise set it to
123 // kInactive and wait for OnIncomingPacket to start the probing.
philipel4a1ec1e2016-08-15 11:51:06 -0700124 if (probing_state_ != ProbingState::kActive)
125 probing_state_ = ProbingState::kInactive;
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700126}
127
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000128int BitrateProber::TimeUntilNextProbe(int64_t now_ms) {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700129 // Probing is not active or probing is already complete.
130 if (probing_state_ != ProbingState::kActive || clusters_.empty())
stefan@webrtc.orge9f0f592015-02-16 15:47:51 +0000131 return -1;
sergeyu6dbbd892017-01-17 15:07:59 -0800132
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000133 int time_until_probe_ms = 0;
sergeyu6dbbd892017-01-17 15:07:59 -0800134 if (next_probe_time_ms_ >= 0) {
135 time_until_probe_ms = next_probe_time_ms_ - now_ms;
136 if (time_until_probe_ms < -kMaxProbeDelayMs) {
Jamie Walch9c8ae4b2018-10-24 10:17:52 -0700137 RTC_DLOG(LS_WARNING) << "Probe delay too high"
138 << " (next_ms:" << next_probe_time_ms_
139 << ", now_ms: " << now_ms << ")";
sergeyu6dbbd892017-01-17 15:07:59 -0800140 return -1;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000141 }
142 }
sergeyu6dbbd892017-01-17 15:07:59 -0800143
Stefan Holmer01b48882015-05-05 10:21:24 +0200144 return std::max(time_until_probe_ms, 0);
145}
146
philipelc7bf32a2017-02-17 03:59:43 -0800147PacedPacketInfo BitrateProber::CurrentCluster() const {
philipeldd324862016-05-06 17:06:14 +0200148 RTC_DCHECK(!clusters_.empty());
philipeld1d247f2017-05-04 08:35:52 -0700149 RTC_DCHECK(probing_state_ == ProbingState::kActive);
philipelc7bf32a2017-02-17 03:59:43 -0800150 return clusters_.front().pace_info;
philipeldd324862016-05-06 17:06:14 +0200151}
152
isheriffcc5903e2016-10-04 08:29:38 -0700153// Probe size is recommended based on the probe bitrate required. We choose
154// a minimum of twice |kMinProbeDeltaMs| interval to allow scheduling to be
155// feasible.
156size_t BitrateProber::RecommendedMinProbeSize() const {
157 RTC_DCHECK(!clusters_.empty());
philipelc7bf32a2017-02-17 03:59:43 -0800158 return clusters_.front().pace_info.send_bitrate_bps * 2 * kMinProbeDeltaMs /
159 (8 * 1000);
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000160}
161
isheriffcc5903e2016-10-04 08:29:38 -0700162void BitrateProber::ProbeSent(int64_t now_ms, size_t bytes) {
163 RTC_DCHECK(probing_state_ == ProbingState::kActive);
kwibergaf476c72016-11-28 15:21:39 -0800164 RTC_DCHECK_GT(bytes, 0);
sergeyu6dbbd892017-01-17 15:07:59 -0800165
philipeldd324862016-05-06 17:06:14 +0200166 if (!clusters_.empty()) {
167 ProbeCluster* cluster = &clusters_.front();
sergeyu6dbbd892017-01-17 15:07:59 -0800168 if (cluster->sent_probes == 0) {
169 RTC_DCHECK_EQ(cluster->time_started_ms, -1);
170 cluster->time_started_ms = now_ms;
171 }
philipelfd58b612017-01-04 07:05:25 -0800172 cluster->sent_bytes += static_cast<int>(bytes);
173 cluster->sent_probes += 1;
philipeld1d247f2017-05-04 08:35:52 -0700174 next_probe_time_ms_ = GetNextProbeTime(*cluster);
philipelc7bf32a2017-02-17 03:59:43 -0800175 if (cluster->sent_bytes >= cluster->pace_info.probe_cluster_min_bytes &&
176 cluster->sent_probes >= cluster->pace_info.probe_cluster_min_probes) {
Jonas Olsson8f433842019-03-25 10:10:31 +0100177 RTC_HISTOGRAM_COUNTS_100000("WebRTC.BWE.Probing.ProbeClusterSizeInBytes",
178 cluster->sent_bytes);
179 RTC_HISTOGRAM_COUNTS_100("WebRTC.BWE.Probing.ProbesPerCluster",
180 cluster->sent_probes);
181 RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.Probing.TimePerProbeCluster",
182 now_ms - cluster->time_started_ms);
183
philipeldd324862016-05-06 17:06:14 +0200184 clusters_.pop();
philipelfd58b612017-01-04 07:05:25 -0800185 }
philipel1a93cde2016-06-03 01:41:45 -0700186 if (clusters_.empty())
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700187 probing_state_ = ProbingState::kSuspended;
philipeldd324862016-05-06 17:06:14 +0200188 }
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000189}
sergeyu6dbbd892017-01-17 15:07:59 -0800190
191int64_t BitrateProber::GetNextProbeTime(const ProbeCluster& cluster) {
philipelc7bf32a2017-02-17 03:59:43 -0800192 RTC_CHECK_GT(cluster.pace_info.send_bitrate_bps, 0);
sergeyu6dbbd892017-01-17 15:07:59 -0800193 RTC_CHECK_GE(cluster.time_started_ms, 0);
194
195 // Compute the time delta from the cluster start to ensure probe bitrate stays
196 // close to the target bitrate. Result is in milliseconds.
philipelc7bf32a2017-02-17 03:59:43 -0800197 int64_t delta_ms =
198 (8000ll * cluster.sent_bytes + cluster.pace_info.send_bitrate_bps / 2) /
199 cluster.pace_info.send_bitrate_bps;
sergeyu6dbbd892017-01-17 15:07:59 -0800200 return cluster.time_started_ms + delta_ms;
201}
202
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000203} // namespace webrtc