diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn index d1a45be19a..1b1d9630aa 100644 --- a/webrtc/modules/BUILD.gn +++ b/webrtc/modules/BUILD.gn @@ -145,6 +145,9 @@ if (rtc_include_tests) { "bitrate_controller/bitrate_controller_unittest.cc", "bitrate_controller/send_side_bandwidth_estimation_unittest.cc", "congestion_controller/congestion_controller_unittest.cc", + "congestion_controller/delay_based_bwe_unittest.cc", + "congestion_controller/delay_based_bwe_unittest_helper.cc", + "congestion_controller/delay_based_bwe_unittest_helper.h", "media_file/media_file_unittest.cc", "module_common_types_unittest.cc", "pacing/bitrate_prober_unittest.cc", diff --git a/webrtc/modules/congestion_controller/congestion_controller.cc b/webrtc/modules/congestion_controller/congestion_controller.cc index 7582258185..e28a38c1d2 100644 --- a/webrtc/modules/congestion_controller/congestion_controller.cc +++ b/webrtc/modules/congestion_controller/congestion_controller.cc @@ -131,7 +131,7 @@ class WrappingBitrateEstimator : public RemoteBitrateEstimator { // Instantiate RBE for Time Offset or Absolute Send Time extensions. void PickEstimator() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_.get()) { if (using_absolute_send_time_) { - rbe_.reset(new RemoteBitrateEstimatorAbsSendTime(observer_)); + rbe_.reset(new RemoteBitrateEstimatorAbsSendTime(observer_, clock_)); } else { rbe_.reset(new RemoteBitrateEstimatorSingleStream(observer_, clock_)); } @@ -205,7 +205,7 @@ CongestionController::~CongestionController() {} void CongestionController::Init() { transport_feedback_adapter_.SetBitrateEstimator( - new DelayBasedBwe(&transport_feedback_adapter_)); + new DelayBasedBwe(&transport_feedback_adapter_, clock_)); transport_feedback_adapter_.GetBitrateEstimator()->SetMinBitrate( min_bitrate_bps_); } @@ -240,8 +240,8 @@ void CongestionController::ResetBweAndBitrates(int bitrate_bps, if (remote_bitrate_estimator_) remote_bitrate_estimator_->SetMinBitrate(min_bitrate_bps); - RemoteBitrateEstimator* rbe = - new RemoteBitrateEstimatorAbsSendTime(&transport_feedback_adapter_); + RemoteBitrateEstimator* rbe = new RemoteBitrateEstimatorAbsSendTime( + &transport_feedback_adapter_, clock_); transport_feedback_adapter_.SetBitrateEstimator(rbe); rbe->SetMinBitrate(min_bitrate_bps); // TODO(holmer): Trigger a new probe once mid-call probing is implemented. diff --git a/webrtc/modules/congestion_controller/delay_based_bwe.cc b/webrtc/modules/congestion_controller/delay_based_bwe.cc index 3a9537ee3e..b8e774a0be 100644 --- a/webrtc/modules/congestion_controller/delay_based_bwe.cc +++ b/webrtc/modules/congestion_controller/delay_based_bwe.cc @@ -68,8 +68,9 @@ void DelayBasedBwe::AddCluster(std::list* clusters, Cluster* cluster) { clusters->push_back(*cluster); } -DelayBasedBwe::DelayBasedBwe(RemoteBitrateObserver* observer) - : observer_(observer), +DelayBasedBwe::DelayBasedBwe(RemoteBitrateObserver* observer, Clock* clock) + : clock_(clock), + observer_(observer), inter_arrival_(), estimator_(), detector_(OverUseDetectorOptions()), @@ -203,35 +204,6 @@ void DelayBasedBwe::IncomingPacketFeedbackVector( } } -void DelayBasedBwe::IncomingPacket(int64_t arrival_time_ms, - size_t payload_size, - const RTPHeader& header) { - RTC_DCHECK(network_thread_.CalledOnValidThread()); - if (!header.extension.hasAbsoluteSendTime) { - // NOTE! The BitrateEstimatorTest relies on this EXACT log line. - LOG(LS_WARNING) << "RemoteBitrateEstimatorAbsSendTime: Incoming packet " - "is missing absolute send time extension!"; - return; - } - IncomingPacketInfo(arrival_time_ms, header.extension.absoluteSendTime, - payload_size, header.ssrc, PacketInfo::kNotAProbe); -} - -void DelayBasedBwe::IncomingPacket(int64_t arrival_time_ms, - size_t payload_size, - const RTPHeader& header, - int probe_cluster_id) { - RTC_DCHECK(network_thread_.CalledOnValidThread()); - if (!header.extension.hasAbsoluteSendTime) { - // NOTE! The BitrateEstimatorTest relies on this EXACT log line. - LOG(LS_WARNING) << "RemoteBitrateEstimatorAbsSendTime: Incoming packet " - "is missing absolute send time extension!"; - return; - } - IncomingPacketInfo(arrival_time_ms, header.extension.absoluteSendTime, - payload_size, header.ssrc, probe_cluster_id); -} - void DelayBasedBwe::IncomingPacketInfo(int64_t arrival_time_ms, uint32_t send_time_24bits, size_t payload_size, @@ -243,13 +215,13 @@ void DelayBasedBwe::IncomingPacketInfo(int64_t arrival_time_ms, uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift; int64_t send_time_ms = static_cast(timestamp) * kTimestampToMs; - int64_t now_ms = arrival_time_ms; + int64_t now_ms = clock_->TimeInMilliseconds(); // TODO(holmer): SSRCs are only needed for REMB, should be broken out from // here. - incoming_bitrate_.Update(payload_size, now_ms); + incoming_bitrate_.Update(payload_size, arrival_time_ms); if (first_packet_time_ms_ == -1) - first_packet_time_ms_ = arrival_time_ms; + first_packet_time_ms_ = now_ms; uint32_t ts_delta = 0; int64_t t_delta = 0; @@ -294,8 +266,9 @@ void DelayBasedBwe::IncomingPacketInfo(int64_t arrival_time_ms, if (ProcessClusters(now_ms) == ProbeResult::kBitrateUpdated) update_estimate = true; } - if (inter_arrival_->ComputeDeltas(timestamp, arrival_time_ms, payload_size, - &ts_delta, &t_delta, &size_delta)) { + if (inter_arrival_->ComputeDeltas(timestamp, arrival_time_ms, now_ms, + payload_size, &ts_delta, &t_delta, + &size_delta)) { double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift); estimator_->Update(t_delta, ts_delta_ms, size_delta, detector_.State()); detector_.Detect(estimator_->offset(), ts_delta_ms, @@ -309,7 +282,8 @@ void DelayBasedBwe::IncomingPacketInfo(int64_t arrival_time_ms, now_ms - last_update_ms_ > remote_rate_.GetFeedbackInterval()) { update_estimate = true; } else if (detector_.State() == kBwOverusing) { - rtc::Optional incoming_rate = incoming_bitrate_.Rate(now_ms); + rtc::Optional incoming_rate = + incoming_bitrate_.Rate(arrival_time_ms); if (incoming_rate && remote_rate_.TimeToReduceFurther(now_ms, *incoming_rate)) { update_estimate = true; @@ -322,7 +296,7 @@ void DelayBasedBwe::IncomingPacketInfo(int64_t arrival_time_ms, // We also have to update the estimate immediately if we are overusing // and the target bitrate is too high compared to what we are receiving. const RateControlInput input(detector_.State(), - incoming_bitrate_.Rate(now_ms), + incoming_bitrate_.Rate(arrival_time_ms), estimator_->var_noise()); remote_rate_.Update(&input, now_ms); target_bitrate_bps = remote_rate_.UpdateBandwidthEstimate(now_ms); diff --git a/webrtc/modules/congestion_controller/delay_based_bwe.h b/webrtc/modules/congestion_controller/delay_based_bwe.h index 56214de3e5..cdcd139cc1 100644 --- a/webrtc/modules/congestion_controller/delay_based_bwe.h +++ b/webrtc/modules/congestion_controller/delay_based_bwe.h @@ -32,7 +32,7 @@ namespace webrtc { class DelayBasedBwe : public RemoteBitrateEstimator { public: - explicit DelayBasedBwe(RemoteBitrateObserver* observer); + DelayBasedBwe(RemoteBitrateObserver* observer, Clock* clock); virtual ~DelayBasedBwe() {} void IncomingPacketFeedbackVector( @@ -40,12 +40,9 @@ class DelayBasedBwe : public RemoteBitrateEstimator { void IncomingPacket(int64_t arrival_time_ms, size_t payload_size, - const RTPHeader& header) override; - - void IncomingPacket(int64_t arrival_time_ms, - size_t payload_size, - const RTPHeader& header, - int probe_cluster_id); + const RTPHeader& header) override { + RTC_NOTREACHED(); + } // This class relies on Process() being called periodically (at least once // every other second) for streams to be timed out properly. Therefore it @@ -126,13 +123,12 @@ class DelayBasedBwe : public RemoteBitrateEstimator { void TimeoutStreams(int64_t now_ms) EXCLUSIVE_LOCKS_REQUIRED(&crit_); rtc::ThreadChecker network_thread_; + Clock* const clock_; RemoteBitrateObserver* const observer_; std::unique_ptr inter_arrival_; std::unique_ptr estimator_; OveruseDetector detector_; RateStatistics incoming_bitrate_; - std::vector recent_propagation_delta_ms_; - std::vector recent_update_time_ms_; std::list probes_; size_t total_probes_received_; int64_t first_packet_time_ms_; diff --git a/webrtc/modules/congestion_controller/delay_based_bwe_unittest.cc b/webrtc/modules/congestion_controller/delay_based_bwe_unittest.cc index a78dd7fb08..ce0a32d4b0 100644 --- a/webrtc/modules/congestion_controller/delay_based_bwe_unittest.cc +++ b/webrtc/modules/congestion_controller/delay_based_bwe_unittest.cc @@ -8,116 +8,75 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "webrtc/modules/congestion_controller/delay_based_bwe.h" - #include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/constructormagic.h" #include "webrtc/modules/pacing/paced_sender.h" +#include "webrtc/modules/congestion_controller/delay_based_bwe.h" +#include "webrtc/modules/congestion_controller/delay_based_bwe_unittest_helper.h" #include "webrtc/system_wrappers/include/clock.h" namespace webrtc { -class TestDelayBasedBwe : public ::testing::Test, public RemoteBitrateObserver { - public: - static constexpr int kArrivalTimeClockOffsetMs = 60000; - static constexpr int kNumProbes = 5; +namespace { - TestDelayBasedBwe() - : bwe_(this), clock_(0), bitrate_updated_(false), latest_bitrate_(0) {} +constexpr int kNumProbes = 5; +} // namespace - uint32_t AbsSendTime(int64_t t, int64_t denom) { - return (((t << 18) + (denom >> 1)) / denom) & 0x00fffffful; - } - - void IncomingPacket(uint32_t ssrc, - size_t payload_size, - int64_t arrival_time, - uint32_t rtp_timestamp, - uint32_t absolute_send_time, - int probe_cluster_id) { - RTPHeader header; - memset(&header, 0, sizeof(header)); - header.ssrc = ssrc; - header.timestamp = rtp_timestamp; - header.extension.hasAbsoluteSendTime = true; - header.extension.absoluteSendTime = absolute_send_time; - bwe_.IncomingPacket(arrival_time + kArrivalTimeClockOffsetMs, payload_size, - header, probe_cluster_id); - } - - void OnReceiveBitrateChanged(const std::vector& ssrcs, - uint32_t bitrate) { - bitrate_updated_ = true; - latest_bitrate_ = bitrate; - } - - bool bitrate_updated() { - bool res = bitrate_updated_; - bitrate_updated_ = false; - return res; - } - - int latest_bitrate() { return latest_bitrate_; } - - DelayBasedBwe bwe_; - SimulatedClock clock_; - - private: - bool bitrate_updated_; - int latest_bitrate_; -}; - -TEST_F(TestDelayBasedBwe, ProbeDetection) { +TEST_F(DelayBasedBweTest, ProbeDetection) { int64_t now_ms = clock_.TimeInMilliseconds(); + uint16_t seq_num = 0; // First burst sent at 8 * 1000 / 10 = 800 kbps. for (int i = 0; i < kNumProbes; ++i) { clock_.AdvanceTimeMilliseconds(10); now_ms = clock_.TimeInMilliseconds(); - IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000), 0); + IncomingFeedback(now_ms, now_ms, seq_num++, 1000, 0); } - EXPECT_TRUE(bitrate_updated()); + EXPECT_TRUE(bitrate_observer_->updated()); // Second burst sent at 8 * 1000 / 5 = 1600 kbps. for (int i = 0; i < kNumProbes; ++i) { clock_.AdvanceTimeMilliseconds(5); now_ms = clock_.TimeInMilliseconds(); - IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000), 1); + IncomingFeedback(now_ms, now_ms, seq_num++, 1000, 1); } - EXPECT_TRUE(bitrate_updated()); - EXPECT_GT(latest_bitrate(), 1500000); + EXPECT_TRUE(bitrate_observer_->updated()); + EXPECT_GT(bitrate_observer_->latest_bitrate(), 1500000u); } -TEST_F(TestDelayBasedBwe, ProbeDetectionNonPacedPackets) { +TEST_F(DelayBasedBweTest, ProbeDetectionNonPacedPackets) { int64_t now_ms = clock_.TimeInMilliseconds(); + uint16_t seq_num = 0; // 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 < kNumProbes; ++i) { clock_.AdvanceTimeMilliseconds(5); now_ms = clock_.TimeInMilliseconds(); - IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000), 0); + IncomingFeedback(now_ms, now_ms, seq_num++, 1000, 0); // Non-paced packet, arriving 5 ms after. clock_.AdvanceTimeMilliseconds(5); - IncomingPacket(0, PacedSender::kMinProbePacketSize + 1, now_ms, 90 * now_ms, - AbsSendTime(now_ms, 1000), PacketInfo::kNotAProbe); + IncomingFeedback(now_ms, now_ms, seq_num++, + PacedSender::kMinProbePacketSize + 1, + PacketInfo::kNotAProbe); } - EXPECT_TRUE(bitrate_updated()); - EXPECT_GT(latest_bitrate(), 800000); + EXPECT_TRUE(bitrate_observer_->updated()); + EXPECT_GT(bitrate_observer_->latest_bitrate(), 800000u); } // Packets will require 5 ms to be transmitted to the receiver, causing packets // of the second probe to be dispersed. -TEST_F(TestDelayBasedBwe, ProbeDetectionTooHighBitrate) { +TEST_F(DelayBasedBweTest, ProbeDetectionTooHighBitrate) { int64_t now_ms = clock_.TimeInMilliseconds(); int64_t send_time_ms = 0; + uint16_t seq_num = 0; // First burst sent at 8 * 1000 / 10 = 800 kbps. for (int i = 0; i < kNumProbes; ++i) { clock_.AdvanceTimeMilliseconds(10); now_ms = clock_.TimeInMilliseconds(); send_time_ms += 10; - IncomingPacket(0, 1000, now_ms, 90 * send_time_ms, - AbsSendTime(send_time_ms, 1000), 0); + IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 0); } // Second burst sent at 8 * 1000 / 5 = 1600 kbps, arriving at 8 * 1000 / 8 = @@ -126,16 +85,16 @@ TEST_F(TestDelayBasedBwe, ProbeDetectionTooHighBitrate) { clock_.AdvanceTimeMilliseconds(8); now_ms = clock_.TimeInMilliseconds(); send_time_ms += 5; - IncomingPacket(0, 1000, now_ms, send_time_ms, - AbsSendTime(send_time_ms, 1000), 1); + IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 1); } - EXPECT_TRUE(bitrate_updated()); - EXPECT_NEAR(latest_bitrate(), 800000, 10000); + EXPECT_TRUE(bitrate_observer_->updated()); + EXPECT_NEAR(bitrate_observer_->latest_bitrate(), 800000u, 10000u); } -TEST_F(TestDelayBasedBwe, ProbeDetectionSlightlyFasterArrival) { +TEST_F(DelayBasedBweTest, ProbeDetectionSlightlyFasterArrival) { int64_t now_ms = clock_.TimeInMilliseconds(); + uint16_t seq_num = 0; // First burst sent at 8 * 1000 / 10 = 800 kbps. // Arriving at 8 * 1000 / 5 = 1600 kbps. int64_t send_time_ms = 0; @@ -143,16 +102,16 @@ TEST_F(TestDelayBasedBwe, ProbeDetectionSlightlyFasterArrival) { clock_.AdvanceTimeMilliseconds(5); send_time_ms += 10; now_ms = clock_.TimeInMilliseconds(); - IncomingPacket(0, 1000, now_ms, 90 * send_time_ms, - AbsSendTime(send_time_ms, 1000), 23); + IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 23); } - EXPECT_TRUE(bitrate_updated()); - EXPECT_GT(latest_bitrate(), 800000); + EXPECT_TRUE(bitrate_observer_->updated()); + EXPECT_GT(bitrate_observer_->latest_bitrate(), 800000u); } -TEST_F(TestDelayBasedBwe, ProbeDetectionFasterArrival) { +TEST_F(DelayBasedBweTest, ProbeDetectionFasterArrival) { int64_t now_ms = clock_.TimeInMilliseconds(); + uint16_t seq_num = 0; // First burst sent at 8 * 1000 / 10 = 800 kbps. // Arriving at 8 * 1000 / 5 = 1600 kbps. int64_t send_time_ms = 0; @@ -160,15 +119,15 @@ TEST_F(TestDelayBasedBwe, ProbeDetectionFasterArrival) { clock_.AdvanceTimeMilliseconds(1); send_time_ms += 10; now_ms = clock_.TimeInMilliseconds(); - IncomingPacket(0, 1000, now_ms, 90 * send_time_ms, - AbsSendTime(send_time_ms, 1000), 0); + IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 0); } - EXPECT_FALSE(bitrate_updated()); + EXPECT_FALSE(bitrate_observer_->updated()); } -TEST_F(TestDelayBasedBwe, ProbeDetectionSlowerArrival) { +TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrival) { int64_t now_ms = clock_.TimeInMilliseconds(); + uint16_t seq_num = 0; // First burst sent at 8 * 1000 / 5 = 1600 kbps. // Arriving at 8 * 1000 / 7 = 1142 kbps. int64_t send_time_ms = 0; @@ -176,16 +135,16 @@ TEST_F(TestDelayBasedBwe, ProbeDetectionSlowerArrival) { clock_.AdvanceTimeMilliseconds(7); send_time_ms += 5; now_ms = clock_.TimeInMilliseconds(); - IncomingPacket(0, 1000, now_ms, 90 * send_time_ms, - AbsSendTime(send_time_ms, 1000), 1); + IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 1); } - EXPECT_TRUE(bitrate_updated()); - EXPECT_NEAR(latest_bitrate(), 1140000, 10000); + EXPECT_TRUE(bitrate_observer_->updated()); + EXPECT_NEAR(bitrate_observer_->latest_bitrate(), 1140000u, 10000u); } -TEST_F(TestDelayBasedBwe, ProbeDetectionSlowerArrivalHighBitrate) { +TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrivalHighBitrate) { int64_t now_ms = clock_.TimeInMilliseconds(); + uint16_t seq_num = 0; // Burst sent at 8 * 1000 / 1 = 8000 kbps. // Arriving at 8 * 1000 / 2 = 4000 kbps. int64_t send_time_ms = 0; @@ -193,39 +152,106 @@ TEST_F(TestDelayBasedBwe, ProbeDetectionSlowerArrivalHighBitrate) { clock_.AdvanceTimeMilliseconds(2); send_time_ms += 1; now_ms = clock_.TimeInMilliseconds(); - IncomingPacket(0, 1000, now_ms, 90 * send_time_ms, - AbsSendTime(send_time_ms, 1000), 1); + IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 1); } - EXPECT_TRUE(bitrate_updated()); - EXPECT_NEAR(latest_bitrate(), 4000000u, 10000); + EXPECT_TRUE(bitrate_observer_->updated()); + EXPECT_NEAR(bitrate_observer_->latest_bitrate(), 4000000u, 10000u); } -TEST_F(TestDelayBasedBwe, ProbingIgnoresSmallPackets) { +TEST_F(DelayBasedBweTest, ProbingIgnoresSmallPackets) { int64_t now_ms = clock_.TimeInMilliseconds(); + uint16_t seq_num = 0; // Probing with 200 bytes every 10 ms, should be ignored by the probe // detection. for (int i = 0; i < kNumProbes; ++i) { clock_.AdvanceTimeMilliseconds(10); now_ms = clock_.TimeInMilliseconds(); - IncomingPacket(0, PacedSender::kMinProbePacketSize, now_ms, 90 * now_ms, - AbsSendTime(now_ms, 1000), 1); + IncomingFeedback(now_ms, now_ms, seq_num++, + PacedSender::kMinProbePacketSize, 1); } - EXPECT_FALSE(bitrate_updated()); + EXPECT_FALSE(bitrate_observer_->updated()); // Followed by a probe with 1000 bytes packets, should be detected as a // probe. for (int i = 0; i < kNumProbes; ++i) { clock_.AdvanceTimeMilliseconds(10); now_ms = clock_.TimeInMilliseconds(); - IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000), 1); + IncomingFeedback(now_ms, now_ms, seq_num++, 1000, 1); } // Wait long enough so that we can call Process again. clock_.AdvanceTimeMilliseconds(1000); - EXPECT_TRUE(bitrate_updated()); - EXPECT_NEAR(latest_bitrate(), 800000u, 10000); + EXPECT_TRUE(bitrate_observer_->updated()); + EXPECT_NEAR(bitrate_observer_->latest_bitrate(), 800000u, 10000u); +} + +TEST_F(DelayBasedBweTest, InitialBehavior) { + InitialBehaviorTestHelper(674840); +} + +TEST_F(DelayBasedBweTest, RateIncreaseReordering) { + RateIncreaseReorderingTestHelper(674840); +} + +TEST_F(DelayBasedBweTest, RateIncreaseRtpTimestamps) { + RateIncreaseRtpTimestampsTestHelper(1240); +} + +TEST_F(DelayBasedBweTest, CapacityDropOneStream) { + CapacityDropTestHelper(1, false, 633, 0); +} + +TEST_F(DelayBasedBweTest, CapacityDropPosOffsetChange) { + CapacityDropTestHelper(1, false, 200, 30000); +} + +TEST_F(DelayBasedBweTest, CapacityDropNegOffsetChange) { + CapacityDropTestHelper(1, false, 733, -30000); +} + +TEST_F(DelayBasedBweTest, CapacityDropOneStreamWrap) { + CapacityDropTestHelper(1, true, 633, 0); +} + +TEST_F(DelayBasedBweTest, CapacityDropTwoStreamsWrap) { + CapacityDropTestHelper(2, true, 567, 0); +} + +TEST_F(DelayBasedBweTest, CapacityDropThreeStreamsWrap) { + CapacityDropTestHelper(3, true, 633, 0); +} + +TEST_F(DelayBasedBweTest, CapacityDropThirteenStreamsWrap) { + CapacityDropTestHelper(13, true, 733, 0); +} + +TEST_F(DelayBasedBweTest, CapacityDropNineteenStreamsWrap) { + CapacityDropTestHelper(19, true, 667, 0); +} + +TEST_F(DelayBasedBweTest, CapacityDropThirtyStreamsWrap) { + CapacityDropTestHelper(30, true, 667, 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); } } // namespace webrtc diff --git a/webrtc/modules/congestion_controller/delay_based_bwe_unittest_helper.cc b/webrtc/modules/congestion_controller/delay_based_bwe_unittest_helper.cc new file mode 100644 index 0000000000..c6907f7a0b --- /dev/null +++ b/webrtc/modules/congestion_controller/delay_based_bwe_unittest_helper.cc @@ -0,0 +1,500 @@ +/* + * 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 "webrtc/modules/congestion_controller/delay_based_bwe_unittest_helper.h" + +#include +#include +#include + +#include "webrtc/base/checks.h" +#include "webrtc/modules/congestion_controller/delay_based_bwe.h" + +namespace webrtc { + +const size_t kMtu = 1200; +const uint32_t kAcceptedBitrateErrorBps = 50000; + +// Number of packets needed before we have a valid estimate. +const int kNumInitialPackets = 2; + +namespace test { + +void TestBitrateObserver::OnReceiveBitrateChanged( + const std::vector& ssrcs, + uint32_t bitrate) { + latest_bitrate_ = bitrate; + updated_ = true; +} + +RtpStream::RtpStream(int fps, int bitrate_bps) + : fps_(fps), + bitrate_bps_(bitrate_bps), + next_rtp_time_(0), + sequence_number_(0) { + RTC_CHECK_GT(fps_, 0); +} + +// Generates a new frame for this stream. If called too soon after the +// previous frame, no frame will be generated. The frame is split into +// packets. +int64_t RtpStream::GenerateFrame(int64_t time_now_us, + std::vector* packets) { + if (time_now_us < next_rtp_time_) { + return next_rtp_time_; + } + RTC_CHECK(packets != NULL); + size_t bits_per_frame = (bitrate_bps_ + fps_ / 2) / fps_; + size_t n_packets = + std::max((bits_per_frame + 4 * kMtu) / (8 * kMtu), 1u); + size_t payload_size = (bits_per_frame + 4 * n_packets) / (8 * n_packets); + for (size_t i = 0; i < n_packets; ++i) { + PacketInfo packet(-1, sequence_number_++); + packet.send_time_ms = (time_now_us + kSendSideOffsetUs) / 1000; + packet.payload_size = payload_size; + packet.probe_cluster_id = PacketInfo::kNotAProbe; + packets->push_back(packet); + } + next_rtp_time_ = time_now_us + (1000000 + fps_ / 2) / fps_; + return next_rtp_time_; +} + +// The send-side time when the next frame can be generated. +int64_t RtpStream::next_rtp_time() const { + return next_rtp_time_; +} + +void RtpStream::set_bitrate_bps(int bitrate_bps) { + ASSERT_GE(bitrate_bps, 0); + bitrate_bps_ = bitrate_bps; +} + +int RtpStream::bitrate_bps() const { + return bitrate_bps_; +} + +bool RtpStream::Compare(const std::unique_ptr& lhs, + const std::unique_ptr& rhs) { + return lhs->next_rtp_time_ < rhs->next_rtp_time_; +} + +StreamGenerator::StreamGenerator(int capacity, int64_t time_now) + : capacity_(capacity), prev_arrival_time_us_(time_now) {} + +// Add a new stream. +void StreamGenerator::AddStream(RtpStream* stream) { + streams_.push_back(std::unique_ptr(stream)); +} + +// Set the link capacity. +void StreamGenerator::set_capacity_bps(int capacity_bps) { + ASSERT_GT(capacity_bps, 0); + capacity_ = capacity_bps; +} + +// Divides |bitrate_bps| among all streams. The allocated bitrate per stream +// is decided by the current allocation ratios. +void StreamGenerator::SetBitrateBps(int bitrate_bps) { + ASSERT_GE(streams_.size(), 0u); + int total_bitrate_before = 0; + for (const auto& stream : streams_) { + total_bitrate_before += stream->bitrate_bps(); + } + int64_t bitrate_before = 0; + int total_bitrate_after = 0; + for (const auto& stream : streams_) { + bitrate_before += stream->bitrate_bps(); + int64_t bitrate_after = + (bitrate_before * bitrate_bps + total_bitrate_before / 2) / + total_bitrate_before; + stream->set_bitrate_bps(bitrate_after - total_bitrate_after); + total_bitrate_after += stream->bitrate_bps(); + } + ASSERT_EQ(bitrate_before, total_bitrate_before); + EXPECT_EQ(total_bitrate_after, bitrate_bps); +} + +// TODO(holmer): Break out the channel simulation part from this class to make +// it possible to simulate different types of channels. +int64_t StreamGenerator::GenerateFrame(std::vector* packets, + int64_t time_now_us) { + RTC_CHECK(packets != NULL); + RTC_CHECK(packets->empty()); + RTC_CHECK_GT(capacity_, 0); + auto it = + std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare); + (*it)->GenerateFrame(time_now_us, packets); + int i = 0; + for (PacketInfo& packet : *packets) { + int capacity_bpus = capacity_ / 1000; + int64_t required_network_time_us = + (8 * 1000 * packet.payload_size + capacity_bpus / 2) / capacity_bpus; + prev_arrival_time_us_ = + std::max(time_now_us + required_network_time_us, + prev_arrival_time_us_ + required_network_time_us); + packet.arrival_time_ms = prev_arrival_time_us_ / 1000; + ++i; + } + it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare); + return std::max((*it)->next_rtp_time(), time_now_us); +} +} // namespace test + +DelayBasedBweTest::DelayBasedBweTest() + : clock_(100000000), + bitrate_observer_(new test::TestBitrateObserver), + bitrate_estimator_(new DelayBasedBwe(bitrate_observer_.get(), &clock_)), + stream_generator_( + new test::StreamGenerator(1e6, // Capacity. + clock_.TimeInMicroseconds())), + arrival_time_offset_ms_(0) {} + +DelayBasedBweTest::~DelayBasedBweTest() {} + +void DelayBasedBweTest::AddDefaultStream() { + stream_generator_->AddStream(new test::RtpStream(30, 3e5)); +} + +const uint32_t DelayBasedBweTest::kDefaultSsrc = 0; + +void DelayBasedBweTest::IncomingFeedback(int64_t arrival_time_ms, + int64_t send_time_ms, + uint16_t sequence_number, + size_t payload_size) { + IncomingFeedback(arrival_time_ms, send_time_ms, sequence_number, payload_size, + 0); +} + +void DelayBasedBweTest::IncomingFeedback(int64_t arrival_time_ms, + int64_t send_time_ms, + uint16_t sequence_number, + size_t payload_size, + int probe_cluster_id) { + RTC_CHECK_GE(arrival_time_ms + arrival_time_offset_ms_, 0); + PacketInfo packet(arrival_time_ms + arrival_time_offset_ms_, send_time_ms, + sequence_number, payload_size, probe_cluster_id); + std::vector packets; + packets.push_back(packet); + bitrate_estimator_->IncomingPacketFeedbackVector(packets); +} + +// Generates a frame of packets belonging to a stream at a given bitrate and +// with a given ssrc. The stream is pushed through a very simple simulated +// network, and is then given to the receive-side bandwidth estimator. +// Returns true if an over-use was seen, false otherwise. +// The StreamGenerator::updated() should be used to check for any changes in +// target bitrate after the call to this function. +bool DelayBasedBweTest::GenerateAndProcessFrame(uint32_t ssrc, + uint32_t bitrate_bps) { + stream_generator_->SetBitrateBps(bitrate_bps); + std::vector packets; + int64_t next_time_us = + stream_generator_->GenerateFrame(&packets, clock_.TimeInMicroseconds()); + if (packets.empty()) + return false; + + bool overuse = false; + bitrate_observer_->Reset(); + clock_.AdvanceTimeMicroseconds(1000 * packets.back().arrival_time_ms - + clock_.TimeInMicroseconds()); + for (auto& packet : packets) { + RTC_CHECK_GE(packet.arrival_time_ms + arrival_time_offset_ms_, 0); + packet.arrival_time_ms += arrival_time_offset_ms_; + } + bitrate_estimator_->IncomingPacketFeedbackVector(packets); + + if (bitrate_observer_->updated()) { + if (bitrate_observer_->latest_bitrate() < bitrate_bps) + overuse = true; + } + + clock_.AdvanceTimeMicroseconds(next_time_us - clock_.TimeInMicroseconds()); + return overuse; +} + +// Run the bandwidth estimator with a stream of |number_of_frames| frames, or +// until it reaches |target_bitrate|. +// Can for instance be used to run the estimator for some time to get it +// into a steady state. +uint32_t DelayBasedBweTest::SteadyStateRun(uint32_t ssrc, + int max_number_of_frames, + uint32_t start_bitrate, + uint32_t min_bitrate, + uint32_t max_bitrate, + uint32_t target_bitrate) { + uint32_t bitrate_bps = start_bitrate; + bool bitrate_update_seen = false; + // Produce |number_of_frames| frames and give them to the estimator. + for (int i = 0; i < max_number_of_frames; ++i) { + bool overuse = GenerateAndProcessFrame(ssrc, bitrate_bps); + if (overuse) { + EXPECT_LT(bitrate_observer_->latest_bitrate(), max_bitrate); + EXPECT_GT(bitrate_observer_->latest_bitrate(), min_bitrate); + bitrate_bps = bitrate_observer_->latest_bitrate(); + bitrate_update_seen = true; + } else if (bitrate_observer_->updated()) { + bitrate_bps = bitrate_observer_->latest_bitrate(); + bitrate_observer_->Reset(); + } + if (bitrate_update_seen && bitrate_bps > target_bitrate) { + break; + } + } + EXPECT_TRUE(bitrate_update_seen); + return bitrate_bps; +} + +void DelayBasedBweTest::InitialBehaviorTestHelper( + uint32_t expected_converge_bitrate) { + const int kFramerate = 50; // 50 fps to avoid rounding errors. + const int kFrameIntervalMs = 1000 / kFramerate; + uint32_t bitrate_bps = 0; + int64_t send_time_ms = 0; + uint16_t sequence_number = 0; + std::vector ssrcs; + EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps)); + EXPECT_EQ(0u, ssrcs.size()); + clock_.AdvanceTimeMilliseconds(1000); + bitrate_estimator_->Process(); + EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps)); + EXPECT_FALSE(bitrate_observer_->updated()); + bitrate_observer_->Reset(); + clock_.AdvanceTimeMilliseconds(1000); + // Inserting packets for 5 seconds to get a valid estimate. + for (int i = 0; i < 5 * kFramerate + 1 + kNumInitialPackets; ++i) { + if (i == kNumInitialPackets) { + bitrate_estimator_->Process(); + EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps)); + EXPECT_EQ(0u, ssrcs.size()); + EXPECT_FALSE(bitrate_observer_->updated()); + bitrate_observer_->Reset(); + } + + IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms, + sequence_number++, kMtu); + clock_.AdvanceTimeMilliseconds(1000 / kFramerate); + send_time_ms += kFrameIntervalMs; + } + bitrate_estimator_->Process(); + EXPECT_TRUE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps)); + ASSERT_EQ(1u, ssrcs.size()); + EXPECT_EQ(kDefaultSsrc, ssrcs.front()); + EXPECT_NEAR(expected_converge_bitrate, bitrate_bps, kAcceptedBitrateErrorBps); + EXPECT_TRUE(bitrate_observer_->updated()); + bitrate_observer_->Reset(); + EXPECT_EQ(bitrate_observer_->latest_bitrate(), bitrate_bps); + bitrate_estimator_->RemoveStream(kDefaultSsrc); + EXPECT_TRUE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps)); + ASSERT_EQ(0u, ssrcs.size()); + EXPECT_EQ(0u, bitrate_bps); +} + +void DelayBasedBweTest::RateIncreaseReorderingTestHelper( + uint32_t expected_bitrate_bps) { + const int kFramerate = 50; // 50 fps to avoid rounding errors. + const int kFrameIntervalMs = 1000 / kFramerate; + int64_t send_time_ms = 0; + uint16_t sequence_number = 0; + // Inserting packets for five seconds to get a valid estimate. + for (int i = 0; i < 5 * kFramerate + 1 + kNumInitialPackets; ++i) { + // TODO(sprang): Remove this hack once the single stream estimator is gone, + // as it doesn't do anything in Process(). + if (i == kNumInitialPackets) { + // Process after we have enough frames to get a valid input rate estimate. + bitrate_estimator_->Process(); + EXPECT_FALSE(bitrate_observer_->updated()); // No valid estimate. + } + + IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms, + sequence_number++, kMtu); + clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); + send_time_ms += kFrameIntervalMs; + } + bitrate_estimator_->Process(); + EXPECT_TRUE(bitrate_observer_->updated()); + EXPECT_NEAR(expected_bitrate_bps, bitrate_observer_->latest_bitrate(), + kAcceptedBitrateErrorBps); + for (int i = 0; i < 10; ++i) { + clock_.AdvanceTimeMilliseconds(2 * kFrameIntervalMs); + send_time_ms += 2 * kFrameIntervalMs; + IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms, + sequence_number + 2, 1000); + IncomingFeedback(clock_.TimeInMilliseconds(), + send_time_ms - kFrameIntervalMs, sequence_number + 1, + 1000); + sequence_number += 2; + } + bitrate_estimator_->Process(); + EXPECT_TRUE(bitrate_observer_->updated()); + EXPECT_NEAR(expected_bitrate_bps, bitrate_observer_->latest_bitrate(), + kAcceptedBitrateErrorBps); +} + +// Make sure we initially increase the bitrate as expected. +void DelayBasedBweTest::RateIncreaseRtpTimestampsTestHelper( + int expected_iterations) { + // This threshold corresponds approximately to increasing linearly with + // bitrate(i) = 1.04 * bitrate(i-1) + 1000 + // until bitrate(i) > 500000, with bitrate(1) ~= 30000. + uint32_t bitrate_bps = 30000; + int iterations = 0; + AddDefaultStream(); + // Feed the estimator with a stream of packets and verify that it reaches + // 500 kbps at the expected time. + while (bitrate_bps < 5e5) { + bool overuse = GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps); + if (overuse) { + EXPECT_GT(bitrate_observer_->latest_bitrate(), bitrate_bps); + bitrate_bps = bitrate_observer_->latest_bitrate(); + bitrate_observer_->Reset(); + } else if (bitrate_observer_->updated()) { + bitrate_bps = bitrate_observer_->latest_bitrate(); + bitrate_observer_->Reset(); + } + ++iterations; + ASSERT_LE(iterations, expected_iterations); + } + ASSERT_EQ(expected_iterations, iterations); +} + +void DelayBasedBweTest::CapacityDropTestHelper( + int number_of_streams, + bool wrap_time_stamp, + uint32_t expected_bitrate_drop_delta, + int64_t receiver_clock_offset_change_ms) { + const int kFramerate = 30; + const int kStartBitrate = 900e3; + const int kMinExpectedBitrate = 800e3; + const int kMaxExpectedBitrate = 1100e3; + const uint32_t kInitialCapacityBps = 1000e3; + const uint32_t kReducedCapacityBps = 500e3; + + int steady_state_time = 0; + if (number_of_streams <= 1) { + steady_state_time = 10; + AddDefaultStream(); + } else { + steady_state_time = 10 * number_of_streams; + int bitrate_sum = 0; + int kBitrateDenom = number_of_streams * (number_of_streams - 1); + for (int i = 0; i < number_of_streams; i++) { + // First stream gets half available bitrate, while the rest share the + // remaining half i.e.: 1/2 = Sum[n/(N*(N-1))] for n=1..N-1 (rounded up) + int bitrate = kStartBitrate / 2; + if (i > 0) { + bitrate = (kStartBitrate * i + kBitrateDenom / 2) / kBitrateDenom; + } + stream_generator_->AddStream(new test::RtpStream(kFramerate, bitrate)); + bitrate_sum += bitrate; + } + ASSERT_EQ(bitrate_sum, kStartBitrate); + } + + // Run in steady state to make the estimator converge. + stream_generator_->set_capacity_bps(kInitialCapacityBps); + uint32_t bitrate_bps = SteadyStateRun( + kDefaultSsrc, steady_state_time * kFramerate, kStartBitrate, + kMinExpectedBitrate, kMaxExpectedBitrate, kInitialCapacityBps); + EXPECT_NEAR(kInitialCapacityBps, bitrate_bps, 130000u); + bitrate_observer_->Reset(); + + // Add an offset to make sure the BWE can handle it. + arrival_time_offset_ms_ += receiver_clock_offset_change_ms; + + // Reduce the capacity and verify the decrease time. + stream_generator_->set_capacity_bps(kReducedCapacityBps); + int64_t overuse_start_time = clock_.TimeInMilliseconds(); + int64_t bitrate_drop_time = -1; + for (int i = 0; i < 100 * number_of_streams; ++i) { + GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps); + if (bitrate_drop_time == -1 && + bitrate_observer_->latest_bitrate() <= kReducedCapacityBps) { + bitrate_drop_time = clock_.TimeInMilliseconds(); + } + if (bitrate_observer_->updated()) + bitrate_bps = bitrate_observer_->latest_bitrate(); + } + + EXPECT_NEAR(expected_bitrate_drop_delta, + bitrate_drop_time - overuse_start_time, 33); +} + +void DelayBasedBweTest::TestTimestampGroupingTestHelper() { + const int kFramerate = 50; // 50 fps to avoid rounding errors. + const int kFrameIntervalMs = 1000 / kFramerate; + int64_t send_time_ms = 0; + uint16_t sequence_number = 0; + // Initial set of frames to increase the bitrate. 6 seconds to have enough + // time for the first estimate to be generated and for Process() to be called. + for (int i = 0; i <= 6 * kFramerate; ++i) { + IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms, + sequence_number++, 1000); + + bitrate_estimator_->Process(); + clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); + send_time_ms += kFrameIntervalMs; + } + EXPECT_TRUE(bitrate_observer_->updated()); + EXPECT_GE(bitrate_observer_->latest_bitrate(), 400000u); + + // Insert batches of frames which were sent very close in time. Also simulate + // capacity over-use to see that we back off correctly. + const int kTimestampGroupLength = 15; + for (int i = 0; i < 100; ++i) { + for (int j = 0; j < kTimestampGroupLength; ++j) { + // Insert |kTimestampGroupLength| frames with just 1 timestamp ticks in + // between. Should be treated as part of the same group by the estimator. + IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms, + sequence_number++, 100); + clock_.AdvanceTimeMilliseconds(kFrameIntervalMs / kTimestampGroupLength); + send_time_ms += 1; + } + // Increase time until next batch to simulate over-use. + clock_.AdvanceTimeMilliseconds(10); + send_time_ms += kFrameIntervalMs - kTimestampGroupLength; + bitrate_estimator_->Process(); + } + EXPECT_TRUE(bitrate_observer_->updated()); + // Should have reduced the estimate. + EXPECT_LT(bitrate_observer_->latest_bitrate(), 400000u); +} + +void DelayBasedBweTest::TestWrappingHelper(int silence_time_s) { + const int kFramerate = 100; + const int kFrameIntervalMs = 1000 / kFramerate; + int64_t send_time_ms = 0; + uint16_t sequence_number = 0; + + for (size_t i = 0; i < 3000; ++i) { + IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms, + sequence_number++, 1000); + clock_.AdvanceTimeMilliseconds(kFrameIntervalMs); + send_time_ms += kFrameIntervalMs; + bitrate_estimator_->Process(); + } + uint32_t bitrate_before = 0; + std::vector ssrcs; + bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_before); + + clock_.AdvanceTimeMilliseconds(silence_time_s * 1000); + send_time_ms += silence_time_s * 1000; + bitrate_estimator_->Process(); + + for (size_t i = 0; i < 21; ++i) { + IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms, + sequence_number++, 1000); + clock_.AdvanceTimeMilliseconds(2 * kFrameIntervalMs); + send_time_ms += kFrameIntervalMs; + bitrate_estimator_->Process(); + } + uint32_t bitrate_after = 0; + bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_after); + EXPECT_LT(bitrate_after, bitrate_before); +} +} // namespace webrtc diff --git a/webrtc/modules/congestion_controller/delay_based_bwe_unittest_helper.h b/webrtc/modules/congestion_controller/delay_based_bwe_unittest_helper.h new file mode 100644 index 0000000000..c91c580272 --- /dev/null +++ b/webrtc/modules/congestion_controller/delay_based_bwe_unittest_helper.h @@ -0,0 +1,172 @@ +/* + * 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. + */ + +#ifndef WEBRTC_MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_UNITTEST_HELPER_H_ +#define WEBRTC_MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_UNITTEST_HELPER_H_ + +#include +#include +#include +#include +#include + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/constructormagic.h" +#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h" +#include "webrtc/system_wrappers/include/clock.h" + +namespace webrtc { +namespace test { + +class TestBitrateObserver : public RemoteBitrateObserver { + public: + TestBitrateObserver() : updated_(false), latest_bitrate_(0) {} + virtual ~TestBitrateObserver() {} + + void OnReceiveBitrateChanged(const std::vector& ssrcs, + uint32_t bitrate) override; + + void Reset() { updated_ = false; } + + bool updated() const { return updated_; } + + uint32_t latest_bitrate() const { return latest_bitrate_; } + + private: + bool updated_; + uint32_t latest_bitrate_; +}; + +class RtpStream { + public: + enum { kSendSideOffsetUs = 1000000 }; + + RtpStream(int fps, int bitrate_bps); + + // Generates a new frame for this stream. If called too soon after the + // previous frame, no frame will be generated. The frame is split into + // packets. + int64_t GenerateFrame(int64_t time_now_us, std::vector* packets); + + // The send-side time when the next frame can be generated. + int64_t next_rtp_time() const; + + void set_bitrate_bps(int bitrate_bps); + + int bitrate_bps() const; + + static bool Compare(const std::unique_ptr& lhs, + const std::unique_ptr& rhs); + + private: + int fps_; + int bitrate_bps_; + int64_t next_rtp_time_; + uint16_t sequence_number_; + + RTC_DISALLOW_COPY_AND_ASSIGN(RtpStream); +}; + +class StreamGenerator { + public: + StreamGenerator(int capacity, int64_t time_now); + + // Add a new stream. + void AddStream(RtpStream* stream); + + // Set the link capacity. + void set_capacity_bps(int capacity_bps); + + // Divides |bitrate_bps| among all streams. The allocated bitrate per stream + // is decided by the initial allocation ratios. + void SetBitrateBps(int bitrate_bps); + + // Set the RTP timestamp offset for the stream identified by |ssrc|. + void set_rtp_timestamp_offset(uint32_t ssrc, uint32_t offset); + + // TODO(holmer): Break out the channel simulation part from this class to make + // it possible to simulate different types of channels. + int64_t GenerateFrame(std::vector* packets, int64_t time_now_us); + + private: + // Capacity of the simulated channel in bits per second. + int capacity_; + // The time when the last packet arrived. + int64_t prev_arrival_time_us_; + // All streams being transmitted on this simulated channel. + std::vector> streams_; + + RTC_DISALLOW_COPY_AND_ASSIGN(StreamGenerator); +}; +} // namespace test + +class DelayBasedBweTest : public ::testing::Test { + public: + DelayBasedBweTest(); + virtual ~DelayBasedBweTest(); + + protected: + void AddDefaultStream(); + + // Helpers to insert a single packet into the delay-based BWE. + void IncomingFeedback(int64_t arrival_time_ms, + int64_t send_time_ms, + uint16_t sequence_number, + size_t payload_size); + void IncomingFeedback(int64_t arrival_time_ms, + int64_t send_time_ms, + uint16_t sequence_number, + size_t payload_size, + int probe_cluster_id); + + // Generates a frame of packets belonging to a stream at a given bitrate and + // with a given ssrc. The stream is pushed through a very simple simulated + // network, and is then given to the receive-side bandwidth estimator. + // Returns true if an over-use was seen, false otherwise. + // The StreamGenerator::updated() should be used to check for any changes in + // target bitrate after the call to this function. + bool GenerateAndProcessFrame(uint32_t ssrc, uint32_t bitrate_bps); + + // Run the bandwidth estimator with a stream of |number_of_frames| frames, or + // until it reaches |target_bitrate|. + // Can for instance be used to run the estimator for some time to get it + // into a steady state. + uint32_t SteadyStateRun(uint32_t ssrc, + int number_of_frames, + uint32_t start_bitrate, + uint32_t min_bitrate, + uint32_t max_bitrate, + uint32_t target_bitrate); + + void TestTimestampGroupingTestHelper(); + + void TestWrappingHelper(int silence_time_s); + + void InitialBehaviorTestHelper(uint32_t expected_converge_bitrate); + void RateIncreaseReorderingTestHelper(uint32_t expected_bitrate); + void RateIncreaseRtpTimestampsTestHelper(int expected_iterations); + void CapacityDropTestHelper(int number_of_streams, + bool wrap_time_stamp, + uint32_t expected_bitrate_drop_delta, + int64_t receiver_clock_offset_change_ms); + + static const uint32_t kDefaultSsrc; + + SimulatedClock clock_; // Time at the receiver. + std::unique_ptr bitrate_observer_; + std::unique_ptr bitrate_estimator_; + std::unique_ptr stream_generator_; + int64_t arrival_time_offset_ms_; + + RTC_DISALLOW_COPY_AND_ASSIGN(DelayBasedBweTest); +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_UNITTEST_HELPER_H_ diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index 3d41878068..88b814257e 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -274,6 +274,8 @@ 'bitrate_controller/send_side_bandwidth_estimation_unittest.cc', 'congestion_controller/congestion_controller_unittest.cc', 'congestion_controller/delay_based_bwe_unittest.cc', + 'congestion_controller/delay_based_bwe_unittest_helper.cc', + 'congestion_controller/delay_based_bwe_unittest_helper.h', 'media_file/media_file_unittest.cc', 'module_common_types_unittest.cc', 'pacing/bitrate_prober_unittest.cc', diff --git a/webrtc/modules/remote_bitrate_estimator/inter_arrival.cc b/webrtc/modules/remote_bitrate_estimator/inter_arrival.cc index 1b7ce07583..1b2dc43db2 100644 --- a/webrtc/modules/remote_bitrate_estimator/inter_arrival.cc +++ b/webrtc/modules/remote_bitrate_estimator/inter_arrival.cc @@ -27,10 +27,12 @@ InterArrival::InterArrival(uint32_t timestamp_group_length_ticks, current_timestamp_group_(), prev_timestamp_group_(), timestamp_to_ms_coeff_(timestamp_to_ms_coeff), - burst_grouping_(enable_burst_grouping) {} + burst_grouping_(enable_burst_grouping), + num_consecutive_reordered_packets_(0) {} bool InterArrival::ComputeDeltas(uint32_t timestamp, int64_t arrival_time_ms, + int64_t system_time_ms, size_t packet_size, uint32_t* timestamp_delta, int64_t* arrival_time_delta_ms, @@ -53,13 +55,32 @@ bool InterArrival::ComputeDeltas(uint32_t timestamp, prev_timestamp_group_.timestamp; *arrival_time_delta_ms = current_timestamp_group_.complete_time_ms - prev_timestamp_group_.complete_time_ms; + // Check system time differences to see if we have an unproportional jump + // in arrival time. In that case reset the inter-arrival computations. + int64_t system_time_delta_ms = + current_timestamp_group_.last_system_time_ms - + prev_timestamp_group_.last_system_time_ms; + if (*arrival_time_delta_ms - system_time_delta_ms >= + kArrivalTimeOffsetThresholdMs) { + LOG(LS_WARNING) << "The arrival time clock offset has changed (diff = " + << *arrival_time_delta_ms - system_time_delta_ms + << " ms), resetting."; + Reset(); + return false; + } if (*arrival_time_delta_ms < 0) { // The group of packets has been reordered since receiving its local // arrival timestamp. - LOG(LS_WARNING) << "Packets are being reordered on the path from the " - "socket to the bandwidth estimator. Ignoring this " - "packet for bandwidth estimation."; + ++num_consecutive_reordered_packets_; + if (num_consecutive_reordered_packets_ >= kReorderedResetThreshold) { + LOG(LS_WARNING) << "Packets are being reordered on the path from the " + "socket to the bandwidth estimator. Ignoring this " + "packet for bandwidth estimation, resetting."; + Reset(); + } return false; + } else { + num_consecutive_reordered_packets_ = 0; } assert(*arrival_time_delta_ms >= 0); *packet_size_delta = static_cast(current_timestamp_group_.size) - @@ -78,6 +99,7 @@ bool InterArrival::ComputeDeltas(uint32_t timestamp, // Accumulate the frame size. current_timestamp_group_.size += packet_size; current_timestamp_group_.complete_time_ms = arrival_time_ms; + current_timestamp_group_.last_system_time_ms = system_time_ms; return calculated_deltas; } @@ -126,4 +148,10 @@ bool InterArrival::BelongsToBurst(int64_t arrival_time_ms, return propagation_delta_ms < 0 && arrival_time_delta_ms <= kBurstDeltaThresholdMs; } + +void InterArrival::Reset() { + num_consecutive_reordered_packets_ = 0; + current_timestamp_group_ = TimestampGroup(); + prev_timestamp_group_ = TimestampGroup(); +} } // namespace webrtc diff --git a/webrtc/modules/remote_bitrate_estimator/inter_arrival.h b/webrtc/modules/remote_bitrate_estimator/inter_arrival.h index 427bafcf96..088b925d2e 100644 --- a/webrtc/modules/remote_bitrate_estimator/inter_arrival.h +++ b/webrtc/modules/remote_bitrate_estimator/inter_arrival.h @@ -23,6 +23,11 @@ namespace webrtc { // a client defined rate. class InterArrival { public: + // After this many packet groups received out of order InterArrival will + // reset, assuming that clocks have made a jump. + static constexpr int kReorderedResetThreshold = 3; + static constexpr int64_t kArrivalTimeOffsetThresholdMs = 3000; + // A timestamp group is defined as all packets with a timestamp which are at // most timestamp_group_length_ticks older than the first timestamp in that // group. @@ -40,6 +45,7 @@ class InterArrival { // |packet_size_delta| (output) is the computed size delta. bool ComputeDeltas(uint32_t timestamp, int64_t arrival_time_ms, + int64_t system_time_ms, size_t packet_size, uint32_t* timestamp_delta, int64_t* arrival_time_delta_ms, @@ -61,6 +67,7 @@ class InterArrival { uint32_t first_timestamp; uint32_t timestamp; int64_t complete_time_ms; + int64_t last_system_time_ms; }; // Returns true if the packet with timestamp |timestamp| arrived in order. @@ -72,11 +79,14 @@ class InterArrival { bool BelongsToBurst(int64_t arrival_time_ms, uint32_t timestamp) const; + void Reset(); + const uint32_t kTimestampGroupLengthTicks; TimestampGroup current_timestamp_group_; TimestampGroup prev_timestamp_group_; double timestamp_to_ms_coeff_; bool burst_grouping_; + int num_consecutive_reordered_packets_; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(InterArrival); }; diff --git a/webrtc/modules/remote_bitrate_estimator/inter_arrival_unittest.cc b/webrtc/modules/remote_bitrate_estimator/inter_arrival_unittest.cc index 3b4151b3b7..f255285b63 100644 --- a/webrtc/modules/remote_bitrate_estimator/inter_arrival_unittest.cc +++ b/webrtc/modules/remote_bitrate_estimator/inter_arrival_unittest.cc @@ -34,6 +34,8 @@ const double kAstToMs = 1000.0 / static_cast(1 << kInterArrivalShift); class InterArrivalTest : public ::testing::Test { protected: virtual void SetUp() { + inter_arrival_.reset( + new InterArrival(kTimestampGroupLengthUs / 1000, 1.0, true)); inter_arrival_rtp_.reset(new InterArrival( MakeRtpTimestamp(kTimestampGroupLengthUs), kRtpTimestampToMs, @@ -149,6 +151,8 @@ class InterArrivalTest : public ::testing::Test { timestamp_near); } + std::unique_ptr inter_arrival_; + private: static uint32_t MakeRtpTimestamp(int64_t us) { return static_cast(static_cast(us * 90 + 500) / 1000); @@ -166,12 +170,9 @@ class InterArrivalTest : public ::testing::Test { uint32_t dummy_timestamp = 101; int64_t dummy_arrival_time_ms = 303; int dummy_packet_size = 909; - bool computed = inter_arrival->ComputeDeltas(timestamp, - arrival_time_ms, - packet_size, - &dummy_timestamp, - &dummy_arrival_time_ms, - &dummy_packet_size); + bool computed = inter_arrival->ComputeDeltas( + timestamp, arrival_time_ms, arrival_time_ms, packet_size, + &dummy_timestamp, &dummy_arrival_time_ms, &dummy_packet_size); EXPECT_EQ(computed, false); EXPECT_EQ(101ul, dummy_timestamp); EXPECT_EQ(303, dummy_arrival_time_ms); @@ -188,12 +189,9 @@ class InterArrivalTest : public ::testing::Test { uint32_t delta_timestamp = 101; int64_t delta_arrival_time_ms = 303; int delta_packet_size = 909; - bool computed = inter_arrival->ComputeDeltas(timestamp, - arrival_time_ms, - packet_size, - &delta_timestamp, - &delta_arrival_time_ms, - &delta_packet_size); + bool computed = inter_arrival->ComputeDeltas( + timestamp, arrival_time_ms, arrival_time_ms, packet_size, + &delta_timestamp, &delta_arrival_time_ms, &delta_packet_size); EXPECT_EQ(true, computed); EXPECT_NEAR(expected_timestamp_delta, delta_timestamp, timestamp_near); EXPECT_EQ(expected_arrival_time_delta_ms, delta_arrival_time_ms); @@ -419,5 +417,121 @@ TEST_F(InterArrivalTest, RtpTimestampWrapOutOfOrderWithinGroup) { TEST_F(InterArrivalTest, AbsSendTimeWrapOutOfOrderWithinGroup) { WrapTestHelper(kStartAbsSendTimeWrapUs, 1, true); } + +TEST_F(InterArrivalTest, PositiveArrivalTimeJump) { + const size_t kPacketSize = 1000; + uint32_t send_time_ms = 10000; + int64_t arrival_time_ms = 20000; + int64_t system_time_ms = 30000; + + uint32_t send_delta; + int64_t arrival_delta; + int size_delta; + EXPECT_FALSE(inter_arrival_->ComputeDeltas( + send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, + &arrival_delta, &size_delta)); + + const int kTimeDeltaMs = 30; + send_time_ms += kTimeDeltaMs; + arrival_time_ms += kTimeDeltaMs; + system_time_ms += kTimeDeltaMs; + EXPECT_FALSE(inter_arrival_->ComputeDeltas( + send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, + &arrival_delta, &size_delta)); + + send_time_ms += kTimeDeltaMs; + arrival_time_ms += kTimeDeltaMs + InterArrival::kArrivalTimeOffsetThresholdMs; + system_time_ms += kTimeDeltaMs; + EXPECT_TRUE(inter_arrival_->ComputeDeltas( + send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, + &arrival_delta, &size_delta)); + EXPECT_EQ(kTimeDeltaMs, static_cast(send_delta)); + EXPECT_EQ(kTimeDeltaMs, arrival_delta); + EXPECT_EQ(size_delta, 0); + + send_time_ms += kTimeDeltaMs; + arrival_time_ms += kTimeDeltaMs; + system_time_ms += kTimeDeltaMs; + // The previous arrival time jump should now be detected and cause a reset. + EXPECT_FALSE(inter_arrival_->ComputeDeltas( + send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, + &arrival_delta, &size_delta)); + + // The two next packets will not give a valid delta since we're in the initial + // state. + for (int i = 0; i < 2; ++i) { + send_time_ms += kTimeDeltaMs; + arrival_time_ms += kTimeDeltaMs; + system_time_ms += kTimeDeltaMs; + EXPECT_FALSE(inter_arrival_->ComputeDeltas( + send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, + &arrival_delta, &size_delta)); + } + + send_time_ms += kTimeDeltaMs; + arrival_time_ms += kTimeDeltaMs; + system_time_ms += kTimeDeltaMs; + EXPECT_TRUE(inter_arrival_->ComputeDeltas( + send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, + &arrival_delta, &size_delta)); + EXPECT_EQ(kTimeDeltaMs, static_cast(send_delta)); + EXPECT_EQ(kTimeDeltaMs, arrival_delta); + EXPECT_EQ(size_delta, 0); +} + +TEST_F(InterArrivalTest, NegativeArrivalTimeJump) { + const size_t kPacketSize = 1000; + uint32_t send_time_ms = 10000; + int64_t arrival_time_ms = 20000; + int64_t system_time_ms = 30000; + + uint32_t send_delta; + int64_t arrival_delta; + int size_delta; + EXPECT_FALSE(inter_arrival_->ComputeDeltas( + send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, + &arrival_delta, &size_delta)); + + const int kTimeDeltaMs = 30; + send_time_ms += kTimeDeltaMs; + arrival_time_ms += kTimeDeltaMs; + system_time_ms += kTimeDeltaMs; + EXPECT_FALSE(inter_arrival_->ComputeDeltas( + send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, + &arrival_delta, &size_delta)); + + send_time_ms += kTimeDeltaMs; + arrival_time_ms += kTimeDeltaMs; + system_time_ms += kTimeDeltaMs; + EXPECT_TRUE(inter_arrival_->ComputeDeltas( + send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, + &arrival_delta, &size_delta)); + EXPECT_EQ(kTimeDeltaMs, static_cast(send_delta)); + EXPECT_EQ(kTimeDeltaMs, arrival_delta); + EXPECT_EQ(size_delta, 0); + + // Three out of order will fail, after that we will be reset and two more will + // fail before we get our first valid delta after the reset. + arrival_time_ms -= 1000; + for (int i = 0; i < InterArrival::kReorderedResetThreshold + 3; ++i) { + send_time_ms += kTimeDeltaMs; + arrival_time_ms += kTimeDeltaMs; + system_time_ms += kTimeDeltaMs; + // The previous arrival time jump should now be detected and cause a reset. + EXPECT_FALSE(inter_arrival_->ComputeDeltas( + send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, + &arrival_delta, &size_delta)); + } + + send_time_ms += kTimeDeltaMs; + arrival_time_ms += kTimeDeltaMs; + system_time_ms += kTimeDeltaMs; + EXPECT_TRUE(inter_arrival_->ComputeDeltas( + send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta, + &arrival_delta, &size_delta)); + EXPECT_EQ(kTimeDeltaMs, static_cast(send_delta)); + EXPECT_EQ(kTimeDeltaMs, arrival_delta); + EXPECT_EQ(size_delta, 0); +} } // namespace testing } // namespace webrtc diff --git a/webrtc/modules/remote_bitrate_estimator/overuse_detector_unittest.cc b/webrtc/modules/remote_bitrate_estimator/overuse_detector_unittest.cc index d4e4edb29a..1094585c72 100644 --- a/webrtc/modules/remote_bitrate_estimator/overuse_detector_unittest.cc +++ b/webrtc/modules/remote_bitrate_estimator/overuse_detector_unittest.cc @@ -95,12 +95,9 @@ class OveruseDetectorTest : public ::testing::Test { uint32_t timestamp_delta; int64_t time_delta; int size_delta; - if (inter_arrival_->ComputeDeltas(rtp_timestamp, - receive_time_ms, - packet_size, - ×tamp_delta, - &time_delta, - &size_delta)) { + if (inter_arrival_->ComputeDeltas( + rtp_timestamp, receive_time_ms, receive_time_ms, packet_size, + ×tamp_delta, &time_delta, &size_delta)) { double timestamp_delta_ms = timestamp_delta / 90.0; overuse_estimator_->Update(time_delta, timestamp_delta_ms, size_delta, overuse_detector_->State()); diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc index 21c54d1c63..33bbe7d9b3 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.cc @@ -79,8 +79,10 @@ bool RemoteBitrateEstimatorAbsSendTime::IsWithinClusterBounds( } RemoteBitrateEstimatorAbsSendTime::RemoteBitrateEstimatorAbsSendTime( - RemoteBitrateObserver* observer) - : observer_(observer), + RemoteBitrateObserver* observer, + Clock* clock) + : clock_(clock), + observer_(observer), inter_arrival_(), estimator_(), detector_(OverUseDetectorOptions()), @@ -234,18 +236,19 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo( uint32_t send_time_24bits, size_t payload_size, uint32_t ssrc) { - assert(send_time_24bits < (1ul << 24)); + RTC_CHECK(send_time_24bits < (1ul << 24)); // Shift up send time to use the full 32 bits that inter_arrival works with, // so wrapping works properly. uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift; int64_t send_time_ms = static_cast(timestamp) * kTimestampToMs; - int64_t now_ms = arrival_time_ms; + int64_t now_ms = clock_->TimeInMilliseconds(); // TODO(holmer): SSRCs are only needed for REMB, should be broken out from // here. // Check if incoming bitrate estimate is valid, and if it needs to be reset. - rtc::Optional incoming_bitrate = incoming_bitrate_.Rate(now_ms); + rtc::Optional incoming_bitrate = + incoming_bitrate_.Rate(arrival_time_ms); if (incoming_bitrate) { incoming_bitrate_initialized_ = true; } else if (incoming_bitrate_initialized_) { @@ -255,10 +258,10 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo( incoming_bitrate_.Reset(); incoming_bitrate_initialized_ = false; } - incoming_bitrate_.Update(payload_size, now_ms); + incoming_bitrate_.Update(payload_size, arrival_time_ms); if (first_packet_time_ms_ == -1) - first_packet_time_ms_ = arrival_time_ms; + first_packet_time_ms_ = now_ms; uint32_t ts_delta = 0; int64_t t_delta = 0; @@ -300,8 +303,9 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo( if (ProcessClusters(now_ms) == ProbeResult::kBitrateUpdated) update_estimate = true; } - if (inter_arrival_->ComputeDeltas(timestamp, arrival_time_ms, payload_size, - &ts_delta, &t_delta, &size_delta)) { + if (inter_arrival_->ComputeDeltas(timestamp, arrival_time_ms, now_ms, + payload_size, &ts_delta, &t_delta, + &size_delta)) { double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift); estimator_->Update(t_delta, ts_delta_ms, size_delta, detector_.State()); detector_.Detect(estimator_->offset(), ts_delta_ms, @@ -315,7 +319,8 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo( now_ms - last_update_ms_ > remote_rate_.GetFeedbackInterval()) { update_estimate = true; } else if (detector_.State() == kBwOverusing) { - rtc::Optional incoming_rate = incoming_bitrate_.Rate(now_ms); + rtc::Optional incoming_rate = + incoming_bitrate_.Rate(arrival_time_ms); if (incoming_rate && remote_rate_.TimeToReduceFurther(now_ms, *incoming_rate)) { update_estimate = true; @@ -328,7 +333,7 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo( // We also have to update the estimate immediately if we are overusing // and the target bitrate is too high compared to what we are receiving. const RateControlInput input(detector_.State(), - incoming_bitrate_.Rate(now_ms), + incoming_bitrate_.Rate(arrival_time_ms), estimator_->var_noise()); remote_rate_.Update(&input, now_ms); target_bitrate_bps = remote_rate_.UpdateBandwidthEstimate(now_ms); diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h index a1274d673d..98305bd0a1 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h @@ -68,7 +68,8 @@ struct Cluster { class RemoteBitrateEstimatorAbsSendTime : public RemoteBitrateEstimator { public: - explicit RemoteBitrateEstimatorAbsSendTime(RemoteBitrateObserver* observer); + RemoteBitrateEstimatorAbsSendTime(RemoteBitrateObserver* observer, + Clock* clock); virtual ~RemoteBitrateEstimatorAbsSendTime() {} void IncomingPacketFeedbackVector( @@ -117,6 +118,7 @@ class RemoteBitrateEstimatorAbsSendTime : public RemoteBitrateEstimator { void TimeoutStreams(int64_t now_ms) EXCLUSIVE_LOCKS_REQUIRED(&crit_); rtc::ThreadChecker network_thread_; + Clock* const clock_; RemoteBitrateObserver* const observer_; std::unique_ptr inter_arrival_; std::unique_ptr estimator_; diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc index 611a18d907..fcfb8f4f83 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time_unittest.cc @@ -20,7 +20,7 @@ class RemoteBitrateEstimatorAbsSendTimeTest : RemoteBitrateEstimatorAbsSendTimeTest() {} virtual void SetUp() { bitrate_estimator_.reset(new RemoteBitrateEstimatorAbsSendTime( - bitrate_observer_.get())); + bitrate_observer_.get(), &clock_)); } protected: RTC_DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorAbsSendTimeTest); @@ -39,31 +39,39 @@ TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, RateIncreaseRtpTimestamps) { } TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropOneStream) { - CapacityDropTestHelper(1, false, 667); + CapacityDropTestHelper(1, false, 633, 0); +} + +TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropPosOffsetChange) { + CapacityDropTestHelper(1, false, 267, 30000); +} + +TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropNegOffsetChange) { + CapacityDropTestHelper(1, false, 267, -30000); } TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropOneStreamWrap) { - CapacityDropTestHelper(1, true, 667); + CapacityDropTestHelper(1, true, 633, 0); } TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropTwoStreamsWrap) { - CapacityDropTestHelper(2, true, 633); + CapacityDropTestHelper(2, true, 633, 0); } TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThreeStreamsWrap) { - CapacityDropTestHelper(3, true, 633); + CapacityDropTestHelper(3, true, 633, 0); } TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThirteenStreamsWrap) { - CapacityDropTestHelper(13, true, 667); + CapacityDropTestHelper(13, true, 667, 0); } TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropNineteenStreamsWrap) { - CapacityDropTestHelper(19, true, 667); + CapacityDropTestHelper(19, true, 667, 0); } TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThirtyStreamsWrap) { - CapacityDropTestHelper(30, true, 667); + CapacityDropTestHelper(30, true, 667, 0); } TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, TestTimestampGrouping) { diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc index 182cbf9b1e..d97bb41784 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.cc @@ -109,9 +109,9 @@ void RemoteBitrateEstimatorSingleStream::IncomingPacket( uint32_t timestamp_delta = 0; int64_t time_delta = 0; int size_delta = 0; - if (estimator->inter_arrival.ComputeDeltas(rtp_timestamp, arrival_time_ms, - payload_size, ×tamp_delta, - &time_delta, &size_delta)) { + if (estimator->inter_arrival.ComputeDeltas( + rtp_timestamp, arrival_time_ms, now_ms, payload_size, + ×tamp_delta, &time_delta, &size_delta)) { double timestamp_delta_ms = timestamp_delta * kTimestampToMs; estimator->estimator.Update(time_delta, timestamp_delta_ms, size_delta, estimator->detector.State()); diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc index 98f495eac8..86c272b7f5 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream_unittest.cc @@ -39,31 +39,31 @@ TEST_F(RemoteBitrateEstimatorSingleTest, RateIncreaseRtpTimestamps) { } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStream) { - CapacityDropTestHelper(1, false, 633); + CapacityDropTestHelper(1, false, 633, 0); } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStreamWrap) { - CapacityDropTestHelper(1, true, 633); + CapacityDropTestHelper(1, true, 633, 0); } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropTwoStreamsWrap) { - CapacityDropTestHelper(2, true, 767); + CapacityDropTestHelper(2, true, 767, 0); } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThreeStreamsWrap) { - CapacityDropTestHelper(3, true, 567); + CapacityDropTestHelper(3, true, 567, 0); } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirteenStreamsWrap) { - CapacityDropTestHelper(13, true, 567); + CapacityDropTestHelper(13, true, 567, 0); } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropNineteenStreamsWrap) { - CapacityDropTestHelper(19, true, 700); + CapacityDropTestHelper(19, true, 700, 0); } TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirtyStreamsWrap) { - CapacityDropTestHelper(30, true, 733); + CapacityDropTestHelper(30, true, 733, 0); } TEST_F(RemoteBitrateEstimatorSingleTest, TestTimestampGrouping) { diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc index f9588096a0..3c1a914d28 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.cc @@ -13,6 +13,8 @@ #include #include +#include "webrtc/base/checks.h" + namespace webrtc { const size_t kMtu = 1200; @@ -77,7 +79,7 @@ int64_t RtpStream::GenerateFrame(int64_t time_now_us, PacketList* packets) { } // The send-side time when the next frame can be generated. -double RtpStream::next_rtp_time() const { +int64_t RtpStream::next_rtp_time() const { return next_rtp_time_; } @@ -116,7 +118,7 @@ bool RtpStream::Compare(const std::pair& left, return left.second->next_rtp_time_ < right.second->next_rtp_time_; } -StreamGenerator::StreamGenerator(int capacity, double time_now) +StreamGenerator::StreamGenerator(int capacity, int64_t time_now) : capacity_(capacity), prev_arrival_time_us_(time_now) {} @@ -187,16 +189,17 @@ int64_t StreamGenerator::GenerateFrame(RtpStream::PacketList* packets, ++i; } it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare); - return (*it).second->next_rtp_time(); + return std::max((*it).second->next_rtp_time(), time_now_us); } } // namespace testing RemoteBitrateEstimatorTest::RemoteBitrateEstimatorTest() - : clock_(0), + : clock_(100000000), bitrate_observer_(new testing::TestBitrateObserver), stream_generator_(new testing::StreamGenerator( 1e6, // Capacity. - clock_.TimeInMicroseconds())) {} + clock_.TimeInMicroseconds())), + arrival_time_offset_ms_(0) {} RemoteBitrateEstimatorTest::~RemoteBitrateEstimatorTest() {} @@ -231,7 +234,8 @@ void RemoteBitrateEstimatorTest::IncomingPacket(uint32_t ssrc, header.timestamp = rtp_timestamp; header.extension.hasAbsoluteSendTime = true; header.extension.absoluteSendTime = absolute_send_time; - bitrate_estimator_->IncomingPacket(arrival_time + kArrivalTimeClockOffsetMs, + RTC_CHECK_GE(arrival_time + arrival_time_offset_ms_, 0); + bitrate_estimator_->IncomingPacket(arrival_time + arrival_time_offset_ms_, payload_size, header); } @@ -243,6 +247,7 @@ void RemoteBitrateEstimatorTest::IncomingPacket(uint32_t ssrc, // target bitrate after the call to this function. bool RemoteBitrateEstimatorTest::GenerateAndProcessFrame(uint32_t ssrc, uint32_t bitrate_bps) { + RTC_DCHECK_GT(bitrate_bps, 0u); stream_generator_->SetBitrateBps(bitrate_bps); testing::RtpStream::PacketList packets; int64_t next_time_us = stream_generator_->GenerateFrame( @@ -429,7 +434,8 @@ void RemoteBitrateEstimatorTest::RateIncreaseRtpTimestampsTestHelper( void RemoteBitrateEstimatorTest::CapacityDropTestHelper( int number_of_streams, bool wrap_time_stamp, - uint32_t expected_bitrate_drop_delta) { + uint32_t expected_bitrate_drop_delta, + int64_t receiver_clock_offset_change_ms) { const int kFramerate = 30; const int kStartBitrate = 900e3; const int kMinExpectedBitrate = 800e3; @@ -477,6 +483,9 @@ void RemoteBitrateEstimatorTest::CapacityDropTestHelper( EXPECT_NEAR(kInitialCapacityBps, bitrate_bps, 130000u); bitrate_observer_->Reset(); + // Add an offset to make sure the BWE can handle it. + arrival_time_offset_ms_ += receiver_clock_offset_change_ms; + // Reduce the capacity and verify the decrease time. stream_generator_->set_capacity_bps(kReducedCapacityBps); int64_t overuse_start_time = clock_.TimeInMilliseconds(); @@ -487,7 +496,8 @@ void RemoteBitrateEstimatorTest::CapacityDropTestHelper( bitrate_observer_->latest_bitrate() <= kReducedCapacityBps) { bitrate_drop_time = clock_.TimeInMilliseconds(); } - bitrate_bps = bitrate_observer_->latest_bitrate(); + if (bitrate_observer_->updated()) + bitrate_bps = bitrate_observer_->latest_bitrate(); } EXPECT_NEAR(expected_bitrate_drop_delta, diff --git a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h index b4bff670e7..4822d40e8b 100644 --- a/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h +++ b/webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_unittest_helper.h @@ -79,7 +79,7 @@ class RtpStream { int64_t GenerateFrame(int64_t time_now_us, PacketList* packets); // The send-side time when the next frame can be generated. - double next_rtp_time() const; + int64_t next_rtp_time() const; // Generates an RTCP packet. RtcpPacket* Rtcp(int64_t time_now_us); @@ -112,7 +112,7 @@ class StreamGenerator { public: typedef std::list RtcpList; - StreamGenerator(int capacity, double time_now); + StreamGenerator(int capacity, int64_t time_now); ~StreamGenerator(); @@ -203,15 +203,16 @@ class RemoteBitrateEstimatorTest : public ::testing::Test { void RateIncreaseRtpTimestampsTestHelper(int expected_iterations); void CapacityDropTestHelper(int number_of_streams, bool wrap_time_stamp, - uint32_t expected_bitrate_drop_delta); + uint32_t expected_bitrate_drop_delta, + int64_t receiver_clock_offset_change_ms); static const uint32_t kDefaultSsrc; - static const int kArrivalTimeClockOffsetMs = 60000; SimulatedClock clock_; // Time at the receiver. std::unique_ptr bitrate_observer_; std::unique_ptr bitrate_estimator_; std::unique_ptr stream_generator_; + int64_t arrival_time_offset_ms_; RTC_DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorTest); }; diff --git a/webrtc/modules/remote_bitrate_estimator/test/estimators/remb.cc b/webrtc/modules/remote_bitrate_estimator/test/estimators/remb.cc index 1c878b9f15..b1f364b451 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/estimators/remb.cc +++ b/webrtc/modules/remote_bitrate_estimator/test/estimators/remb.cc @@ -71,7 +71,7 @@ RembReceiver::RembReceiver(int flow_id, bool plot) recv_stats_(ReceiveStatistics::Create(&clock_)), latest_estimate_bps_(-1), last_feedback_ms_(-1), - estimator_(new RemoteBitrateEstimatorAbsSendTime(this)) { + estimator_(new RemoteBitrateEstimatorAbsSendTime(this, &clock_)) { std::stringstream ss; ss << "Estimate_" << flow_id_ << "#1"; estimate_log_prefix_ = ss.str(); diff --git a/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.cc b/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.cc index 6d79e09815..777761a03a 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.cc +++ b/webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.cc @@ -25,7 +25,7 @@ FullBweSender::FullBweSender(int kbps, BitrateObserver* observer, Clock* clock) BitrateController::CreateBitrateController(clock, observer, &event_log_)), - rbe_(new RemoteBitrateEstimatorAbsSendTime(this)), + rbe_(new RemoteBitrateEstimatorAbsSendTime(this, clock)), feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()), clock_(clock), send_time_history_(clock_, 10000), diff --git a/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc b/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc index 7ae6ede363..2b2e2653d6 100644 --- a/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc +++ b/webrtc/modules/remote_bitrate_estimator/tools/bwe_rtp.cc @@ -117,9 +117,9 @@ bool ParseArgsAndSetupEstimator(int argc, switch (extension) { case webrtc::kRtpExtensionAbsoluteSendTime: { *estimator = - new webrtc::RemoteBitrateEstimatorAbsSendTime(observer); - *estimator_used = "AbsoluteSendTimeRemoteBitrateEstimator"; - break; + new webrtc::RemoteBitrateEstimatorAbsSendTime(observer, clock); + *estimator_used = "AbsoluteSendTimeRemoteBitrateEstimator"; + break; } case webrtc::kRtpExtensionTransmissionTimeOffset: { *estimator =