blob: bdf48fda1de5a793fb68f3545a16ba842f184c60 [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
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000039} // namespace
40
41BitrateProber::BitrateProber()
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070042 : probing_state_(ProbingState::kDisabled),
sergeyu6dbbd892017-01-17 15:07:59 -080043 next_probe_time_ms_(-1),
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070044 next_cluster_id_(0) {
45 SetEnabled(true);
46}
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000047
48void BitrateProber::SetEnabled(bool enable) {
49 if (enable) {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070050 if (probing_state_ == ProbingState::kDisabled) {
51 probing_state_ = ProbingState::kInactive;
52 LOG(LS_INFO) << "Bandwidth probing enabled, set to inactive";
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000053 }
54 } else {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070055 probing_state_ = ProbingState::kDisabled;
56 LOG(LS_INFO) << "Bandwidth probing disabled";
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000057 }
58}
59
60bool BitrateProber::IsProbing() const {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070061 return probing_state_ == ProbingState::kActive;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000062}
63
philipel4a1ec1e2016-08-15 11:51:06 -070064void BitrateProber::OnIncomingPacket(size_t packet_size) {
Peter Boström0453ef82016-02-16 16:23:08 +010065 // Don't initialize probing unless we have something large enough to start
66 // probing.
philipel4a1ec1e2016-08-15 11:51:06 -070067 if (probing_state_ == ProbingState::kInactive &&
philipeleb680ea2016-08-17 11:11:59 +020068 !clusters_.empty() &&
philipel4a1ec1e2016-08-15 11:51:06 -070069 packet_size >= PacedSender::kMinProbePacketSize) {
sergeyu6dbbd892017-01-17 15:07:59 -080070 // Send next probe right away.
71 next_probe_time_ms_ = -1;
philipel4a1ec1e2016-08-15 11:51:06 -070072 probing_state_ = ProbingState::kActive;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +000073 }
philipel4a1ec1e2016-08-15 11:51:06 -070074}
75
philipelfd58b612017-01-04 07:05:25 -080076void BitrateProber::CreateProbeCluster(int bitrate_bps) {
Irfan Sheriffb2540bb2016-09-12 12:28:54 -070077 RTC_DCHECK(probing_state_ != ProbingState::kDisabled);
philipel4a1ec1e2016-08-15 11:51:06 -070078 ProbeCluster cluster;
philipelfd58b612017-01-04 07:05:25 -080079 cluster.min_probes = kMinProbePacketsSent;
80 cluster.min_bytes = bitrate_bps * kMinProbeDurationMs / 8000;
81 cluster.bitrate_bps = bitrate_bps;
philipel4a1ec1e2016-08-15 11:51:06 -070082 cluster.id = next_cluster_id_++;
83 clusters_.push(cluster);
philipelfd58b612017-01-04 07:05:25 -080084
85 LOG(LS_INFO) << "Probe cluster (bitrate:min bytes:min packets): ("
86 << cluster.bitrate_bps << ":" << cluster.min_bytes << ":"
87 << cluster.min_probes << ")";
88 // If we are already probing, continue to do so. Otherwise set it to
89 // kInactive and wait for OnIncomingPacket to start the probing.
philipel4a1ec1e2016-08-15 11:51:06 -070090 if (probing_state_ != ProbingState::kActive)
91 probing_state_ = ProbingState::kInactive;
Irfan Sheriff6e11efa2016-08-02 12:57:37 -070092}
93
94void BitrateProber::ResetState() {
sergeyu6dbbd892017-01-17 15:07:59 -080095 RTC_DCHECK(probing_state_ == ProbingState::kActive);
sprangebfbc8e2017-01-10 01:27:28 -080096
philipel4a1ec1e2016-08-15 11:51:06 -070097 // Recreate all probing clusters.
98 std::queue<ProbeCluster> clusters;
99 clusters.swap(clusters_);
100 while (!clusters.empty()) {
sergeyu6dbbd892017-01-17 15:07:59 -0800101 if (clusters.front().retries < kMaxRetryAttempts) {
102 CreateProbeCluster(clusters.front().bitrate_bps);
103 clusters_.back().retries = clusters.front().retries + 1;
104 }
philipel4a1ec1e2016-08-15 11:51:06 -0700105 clusters.pop();
106 }
sergeyu6dbbd892017-01-17 15:07:59 -0800107
108 probing_state_ = ProbingState::kInactive;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000109}
110
111int BitrateProber::TimeUntilNextProbe(int64_t now_ms) {
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700112 // Probing is not active or probing is already complete.
113 if (probing_state_ != ProbingState::kActive || clusters_.empty())
stefan@webrtc.orge9f0f592015-02-16 15:47:51 +0000114 return -1;
sergeyu6dbbd892017-01-17 15:07:59 -0800115
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000116 int time_until_probe_ms = 0;
sergeyu6dbbd892017-01-17 15:07:59 -0800117 if (next_probe_time_ms_ >= 0) {
118 time_until_probe_ms = next_probe_time_ms_ - now_ms;
119 if (time_until_probe_ms < -kMaxProbeDelayMs) {
120 ResetState();
121 return -1;
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000122 }
123 }
sergeyu6dbbd892017-01-17 15:07:59 -0800124
Stefan Holmer01b48882015-05-05 10:21:24 +0200125 return std::max(time_until_probe_ms, 0);
126}
127
philipeldd324862016-05-06 17:06:14 +0200128int BitrateProber::CurrentClusterId() const {
129 RTC_DCHECK(!clusters_.empty());
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700130 RTC_DCHECK(ProbingState::kActive == probing_state_);
philipeldd324862016-05-06 17:06:14 +0200131 return clusters_.front().id;
132}
133
isheriffcc5903e2016-10-04 08:29:38 -0700134// Probe size is recommended based on the probe bitrate required. We choose
135// a minimum of twice |kMinProbeDeltaMs| interval to allow scheduling to be
136// feasible.
137size_t BitrateProber::RecommendedMinProbeSize() const {
138 RTC_DCHECK(!clusters_.empty());
philipelfd58b612017-01-04 07:05:25 -0800139 return clusters_.front().bitrate_bps * 2 * kMinProbeDeltaMs / (8 * 1000);
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000140}
141
isheriffcc5903e2016-10-04 08:29:38 -0700142void BitrateProber::ProbeSent(int64_t now_ms, size_t bytes) {
143 RTC_DCHECK(probing_state_ == ProbingState::kActive);
kwibergaf476c72016-11-28 15:21:39 -0800144 RTC_DCHECK_GT(bytes, 0);
sergeyu6dbbd892017-01-17 15:07:59 -0800145
philipeldd324862016-05-06 17:06:14 +0200146 if (!clusters_.empty()) {
147 ProbeCluster* cluster = &clusters_.front();
sergeyu6dbbd892017-01-17 15:07:59 -0800148 if (cluster->sent_probes == 0) {
149 RTC_DCHECK_EQ(cluster->time_started_ms, -1);
150 cluster->time_started_ms = now_ms;
151 }
philipelfd58b612017-01-04 07:05:25 -0800152 cluster->sent_bytes += static_cast<int>(bytes);
153 cluster->sent_probes += 1;
sergeyu6dbbd892017-01-17 15:07:59 -0800154 next_probe_time_ms_ = GetNextProbeTime(clusters_.front());
philipelfd58b612017-01-04 07:05:25 -0800155 if (cluster->sent_bytes >= cluster->min_bytes &&
156 cluster->sent_probes >= cluster->min_probes) {
philipeldd324862016-05-06 17:06:14 +0200157 clusters_.pop();
philipelfd58b612017-01-04 07:05:25 -0800158 }
philipel1a93cde2016-06-03 01:41:45 -0700159 if (clusters_.empty())
Irfan Sheriff6e11efa2016-08-02 12:57:37 -0700160 probing_state_ = ProbingState::kSuspended;
philipeldd324862016-05-06 17:06:14 +0200161 }
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000162}
sergeyu6dbbd892017-01-17 15:07:59 -0800163
164int64_t BitrateProber::GetNextProbeTime(const ProbeCluster& cluster) {
165 RTC_CHECK_GT(cluster.bitrate_bps, 0);
166 RTC_CHECK_GE(cluster.time_started_ms, 0);
167
168 // Compute the time delta from the cluster start to ensure probe bitrate stays
169 // close to the target bitrate. Result is in milliseconds.
170 int64_t delta_ms = (8000ll * cluster.sent_bytes + cluster.bitrate_bps / 2) /
171 cluster.bitrate_bps;
172 return cluster.time_started_ms + delta_ms;
173}
174
175
stefan@webrtc.org82462aa2014-10-23 11:57:05 +0000176} // namespace webrtc