blob: 51249b14eaeaa88b57be97e8a00084ac4061da13 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
stefan@webrtc.org9354cc92012-06-07 08:10:14 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
Stefan Holmerfb8fc532016-04-22 15:48:23 +020011#include <algorithm>
12
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "rtc_base/rate_statistics.h"
14#include "test/gtest.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000015
16namespace {
17
sprang@webrtc.org37968a92013-12-03 10:31:59 +000018using webrtc::RateStatistics;
niklase@google.com470e71d2011-07-07 08:21:25 +000019
Stefan Holmerfb8fc532016-04-22 15:48:23 +020020const int64_t kWindowMs = 500;
21
sprang@webrtc.org37968a92013-12-03 10:31:59 +000022class RateStatisticsTest : public ::testing::Test {
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000023 protected:
Stefan Holmerfb8fc532016-04-22 15:48:23 +020024 RateStatisticsTest() : stats_(kWindowMs, 8000) {}
sprang@webrtc.org37968a92013-12-03 10:31:59 +000025 RateStatistics stats_;
niklase@google.com470e71d2011-07-07 08:21:25 +000026};
27
sprang@webrtc.org37968a92013-12-03 10:31:59 +000028TEST_F(RateStatisticsTest, TestStrictMode) {
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000029 int64_t now_ms = 0;
Erik Språng51e60302016-06-10 22:13:21 +020030 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
31
32 const uint32_t kPacketSize = 1500u;
33 const uint32_t kExpectedRateBps = kPacketSize * 1000 * 8;
34
35 // Single data point is not enough for valid estimate.
36 stats_.Update(kPacketSize, now_ms++);
37 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
38
Stefan Holmerfb8fc532016-04-22 15:48:23 +020039 // Expecting 1200 kbps since the window is initially kept small and grows as
40 // we have more data.
Erik Språng51e60302016-06-10 22:13:21 +020041 stats_.Update(kPacketSize, now_ms);
42 EXPECT_EQ(kExpectedRateBps, *stats_.Rate(now_ms));
43
sprang@webrtc.org37968a92013-12-03 10:31:59 +000044 stats_.Reset();
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000045 // Expecting 0 after init.
Erik Språng51e60302016-06-10 22:13:21 +020046 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
47
48 const int kInterval = 10;
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000049 for (int i = 0; i < 100000; ++i) {
Erik Språng51e60302016-06-10 22:13:21 +020050 if (i % kInterval == 0)
51 stats_.Update(kPacketSize, now_ms);
52
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000053 // Approximately 1200 kbps expected. Not exact since when packets
54 // are removed we will jump 10 ms to the next packet.
Erik Språng51e60302016-06-10 22:13:21 +020055 if (i > kInterval) {
56 rtc::Optional<uint32_t> rate = stats_.Rate(now_ms);
57 EXPECT_TRUE(static_cast<bool>(rate));
58 uint32_t samples = i / kInterval + 1;
59 uint64_t total_bits = samples * kPacketSize * 8;
60 uint32_t rate_bps = static_cast<uint32_t>((1000 * total_bits) / (i + 1));
61 EXPECT_NEAR(rate_bps, *rate, 22000u);
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000062 }
63 now_ms += 1;
64 }
Stefan Holmerfb8fc532016-04-22 15:48:23 +020065 now_ms += kWindowMs;
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000066 // The window is 2 seconds. If nothing has been received for that time
67 // the estimate should be 0.
Erik Språng51e60302016-06-10 22:13:21 +020068 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
niklase@google.com470e71d2011-07-07 08:21:25 +000069}
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000070
sprang@webrtc.org37968a92013-12-03 10:31:59 +000071TEST_F(RateStatisticsTest, IncreasingThenDecreasingBitrate) {
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000072 int64_t now_ms = 0;
sprang@webrtc.org37968a92013-12-03 10:31:59 +000073 stats_.Reset();
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000074 // Expecting 0 after init.
Erik Språng51e60302016-06-10 22:13:21 +020075 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
76
77 stats_.Update(1000, ++now_ms);
Stefan Holmerfb8fc532016-04-22 15:48:23 +020078 const uint32_t kExpectedBitrate = 8000000;
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000079 // 1000 bytes per millisecond until plateau is reached.
Stefan Holmerfb8fc532016-04-22 15:48:23 +020080 int prev_error = kExpectedBitrate;
Erik Språng51e60302016-06-10 22:13:21 +020081 rtc::Optional<uint32_t> bitrate;
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000082 while (++now_ms < 10000) {
83 stats_.Update(1000, now_ms);
Stefan Holmerfb8fc532016-04-22 15:48:23 +020084 bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 22:13:21 +020085 EXPECT_TRUE(static_cast<bool>(bitrate));
86 int error = kExpectedBitrate - *bitrate;
Stefan Holmerfb8fc532016-04-22 15:48:23 +020087 error = std::abs(error);
88 // Expect the estimation error to decrease as the window is extended.
89 EXPECT_LE(error, prev_error + 1);
90 prev_error = error;
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000091 }
Stefan Holmerfb8fc532016-04-22 15:48:23 +020092 // Window filled, expect to be close to 8000000.
Erik Språng51e60302016-06-10 22:13:21 +020093 EXPECT_EQ(kExpectedBitrate, *bitrate);
Stefan Holmerfb8fc532016-04-22 15:48:23 +020094
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000095 // 1000 bytes per millisecond until 10-second mark, 8000 kbps expected.
96 while (++now_ms < 10000) {
97 stats_.Update(1000, now_ms);
sprang@webrtc.org37968a92013-12-03 10:31:59 +000098 bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 22:13:21 +020099 EXPECT_EQ(kExpectedBitrate, *bitrate);
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000100 }
Erik Språng51e60302016-06-10 22:13:21 +0200101
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000102 // Zero bytes per millisecond until 0 is reached.
103 while (++now_ms < 20000) {
104 stats_.Update(0, now_ms);
Erik Språng51e60302016-06-10 22:13:21 +0200105 rtc::Optional<uint32_t> new_bitrate = stats_.Rate(now_ms);
106 if (static_cast<bool>(new_bitrate) && *new_bitrate != *bitrate) {
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000107 // New bitrate must be lower than previous one.
Erik Språng51e60302016-06-10 22:13:21 +0200108 EXPECT_LT(*new_bitrate, *bitrate);
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000109 } else {
110 // 0 kbps expected.
Erik Språng51e60302016-06-10 22:13:21 +0200111 EXPECT_EQ(0u, *new_bitrate);
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000112 break;
113 }
114 bitrate = new_bitrate;
115 }
Erik Språng51e60302016-06-10 22:13:21 +0200116
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000117 // Zero bytes per millisecond until 20-second mark, 0 kbps expected.
118 while (++now_ms < 20000) {
119 stats_.Update(0, now_ms);
Erik Språng51e60302016-06-10 22:13:21 +0200120 EXPECT_EQ(0u, *stats_.Rate(now_ms));
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000121 }
122}
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200123
124TEST_F(RateStatisticsTest, ResetAfterSilence) {
125 int64_t now_ms = 0;
126 stats_.Reset();
127 // Expecting 0 after init.
Erik Språng51e60302016-06-10 22:13:21 +0200128 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
129
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200130 const uint32_t kExpectedBitrate = 8000000;
131 // 1000 bytes per millisecond until the window has been filled.
132 int prev_error = kExpectedBitrate;
Erik Språng51e60302016-06-10 22:13:21 +0200133 rtc::Optional<uint32_t> bitrate;
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200134 while (++now_ms < 10000) {
135 stats_.Update(1000, now_ms);
136 bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 22:13:21 +0200137 if (bitrate) {
138 int error = kExpectedBitrate - *bitrate;
139 error = std::abs(error);
140 // Expect the estimation error to decrease as the window is extended.
141 EXPECT_LE(error, prev_error + 1);
142 prev_error = error;
143 }
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200144 }
145 // Window filled, expect to be close to 8000000.
Erik Språng51e60302016-06-10 22:13:21 +0200146 EXPECT_EQ(kExpectedBitrate, *bitrate);
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200147
148 now_ms += kWindowMs + 1;
Erik Språng51e60302016-06-10 22:13:21 +0200149 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200150 stats_.Update(1000, now_ms);
Erik Språng51e60302016-06-10 22:13:21 +0200151 ++now_ms;
152 stats_.Update(1000, now_ms);
153 // We expect two samples of 1000 bytes, and that the bitrate is measured over
154 // 500 ms, i.e. 2 * 8 * 1000 / 0.500 = 32000.
155 EXPECT_EQ(32000u, *stats_.Rate(now_ms));
156
157 // Reset, add the same samples again.
158 stats_.Reset();
159 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
160 stats_.Update(1000, now_ms);
161 ++now_ms;
162 stats_.Update(1000, now_ms);
163 // We expect two samples of 1000 bytes, and that the bitrate is measured over
164 // 2 ms (window size has been reset) i.e. 2 * 8 * 1000 / 0.002 = 8000000.
165 EXPECT_EQ(kExpectedBitrate, *stats_.Rate(now_ms));
166}
167
168TEST_F(RateStatisticsTest, HandlesChangingWindowSize) {
169 int64_t now_ms = 0;
170 stats_.Reset();
171
172 // Sanity test window size.
173 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
174 EXPECT_FALSE(stats_.SetWindowSize(kWindowMs + 1, now_ms));
175 EXPECT_FALSE(stats_.SetWindowSize(0, now_ms));
176 EXPECT_TRUE(stats_.SetWindowSize(1, now_ms));
177 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
178
179 // Fill the buffer at a rate of 1 byte / millisecond (8 kbps).
180 const int kBatchSize = 10;
181 for (int i = 0; i <= kWindowMs; i += kBatchSize)
182 stats_.Update(kBatchSize, now_ms += kBatchSize);
183 EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
184
185 // Halve the window size, rate should stay the same.
186 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs / 2, now_ms));
187 EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
188
189 // Double the window size again, rate should stay the same. (As the window
190 // won't actually expand until new bit and bobs fall into it.
191 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
192 EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
193
194 // Fill the now empty half with bits it twice the rate.
195 for (int i = 0; i < kWindowMs / 2; i += kBatchSize)
196 stats_.Update(kBatchSize * 2, now_ms += kBatchSize);
197
198 // Rate should have increase be 50%.
199 EXPECT_EQ(static_cast<uint32_t>((8000 * 3) / 2), *stats_.Rate(now_ms));
200}
201
202TEST_F(RateStatisticsTest, RespectsWindowSizeEdges) {
203 int64_t now_ms = 0;
204 stats_.Reset();
205 // Expecting 0 after init.
206 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
207
208 // One byte per ms, using one big sample.
209 stats_.Update(kWindowMs, now_ms);
210 now_ms += kWindowMs - 2;
211 // Shouldn't work! (Only one sample, not full window size.)
212 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
213
214 // Window size should be full, and the single data point should be accepted.
215 ++now_ms;
216 rtc::Optional<uint32_t> bitrate = stats_.Rate(now_ms);
217 EXPECT_TRUE(static_cast<bool>(bitrate));
218 EXPECT_EQ(1000 * 8u, *bitrate);
219
220 // Add another, now we have twice the bitrate.
221 stats_.Update(kWindowMs, now_ms);
222 bitrate = stats_.Rate(now_ms);
223 EXPECT_TRUE(static_cast<bool>(bitrate));
224 EXPECT_EQ(2 * 1000 * 8u, *bitrate);
225
226 // Now that first sample should drop out...
227 now_ms += 1;
228 bitrate = stats_.Rate(now_ms);
229 EXPECT_TRUE(static_cast<bool>(bitrate));
230 EXPECT_EQ(1000 * 8u, *bitrate);
231}
232
233TEST_F(RateStatisticsTest, HandlesZeroCounts) {
234 int64_t now_ms = 0;
235 stats_.Reset();
236 // Expecting 0 after init.
237 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
238
239 stats_.Update(kWindowMs, now_ms);
240 now_ms += kWindowMs - 1;
241 stats_.Update(0, now_ms);
242 rtc::Optional<uint32_t> bitrate = stats_.Rate(now_ms);
243 EXPECT_TRUE(static_cast<bool>(bitrate));
244 EXPECT_EQ(1000 * 8u, *bitrate);
245
246 // Move window along so first data point falls out.
247 ++now_ms;
248 bitrate = stats_.Rate(now_ms);
249 EXPECT_TRUE(static_cast<bool>(bitrate));
250 EXPECT_EQ(0u, *bitrate);
251
252 // Move window so last data point falls out.
253 now_ms += kWindowMs;
254 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
255}
256
257TEST_F(RateStatisticsTest, HandlesQuietPeriods) {
258 int64_t now_ms = 0;
259 stats_.Reset();
260 // Expecting 0 after init.
261 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
262
263 stats_.Update(0, now_ms);
264 now_ms += kWindowMs - 1;
265 rtc::Optional<uint32_t> bitrate = stats_.Rate(now_ms);
266 EXPECT_TRUE(static_cast<bool>(bitrate));
267 EXPECT_EQ(0u, *bitrate);
268
269 // Move window along so first data point falls out.
270 ++now_ms;
271 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
272
273 // Move window a long way out.
274 now_ms += 2 * kWindowMs;
275 stats_.Update(0, now_ms);
276 bitrate = stats_.Rate(now_ms);
277 EXPECT_TRUE(static_cast<bool>(bitrate));
278 EXPECT_EQ(0u, *bitrate);
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200279}
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +0000280} // namespace