• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 "modules/pacing/bitrate_prober.h"
12 
13 #include <algorithm>
14 
15 #include "absl/memory/memory.h"
16 #include "api/rtc_event_log/rtc_event.h"
17 #include "api/rtc_event_log/rtc_event_log.h"
18 #include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21 #include "system_wrappers/include/metrics.h"
22 
23 namespace webrtc {
24 
25 namespace {
26 // The min probe packet size is scaled with the bitrate we're probing at.
27 // This defines the max min probe packet size, meaning that on high bitrates
28 // we have a min probe packet size of 200 bytes.
29 constexpr DataSize kMinProbePacketSize = DataSize::Bytes(200);
30 
31 constexpr TimeDelta kProbeClusterTimeout = TimeDelta::Seconds(5);
32 
33 }  // namespace
34 
BitrateProberConfig(const WebRtcKeyValueConfig * key_value_config)35 BitrateProberConfig::BitrateProberConfig(
36     const WebRtcKeyValueConfig* key_value_config)
37     : min_probe_packets_sent("min_probe_packets_sent", 5),
38       min_probe_delta("min_probe_delta", TimeDelta::Millis(1)),
39       min_probe_duration("min_probe_duration", TimeDelta::Millis(15)),
40       max_probe_delay("max_probe_delay", TimeDelta::Millis(3)),
41       // TODO(bugs.webrtc.org/11780): Change to default true.
42       abort_delayed_probes("abort_delayed_probes", false) {
43   ParseFieldTrial(
44       {&min_probe_packets_sent, &min_probe_delta, &min_probe_duration,
45        &max_probe_delay, &abort_delayed_probes},
46       key_value_config->Lookup("WebRTC-Bwe-ProbingConfiguration"));
47   ParseFieldTrial(
48       {&min_probe_packets_sent, &min_probe_delta, &min_probe_duration,
49        &max_probe_delay, &abort_delayed_probes},
50       key_value_config->Lookup("WebRTC-Bwe-ProbingBehavior"));
51 }
52 
~BitrateProber()53 BitrateProber::~BitrateProber() {
54   RTC_HISTOGRAM_COUNTS_1000("WebRTC.BWE.Probing.TotalProbeClustersRequested",
55                             total_probe_count_);
56   RTC_HISTOGRAM_COUNTS_1000("WebRTC.BWE.Probing.TotalFailedProbeClusters",
57                             total_failed_probe_count_);
58 }
59 
BitrateProber(const WebRtcKeyValueConfig & field_trials)60 BitrateProber::BitrateProber(const WebRtcKeyValueConfig& field_trials)
61     : probing_state_(ProbingState::kDisabled),
62       next_probe_time_(Timestamp::PlusInfinity()),
63       total_probe_count_(0),
64       total_failed_probe_count_(0),
65       config_(&field_trials) {
66   SetEnabled(true);
67 }
68 
SetEnabled(bool enable)69 void BitrateProber::SetEnabled(bool enable) {
70   if (enable) {
71     if (probing_state_ == ProbingState::kDisabled) {
72       probing_state_ = ProbingState::kInactive;
73       RTC_LOG(LS_INFO) << "Bandwidth probing enabled, set to inactive";
74     }
75   } else {
76     probing_state_ = ProbingState::kDisabled;
77     RTC_LOG(LS_INFO) << "Bandwidth probing disabled";
78   }
79 }
80 
OnIncomingPacket(DataSize packet_size)81 void BitrateProber::OnIncomingPacket(DataSize packet_size) {
82   // Don't initialize probing unless we have something large enough to start
83   // probing.
84   if (probing_state_ == ProbingState::kInactive && !clusters_.empty() &&
85       packet_size >= std::min(RecommendedMinProbeSize(), kMinProbePacketSize)) {
86     // Send next probe right away.
87     next_probe_time_ = Timestamp::MinusInfinity();
88     probing_state_ = ProbingState::kActive;
89   }
90 }
91 
CreateProbeCluster(DataRate bitrate,Timestamp now,int cluster_id)92 void BitrateProber::CreateProbeCluster(DataRate bitrate,
93                                        Timestamp now,
94                                        int cluster_id) {
95   RTC_DCHECK(probing_state_ != ProbingState::kDisabled);
96   RTC_DCHECK_GT(bitrate, DataRate::Zero());
97 
98   total_probe_count_++;
99   while (!clusters_.empty() &&
100          now - clusters_.front().created_at > kProbeClusterTimeout) {
101     clusters_.pop();
102     total_failed_probe_count_++;
103   }
104 
105   ProbeCluster cluster;
106   cluster.created_at = now;
107   cluster.pace_info.probe_cluster_min_probes = config_.min_probe_packets_sent;
108   cluster.pace_info.probe_cluster_min_bytes =
109       (bitrate * config_.min_probe_duration.Get()).bytes();
110   RTC_DCHECK_GE(cluster.pace_info.probe_cluster_min_bytes, 0);
111   cluster.pace_info.send_bitrate_bps = bitrate.bps();
112   cluster.pace_info.probe_cluster_id = cluster_id;
113   clusters_.push(cluster);
114 
115   RTC_LOG(LS_INFO) << "Probe cluster (bitrate:min bytes:min packets): ("
116                    << cluster.pace_info.send_bitrate_bps << ":"
117                    << cluster.pace_info.probe_cluster_min_bytes << ":"
118                    << cluster.pace_info.probe_cluster_min_probes << ")";
119   // If we are already probing, continue to do so. Otherwise set it to
120   // kInactive and wait for OnIncomingPacket to start the probing.
121   if (probing_state_ != ProbingState::kActive)
122     probing_state_ = ProbingState::kInactive;
123 }
124 
NextProbeTime(Timestamp now) const125 Timestamp BitrateProber::NextProbeTime(Timestamp now) const {
126   // Probing is not active or probing is already complete.
127   if (probing_state_ != ProbingState::kActive || clusters_.empty()) {
128     return Timestamp::PlusInfinity();
129   }
130 
131   // Legacy behavior, just warn about late probe and return as if not probing.
132   if (!config_.abort_delayed_probes && next_probe_time_.IsFinite() &&
133       now - next_probe_time_ > config_.max_probe_delay.Get()) {
134     RTC_DLOG(LS_WARNING) << "Probe delay too high"
135                             " (next_ms:"
136                          << next_probe_time_.ms() << ", now_ms: " << now.ms()
137                          << ")";
138     return Timestamp::PlusInfinity();
139   }
140 
141   return next_probe_time_;
142 }
143 
CurrentCluster(Timestamp now)144 absl::optional<PacedPacketInfo> BitrateProber::CurrentCluster(Timestamp now) {
145   if (clusters_.empty() || probing_state_ != ProbingState::kActive) {
146     return absl::nullopt;
147   }
148 
149   if (config_.abort_delayed_probes && next_probe_time_.IsFinite() &&
150       now - next_probe_time_ > config_.max_probe_delay.Get()) {
151     RTC_DLOG(LS_WARNING) << "Probe delay too high"
152                             " (next_ms:"
153                          << next_probe_time_.ms() << ", now_ms: " << now.ms()
154                          << "), discarding probe cluster.";
155     clusters_.pop();
156     if (clusters_.empty()) {
157       probing_state_ = ProbingState::kSuspended;
158       return absl::nullopt;
159     }
160   }
161 
162   PacedPacketInfo info = clusters_.front().pace_info;
163   info.probe_cluster_bytes_sent = clusters_.front().sent_bytes;
164   return info;
165 }
166 
167 // Probe size is recommended based on the probe bitrate required. We choose
168 // a minimum of twice |kMinProbeDeltaMs| interval to allow scheduling to be
169 // feasible.
RecommendedMinProbeSize() const170 DataSize BitrateProber::RecommendedMinProbeSize() const {
171   if (clusters_.empty()) {
172     return DataSize::Zero();
173   }
174   DataRate send_rate =
175       DataRate::BitsPerSec(clusters_.front().pace_info.send_bitrate_bps);
176   return 2 * send_rate * config_.min_probe_delta;
177 }
178 
ProbeSent(Timestamp now,DataSize size)179 void BitrateProber::ProbeSent(Timestamp now, DataSize size) {
180   RTC_DCHECK(probing_state_ == ProbingState::kActive);
181   RTC_DCHECK(!size.IsZero());
182 
183   if (!clusters_.empty()) {
184     ProbeCluster* cluster = &clusters_.front();
185     if (cluster->sent_probes == 0) {
186       RTC_DCHECK(cluster->started_at.IsInfinite());
187       cluster->started_at = now;
188     }
189     cluster->sent_bytes += size.bytes<int>();
190     cluster->sent_probes += 1;
191     next_probe_time_ = CalculateNextProbeTime(*cluster);
192     if (cluster->sent_bytes >= cluster->pace_info.probe_cluster_min_bytes &&
193         cluster->sent_probes >= cluster->pace_info.probe_cluster_min_probes) {
194       RTC_HISTOGRAM_COUNTS_100000("WebRTC.BWE.Probing.ProbeClusterSizeInBytes",
195                                   cluster->sent_bytes);
196       RTC_HISTOGRAM_COUNTS_100("WebRTC.BWE.Probing.ProbesPerCluster",
197                                cluster->sent_probes);
198       RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.Probing.TimePerProbeCluster",
199                                  (now - cluster->started_at).ms());
200 
201       clusters_.pop();
202     }
203     if (clusters_.empty()) {
204       probing_state_ = ProbingState::kSuspended;
205     }
206   }
207 }
208 
CalculateNextProbeTime(const ProbeCluster & cluster) const209 Timestamp BitrateProber::CalculateNextProbeTime(
210     const ProbeCluster& cluster) const {
211   RTC_CHECK_GT(cluster.pace_info.send_bitrate_bps, 0);
212   RTC_CHECK(cluster.started_at.IsFinite());
213 
214   // Compute the time delta from the cluster start to ensure probe bitrate stays
215   // close to the target bitrate. Result is in milliseconds.
216   DataSize sent_bytes = DataSize::Bytes(cluster.sent_bytes);
217   DataRate send_bitrate =
218       DataRate::BitsPerSec(cluster.pace_info.send_bitrate_bps);
219   TimeDelta delta = sent_bytes / send_bitrate;
220   return cluster.started_at + delta;
221 }
222 
223 }  // namespace webrtc
224