blob: e4de4a8dadc120c869b91dd4110ac887e34692e9 [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
11#include "webrtc/modules/pacing/bitrate_prober.h"
12
Stefan Holmer01b48882015-05-05 10:21:24 +020013#include <algorithm>
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000014
philipeldd324862016-05-06 17:06:14 +020015#include "webrtc/base/checks.h"
Peter Boström7c704b82015-12-04 16:13:05 +010016#include "webrtc/base/logging.h"
philipelc3b3f7a2017-03-29 01:23:13 -070017#include "webrtc/logging/rtc_event_log/rtc_event_log.h"
Henrik Kjellander0b9e29c2015-11-16 11:12:24 +010018#include "webrtc/modules/pacing/paced_sender.h"
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000019
20namespace webrtc {
21
22namespace {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070023
isheriffcc5903e2016-10-04 08:29:38 -070024// A minimum interval between probes to allow scheduling to be feasible.
25constexpr int kMinProbeDeltaMs = 1;
26
philipelfd58b612017-01-04 07:05:25 -080027// The minimum number probing packets used.
28constexpr int kMinProbePacketsSent = 5;
29
30// The minimum probing duration in ms.
31constexpr int kMinProbeDurationMs = 15;
32
sergeyu6dbbd892017-01-17 15:07:59 -080033// Maximum amount of time each probe can be delayed. Probe cluster is reset and
34// retried from the start when this limit is reached.
35constexpr int kMaxProbeDelayMs = 3;
36
37// Number of times probing is retried before the cluster is dropped.
38constexpr int kMaxRetryAttempts = 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
51BitrateProber::BitrateProber(RtcEventLog* event_log)
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070052 : probing_state_(ProbingState::kDisabled),
sergeyu6dbbd892017-01-17 15:07:59 -080053 next_probe_time_ms_(-1),
philipelc3b3f7a2017-03-29 01:23:13 -070054 next_cluster_id_(0),
55 event_log_(event_log) {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070056 SetEnabled(true);
57}
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000058
59void BitrateProber::SetEnabled(bool enable) {
60 if (enable) {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070061 if (probing_state_ == ProbingState::kDisabled) {
62 probing_state_ = ProbingState::kInactive;
63 LOG(LS_INFO) << "Bandwidth probing enabled, set to inactive";
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000064 }
65 } else {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070066 probing_state_ = ProbingState::kDisabled;
67 LOG(LS_INFO) << "Bandwidth probing disabled";
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000068 }
69}
70
71bool BitrateProber::IsProbing() const {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070072 return probing_state_ == ProbingState::kActive;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000073}
74
philipel4a1ec1e2016-08-15 11:51:06 -070075void BitrateProber::OnIncomingPacket(size_t packet_size) {
Peter Boström0453ef82016-02-16 16:23:08 +010076 // Don't initialize probing unless we have something large enough to start
77 // probing.
stefanf00497c2017-01-27 02:27:33 -080078 if (probing_state_ == ProbingState::kInactive && !clusters_.empty() &&
79 packet_size >=
80 std::min<size_t>(RecommendedMinProbeSize(), kMinProbePacketSize)) {
sergeyu6dbbd892017-01-17 15:07:59 -080081 // Send next probe right away.
82 next_probe_time_ms_ = -1;
philipel4a1ec1e2016-08-15 11:51:06 -070083 probing_state_ = ProbingState::kActive;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000084 }
philipel4a1ec1e2016-08-15 11:51:06 -070085}
86
Stefan Holmer0e3213a2017-02-08 15:19:05 +010087void BitrateProber::CreateProbeCluster(int bitrate_bps, int64_t now_ms) {
Irfan Sheriffb2540bb2016-09-12 12:28:54 -070088 RTC_DCHECK(probing_state_ != ProbingState::kDisabled);
Stefan Holmer0e3213a2017-02-08 15:19:05 +010089 while (!clusters_.empty() &&
90 now_ms - clusters_.front().time_created_ms > kProbeClusterTimeoutMs) {
91 clusters_.pop();
92 }
93
philipel4a1ec1e2016-08-15 11:51:06 -070094 ProbeCluster cluster;
Stefan Holmer0e3213a2017-02-08 15:19:05 +010095 cluster.time_created_ms = now_ms;
philipelc7bf32a2017-02-17 03:59:43 -080096 cluster.pace_info.probe_cluster_min_probes = kMinProbePacketsSent;
97 cluster.pace_info.probe_cluster_min_bytes =
98 bitrate_bps * kMinProbeDurationMs / 8000;
99 cluster.pace_info.send_bitrate_bps = bitrate_bps;
100 cluster.pace_info.probe_cluster_id = next_cluster_id_++;
philipel4a1ec1e2016-08-15 11:51:06 -0700101 clusters_.push(cluster);
philipelc3b3f7a2017-03-29 01:23:13 -0700102 if (event_log_)
103 event_log_->LogProbeClusterCreated(
104 cluster.pace_info.probe_cluster_id, cluster.pace_info.send_bitrate_bps,
105 cluster.pace_info.probe_cluster_min_probes,
106 cluster.pace_info.probe_cluster_min_bytes);
philipelfd58b612017-01-04 07:05:25 -0800107
108 LOG(LS_INFO) << "Probe cluster (bitrate:min bytes:min packets): ("
philipelc7bf32a2017-02-17 03:59:43 -0800109 << cluster.pace_info.send_bitrate_bps << ":"
110 << cluster.pace_info.probe_cluster_min_bytes << ":"
111 << cluster.pace_info.probe_cluster_min_probes << ")";
philipelfd58b612017-01-04 07:05:25 -0800112 // If we are already probing, continue to do so. Otherwise set it to
113 // kInactive and wait for OnIncomingPacket to start the probing.
philipel4a1ec1e2016-08-15 11:51:06 -0700114 if (probing_state_ != ProbingState::kActive)
115 probing_state_ = ProbingState::kInactive;
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700116}
117
Stefan Holmer0e3213a2017-02-08 15:19:05 +0100118void BitrateProber::ResetState(int64_t now_ms) {
sergeyu6dbbd892017-01-17 15:07:59 -0800119 RTC_DCHECK(probing_state_ == ProbingState::kActive);
sprangebfbc8e2017-01-10 01:27:28 -0800120
philipel4a1ec1e2016-08-15 11:51:06 -0700121 // Recreate all probing clusters.
122 std::queue<ProbeCluster> clusters;
123 clusters.swap(clusters_);
124 while (!clusters.empty()) {
sergeyu6dbbd892017-01-17 15:07:59 -0800125 if (clusters.front().retries < kMaxRetryAttempts) {
philipelc7bf32a2017-02-17 03:59:43 -0800126 CreateProbeCluster(clusters.front().pace_info.send_bitrate_bps, now_ms);
sergeyu6dbbd892017-01-17 15:07:59 -0800127 clusters_.back().retries = clusters.front().retries + 1;
128 }
philipel4a1ec1e2016-08-15 11:51:06 -0700129 clusters.pop();
130 }
sergeyu6dbbd892017-01-17 15:07:59 -0800131
132 probing_state_ = ProbingState::kInactive;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000133}
134
135int BitrateProber::TimeUntilNextProbe(int64_t now_ms) {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700136 // Probing is not active or probing is already complete.
137 if (probing_state_ != ProbingState::kActive || clusters_.empty())
stefan@webrtc.orge9f0f592015-02-16 15:47:51 +0000138 return -1;
sergeyu6dbbd892017-01-17 15:07:59 -0800139
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000140 int time_until_probe_ms = 0;
sergeyu6dbbd892017-01-17 15:07:59 -0800141 if (next_probe_time_ms_ >= 0) {
142 time_until_probe_ms = next_probe_time_ms_ - now_ms;
143 if (time_until_probe_ms < -kMaxProbeDelayMs) {
Stefan Holmer0e3213a2017-02-08 15:19:05 +0100144 ResetState(now_ms);
sergeyu6dbbd892017-01-17 15:07:59 -0800145 return -1;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000146 }
147 }
sergeyu6dbbd892017-01-17 15:07:59 -0800148
Stefan Holmer01b48882015-05-05 10:21:24 +0200149 return std::max(time_until_probe_ms, 0);
150}
151
philipelc7bf32a2017-02-17 03:59:43 -0800152PacedPacketInfo BitrateProber::CurrentCluster() const {
philipeldd324862016-05-06 17:06:14 +0200153 RTC_DCHECK(!clusters_.empty());
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700154 RTC_DCHECK(ProbingState::kActive == probing_state_);
philipelc7bf32a2017-02-17 03:59:43 -0800155 return clusters_.front().pace_info;
philipeldd324862016-05-06 17:06:14 +0200156}
157
isheriffcc5903e2016-10-04 08:29:38 -0700158// Probe size is recommended based on the probe bitrate required. We choose
159// a minimum of twice |kMinProbeDeltaMs| interval to allow scheduling to be
160// feasible.
161size_t BitrateProber::RecommendedMinProbeSize() const {
162 RTC_DCHECK(!clusters_.empty());
philipelc7bf32a2017-02-17 03:59:43 -0800163 return clusters_.front().pace_info.send_bitrate_bps * 2 * kMinProbeDeltaMs /
164 (8 * 1000);
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000165}
166
isheriffcc5903e2016-10-04 08:29:38 -0700167void BitrateProber::ProbeSent(int64_t now_ms, size_t bytes) {
168 RTC_DCHECK(probing_state_ == ProbingState::kActive);
kwibergaf476c72016-11-28 15:21:39 -0800169 RTC_DCHECK_GT(bytes, 0);
sergeyu6dbbd892017-01-17 15:07:59 -0800170
philipeldd324862016-05-06 17:06:14 +0200171 if (!clusters_.empty()) {
172 ProbeCluster* cluster = &clusters_.front();
sergeyu6dbbd892017-01-17 15:07:59 -0800173 if (cluster->sent_probes == 0) {
174 RTC_DCHECK_EQ(cluster->time_started_ms, -1);
175 cluster->time_started_ms = now_ms;
176 }
philipelfd58b612017-01-04 07:05:25 -0800177 cluster->sent_bytes += static_cast<int>(bytes);
178 cluster->sent_probes += 1;
sergeyu6dbbd892017-01-17 15:07:59 -0800179 next_probe_time_ms_ = GetNextProbeTime(clusters_.front());
philipelc7bf32a2017-02-17 03:59:43 -0800180 if (cluster->sent_bytes >= cluster->pace_info.probe_cluster_min_bytes &&
181 cluster->sent_probes >= cluster->pace_info.probe_cluster_min_probes) {
philipeldd324862016-05-06 17:06:14 +0200182 clusters_.pop();
philipelfd58b612017-01-04 07:05:25 -0800183 }
philipel1a93cde2016-06-03 01:41:45 -0700184 if (clusters_.empty())
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700185 probing_state_ = ProbingState::kSuspended;
philipeldd324862016-05-06 17:06:14 +0200186 }
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000187}
sergeyu6dbbd892017-01-17 15:07:59 -0800188
189int64_t BitrateProber::GetNextProbeTime(const ProbeCluster& cluster) {
philipelc7bf32a2017-02-17 03:59:43 -0800190 RTC_CHECK_GT(cluster.pace_info.send_bitrate_bps, 0);
sergeyu6dbbd892017-01-17 15:07:59 -0800191 RTC_CHECK_GE(cluster.time_started_ms, 0);
192
193 // Compute the time delta from the cluster start to ensure probe bitrate stays
194 // close to the target bitrate. Result is in milliseconds.
philipelc7bf32a2017-02-17 03:59:43 -0800195 int64_t delta_ms =
196 (8000ll * cluster.sent_bytes + cluster.pace_info.send_bitrate_bps / 2) /
197 cluster.pace_info.send_bitrate_bps;
sergeyu6dbbd892017-01-17 15:07:59 -0800198 return cluster.time_started_ms + delta_ms;
199}
200
201
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000202} // namespace webrtc