summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/bitrate_tracker_unittest.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/rtc_base/bitrate_tracker_unittest.cc
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/rtc_base/bitrate_tracker_unittest.cc')
-rw-r--r--third_party/libwebrtc/rtc_base/bitrate_tracker_unittest.cc267
1 files changed, 267 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/bitrate_tracker_unittest.cc b/third_party/libwebrtc/rtc_base/bitrate_tracker_unittest.cc
new file mode 100644
index 0000000000..2129aebfdd
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/bitrate_tracker_unittest.cc
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2023 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/bitrate_tracker.h"
+
+#include <cstdlib>
+#include <limits>
+
+#include "absl/types/optional.h"
+#include "api/units/data_rate.h"
+#include "api/units/time_delta.h"
+#include "api/units/timestamp.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+using ::testing::AllOf;
+using ::testing::Ge;
+using ::testing::Le;
+
+constexpr TimeDelta kWindow = TimeDelta::Millis(500);
+constexpr TimeDelta kEpsilon = TimeDelta::Millis(1);
+
+TEST(BitrateTrackerTest, ReturnsNulloptInitially) {
+ Timestamp now = Timestamp::Seconds(12'345);
+ BitrateTracker stats(kWindow);
+
+ EXPECT_EQ(stats.Rate(now), absl::nullopt);
+}
+
+TEST(BitrateTrackerTest, ReturnsNulloptAfterSingleDataPoint) {
+ Timestamp now = Timestamp::Seconds(12'345);
+ BitrateTracker stats(kWindow);
+
+ stats.Update(1'500, now);
+ now += TimeDelta::Millis(10);
+
+ EXPECT_EQ(stats.Rate(now), absl::nullopt);
+}
+
+TEST(BitrateTrackerTest, ReturnsRateAfterTwoMeasurements) {
+ Timestamp now = Timestamp::Seconds(12'345);
+ BitrateTracker stats(kWindow);
+
+ stats.Update(1'500, now);
+ now += TimeDelta::Millis(10);
+ stats.Update(1'500, now);
+
+ // One packet every 10ms would result in 1.2 Mbps, but until window is full,
+ // it could be treated as two packets in ~10ms window, measuring twice that
+ // bitrate.
+ EXPECT_THAT(stats.Rate(now), AllOf(Ge(DataRate::BitsPerSec(1'200'000)),
+ Le(DataRate::BitsPerSec(2'400'000))));
+}
+
+TEST(BitrateTrackerTest, MeasuresConstantRate) {
+ const Timestamp start = Timestamp::Seconds(12'345);
+ const TimeDelta kInterval = TimeDelta::Millis(10);
+ const DataSize kPacketSize = DataSize::Bytes(1'500);
+ const DataRate kConstantRate = kPacketSize / kInterval;
+
+ Timestamp now = start;
+ BitrateTracker stats(kWindow);
+
+ stats.Update(kPacketSize, now);
+ DataSize total_size = kPacketSize;
+ DataRate last_error = DataRate::PlusInfinity();
+ for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kInterval) {
+ SCOPED_TRACE(i);
+ now += kInterval;
+ total_size += kPacketSize;
+ stats.Update(kPacketSize, now);
+
+ // Until window is full, bitrate is measured over a smaller window and might
+ // look larger than the constant rate.
+ absl::optional<DataRate> bitrate = stats.Rate(now);
+ ASSERT_THAT(bitrate,
+ AllOf(Ge(kConstantRate), Le(total_size / (now - start))));
+
+ // Expect the estimation error to decrease as the window is extended.
+ DataRate error = *bitrate - kConstantRate;
+ EXPECT_LE(error, last_error);
+ last_error = error;
+ }
+
+ // Once window is full, bitrate measurment should be stable.
+ for (TimeDelta i = TimeDelta::Zero(); i < kInterval;
+ i += TimeDelta::Millis(1)) {
+ SCOPED_TRACE(i);
+ EXPECT_EQ(stats.Rate(now + i), kConstantRate);
+ }
+}
+
+TEST(BitrateTrackerTest, IncreasingThenDecreasingBitrate) {
+ const DataSize kLargePacketSize = DataSize::Bytes(1'500);
+ const DataSize kSmallPacketSize = DataSize::Bytes(300);
+ const TimeDelta kLargeInterval = TimeDelta::Millis(10);
+ const TimeDelta kSmallInterval = TimeDelta::Millis(2);
+
+ Timestamp now = Timestamp::Seconds(12'345);
+ BitrateTracker stats(kWindow);
+
+ stats.Update(kLargePacketSize, now);
+ for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kLargeInterval) {
+ SCOPED_TRACE(i);
+ now += kLargeInterval;
+ stats.Update(kLargePacketSize, now);
+ }
+ absl::optional<DataRate> last_bitrate = stats.Rate(now);
+ EXPECT_EQ(last_bitrate, kLargePacketSize / kLargeInterval);
+
+ // Decrease bitrate with smaller measurments.
+ for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kLargeInterval) {
+ SCOPED_TRACE(i);
+ now += kLargeInterval;
+ stats.Update(kSmallPacketSize, now);
+
+ absl::optional<DataRate> bitrate = stats.Rate(now);
+ EXPECT_LT(bitrate, last_bitrate);
+
+ last_bitrate = bitrate;
+ }
+ EXPECT_EQ(last_bitrate, kSmallPacketSize / kLargeInterval);
+
+ // Increase bitrate with more frequent measurments.
+ for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kSmallInterval) {
+ SCOPED_TRACE(i);
+ now += kSmallInterval;
+ stats.Update(kSmallPacketSize, now);
+
+ absl::optional<DataRate> bitrate = stats.Rate(now);
+ EXPECT_GE(bitrate, last_bitrate);
+
+ last_bitrate = bitrate;
+ }
+ EXPECT_EQ(last_bitrate, kSmallPacketSize / kSmallInterval);
+}
+
+TEST(BitrateTrackerTest, ResetAfterSilence) {
+ const TimeDelta kInterval = TimeDelta::Millis(10);
+ const DataSize kPacketSize = DataSize::Bytes(1'500);
+
+ Timestamp now = Timestamp::Seconds(12'345);
+ BitrateTracker stats(kWindow);
+
+ // Feed data until window has been filled.
+ stats.Update(kPacketSize, now);
+ for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kInterval) {
+ now += kInterval;
+ stats.Update(kPacketSize, now);
+ }
+ ASSERT_GT(stats.Rate(now), DataRate::Zero());
+
+ now += kWindow + kEpsilon;
+ // Silence over window size should trigger auto reset for coming sample.
+ EXPECT_EQ(stats.Rate(now), absl::nullopt);
+ stats.Update(kPacketSize, now);
+ // Single measurment after reset is not enough to estimate the rate.
+ EXPECT_EQ(stats.Rate(now), absl::nullopt);
+
+ // Manual reset, add the same check again.
+ stats.Reset();
+ EXPECT_EQ(stats.Rate(now), absl::nullopt);
+ now += kInterval;
+ stats.Update(kPacketSize, now);
+ EXPECT_EQ(stats.Rate(now), absl::nullopt);
+}
+
+TEST(BitrateTrackerTest, HandlesChangingWindowSize) {
+ Timestamp now = Timestamp::Seconds(12'345);
+ BitrateTracker stats(kWindow);
+
+ // Check window size is validated.
+ EXPECT_TRUE(stats.SetWindowSize(kWindow, now));
+ EXPECT_FALSE(stats.SetWindowSize(kWindow + kEpsilon, now));
+ EXPECT_FALSE(stats.SetWindowSize(TimeDelta::Zero(), now));
+ EXPECT_TRUE(stats.SetWindowSize(kEpsilon, now));
+ EXPECT_TRUE(stats.SetWindowSize(kWindow, now));
+
+ // Fill the buffer at a rate of 10 bytes per 10 ms (8 kbps).
+ const DataSize kValue = DataSize::Bytes(10);
+ const TimeDelta kInterval = TimeDelta::Millis(10);
+ for (TimeDelta i = TimeDelta::Zero(); i < kWindow; i += kInterval) {
+ now += kInterval;
+ stats.Update(kValue, now);
+ }
+ ASSERT_GT(stats.Rate(now), DataRate::BitsPerSec(8'000));
+
+ // Halve the window size, rate should stay the same.
+ EXPECT_TRUE(stats.SetWindowSize(kWindow / 2, now));
+ EXPECT_EQ(stats.Rate(now), DataRate::BitsPerSec(8'000));
+
+ // Double the window size again, rate should stay the same.
+ // The window won't actually expand until new calls to the `Update`.
+ EXPECT_TRUE(stats.SetWindowSize(kWindow, now));
+ EXPECT_EQ(stats.Rate(now), DataRate::BitsPerSec(8'000));
+
+ // Fill the now empty window half at twice the rate.
+ for (TimeDelta i = TimeDelta::Zero(); i < kWindow / 2; i += kInterval) {
+ now += kInterval;
+ stats.Update(2 * kValue, now);
+ }
+
+ // Rate should have increased by 50%.
+ EXPECT_EQ(stats.Rate(now), DataRate::BitsPerSec(12'000));
+}
+
+TEST(BitrateTrackerTest, HandlesZeroCounts) {
+ const DataSize kPacketSize = DataSize::Bytes(1'500);
+ const TimeDelta kInterval = TimeDelta::Millis(10);
+ const Timestamp start = Timestamp::Seconds(12'345);
+
+ Timestamp now = start;
+ BitrateTracker stats(kWindow);
+
+ stats.Update(kPacketSize, now);
+ ASSERT_EQ(stats.Rate(now), absl::nullopt);
+ now += kInterval;
+ stats.Update(0, now);
+ absl::optional<DataRate> last_bitrate = stats.Rate(now);
+ EXPECT_GT(last_bitrate, DataRate::Zero());
+ now += kInterval;
+ while (now < start + kWindow) {
+ SCOPED_TRACE(now - start);
+ stats.Update(0, now);
+
+ absl::optional<DataRate> bitrate = stats.Rate(now);
+ EXPECT_GT(bitrate, DataRate::Zero());
+ // As window expands, average bitrate decreases.
+ EXPECT_LT(bitrate, last_bitrate);
+
+ last_bitrate = bitrate;
+ now += kInterval;
+ }
+
+ // Initial kPacketSize should be outside the window now, so overall bitrate
+ // should be zero
+ EXPECT_EQ(stats.Rate(now), DataRate::Zero());
+
+ // Single measurment should be enough to get non zero rate.
+ stats.Update(kPacketSize, now);
+ EXPECT_EQ(stats.Rate(now), kPacketSize / kWindow);
+}
+
+TEST(BitrateTrackerTest, ReturnsNulloptWhenOverflows) {
+ Timestamp now = Timestamp::Seconds(12'345);
+ BitrateTracker stats(kWindow);
+
+ int64_t very_large_number = std::numeric_limits<int64_t>::max();
+ stats.Update(very_large_number, now);
+ now += kEpsilon;
+ stats.Update(very_large_number, now);
+
+ EXPECT_EQ(stats.Rate(now), absl::nullopt);
+}
+
+} // namespace
+} // namespace webrtc