• 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 "api/units/data_rate.h"
16 #include "api/units/time_delta.h"
17 #include "api/units/timestamp.h"
18 #include "test/explicit_key_value_config.h"
19 #include "test/gtest.h"
20 
21 namespace webrtc {
22 
TEST(BitrateProberTest,VerifyStatesAndTimeBetweenProbes)23 TEST(BitrateProberTest, VerifyStatesAndTimeBetweenProbes) {
24   const FieldTrialBasedConfig config;
25   BitrateProber prober(config);
26   EXPECT_FALSE(prober.is_probing());
27 
28   Timestamp now = Timestamp::Zero();
29   const Timestamp start_time = now;
30   EXPECT_EQ(prober.NextProbeTime(now), Timestamp::PlusInfinity());
31 
32   const DataRate kTestBitrate1 = DataRate::KilobitsPerSec(900);
33   const DataRate kTestBitrate2 = DataRate::KilobitsPerSec(1800);
34   const int kClusterSize = 5;
35   const DataSize kProbeSize = DataSize::Bytes(1000);
36   const TimeDelta kMinProbeDuration = TimeDelta::Millis(15);
37 
38   prober.CreateProbeCluster({.at_time = now,
39                              .target_data_rate = kTestBitrate1,
40                              .target_duration = TimeDelta::Millis(15),
41                              .target_probe_count = 5,
42                              .id = 0});
43   prober.CreateProbeCluster({.at_time = now,
44                              .target_data_rate = kTestBitrate2,
45                              .target_duration = TimeDelta::Millis(15),
46                              .target_probe_count = 5,
47                              .id = 1});
48   EXPECT_FALSE(prober.is_probing());
49 
50   prober.OnIncomingPacket(kProbeSize);
51   EXPECT_TRUE(prober.is_probing());
52   EXPECT_EQ(0, prober.CurrentCluster(now)->probe_cluster_id);
53 
54   // First packet should probe as soon as possible.
55   EXPECT_EQ(Timestamp::MinusInfinity(), prober.NextProbeTime(now));
56 
57   for (int i = 0; i < kClusterSize; ++i) {
58     now = std::max(now, prober.NextProbeTime(now));
59     EXPECT_EQ(now, std::max(now, prober.NextProbeTime(now)));
60     EXPECT_EQ(0, prober.CurrentCluster(now)->probe_cluster_id);
61     prober.ProbeSent(now, kProbeSize);
62   }
63 
64   EXPECT_GE(now - start_time, kMinProbeDuration);
65   // Verify that the actual bitrate is withing 10% of the target.
66   DataRate bitrate = kProbeSize * (kClusterSize - 1) / (now - start_time);
67   EXPECT_GT(bitrate, kTestBitrate1 * 0.9);
68   EXPECT_LT(bitrate, kTestBitrate1 * 1.1);
69 
70   now = std::max(now, prober.NextProbeTime(now));
71   Timestamp probe2_started = now;
72 
73   for (int i = 0; i < kClusterSize; ++i) {
74     now = std::max(now, prober.NextProbeTime(now));
75     EXPECT_EQ(now, std::max(now, prober.NextProbeTime(now)));
76     EXPECT_EQ(1, prober.CurrentCluster(now)->probe_cluster_id);
77     prober.ProbeSent(now, kProbeSize);
78   }
79 
80   // Verify that the actual bitrate is withing 10% of the target.
81   TimeDelta duration = now - probe2_started;
82   EXPECT_GE(duration, kMinProbeDuration);
83   bitrate = (kProbeSize * (kClusterSize - 1)) / duration;
84   EXPECT_GT(bitrate, kTestBitrate2 * 0.9);
85   EXPECT_LT(bitrate, kTestBitrate2 * 1.1);
86 
87   EXPECT_EQ(prober.NextProbeTime(now), Timestamp::PlusInfinity());
88   EXPECT_FALSE(prober.is_probing());
89 }
90 
TEST(BitrateProberTest,DoesntProbeWithoutRecentPackets)91 TEST(BitrateProberTest, DoesntProbeWithoutRecentPackets) {
92   const FieldTrialBasedConfig config;
93   BitrateProber prober(config);
94   const DataSize kProbeSize = DataSize::Bytes(1000);
95 
96   Timestamp now = Timestamp::Zero();
97   EXPECT_EQ(prober.NextProbeTime(now), Timestamp::PlusInfinity());
98 
99   prober.CreateProbeCluster({.at_time = now,
100                              .target_data_rate = DataRate::KilobitsPerSec(900),
101                              .target_duration = TimeDelta::Millis(15),
102                              .target_probe_count = 5,
103                              .id = 0});
104   EXPECT_FALSE(prober.is_probing());
105 
106   prober.OnIncomingPacket(kProbeSize);
107   EXPECT_TRUE(prober.is_probing());
108   EXPECT_EQ(now, std::max(now, prober.NextProbeTime(now)));
109   prober.ProbeSent(now, kProbeSize);
110 }
111 
TEST(BitrateProberTest,DiscardsDelayedProbes)112 TEST(BitrateProberTest, DiscardsDelayedProbes) {
113   const TimeDelta kMaxProbeDelay = TimeDelta::Millis(3);
114   const test::ExplicitKeyValueConfig trials(
115       "WebRTC-Bwe-ProbingBehavior/"
116       "abort_delayed_probes:1,"
117       "max_probe_delay:3ms/");
118   BitrateProber prober(trials);
119   const DataSize kProbeSize = DataSize::Bytes(1000);
120 
121   Timestamp now = Timestamp::Zero();
122 
123   // Add two probe clusters.
124   prober.CreateProbeCluster({.at_time = now,
125                              .target_data_rate = DataRate::KilobitsPerSec(900),
126                              .target_duration = TimeDelta::Millis(15),
127                              .target_probe_count = 5,
128                              .id = 0});
129 
130   prober.OnIncomingPacket(kProbeSize);
131   EXPECT_TRUE(prober.is_probing());
132   EXPECT_EQ(prober.CurrentCluster(now)->probe_cluster_id, 0);
133   // Advance to first probe time and indicate sent probe.
134   now = std::max(now, prober.NextProbeTime(now));
135   prober.ProbeSent(now, kProbeSize);
136 
137   // Advance time 1ms past timeout for the next probe.
138   Timestamp next_probe_time = prober.NextProbeTime(now);
139   EXPECT_GT(next_probe_time, now);
140   now += next_probe_time - now + kMaxProbeDelay + TimeDelta::Millis(1);
141 
142   // Still indicates the time we wanted to probe at.
143   EXPECT_EQ(prober.NextProbeTime(now), next_probe_time);
144   // First and only cluster removed due to timeout.
145   EXPECT_FALSE(prober.CurrentCluster(now).has_value());
146 }
147 
TEST(BitrateProberTest,LimitsNumberOfPendingProbeClusters)148 TEST(BitrateProberTest, LimitsNumberOfPendingProbeClusters) {
149   const FieldTrialBasedConfig config;
150   BitrateProber prober(config);
151   const DataSize kProbeSize = DataSize::Bytes(1000);
152   Timestamp now = Timestamp::Zero();
153   prober.CreateProbeCluster({.at_time = now,
154                              .target_data_rate = DataRate::KilobitsPerSec(900),
155                              .target_duration = TimeDelta::Millis(15),
156                              .target_probe_count = 5,
157                              .id = 0});
158   prober.OnIncomingPacket(kProbeSize);
159   ASSERT_TRUE(prober.is_probing());
160   ASSERT_EQ(prober.CurrentCluster(now)->probe_cluster_id, 0);
161 
162   for (int i = 1; i < 11; ++i) {
163     prober.CreateProbeCluster(
164         {.at_time = now,
165          .target_data_rate = DataRate::KilobitsPerSec(900),
166          .target_duration = TimeDelta::Millis(15),
167          .target_probe_count = 5,
168          .id = i});
169     prober.OnIncomingPacket(kProbeSize);
170   }
171   // Expect some clusters has been dropped.
172   EXPECT_TRUE(prober.is_probing());
173   EXPECT_GE(prober.CurrentCluster(now)->probe_cluster_id, 5);
174 
175   Timestamp max_expected_probe_time = now + TimeDelta::Seconds(1);
176   while (prober.is_probing() && now < max_expected_probe_time) {
177     now = std::max(now, prober.NextProbeTime(now));
178     prober.ProbeSent(now, kProbeSize);
179   }
180   EXPECT_FALSE(prober.is_probing());
181 }
182 
TEST(BitrateProberTest,DoesntInitializeProbingForSmallPackets)183 TEST(BitrateProberTest, DoesntInitializeProbingForSmallPackets) {
184   const FieldTrialBasedConfig config;
185   BitrateProber prober(config);
186   prober.SetEnabled(true);
187   ASSERT_FALSE(prober.is_probing());
188 
189   prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
190                              .target_data_rate = DataRate::KilobitsPerSec(1000),
191                              .target_duration = TimeDelta::Millis(15),
192                              .target_probe_count = 5,
193                              .id = 0});
194   prober.OnIncomingPacket(DataSize::Bytes(100));
195 
196   EXPECT_FALSE(prober.is_probing());
197 }
198 
TEST(BitrateProberTest,DoesInitializeProbingForSmallPacketsIfConfigured)199 TEST(BitrateProberTest, DoesInitializeProbingForSmallPacketsIfConfigured) {
200   const test::ExplicitKeyValueConfig config(
201       "WebRTC-Bwe-ProbingBehavior/"
202       "min_packet_size:0bytes/");
203   BitrateProber prober(config);
204   prober.SetEnabled(true);
205   ASSERT_FALSE(prober.is_probing());
206 
207   prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
208                              .target_data_rate = DataRate::KilobitsPerSec(1000),
209                              .target_duration = TimeDelta::Millis(15),
210                              .target_probe_count = 5,
211                              .id = 0});
212   prober.OnIncomingPacket(DataSize::Bytes(10));
213 
214   EXPECT_TRUE(prober.is_probing());
215 }
216 
TEST(BitrateProberTest,VerifyProbeSizeOnHighBitrate)217 TEST(BitrateProberTest, VerifyProbeSizeOnHighBitrate) {
218   const FieldTrialBasedConfig config;
219   BitrateProber prober(config);
220 
221   const DataRate kHighBitrate = DataRate::KilobitsPerSec(10000);  // 10 Mbps
222 
223   prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
224                              .target_data_rate = kHighBitrate,
225                              .target_duration = TimeDelta::Millis(15),
226                              .target_probe_count = 5,
227                              .id = 0});
228   // Probe size should ensure a minimum of 1 ms interval.
229   EXPECT_GT(prober.RecommendedMinProbeSize(),
230             kHighBitrate * TimeDelta::Millis(1));
231 }
232 
TEST(BitrateProberTest,ProbeSizeCanBeSetWithFieldTrial)233 TEST(BitrateProberTest, ProbeSizeCanBeSetWithFieldTrial) {
234   const test::ExplicitKeyValueConfig trials(
235       "WebRTC-Bwe-ProbingBehavior/min_probe_delta:20ms/");
236   BitrateProber prober(trials);
237   prober.SetEnabled(true);
238 
239   const DataRate kHighBitrate = DataRate::KilobitsPerSec(10000);  // 10 Mbps
240 
241   prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
242                              .target_data_rate = kHighBitrate,
243                              .target_duration = TimeDelta::Millis(15),
244                              .target_probe_count = 5,
245                              .id = 0});
246   EXPECT_EQ(prober.RecommendedMinProbeSize(),
247             kHighBitrate * TimeDelta::Millis(20));
248 
249   prober.OnIncomingPacket(DataSize::Bytes(1000));
250   // Next time to send probe should be "min_probe_delta" if the recommended
251   // number of bytes has been sent.
252   prober.ProbeSent(Timestamp::Zero(), prober.RecommendedMinProbeSize());
253   EXPECT_EQ(prober.NextProbeTime(Timestamp::Zero()),
254             Timestamp::Zero() + TimeDelta::Millis(20));
255 }
256 
TEST(BitrateProberTest,MinumumNumberOfProbingPackets)257 TEST(BitrateProberTest, MinumumNumberOfProbingPackets) {
258   const FieldTrialBasedConfig config;
259   BitrateProber prober(config);
260   // Even when probing at a low bitrate we expect a minimum number
261   // of packets to be sent.
262   const DataRate kBitrate = DataRate::KilobitsPerSec(100);
263   const DataSize kPacketSize = DataSize::Bytes(1000);
264 
265   Timestamp now = Timestamp::Zero();
266   prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
267                              .target_data_rate = kBitrate,
268                              .target_duration = TimeDelta::Millis(15),
269                              .target_probe_count = 5,
270                              .id = 0});
271 
272   prober.OnIncomingPacket(kPacketSize);
273   for (int i = 0; i < 5; ++i) {
274     EXPECT_TRUE(prober.is_probing());
275     prober.ProbeSent(now, kPacketSize);
276   }
277 
278   EXPECT_FALSE(prober.is_probing());
279 }
280 
TEST(BitrateProberTest,ScaleBytesUsedForProbing)281 TEST(BitrateProberTest, ScaleBytesUsedForProbing) {
282   const FieldTrialBasedConfig config;
283   BitrateProber prober(config);
284   const DataRate kBitrate = DataRate::KilobitsPerSec(10000);  // 10 Mbps.
285   const DataSize kPacketSize = DataSize::Bytes(1000);
286   const DataSize kExpectedDataSent = kBitrate * TimeDelta::Millis(15);
287 
288   Timestamp now = Timestamp::Zero();
289   prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
290                              .target_data_rate = kBitrate,
291                              .target_duration = TimeDelta::Millis(15),
292                              .target_probe_count = 5,
293                              .id = 0});
294   prober.OnIncomingPacket(kPacketSize);
295   DataSize data_sent = DataSize::Zero();
296   while (data_sent < kExpectedDataSent) {
297     ASSERT_TRUE(prober.is_probing());
298     prober.ProbeSent(now, kPacketSize);
299     data_sent += kPacketSize;
300   }
301 
302   EXPECT_FALSE(prober.is_probing());
303 }
304 
TEST(BitrateProberTest,HighBitrateProbing)305 TEST(BitrateProberTest, HighBitrateProbing) {
306   const FieldTrialBasedConfig config;
307   BitrateProber prober(config);
308   const DataRate kBitrate = DataRate::KilobitsPerSec(1000000);  // 1 Gbps.
309   const DataSize kPacketSize = DataSize::Bytes(1000);
310   const DataSize kExpectedDataSent = kBitrate * TimeDelta::Millis(15);
311 
312   Timestamp now = Timestamp::Zero();
313   prober.CreateProbeCluster({.at_time = Timestamp::Zero(),
314                              .target_data_rate = kBitrate,
315                              .target_duration = TimeDelta::Millis(15),
316                              .target_probe_count = 5,
317                              .id = 0});
318   prober.OnIncomingPacket(kPacketSize);
319   DataSize data_sent = DataSize::Zero();
320   while (data_sent < kExpectedDataSent) {
321     ASSERT_TRUE(prober.is_probing());
322     prober.ProbeSent(now, kPacketSize);
323     data_sent += kPacketSize;
324   }
325 
326   EXPECT_FALSE(prober.is_probing());
327 }
328 
TEST(BitrateProberTest,ProbeClusterTimeout)329 TEST(BitrateProberTest, ProbeClusterTimeout) {
330   const FieldTrialBasedConfig config;
331   BitrateProber prober(config);
332   const DataRate kBitrate = DataRate::KilobitsPerSec(300);
333   const DataSize kSmallPacketSize = DataSize::Bytes(20);
334   // Expecting two probe clusters of 5 packets each.
335   const DataSize kExpectedDataSent = kSmallPacketSize * 2 * 5;
336   const TimeDelta kTimeout = TimeDelta::Millis(5000);
337 
338   Timestamp now = Timestamp::Zero();
339   prober.CreateProbeCluster({.at_time = now,
340                              .target_data_rate = kBitrate,
341                              .target_duration = TimeDelta::Millis(15),
342                              .target_probe_count = 5,
343                              .id = 0});
344   prober.OnIncomingPacket(kSmallPacketSize);
345   EXPECT_FALSE(prober.is_probing());
346   now += kTimeout;
347   prober.CreateProbeCluster({.at_time = now,
348                              .target_data_rate = kBitrate / 10,
349                              .target_duration = TimeDelta::Millis(15),
350                              .target_probe_count = 5,
351                              .id = 1});
352   prober.OnIncomingPacket(kSmallPacketSize);
353   EXPECT_FALSE(prober.is_probing());
354   now += TimeDelta::Millis(1);
355   prober.CreateProbeCluster({.at_time = now,
356                              .target_data_rate = kBitrate / 10,
357                              .target_duration = TimeDelta::Millis(15),
358                              .target_probe_count = 5,
359                              .id = 2});
360   prober.OnIncomingPacket(kSmallPacketSize);
361   EXPECT_TRUE(prober.is_probing());
362   DataSize data_sent = DataSize::Zero();
363   while (data_sent < kExpectedDataSent) {
364     ASSERT_TRUE(prober.is_probing());
365     prober.ProbeSent(now, kSmallPacketSize);
366     data_sent += kSmallPacketSize;
367   }
368 
369   EXPECT_FALSE(prober.is_probing());
370 }
371 }  // namespace webrtc
372