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