| /* |
| * Copyright (c) 2016 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/congestion_controller/goog_cc/delay_based_bwe.h" |
| |
| #include <string> |
| |
| #include "api/transport/network_types.h" |
| #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h" |
| #include "modules/congestion_controller/goog_cc/delay_based_bwe_unittest_helper.h" |
| #include "system_wrappers/include/clock.h" |
| #include "test/gtest.h" |
| |
| namespace webrtc { |
| |
| namespace { |
| constexpr int kNumProbesCluster0 = 5; |
| constexpr int kNumProbesCluster1 = 8; |
| const PacedPacketInfo kPacingInfo0(0, kNumProbesCluster0, 2000); |
| const PacedPacketInfo kPacingInfo1(1, kNumProbesCluster1, 4000); |
| constexpr float kTargetUtilizationFraction = 0.95f; |
| } // namespace |
| |
| TEST_F(DelayBasedBweTest, ProbeDetection) { |
| int64_t now_ms = clock_.TimeInMilliseconds(); |
| |
| // First burst sent at 8 * 1000 / 10 = 800 kbps. |
| for (int i = 0; i < kNumProbesCluster0; ++i) { |
| clock_.AdvanceTimeMilliseconds(10); |
| now_ms = clock_.TimeInMilliseconds(); |
| IncomingFeedback(now_ms, now_ms, 1000, kPacingInfo0); |
| } |
| EXPECT_TRUE(bitrate_observer_.updated()); |
| |
| // Second burst sent at 8 * 1000 / 5 = 1600 kbps. |
| for (int i = 0; i < kNumProbesCluster1; ++i) { |
| clock_.AdvanceTimeMilliseconds(5); |
| now_ms = clock_.TimeInMilliseconds(); |
| IncomingFeedback(now_ms, now_ms, 1000, kPacingInfo1); |
| } |
| |
| EXPECT_TRUE(bitrate_observer_.updated()); |
| EXPECT_GT(bitrate_observer_.latest_bitrate(), 1500000u); |
| } |
| |
| TEST_F(DelayBasedBweTest, ProbeDetectionNonPacedPackets) { |
| int64_t now_ms = clock_.TimeInMilliseconds(); |
| // First burst sent at 8 * 1000 / 10 = 800 kbps, but with every other packet |
| // not being paced which could mess things up. |
| for (int i = 0; i < kNumProbesCluster0; ++i) { |
| clock_.AdvanceTimeMilliseconds(5); |
| now_ms = clock_.TimeInMilliseconds(); |
| IncomingFeedback(now_ms, now_ms, 1000, kPacingInfo0); |
| // Non-paced packet, arriving 5 ms after. |
| clock_.AdvanceTimeMilliseconds(5); |
| IncomingFeedback(now_ms, now_ms, 100, PacedPacketInfo()); |
| } |
| |
| EXPECT_TRUE(bitrate_observer_.updated()); |
| EXPECT_GT(bitrate_observer_.latest_bitrate(), 800000u); |
| } |
| |
| TEST_F(DelayBasedBweTest, ProbeDetectionFasterArrival) { |
| int64_t now_ms = clock_.TimeInMilliseconds(); |
| // First burst sent at 8 * 1000 / 10 = 800 kbps. |
| // Arriving at 8 * 1000 / 5 = 1600 kbps. |
| int64_t send_time_ms = 0; |
| for (int i = 0; i < kNumProbesCluster0; ++i) { |
| clock_.AdvanceTimeMilliseconds(1); |
| send_time_ms += 10; |
| now_ms = clock_.TimeInMilliseconds(); |
| IncomingFeedback(now_ms, send_time_ms, 1000, kPacingInfo0); |
| } |
| |
| EXPECT_FALSE(bitrate_observer_.updated()); |
| } |
| |
| TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrival) { |
| int64_t now_ms = clock_.TimeInMilliseconds(); |
| // First burst sent at 8 * 1000 / 5 = 1600 kbps. |
| // Arriving at 8 * 1000 / 7 = 1142 kbps. |
| // Since the receive rate is significantly below the send rate, we expect to |
| // use 95% of the estimated capacity. |
| int64_t send_time_ms = 0; |
| for (int i = 0; i < kNumProbesCluster1; ++i) { |
| clock_.AdvanceTimeMilliseconds(7); |
| send_time_ms += 5; |
| now_ms = clock_.TimeInMilliseconds(); |
| IncomingFeedback(now_ms, send_time_ms, 1000, kPacingInfo1); |
| } |
| |
| EXPECT_TRUE(bitrate_observer_.updated()); |
| EXPECT_NEAR(bitrate_observer_.latest_bitrate(), |
| kTargetUtilizationFraction * 1140000u, 10000u); |
| } |
| |
| TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrivalHighBitrate) { |
| int64_t now_ms = clock_.TimeInMilliseconds(); |
| // Burst sent at 8 * 1000 / 1 = 8000 kbps. |
| // Arriving at 8 * 1000 / 2 = 4000 kbps. |
| // Since the receive rate is significantly below the send rate, we expect to |
| // use 95% of the estimated capacity. |
| int64_t send_time_ms = 0; |
| for (int i = 0; i < kNumProbesCluster1; ++i) { |
| clock_.AdvanceTimeMilliseconds(2); |
| send_time_ms += 1; |
| now_ms = clock_.TimeInMilliseconds(); |
| IncomingFeedback(now_ms, send_time_ms, 1000, kPacingInfo1); |
| } |
| |
| EXPECT_TRUE(bitrate_observer_.updated()); |
| EXPECT_NEAR(bitrate_observer_.latest_bitrate(), |
| kTargetUtilizationFraction * 4000000u, 10000u); |
| } |
| |
| TEST_F(DelayBasedBweTest, GetExpectedBwePeriodMs) { |
| auto default_interval = bitrate_estimator_->GetExpectedBwePeriod(); |
| EXPECT_GT(default_interval.ms(), 0); |
| CapacityDropTestHelper(1, true, 333, 0); |
| auto interval = bitrate_estimator_->GetExpectedBwePeriod(); |
| EXPECT_GT(interval.ms(), 0); |
| EXPECT_NE(interval.ms(), default_interval.ms()); |
| } |
| |
| TEST_F(DelayBasedBweTest, InitialBehavior) { |
| InitialBehaviorTestHelper(730000); |
| } |
| |
| TEST_F(DelayBasedBweTest, RateIncreaseReordering) { |
| RateIncreaseReorderingTestHelper(730000); |
| } |
| TEST_F(DelayBasedBweTest, RateIncreaseRtpTimestamps) { |
| RateIncreaseRtpTimestampsTestHelper(622); |
| } |
| |
| TEST_F(DelayBasedBweTest, CapacityDropOneStream) { |
| CapacityDropTestHelper(1, false, 300, 0); |
| } |
| |
| TEST_F(DelayBasedBweTest, CapacityDropPosOffsetChange) { |
| CapacityDropTestHelper(1, false, 867, 30000); |
| } |
| |
| TEST_F(DelayBasedBweTest, CapacityDropNegOffsetChange) { |
| CapacityDropTestHelper(1, false, 933, -30000); |
| } |
| |
| TEST_F(DelayBasedBweTest, CapacityDropOneStreamWrap) { |
| CapacityDropTestHelper(1, true, 333, 0); |
| } |
| |
| TEST_F(DelayBasedBweTest, TestTimestampGrouping) { |
| TestTimestampGroupingTestHelper(); |
| } |
| |
| TEST_F(DelayBasedBweTest, TestShortTimeoutAndWrap) { |
| // Simulate a client leaving and rejoining the call after 35 seconds. This |
| // will make abs send time wrap, so if streams aren't timed out properly |
| // the next 30 seconds of packets will be out of order. |
| TestWrappingHelper(35); |
| } |
| |
| TEST_F(DelayBasedBweTest, TestLongTimeoutAndWrap) { |
| // Simulate a client leaving and rejoining the call after some multiple of |
| // 64 seconds later. This will cause a zero difference in abs send times due |
| // to the wrap, but a big difference in arrival time, if streams aren't |
| // properly timed out. |
| TestWrappingHelper(10 * 64); |
| } |
| |
| TEST_F(DelayBasedBweTest, TestInitialOveruse) { |
| const DataRate kStartBitrate = DataRate::KilobitsPerSec(300); |
| const DataRate kInitialCapacity = DataRate::KilobitsPerSec(200); |
| const uint32_t kDummySsrc = 0; |
| // High FPS to ensure that we send a lot of packets in a short time. |
| const int kFps = 90; |
| |
| stream_generator_->AddStream(new test::RtpStream(kFps, kStartBitrate.bps())); |
| stream_generator_->set_capacity_bps(kInitialCapacity.bps()); |
| |
| // Needed to initialize the AimdRateControl. |
| bitrate_estimator_->SetStartBitrate(kStartBitrate); |
| |
| // Produce 30 frames (in 1/3 second) and give them to the estimator. |
| int64_t bitrate_bps = kStartBitrate.bps(); |
| bool seen_overuse = false; |
| for (int i = 0; i < 30; ++i) { |
| bool overuse = GenerateAndProcessFrame(kDummySsrc, bitrate_bps); |
| // The purpose of this test is to ensure that we back down even if we don't |
| // have any acknowledged bitrate estimate yet. Hence, if the test works |
| // as expected, we should not have a measured bitrate yet. |
| EXPECT_FALSE(acknowledged_bitrate_estimator_->bitrate().has_value()); |
| if (overuse) { |
| EXPECT_TRUE(bitrate_observer_.updated()); |
| EXPECT_NEAR(bitrate_observer_.latest_bitrate(), kStartBitrate.bps() / 2, |
| 15000); |
| bitrate_bps = bitrate_observer_.latest_bitrate(); |
| seen_overuse = true; |
| break; |
| } else if (bitrate_observer_.updated()) { |
| bitrate_bps = bitrate_observer_.latest_bitrate(); |
| bitrate_observer_.Reset(); |
| } |
| } |
| EXPECT_TRUE(seen_overuse); |
| EXPECT_NEAR(bitrate_observer_.latest_bitrate(), kStartBitrate.bps() / 2, |
| 15000); |
| } |
| |
| TEST_F(DelayBasedBweTest, TestTimestampPrecisionHandling) { |
| // This test does some basic checks to make sure that timestamps with higher |
| // than millisecond precision are handled properly and do not cause any |
| // problems in the estimator. Specifically, previously reported in |
| // webrtc:14023 and described in more details there, the rounding to the |
| // nearest milliseconds caused discrepancy in the accumulated delay. This lead |
| // to false-positive overuse detection. |
| // Technical details of the test: |
| // Send times(ms): 0.000, 9.725, 20.000, 29.725, 40.000, 49.725, ... |
| // Recv times(ms): 0.500, 10.000, 20.500, 30.000, 40.500, 50.000, ... |
| // Send deltas(ms): 9.750, 10.250, 9.750, 10.250, 9.750, ... |
| // Recv deltas(ms): 9.500, 10.500, 9.500, 10.500, 9.500, ... |
| // There is no delay building up between the send times and the receive times, |
| // therefore this case should never lead to an overuse detection. However, if |
| // the time deltas were accidentally rounded to the nearest milliseconds, then |
| // all the send deltas would be equal to 10ms while some recv deltas would |
| // round up to 11ms which would lead in a false illusion of delay build up. |
| uint32_t last_bitrate = bitrate_observer_.latest_bitrate(); |
| for (int i = 0; i < 1000; ++i) { |
| clock_.AdvanceTimeMicroseconds(500); |
| IncomingFeedback(clock_.CurrentTime(), |
| clock_.CurrentTime() - TimeDelta::Micros(500), 1000, |
| PacedPacketInfo()); |
| clock_.AdvanceTimeMicroseconds(9500); |
| IncomingFeedback(clock_.CurrentTime(), |
| clock_.CurrentTime() - TimeDelta::Micros(250), 1000, |
| PacedPacketInfo()); |
| clock_.AdvanceTimeMicroseconds(10000); |
| |
| // The bitrate should never decrease in this test. |
| EXPECT_LE(last_bitrate, bitrate_observer_.latest_bitrate()); |
| last_bitrate = bitrate_observer_.latest_bitrate(); |
| } |
| } |
| |
| class DelayBasedBweTestWithBackoffTimeoutExperiment : public DelayBasedBweTest { |
| public: |
| DelayBasedBweTestWithBackoffTimeoutExperiment() |
| : DelayBasedBweTest( |
| "WebRTC-BweAimdRateControlConfig/initial_backoff_interval:200ms/") { |
| } |
| }; |
| |
| // This test subsumes and improves DelayBasedBweTest.TestInitialOveruse above. |
| TEST_F(DelayBasedBweTestWithBackoffTimeoutExperiment, TestInitialOveruse) { |
| const DataRate kStartBitrate = DataRate::KilobitsPerSec(300); |
| const DataRate kInitialCapacity = DataRate::KilobitsPerSec(200); |
| const uint32_t kDummySsrc = 0; |
| // High FPS to ensure that we send a lot of packets in a short time. |
| const int kFps = 90; |
| |
| stream_generator_->AddStream(new test::RtpStream(kFps, kStartBitrate.bps())); |
| stream_generator_->set_capacity_bps(kInitialCapacity.bps()); |
| |
| // Needed to initialize the AimdRateControl. |
| bitrate_estimator_->SetStartBitrate(kStartBitrate); |
| |
| // Produce 30 frames (in 1/3 second) and give them to the estimator. |
| int64_t bitrate_bps = kStartBitrate.bps(); |
| bool seen_overuse = false; |
| for (int frames = 0; frames < 30 && !seen_overuse; ++frames) { |
| bool overuse = GenerateAndProcessFrame(kDummySsrc, bitrate_bps); |
| // The purpose of this test is to ensure that we back down even if we don't |
| // have any acknowledged bitrate estimate yet. Hence, if the test works |
| // as expected, we should not have a measured bitrate yet. |
| EXPECT_FALSE(acknowledged_bitrate_estimator_->bitrate().has_value()); |
| if (overuse) { |
| EXPECT_TRUE(bitrate_observer_.updated()); |
| EXPECT_NEAR(bitrate_observer_.latest_bitrate(), kStartBitrate.bps() / 2, |
| 15000); |
| bitrate_bps = bitrate_observer_.latest_bitrate(); |
| seen_overuse = true; |
| } else if (bitrate_observer_.updated()) { |
| bitrate_bps = bitrate_observer_.latest_bitrate(); |
| bitrate_observer_.Reset(); |
| } |
| } |
| EXPECT_TRUE(seen_overuse); |
| // Continue generating an additional 15 frames (equivalent to 167 ms) and |
| // verify that we don't back down further. |
| for (int frames = 0; frames < 15 && seen_overuse; ++frames) { |
| bool overuse = GenerateAndProcessFrame(kDummySsrc, bitrate_bps); |
| EXPECT_FALSE(overuse); |
| if (bitrate_observer_.updated()) { |
| bitrate_bps = bitrate_observer_.latest_bitrate(); |
| EXPECT_GE(bitrate_bps, kStartBitrate.bps() / 2 - 15000); |
| EXPECT_LE(bitrate_bps, kInitialCapacity.bps() + 15000); |
| bitrate_observer_.Reset(); |
| } |
| } |
| } |
| |
| } // namespace webrtc |