blob: 37bdecf3b4b30d86075bb0df84ec011168d4f669 [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"
Henrik Kjellander0b9e29c2015-11-16 11:12:24 +010017#include "webrtc/modules/pacing/paced_sender.h"
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000018
19namespace webrtc {
20
21namespace {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070022
isheriffcc5903e2016-10-04 08:29:38 -070023// A minimum interval between probes to allow scheduling to be feasible.
24constexpr int kMinProbeDeltaMs = 1;
25
philipelfd58b612017-01-04 07:05:25 -080026// The minimum number probing packets used.
27constexpr int kMinProbePacketsSent = 5;
28
29// The minimum probing duration in ms.
30constexpr int kMinProbeDurationMs = 15;
31
sergeyu6dbbd892017-01-17 15:07:59 -080032// Maximum amount of time each probe can be delayed. Probe cluster is reset and
33// retried from the start when this limit is reached.
34constexpr int kMaxProbeDelayMs = 3;
35
36// Number of times probing is retried before the cluster is dropped.
37constexpr int kMaxRetryAttempts = 3;
38
stefanf00497c2017-01-27 02:27:33 -080039// The min probe packet size is scaled with the bitrate we're probing at.
40// This defines the max min probe packet size, meaning that on high bitrates
41// we have a min probe packet size of 200 bytes.
42constexpr size_t kMinProbePacketSize = 200;
43
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000044} // namespace
45
46BitrateProber::BitrateProber()
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070047 : probing_state_(ProbingState::kDisabled),
sergeyu6dbbd892017-01-17 15:07:59 -080048 next_probe_time_ms_(-1),
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070049 next_cluster_id_(0) {
50 SetEnabled(true);
51}
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000052
53void BitrateProber::SetEnabled(bool enable) {
54 if (enable) {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070055 if (probing_state_ == ProbingState::kDisabled) {
56 probing_state_ = ProbingState::kInactive;
57 LOG(LS_INFO) << "Bandwidth probing enabled, set to inactive";
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000058 }
59 } else {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070060 probing_state_ = ProbingState::kDisabled;
61 LOG(LS_INFO) << "Bandwidth probing disabled";
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000062 }
63}
64
65bool BitrateProber::IsProbing() const {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070066 return probing_state_ == ProbingState::kActive;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000067}
68
philipel4a1ec1e2016-08-15 11:51:06 -070069void BitrateProber::OnIncomingPacket(size_t packet_size) {
Peter Boström0453ef82016-02-16 16:23:08 +010070 // Don't initialize probing unless we have something large enough to start
71 // probing.
stefanf00497c2017-01-27 02:27:33 -080072 if (probing_state_ == ProbingState::kInactive && !clusters_.empty() &&
73 packet_size >=
74 std::min<size_t>(RecommendedMinProbeSize(), kMinProbePacketSize)) {
sergeyu6dbbd892017-01-17 15:07:59 -080075 // Send next probe right away.
76 next_probe_time_ms_ = -1;
philipel4a1ec1e2016-08-15 11:51:06 -070077 probing_state_ = ProbingState::kActive;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000078 }
philipel4a1ec1e2016-08-15 11:51:06 -070079}
80
philipelfd58b612017-01-04 07:05:25 -080081void BitrateProber::CreateProbeCluster(int bitrate_bps) {
Irfan Sheriffb2540bb2016-09-12 12:28:54 -070082 RTC_DCHECK(probing_state_ != ProbingState::kDisabled);
philipel4a1ec1e2016-08-15 11:51:06 -070083 ProbeCluster cluster;
philipelfd58b612017-01-04 07:05:25 -080084 cluster.min_probes = kMinProbePacketsSent;
85 cluster.min_bytes = bitrate_bps * kMinProbeDurationMs / 8000;
86 cluster.bitrate_bps = bitrate_bps;
philipel4a1ec1e2016-08-15 11:51:06 -070087 cluster.id = next_cluster_id_++;
88 clusters_.push(cluster);
philipelfd58b612017-01-04 07:05:25 -080089
90 LOG(LS_INFO) << "Probe cluster (bitrate:min bytes:min packets): ("
91 << cluster.bitrate_bps << ":" << cluster.min_bytes << ":"
92 << cluster.min_probes << ")";
93 // If we are already probing, continue to do so. Otherwise set it to
94 // kInactive and wait for OnIncomingPacket to start the probing.
philipel4a1ec1e2016-08-15 11:51:06 -070095 if (probing_state_ != ProbingState::kActive)
96 probing_state_ = ProbingState::kInactive;
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070097}
98
99void BitrateProber::ResetState() {
sergeyu6dbbd892017-01-17 15:07:59 -0800100 RTC_DCHECK(probing_state_ == ProbingState::kActive);
sprangebfbc8e2017-01-10 01:27:28 -0800101
philipel4a1ec1e2016-08-15 11:51:06 -0700102 // Recreate all probing clusters.
103 std::queue<ProbeCluster> clusters;
104 clusters.swap(clusters_);
105 while (!clusters.empty()) {
sergeyu6dbbd892017-01-17 15:07:59 -0800106 if (clusters.front().retries < kMaxRetryAttempts) {
107 CreateProbeCluster(clusters.front().bitrate_bps);
108 clusters_.back().retries = clusters.front().retries + 1;
109 }
philipel4a1ec1e2016-08-15 11:51:06 -0700110 clusters.pop();
111 }
sergeyu6dbbd892017-01-17 15:07:59 -0800112
113 probing_state_ = ProbingState::kInactive;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000114}
115
116int BitrateProber::TimeUntilNextProbe(int64_t now_ms) {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700117 // Probing is not active or probing is already complete.
118 if (probing_state_ != ProbingState::kActive || clusters_.empty())
stefan@webrtc.orge9f0f592015-02-16 15:47:51 +0000119 return -1;
sergeyu6dbbd892017-01-17 15:07:59 -0800120
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000121 int time_until_probe_ms = 0;
sergeyu6dbbd892017-01-17 15:07:59 -0800122 if (next_probe_time_ms_ >= 0) {
123 time_until_probe_ms = next_probe_time_ms_ - now_ms;
124 if (time_until_probe_ms < -kMaxProbeDelayMs) {
125 ResetState();
126 return -1;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000127 }
128 }
sergeyu6dbbd892017-01-17 15:07:59 -0800129
Stefan Holmer01b48882015-05-05 10:21:24 +0200130 return std::max(time_until_probe_ms, 0);
131}
132
philipeldd324862016-05-06 17:06:14 +0200133int BitrateProber::CurrentClusterId() const {
134 RTC_DCHECK(!clusters_.empty());
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700135 RTC_DCHECK(ProbingState::kActive == probing_state_);
philipeldd324862016-05-06 17:06:14 +0200136 return clusters_.front().id;
137}
138
isheriffcc5903e2016-10-04 08:29:38 -0700139// Probe size is recommended based on the probe bitrate required. We choose
140// a minimum of twice |kMinProbeDeltaMs| interval to allow scheduling to be
141// feasible.
142size_t BitrateProber::RecommendedMinProbeSize() const {
143 RTC_DCHECK(!clusters_.empty());
stefanf00497c2017-01-27 02:27:33 -0800144 return clusters_.front().bitrate_bps * 3 * kMinProbeDeltaMs / (8 * 1000);
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000145}
146
isheriffcc5903e2016-10-04 08:29:38 -0700147void BitrateProber::ProbeSent(int64_t now_ms, size_t bytes) {
148 RTC_DCHECK(probing_state_ == ProbingState::kActive);
kwibergaf476c72016-11-28 15:21:39 -0800149 RTC_DCHECK_GT(bytes, 0);
sergeyu6dbbd892017-01-17 15:07:59 -0800150
philipeldd324862016-05-06 17:06:14 +0200151 if (!clusters_.empty()) {
152 ProbeCluster* cluster = &clusters_.front();
sergeyu6dbbd892017-01-17 15:07:59 -0800153 if (cluster->sent_probes == 0) {
154 RTC_DCHECK_EQ(cluster->time_started_ms, -1);
155 cluster->time_started_ms = now_ms;
156 }
philipelfd58b612017-01-04 07:05:25 -0800157 cluster->sent_bytes += static_cast<int>(bytes);
158 cluster->sent_probes += 1;
sergeyu6dbbd892017-01-17 15:07:59 -0800159 next_probe_time_ms_ = GetNextProbeTime(clusters_.front());
philipelfd58b612017-01-04 07:05:25 -0800160 if (cluster->sent_bytes >= cluster->min_bytes &&
161 cluster->sent_probes >= cluster->min_probes) {
philipeldd324862016-05-06 17:06:14 +0200162 clusters_.pop();
philipelfd58b612017-01-04 07:05:25 -0800163 }
philipel1a93cde2016-06-03 01:41:45 -0700164 if (clusters_.empty())
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700165 probing_state_ = ProbingState::kSuspended;
philipeldd324862016-05-06 17:06:14 +0200166 }
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000167}
sergeyu6dbbd892017-01-17 15:07:59 -0800168
169int64_t BitrateProber::GetNextProbeTime(const ProbeCluster& cluster) {
170 RTC_CHECK_GT(cluster.bitrate_bps, 0);
171 RTC_CHECK_GE(cluster.time_started_ms, 0);
172
173 // Compute the time delta from the cluster start to ensure probe bitrate stays
174 // close to the target bitrate. Result is in milliseconds.
175 int64_t delta_ms = (8000ll * cluster.sent_bytes + cluster.bitrate_bps / 2) /
176 cluster.bitrate_bps;
177 return cluster.time_started_ms + delta_ms;
178}
179
180
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000181} // namespace webrtc