diff options
Diffstat (limited to 'third_party/libwebrtc/modules/pacing/bitrate_prober_unittest.cc')
-rw-r--r-- | third_party/libwebrtc/modules/pacing/bitrate_prober_unittest.cc | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/pacing/bitrate_prober_unittest.cc b/third_party/libwebrtc/modules/pacing/bitrate_prober_unittest.cc new file mode 100644 index 0000000000..3be7d2d99e --- /dev/null +++ b/third_party/libwebrtc/modules/pacing/bitrate_prober_unittest.cc @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2014 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 "modules/pacing/bitrate_prober.h" + +#include <algorithm> + +#include "api/units/data_rate.h" +#include "api/units/time_delta.h" +#include "api/units/timestamp.h" +#include "test/explicit_key_value_config.h" +#include "test/gtest.h" + +namespace webrtc { + +TEST(BitrateProberTest, VerifyStatesAndTimeBetweenProbes) { + const FieldTrialBasedConfig config; + BitrateProber prober(config); + EXPECT_FALSE(prober.is_probing()); + + Timestamp now = Timestamp::Zero(); + const Timestamp start_time = now; + EXPECT_EQ(prober.NextProbeTime(now), Timestamp::PlusInfinity()); + + const DataRate kTestBitrate1 = DataRate::KilobitsPerSec(900); + const DataRate kTestBitrate2 = DataRate::KilobitsPerSec(1800); + const int kClusterSize = 5; + const DataSize kProbeSize = DataSize::Bytes(1000); + const TimeDelta kMinProbeDuration = TimeDelta::Millis(15); + + prober.CreateProbeCluster({.at_time = now, + .target_data_rate = kTestBitrate1, + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + prober.CreateProbeCluster({.at_time = now, + .target_data_rate = kTestBitrate2, + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 1}); + EXPECT_FALSE(prober.is_probing()); + + prober.OnIncomingPacket(kProbeSize); + EXPECT_TRUE(prober.is_probing()); + EXPECT_EQ(0, prober.CurrentCluster(now)->probe_cluster_id); + + // First packet should probe as soon as possible. + EXPECT_EQ(Timestamp::MinusInfinity(), prober.NextProbeTime(now)); + + for (int i = 0; i < kClusterSize; ++i) { + now = std::max(now, prober.NextProbeTime(now)); + EXPECT_EQ(now, std::max(now, prober.NextProbeTime(now))); + EXPECT_EQ(0, prober.CurrentCluster(now)->probe_cluster_id); + prober.ProbeSent(now, kProbeSize); + } + + EXPECT_GE(now - start_time, kMinProbeDuration); + // Verify that the actual bitrate is withing 10% of the target. + DataRate bitrate = kProbeSize * (kClusterSize - 1) / (now - start_time); + EXPECT_GT(bitrate, kTestBitrate1 * 0.9); + EXPECT_LT(bitrate, kTestBitrate1 * 1.1); + + now = std::max(now, prober.NextProbeTime(now)); + Timestamp probe2_started = now; + + for (int i = 0; i < kClusterSize; ++i) { + now = std::max(now, prober.NextProbeTime(now)); + EXPECT_EQ(now, std::max(now, prober.NextProbeTime(now))); + EXPECT_EQ(1, prober.CurrentCluster(now)->probe_cluster_id); + prober.ProbeSent(now, kProbeSize); + } + + // Verify that the actual bitrate is withing 10% of the target. + TimeDelta duration = now - probe2_started; + EXPECT_GE(duration, kMinProbeDuration); + bitrate = (kProbeSize * (kClusterSize - 1)) / duration; + EXPECT_GT(bitrate, kTestBitrate2 * 0.9); + EXPECT_LT(bitrate, kTestBitrate2 * 1.1); + + EXPECT_EQ(prober.NextProbeTime(now), Timestamp::PlusInfinity()); + EXPECT_FALSE(prober.is_probing()); +} + +TEST(BitrateProberTest, DoesntProbeWithoutRecentPackets) { + const FieldTrialBasedConfig config; + BitrateProber prober(config); + const DataSize kProbeSize = DataSize::Bytes(1000); + + Timestamp now = Timestamp::Zero(); + EXPECT_EQ(prober.NextProbeTime(now), Timestamp::PlusInfinity()); + + prober.CreateProbeCluster({.at_time = now, + .target_data_rate = DataRate::KilobitsPerSec(900), + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + EXPECT_FALSE(prober.is_probing()); + + prober.OnIncomingPacket(kProbeSize); + EXPECT_TRUE(prober.is_probing()); + EXPECT_EQ(now, std::max(now, prober.NextProbeTime(now))); + prober.ProbeSent(now, kProbeSize); +} + +TEST(BitrateProberTest, DiscardsDelayedProbes) { + const TimeDelta kMaxProbeDelay = TimeDelta::Millis(3); + const test::ExplicitKeyValueConfig trials( + "WebRTC-Bwe-ProbingBehavior/" + "abort_delayed_probes:1," + "max_probe_delay:3ms/"); + BitrateProber prober(trials); + const DataSize kProbeSize = DataSize::Bytes(1000); + + Timestamp now = Timestamp::Zero(); + + // Add two probe clusters. + prober.CreateProbeCluster({.at_time = now, + .target_data_rate = DataRate::KilobitsPerSec(900), + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + + prober.OnIncomingPacket(kProbeSize); + EXPECT_TRUE(prober.is_probing()); + EXPECT_EQ(prober.CurrentCluster(now)->probe_cluster_id, 0); + // Advance to first probe time and indicate sent probe. + now = std::max(now, prober.NextProbeTime(now)); + prober.ProbeSent(now, kProbeSize); + + // Advance time 1ms past timeout for the next probe. + Timestamp next_probe_time = prober.NextProbeTime(now); + EXPECT_GT(next_probe_time, now); + now += next_probe_time - now + kMaxProbeDelay + TimeDelta::Millis(1); + + // Still indicates the time we wanted to probe at. + EXPECT_EQ(prober.NextProbeTime(now), next_probe_time); + // First and only cluster removed due to timeout. + EXPECT_FALSE(prober.CurrentCluster(now).has_value()); +} + +TEST(BitrateProberTest, LimitsNumberOfPendingProbeClusters) { + const FieldTrialBasedConfig config; + BitrateProber prober(config); + const DataSize kProbeSize = DataSize::Bytes(1000); + Timestamp now = Timestamp::Zero(); + prober.CreateProbeCluster({.at_time = now, + .target_data_rate = DataRate::KilobitsPerSec(900), + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + prober.OnIncomingPacket(kProbeSize); + ASSERT_TRUE(prober.is_probing()); + ASSERT_EQ(prober.CurrentCluster(now)->probe_cluster_id, 0); + + for (int i = 1; i < 11; ++i) { + prober.CreateProbeCluster( + {.at_time = now, + .target_data_rate = DataRate::KilobitsPerSec(900), + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = i}); + prober.OnIncomingPacket(kProbeSize); + } + // Expect some clusters has been dropped. + EXPECT_TRUE(prober.is_probing()); + EXPECT_GE(prober.CurrentCluster(now)->probe_cluster_id, 5); + + Timestamp max_expected_probe_time = now + TimeDelta::Seconds(1); + while (prober.is_probing() && now < max_expected_probe_time) { + now = std::max(now, prober.NextProbeTime(now)); + prober.ProbeSent(now, kProbeSize); + } + EXPECT_FALSE(prober.is_probing()); +} + +TEST(BitrateProberTest, DoesntInitializeProbingForSmallPackets) { + const FieldTrialBasedConfig config; + BitrateProber prober(config); + prober.SetEnabled(true); + ASSERT_FALSE(prober.is_probing()); + + prober.CreateProbeCluster({.at_time = Timestamp::Zero(), + .target_data_rate = DataRate::KilobitsPerSec(1000), + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + prober.OnIncomingPacket(DataSize::Bytes(100)); + + EXPECT_FALSE(prober.is_probing()); +} + +TEST(BitrateProberTest, DoesInitializeProbingForSmallPacketsIfConfigured) { + const test::ExplicitKeyValueConfig config( + "WebRTC-Bwe-ProbingBehavior/" + "min_packet_size:0bytes/"); + BitrateProber prober(config); + prober.SetEnabled(true); + ASSERT_FALSE(prober.is_probing()); + + prober.CreateProbeCluster({.at_time = Timestamp::Zero(), + .target_data_rate = DataRate::KilobitsPerSec(1000), + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + prober.OnIncomingPacket(DataSize::Bytes(10)); + + EXPECT_TRUE(prober.is_probing()); +} + +TEST(BitrateProberTest, VerifyProbeSizeOnHighBitrate) { + const FieldTrialBasedConfig config; + BitrateProber prober(config); + + const DataRate kHighBitrate = DataRate::KilobitsPerSec(10000); // 10 Mbps + + prober.CreateProbeCluster({.at_time = Timestamp::Zero(), + .target_data_rate = kHighBitrate, + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + // Probe size should ensure a minimum of 1 ms interval. + EXPECT_GT(prober.RecommendedMinProbeSize(), + kHighBitrate * TimeDelta::Millis(1)); +} + +TEST(BitrateProberTest, ProbeSizeCanBeSetWithFieldTrial) { + const test::ExplicitKeyValueConfig trials( + "WebRTC-Bwe-ProbingBehavior/min_probe_delta:20ms/"); + BitrateProber prober(trials); + prober.SetEnabled(true); + + const DataRate kHighBitrate = DataRate::KilobitsPerSec(10000); // 10 Mbps + + prober.CreateProbeCluster({.at_time = Timestamp::Zero(), + .target_data_rate = kHighBitrate, + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + EXPECT_EQ(prober.RecommendedMinProbeSize(), + kHighBitrate * TimeDelta::Millis(20)); + + prober.OnIncomingPacket(DataSize::Bytes(1000)); + // Next time to send probe should be "min_probe_delta" if the recommended + // number of bytes has been sent. + prober.ProbeSent(Timestamp::Zero(), prober.RecommendedMinProbeSize()); + EXPECT_EQ(prober.NextProbeTime(Timestamp::Zero()), + Timestamp::Zero() + TimeDelta::Millis(20)); +} + +TEST(BitrateProberTest, MinumumNumberOfProbingPackets) { + const FieldTrialBasedConfig config; + BitrateProber prober(config); + // Even when probing at a low bitrate we expect a minimum number + // of packets to be sent. + const DataRate kBitrate = DataRate::KilobitsPerSec(100); + const DataSize kPacketSize = DataSize::Bytes(1000); + + Timestamp now = Timestamp::Zero(); + prober.CreateProbeCluster({.at_time = Timestamp::Zero(), + .target_data_rate = kBitrate, + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + + prober.OnIncomingPacket(kPacketSize); + for (int i = 0; i < 5; ++i) { + EXPECT_TRUE(prober.is_probing()); + prober.ProbeSent(now, kPacketSize); + } + + EXPECT_FALSE(prober.is_probing()); +} + +TEST(BitrateProberTest, ScaleBytesUsedForProbing) { + const FieldTrialBasedConfig config; + BitrateProber prober(config); + const DataRate kBitrate = DataRate::KilobitsPerSec(10000); // 10 Mbps. + const DataSize kPacketSize = DataSize::Bytes(1000); + const DataSize kExpectedDataSent = kBitrate * TimeDelta::Millis(15); + + Timestamp now = Timestamp::Zero(); + prober.CreateProbeCluster({.at_time = Timestamp::Zero(), + .target_data_rate = kBitrate, + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + prober.OnIncomingPacket(kPacketSize); + DataSize data_sent = DataSize::Zero(); + while (data_sent < kExpectedDataSent) { + ASSERT_TRUE(prober.is_probing()); + prober.ProbeSent(now, kPacketSize); + data_sent += kPacketSize; + } + + EXPECT_FALSE(prober.is_probing()); +} + +TEST(BitrateProberTest, HighBitrateProbing) { + const FieldTrialBasedConfig config; + BitrateProber prober(config); + const DataRate kBitrate = DataRate::KilobitsPerSec(1000000); // 1 Gbps. + const DataSize kPacketSize = DataSize::Bytes(1000); + const DataSize kExpectedDataSent = kBitrate * TimeDelta::Millis(15); + + Timestamp now = Timestamp::Zero(); + prober.CreateProbeCluster({.at_time = Timestamp::Zero(), + .target_data_rate = kBitrate, + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + prober.OnIncomingPacket(kPacketSize); + DataSize data_sent = DataSize::Zero(); + while (data_sent < kExpectedDataSent) { + ASSERT_TRUE(prober.is_probing()); + prober.ProbeSent(now, kPacketSize); + data_sent += kPacketSize; + } + + EXPECT_FALSE(prober.is_probing()); +} + +TEST(BitrateProberTest, ProbeClusterTimeout) { + const FieldTrialBasedConfig config; + BitrateProber prober(config); + const DataRate kBitrate = DataRate::KilobitsPerSec(300); + const DataSize kSmallPacketSize = DataSize::Bytes(20); + // Expecting two probe clusters of 5 packets each. + const DataSize kExpectedDataSent = kSmallPacketSize * 2 * 5; + const TimeDelta kTimeout = TimeDelta::Millis(5000); + + Timestamp now = Timestamp::Zero(); + prober.CreateProbeCluster({.at_time = now, + .target_data_rate = kBitrate, + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 0}); + prober.OnIncomingPacket(kSmallPacketSize); + EXPECT_FALSE(prober.is_probing()); + now += kTimeout; + prober.CreateProbeCluster({.at_time = now, + .target_data_rate = kBitrate / 10, + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 1}); + prober.OnIncomingPacket(kSmallPacketSize); + EXPECT_FALSE(prober.is_probing()); + now += TimeDelta::Millis(1); + prober.CreateProbeCluster({.at_time = now, + .target_data_rate = kBitrate / 10, + .target_duration = TimeDelta::Millis(15), + .target_probe_count = 5, + .id = 2}); + prober.OnIncomingPacket(kSmallPacketSize); + EXPECT_TRUE(prober.is_probing()); + DataSize data_sent = DataSize::Zero(); + while (data_sent < kExpectedDataSent) { + ASSERT_TRUE(prober.is_probing()); + prober.ProbeSent(now, kSmallPacketSize); + data_sent += kSmallPacketSize; + } + + EXPECT_FALSE(prober.is_probing()); +} +} // namespace webrtc |