diff --git a/webrtc/modules/bitrate_controller/bitrate_controller_unittest.cc b/webrtc/modules/bitrate_controller/bitrate_controller_unittest.cc index 8523d505b2..fddab9da7e 100644 --- a/webrtc/modules/bitrate_controller/bitrate_controller_unittest.cc +++ b/webrtc/modules/bitrate_controller/bitrate_controller_unittest.cc @@ -83,6 +83,27 @@ TEST_F(BitrateControllerTest, Basic) { controller_->RemoveBitrateObserver(&bitrate_observer); } +TEST_F(BitrateControllerTest, InitialRemb) { + TestBitrateObserver bitrate_observer; + controller_->SetBitrateObserver(&bitrate_observer, 200000, 100000, 1500000); + const uint32_t kRemb = 1000000u; + const uint32_t kSecondRemb = kRemb + 500000u; + + // Initial REMB applies immediately. + bandwidth_observer_->OnReceivedEstimatedBitrate(kRemb); + webrtc::ReportBlockList report_blocks; + report_blocks.push_back(CreateReportBlock(1, 2, 0, 1)); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 1); + report_blocks.clear(); + EXPECT_EQ(kRemb, bitrate_observer.last_bitrate_); + + // Second REMB doesn't apply immediately. + bandwidth_observer_->OnReceivedEstimatedBitrate(kRemb + 500000); + report_blocks.push_back(CreateReportBlock(1, 2, 0, 21)); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 2001); + EXPECT_LT(bitrate_observer.last_bitrate_, kSecondRemb); +} + TEST_F(BitrateControllerTest, UpdatingBitrateObserver) { TestBitrateObserver bitrate_observer; controller_->SetBitrateObserver(&bitrate_observer, 200000, 100000, 1500000); @@ -105,51 +126,65 @@ TEST_F(BitrateControllerTest, OneBitrateObserverOneRtcpObserver) { TestBitrateObserver bitrate_observer; controller_->SetBitrateObserver(&bitrate_observer, 200000, 100000, 300000); - // Receive a high remb, test bitrate inc. - bandwidth_observer_->OnReceivedEstimatedBitrate(400000); + // First REMB applies immediately. + int64_t time_ms = 1001; + webrtc::ReportBlockList report_blocks; + report_blocks.push_back(CreateReportBlock(1, 2, 0, 1)); + bandwidth_observer_->OnReceivedEstimatedBitrate(200000); EXPECT_EQ(200000u, bitrate_observer.last_bitrate_); EXPECT_EQ(0, bitrate_observer.last_fraction_loss_); EXPECT_EQ(0u, bitrate_observer.last_rtt_); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); + report_blocks.clear(); + time_ms += 2000; + + // Receive a high remb, test bitrate inc. + bandwidth_observer_->OnReceivedEstimatedBitrate(400000); // Test bitrate increase 8% per second. - webrtc::ReportBlockList report_blocks; - report_blocks.push_back(CreateReportBlock(1, 2, 0, 1)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 1); + report_blocks.push_back(CreateReportBlock(1, 2, 0, 21)); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(217000u, bitrate_observer.last_bitrate_); EXPECT_EQ(0, bitrate_observer.last_fraction_loss_); EXPECT_EQ(50u, bitrate_observer.last_rtt_); - - report_blocks.clear(); - report_blocks.push_back(CreateReportBlock(1, 2, 0, 21)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 1001); - EXPECT_EQ(235360u, bitrate_observer.last_bitrate_); - EXPECT_EQ(0, bitrate_observer.last_fraction_loss_); - EXPECT_EQ(50u, bitrate_observer.last_rtt_); + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 41)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 2001); - EXPECT_EQ(255189u, bitrate_observer.last_bitrate_); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); + EXPECT_EQ(235360u, bitrate_observer.last_bitrate_); + EXPECT_EQ(0, bitrate_observer.last_fraction_loss_); + EXPECT_EQ(50u, bitrate_observer.last_rtt_); + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 61)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 3001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); + EXPECT_EQ(255189u, bitrate_observer.last_bitrate_); + time_ms += 1000; + + report_blocks.clear(); + report_blocks.push_back(CreateReportBlock(1, 2, 0, 81)); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(276604u, bitrate_observer.last_bitrate_); + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 801)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 4001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(299732u, bitrate_observer.last_bitrate_); + time_ms += 1000; // Reach max cap. report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 101)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 5001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(300000u, bitrate_observer.last_bitrate_); + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 141)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 7001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(300000u, bitrate_observer.last_bitrate_); // Test that a low REMB trigger immediately. @@ -167,78 +202,86 @@ TEST_F(BitrateControllerTest, OneBitrateObserverTwoRtcpObservers) { TestBitrateObserver bitrate_observer; controller_->SetBitrateObserver(&bitrate_observer, 200000, 100000, 300000); + // REMBs during the first 2 seconds apply immediately. + int64_t time_ms = 1; + webrtc::ReportBlockList report_blocks; + report_blocks.push_back(CreateReportBlock(1, 2, 0, 1)); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); + report_blocks.clear(); + time_ms += 500; + RtcpBandwidthObserver* second_bandwidth_observer = controller_->CreateRtcpBandwidthObserver(); - // Receive a high remb, test bitrate inc. - bandwidth_observer_->OnReceivedEstimatedBitrate(400000); - EXPECT_EQ(200000u, bitrate_observer.last_bitrate_); - EXPECT_EQ(0, bitrate_observer.last_fraction_loss_); - EXPECT_EQ(0u, bitrate_observer.last_rtt_); - // Test start bitrate. - webrtc::ReportBlockList report_blocks; - report_blocks.push_back(CreateReportBlock(1, 2, 0, 1)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 1); + report_blocks.push_back(CreateReportBlock(1, 2, 0, 21)); second_bandwidth_observer->OnReceivedRtcpReceiverReport( report_blocks, 100, 1); EXPECT_EQ(217000u, bitrate_observer.last_bitrate_); EXPECT_EQ(0, bitrate_observer.last_fraction_loss_); EXPECT_EQ(100u, bitrate_observer.last_rtt_); + time_ms += 500; // Test bitrate increase 8% per second. report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 21)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 501); - second_bandwidth_observer->OnReceivedRtcpReceiverReport(report_blocks, 100, - 1001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); + time_ms += 500; + second_bandwidth_observer->OnReceivedRtcpReceiverReport( + report_blocks, 100, time_ms); EXPECT_EQ(235360u, bitrate_observer.last_bitrate_); EXPECT_EQ(0, bitrate_observer.last_fraction_loss_); EXPECT_EQ(100u, bitrate_observer.last_rtt_); + time_ms += 500; // Extra report should not change estimate. report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 31)); - second_bandwidth_observer->OnReceivedRtcpReceiverReport(report_blocks, 100, - 1501); + second_bandwidth_observer->OnReceivedRtcpReceiverReport( + report_blocks, 100, time_ms); EXPECT_EQ(235360u, bitrate_observer.last_bitrate_); + time_ms += 500; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 41)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 2001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(255189u, bitrate_observer.last_bitrate_); // Second report should not change estimate. report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 41)); - second_bandwidth_observer->OnReceivedRtcpReceiverReport(report_blocks, 100, - 2001); + second_bandwidth_observer->OnReceivedRtcpReceiverReport( + report_blocks, 100, time_ms); EXPECT_EQ(255189u, bitrate_observer.last_bitrate_); + time_ms += 1000; // Reports from only one bandwidth observer is ok. report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 61)); - second_bandwidth_observer->OnReceivedRtcpReceiverReport(report_blocks, 50, - 3001); + second_bandwidth_observer->OnReceivedRtcpReceiverReport( + report_blocks, 50, time_ms); EXPECT_EQ(276604u, bitrate_observer.last_bitrate_); + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 81)); - second_bandwidth_observer->OnReceivedRtcpReceiverReport(report_blocks, 50, - 4001); + second_bandwidth_observer->OnReceivedRtcpReceiverReport( + report_blocks, 50, time_ms); EXPECT_EQ(299732u, bitrate_observer.last_bitrate_); + time_ms += 1000; // Reach max cap. report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 121)); second_bandwidth_observer->OnReceivedRtcpReceiverReport( - report_blocks, 50, 5001); + report_blocks, 50, time_ms); EXPECT_EQ(300000u, bitrate_observer.last_bitrate_); + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 141)); second_bandwidth_observer->OnReceivedRtcpReceiverReport( - report_blocks, 50, 6001); + report_blocks, 50, time_ms); EXPECT_EQ(300000u, bitrate_observer.last_bitrate_); // Test that a low REMB trigger immediately. @@ -264,11 +307,18 @@ TEST_F(BitrateControllerTest, OneBitrateObserverMultipleReportBlocks) { controller_->SetBitrateObserver(&bitrate_observer, kStartBitrate, kMinBitrate, kMaxBitrate); + // REMBs during the first 2 seconds apply immediately. + int64_t time_ms = 1001; + webrtc::ReportBlockList report_blocks; + report_blocks.push_back(CreateReportBlock(1, 2, 0, sequence_number[0])); + bandwidth_observer_->OnReceivedEstimatedBitrate(kStartBitrate); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); + report_blocks.clear(); + time_ms += 2000; + // Receive a high REMB, test bitrate increase. bandwidth_observer_->OnReceivedEstimatedBitrate(400000); - webrtc::ReportBlockList report_blocks; - int64_t time_ms = 1001; uint32_t last_bitrate = 0; // Ramp up to max bitrate. for (int i = 0; i < 6; ++i) { @@ -333,20 +383,29 @@ TEST_F(BitrateControllerTest, TwoBitrateObserversOneRtcpObserver) { controller_->SetBitrateObserver(&bitrate_observer_2, 200000, 200000, 300000); controller_->SetBitrateObserver(&bitrate_observer_1, 200000, 100000, 300000); - // Receive a high remb, test bitrate inc. - // Test too low start bitrate, hence lower than sum of min. - bandwidth_observer_->OnReceivedEstimatedBitrate(400000); + // REMBs during the first 2 seconds apply immediately. + int64_t time_ms = 1001; + webrtc::ReportBlockList report_blocks; + report_blocks.push_back(CreateReportBlock(1, 2, 0, 1)); + bandwidth_observer_->OnReceivedEstimatedBitrate(200000); EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); EXPECT_EQ(0, bitrate_observer_1.last_fraction_loss_); EXPECT_EQ(0u, bitrate_observer_1.last_rtt_); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); + report_blocks.clear(); + time_ms += 2000; + + // Receive a high remb, test bitrate inc. + // Test too low start bitrate, hence lower than sum of min. + bandwidth_observer_->OnReceivedEstimatedBitrate(400000); // Test bitrate increase 8% per second, distributed equally. - webrtc::ReportBlockList report_blocks; - report_blocks.push_back(CreateReportBlock(1, 2, 0, 1)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 1001); + report_blocks.push_back(CreateReportBlock(1, 2, 0, 21)); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(112500u, bitrate_observer_1.last_bitrate_); EXPECT_EQ(0, bitrate_observer_1.last_fraction_loss_); EXPECT_EQ(50u, bitrate_observer_1.last_rtt_); + time_ms += 1000; EXPECT_EQ(212500u, bitrate_observer_2.last_bitrate_); EXPECT_EQ(0, bitrate_observer_2.last_fraction_loss_); @@ -354,59 +413,67 @@ TEST_F(BitrateControllerTest, TwoBitrateObserversOneRtcpObserver) { report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 41)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 2001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(126000u, bitrate_observer_1.last_bitrate_); EXPECT_EQ(226000u, bitrate_observer_2.last_bitrate_); + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 61)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 3001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(140580u, bitrate_observer_1.last_bitrate_); EXPECT_EQ(240580u, bitrate_observer_2.last_bitrate_); + time_ms += 1000; // Check that the bitrate sum honor our REMB. report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 101)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 5001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(150000u, bitrate_observer_1.last_bitrate_); EXPECT_EQ(250000u, bitrate_observer_2.last_bitrate_); + time_ms += 1000; // Remove REMB cap, higher than sum of max. bandwidth_observer_->OnReceivedEstimatedBitrate(700000); report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 121)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 6001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(166500u, bitrate_observer_1.last_bitrate_); EXPECT_EQ(266500u, bitrate_observer_2.last_bitrate_); + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 141)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 7001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(184320u, bitrate_observer_1.last_bitrate_); EXPECT_EQ(284320u, bitrate_observer_2.last_bitrate_); + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 161)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 8001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(207130u, bitrate_observer_1.last_bitrate_); EXPECT_EQ(300000u, bitrate_observer_2.last_bitrate_); // Max cap. + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 181)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 9001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(248700u, bitrate_observer_1.last_bitrate_); EXPECT_EQ(300000u, bitrate_observer_2.last_bitrate_); + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 201)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 10001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(293596u, bitrate_observer_1.last_bitrate_); EXPECT_EQ(300000u, bitrate_observer_2.last_bitrate_); + time_ms += 1000; report_blocks.clear(); report_blocks.push_back(CreateReportBlock(1, 2, 0, 221)); - bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, 11001); + bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); EXPECT_EQ(300000u, bitrate_observer_1.last_bitrate_); // Max cap. EXPECT_EQ(300000u, bitrate_observer_2.last_bitrate_); diff --git a/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc b/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc index 5da23f0662..406322a3cd 100644 --- a/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc +++ b/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.cc @@ -56,7 +56,9 @@ SendSideBandwidthEstimation::SendSideBandwidthEstimation() last_fraction_loss_(0), last_round_trip_time_ms_(0), bwe_incoming_(0), - time_last_decrease_ms_(0) {} + time_last_decrease_ms_(0), + first_report_time_ms_(-1) { +} SendSideBandwidthEstimation::~SendSideBandwidthEstimation() {} @@ -88,13 +90,15 @@ void SendSideBandwidthEstimation::CurrentEstimate(uint32_t* bitrate, void SendSideBandwidthEstimation::UpdateReceiverEstimate(uint32_t bandwidth) { bwe_incoming_ = bandwidth; - CapBitrateToThresholds(); + bitrate_ = CapBitrateToThresholds(bitrate_); } void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss, uint32_t rtt, int number_of_packets, uint32_t now_ms) { + if (first_report_time_ms_ == -1) + first_report_time_ms_ = now_ms; // Update RTT. last_round_trip_time_ms_ = rtt; @@ -124,8 +128,16 @@ void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss, } void SendSideBandwidthEstimation::UpdateEstimate(uint32_t now_ms) { + // We trust the REMB during the first 2 seconds if we haven't had any + // packet loss reported, to allow startup bitrate probing. + if (last_fraction_loss_ == 0 && now_ms - first_report_time_ms_ < 2000 && + bwe_incoming_ > bitrate_) { + bitrate_ = CapBitrateToThresholds(bwe_incoming_); + min_bitrate_history_.clear(); + min_bitrate_history_.push_back(std::make_pair(now_ms, bitrate_)); + return; + } UpdateMinHistory(now_ms); - // Only start updating bitrate when receiving receiver blocks. if (time_last_receiver_block_ms_ != 0) { if (last_fraction_loss_ <= 5) { @@ -172,7 +184,7 @@ void SendSideBandwidthEstimation::UpdateEstimate(uint32_t now_ms) { } } } - CapBitrateToThresholds(); + bitrate_ = CapBitrateToThresholds(bitrate_); } void SendSideBandwidthEstimation::UpdateMinHistory(uint32_t now_ms) { @@ -195,19 +207,20 @@ void SendSideBandwidthEstimation::UpdateMinHistory(uint32_t now_ms) { min_bitrate_history_.push_back(std::make_pair(now_ms, bitrate_)); } -void SendSideBandwidthEstimation::CapBitrateToThresholds() { - if (bwe_incoming_ > 0 && bitrate_ > bwe_incoming_) { - bitrate_ = bwe_incoming_; +uint32_t SendSideBandwidthEstimation::CapBitrateToThresholds(uint32_t bitrate) { + if (bwe_incoming_ > 0 && bitrate > bwe_incoming_) { + bitrate = bwe_incoming_; } - if (bitrate_ > max_bitrate_configured_) { - bitrate_ = max_bitrate_configured_; + if (bitrate > max_bitrate_configured_) { + bitrate = max_bitrate_configured_; } - if (bitrate_ < min_bitrate_configured_) { - LOG(LS_WARNING) << "Estimated available bandwidth " << bitrate_ / 1000 + if (bitrate < min_bitrate_configured_) { + LOG(LS_WARNING) << "Estimated available bandwidth " << bitrate / 1000 << " kbps is below configured min bitrate " << min_bitrate_configured_ / 1000 << " kbps."; - bitrate_ = min_bitrate_configured_; + bitrate = min_bitrate_configured_; } + return bitrate; } } // namespace webrtc diff --git a/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h b/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h index eb675d1ca6..6b32385236 100644 --- a/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h +++ b/webrtc/modules/bitrate_controller/send_side_bandwidth_estimation.h @@ -43,7 +43,9 @@ class SendSideBandwidthEstimation { void SetMinBitrate(uint32_t min_bitrate); private: - void CapBitrateToThresholds(); + // Returns the input bitrate capped to the thresholds defined by the max, + // min and incoming bandwidth. + uint32_t CapBitrateToThresholds(uint32_t bitrate); // Updates history of min bitrates. // After this method returns min_bitrate_history_.front().second contains the @@ -66,6 +68,7 @@ class SendSideBandwidthEstimation { uint32_t bwe_incoming_; uint32_t time_last_decrease_ms_; + int64_t first_report_time_ms_; }; } // namespace webrtc #endif // WEBRTC_MODULES_BITRATE_CONTROLLER_SEND_SIDE_BANDWIDTH_ESTIMATION_H_ diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index 082b8871f1..b0c5bb5aa6 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -180,6 +180,7 @@ 'desktop_capture/win/cursor_unittest_resources.rc', 'media_file/source/media_file_unittest.cc', 'module_common_types_unittest.cc', + 'pacing/bitrate_prober_unittest.cc', 'pacing/paced_sender_unittest.cc', 'remote_bitrate_estimator/bwe_simulations.cc', 'remote_bitrate_estimator/include/mock/mock_remote_bitrate_observer.h', diff --git a/webrtc/modules/pacing/BUILD.gn b/webrtc/modules/pacing/BUILD.gn index 58a73aeac7..aa44b0dac8 100644 --- a/webrtc/modules/pacing/BUILD.gn +++ b/webrtc/modules/pacing/BUILD.gn @@ -9,6 +9,8 @@ source_set("pacing") { sources = [ "include/paced_sender.h", + "bitrate_prober.cc", + "bitrate_prober.h", "paced_sender.cc", ] diff --git a/webrtc/modules/pacing/bitrate_prober.cc b/webrtc/modules/pacing/bitrate_prober.cc new file mode 100644 index 0000000000..04e71c5c28 --- /dev/null +++ b/webrtc/modules/pacing/bitrate_prober.cc @@ -0,0 +1,120 @@ +/* + * 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 "webrtc/modules/pacing/bitrate_prober.h" + +#include +#include +#include + +#include "webrtc/system_wrappers/interface/logging.h" + +namespace webrtc { + +namespace { +int ComputeDeltaFromBitrate(size_t packet_size, int bitrate_bps) { + assert(bitrate_bps > 0); + // Compute the time delta needed to send packet_size bytes at bitrate_bps + // bps. Result is in milliseconds. + return static_cast(1000ll * static_cast(packet_size) * 8ll / + bitrate_bps); +} +} // namespace + +BitrateProber::BitrateProber() + : probing_state_(kDisabled), + packet_size_last_send_(0), + time_last_send_ms_(-1) { +} + +void BitrateProber::SetEnabled(bool enable) { + if (enable) { + if (probing_state_ == kDisabled) { + probing_state_ = kAllowedToProbe; + LOG(LS_INFO) << "Initial bandwidth probing enabled"; + } + } else { + probing_state_ = kDisabled; + LOG(LS_INFO) << "Initial bandwidth probing disabled"; + } +} + +bool BitrateProber::IsProbing() const { + return probing_state_ == kProbing; +} + +void BitrateProber::MaybeInitializeProbe(int bitrate_bps) { + if (probing_state_ != kAllowedToProbe) + return; + probe_bitrates_.clear(); + // Max number of packets used for probing. + const int kMaxProbeLength = 15; + const int kMaxNumProbes = 3; + const int kPacketsPerProbe = kMaxProbeLength / kMaxNumProbes; + const float kProbeBitrateMultipliers[kMaxNumProbes] = {2.5, 4, 6}; + int bitrates_bps[kMaxNumProbes]; + std::stringstream bitrate_log; + bitrate_log << "Start probing for bandwidth, bitrates:"; + for (int i = 0; i < kMaxNumProbes; ++i) { + bitrates_bps[i] = kProbeBitrateMultipliers[i] * bitrate_bps; + bitrate_log << " " << bitrates_bps[i]; + for (int j = 0; j < kPacketsPerProbe; ++j) + probe_bitrates_.push_back(bitrates_bps[i]); + } + bitrate_log << ", num packets: " << probe_bitrates_.size(); + LOG(LS_INFO) << bitrate_log.str().c_str(); + probing_state_ = kProbing; +} + +int BitrateProber::TimeUntilNextProbe(int64_t now_ms) { + if (probing_state_ != kDisabled && probe_bitrates_.empty()) { + probing_state_ = kWait; + } + if (probe_bitrates_.empty()) { + // No probe started, or waiting for next probe. + return std::numeric_limits::max(); + } + int64_t elapsed_time_ms = now_ms - time_last_send_ms_; + // We will send the first probe packet immediately if no packet has been + // sent before. + int time_until_probe_ms = 0; + if (packet_size_last_send_ > 0 && probing_state_ == kProbing) { + int next_delta_ms = ComputeDeltaFromBitrate(packet_size_last_send_, + probe_bitrates_.front()); + time_until_probe_ms = next_delta_ms - elapsed_time_ms; + // There is no point in trying to probe with less than 1 ms between packets + // as it essentially means trying to probe at infinite bandwidth. + const int kMinProbeDeltaMs = 1; + // If we have waited more than 3 ms for a new packet to probe with we will + // consider this probing session over. + const int kMaxProbeDelayMs = 3; + if (next_delta_ms < kMinProbeDeltaMs || + time_until_probe_ms < -kMaxProbeDelayMs) { + // We currently disable probing after the first probe, as we only want + // to probe at the beginning of a connection. We should set this to + // kWait if we later want to probe periodically. + probing_state_ = kWait; + LOG(LS_INFO) << "Next delta too small, stop probing."; + time_until_probe_ms = 0; + } + } + return time_until_probe_ms; +} + +void BitrateProber::PacketSent(int64_t now_ms, size_t packet_size) { + assert(packet_size > 0); + packet_size_last_send_ = packet_size; + time_last_send_ms_ = now_ms; + if (probing_state_ != kProbing) + return; + if (!probe_bitrates_.empty()) + probe_bitrates_.pop_front(); +} +} // namespace webrtc diff --git a/webrtc/modules/pacing/bitrate_prober.h b/webrtc/modules/pacing/bitrate_prober.h new file mode 100644 index 0000000000..04a858058f --- /dev/null +++ b/webrtc/modules/pacing/bitrate_prober.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#ifndef WEBRTC_MODULES_PACING_BITRATE_PROBER_H_ +#define WEBRTC_MODULES_PACING_BITRATE_PROBER_H_ + +#include +#include + +#include "webrtc/typedefs.h" + +namespace webrtc { + +// Note that this class isn't thread-safe by itself and therefore relies +// on being protected by the caller. +class BitrateProber { + public: + BitrateProber(); + + void SetEnabled(bool enable); + + // Returns true if the prober is in a probing session, i.e., it currently + // wants packets to be sent out according to the time returned by + // TimeUntilNextProbe(). + bool IsProbing() const; + + // Initializes a new probing session if the prober is allowed to probe. + void MaybeInitializeProbe(int bitrate_bps); + + // Returns the number of milliseconds until the next packet should be sent to + // get accurate probing. + int TimeUntilNextProbe(int64_t now_ms); + + // Called to report to the prober that a packet has been sent, which helps the + // prober know when to move to the next packet in a probe. + void PacketSent(int64_t now_ms, size_t packet_size); + + private: + enum ProbingState { kDisabled, kAllowedToProbe, kProbing, kWait }; + + ProbingState probing_state_; + // Probe bitrate per packet. These are used to compute the delta relative to + // the previous probe packet based on the size and time when that packet was + // sent. + std::list probe_bitrates_; + size_t packet_size_last_send_; + int64_t time_last_send_ms_; +}; +} // namespace webrtc +#endif // WEBRTC_MODULES_PACING_BITRATE_PROBER_H_ diff --git a/webrtc/modules/pacing/bitrate_prober_unittest.cc b/webrtc/modules/pacing/bitrate_prober_unittest.cc new file mode 100644 index 0000000000..15b1cc5830 --- /dev/null +++ b/webrtc/modules/pacing/bitrate_prober_unittest.cc @@ -0,0 +1,57 @@ +/* + * 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 + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/modules/pacing/bitrate_prober.h" + +namespace webrtc { + +TEST(BitrateProberTest, VerifyStatesAndTimeBetweenProbes) { + BitrateProber prober; + EXPECT_FALSE(prober.IsProbing()); + int64_t now_ms = 0; + EXPECT_EQ(std::numeric_limits::max(), prober.TimeUntilNextProbe(now_ms)); + + prober.SetEnabled(true); + EXPECT_FALSE(prober.IsProbing()); + + prober.MaybeInitializeProbe(300000); + EXPECT_TRUE(prober.IsProbing()); + + EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms)); + prober.PacketSent(now_ms, 1000); + + for (int i = 0; i < 4; ++i) { + EXPECT_EQ(10, prober.TimeUntilNextProbe(now_ms)); + now_ms += 5; + EXPECT_EQ(5, prober.TimeUntilNextProbe(now_ms)); + now_ms += 5; + EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms)); + prober.PacketSent(now_ms, 1000); + } + for (int i = 0; i < 5; ++i) { + EXPECT_EQ(6, prober.TimeUntilNextProbe(now_ms)); + now_ms += 6; + EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms)); + prober.PacketSent(now_ms, 1000); + } + for (int i = 0; i < 5; ++i) { + EXPECT_EQ(4, prober.TimeUntilNextProbe(now_ms)); + now_ms += 4; + EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms)); + prober.PacketSent(now_ms, 1000); + } + + EXPECT_EQ(std::numeric_limits::max(), prober.TimeUntilNextProbe(now_ms)); + EXPECT_FALSE(prober.IsProbing()); +} +} // namespace webrtc diff --git a/webrtc/modules/pacing/include/mock/mock_paced_sender.h b/webrtc/modules/pacing/include/mock/mock_paced_sender.h index 6600a9292d..0c9e354d20 100644 --- a/webrtc/modules/pacing/include/mock/mock_paced_sender.h +++ b/webrtc/modules/pacing/include/mock/mock_paced_sender.h @@ -22,7 +22,7 @@ namespace webrtc { class MockPacedSender : public PacedSender { public: - MockPacedSender() : PacedSender(Clock::GetRealTimeClock(), NULL, 0, 0) {} + MockPacedSender() : PacedSender(Clock::GetRealTimeClock(), NULL, 0, 0, 0) {} MOCK_METHOD6(SendPacket, bool(Priority priority, uint32_t ssrc, uint16_t sequence_number, diff --git a/webrtc/modules/pacing/include/paced_sender.h b/webrtc/modules/pacing/include/paced_sender.h index 14a3a3d43b..d3034466b9 100644 --- a/webrtc/modules/pacing/include/paced_sender.h +++ b/webrtc/modules/pacing/include/paced_sender.h @@ -8,8 +8,8 @@ * be found in the AUTHORS file in the root of the source tree. */ -#ifndef WEBRTC_MODULES_PACED_SENDER_H_ -#define WEBRTC_MODULES_PACED_SENDER_H_ +#ifndef WEBRTC_MODULES_PACING_INCLUDE_PACED_SENDER_H_ +#define WEBRTC_MODULES_PACING_INCLUDE_PACED_SENDER_H_ #include #include @@ -20,6 +20,7 @@ #include "webrtc/typedefs.h" namespace webrtc { +class BitrateProber; class Clock; class CriticalSectionWrapper; @@ -67,7 +68,10 @@ class PacedSender : public Module { // overshoots from the encoder. static const float kDefaultPaceMultiplier; - PacedSender(Clock* clock, Callback* callback, int max_bitrate_kbps, + PacedSender(Clock* clock, + Callback* callback, + int bitrate_kbps, + int max_bitrate_kbps, int min_bitrate_kbps); virtual ~PacedSender(); @@ -83,9 +87,14 @@ class PacedSender : public Module { // Resume sending packets. void Resume(); - // Set target bitrates for the pacer. Padding packets will be utilized to - // reach |min_bitrate| unless enough media packets are available. - void UpdateBitrate(int max_bitrate_kbps, int min_bitrate_kbps); + // Set target bitrates for the pacer. + // We will pace out bursts of packets at a bitrate of |max_bitrate_kbps|. + // |bitrate_kbps| is our estimate of what we are allowed to send on average. + // Padding packets will be utilized to reach |min_bitrate| unless enough media + // packets are available. + void UpdateBitrate(int bitrate_kbps, + int max_bitrate_kbps, + int min_bitrate_kbps); // Returns true if we send the packet now, else it will add the packet // information to the queue and call TimeToSendPacket when it's time to send. @@ -103,6 +112,8 @@ class PacedSender : public Module { // Returns the time since the oldest queued packet was enqueued. virtual int QueueInMs() const; + virtual size_t QueueSizePackets() const; + // Returns the number of milliseconds until the module want a worker thread // to call Process. virtual int32_t TimeUntilNextProcess() OVERRIDE; @@ -110,10 +121,13 @@ class PacedSender : public Module { // Process any pending packets in the queue(s). virtual int32_t Process() OVERRIDE; + protected: + virtual bool ProbingExperimentIsEnabled() const; + private: // Return true if next packet in line should be transmitted. // Return packet list that contains the next packet. - bool ShouldSendNextPacket(paced_sender::PacketList** packet_list) + bool ShouldSendNextPacket(paced_sender::PacketList** packet_list, bool probe) EXCLUSIVE_LOCKS_REQUIRED(critsect_); // Local helper function to GetNextPacket. @@ -146,8 +160,12 @@ class PacedSender : public Module { scoped_ptr padding_budget_ GUARDED_BY(critsect_); + scoped_ptr prober_ GUARDED_BY(critsect_); + int bitrate_bps_ GUARDED_BY(critsect_); + int64_t time_last_update_us_ GUARDED_BY(critsect_); - int64_t time_last_send_us_ GUARDED_BY(critsect_); + // Only accessed via process thread. + int64_t time_last_media_send_us_; int64_t capture_time_ms_last_queued_ GUARDED_BY(critsect_); int64_t capture_time_ms_last_sent_ GUARDED_BY(critsect_); @@ -159,4 +177,4 @@ class PacedSender : public Module { GUARDED_BY(critsect_); }; } // namespace webrtc -#endif // WEBRTC_MODULES_PACED_SENDER_H_ +#endif // WEBRTC_MODULES_PACING_INCLUDE_PACED_SENDER_H_ diff --git a/webrtc/modules/pacing/paced_sender.cc b/webrtc/modules/pacing/paced_sender.cc index 6204a9a066..64b3eb1e35 100644 --- a/webrtc/modules/pacing/paced_sender.cc +++ b/webrtc/modules/pacing/paced_sender.cc @@ -16,8 +16,11 @@ #include #include "webrtc/modules/interface/module_common_types.h" +#include "webrtc/modules/pacing/bitrate_prober.h" #include "webrtc/system_wrappers/interface/clock.h" #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" +#include "webrtc/system_wrappers/interface/field_trial.h" +#include "webrtc/system_wrappers/interface/logging.h" #include "webrtc/system_wrappers/interface/trace_event.h" namespace { @@ -71,6 +74,17 @@ class PacketList { return packet_list_.front(); } + size_t size() const { + size_t sum = 0; + for (std::map >::const_iterator it = + sequence_number_set_.begin(); + it != sequence_number_set_.end(); + ++it) { + sum += it->second.size(); + } + return sum; + } + void pop_front() { Packet& packet = packet_list_.front(); uint16_t sequence_number = packet.sequence_number; @@ -131,6 +145,7 @@ const float PacedSender::kDefaultPaceMultiplier = 2.5f; PacedSender::PacedSender(Clock* clock, Callback* callback, + int bitrate_kbps, int max_bitrate_kbps, int min_bitrate_kbps) : clock_(clock), @@ -141,7 +156,10 @@ PacedSender::PacedSender(Clock* clock, max_queue_length_ms_(kDefaultMaxQueueLengthMs), media_budget_(new paced_sender::IntervalBudget(max_bitrate_kbps)), padding_budget_(new paced_sender::IntervalBudget(min_bitrate_kbps)), + prober_(new BitrateProber()), + bitrate_bps_(1000 * bitrate_kbps), time_last_update_us_(clock->TimeInMicroseconds()), + time_last_media_send_us_(-1), capture_time_ms_last_queued_(0), capture_time_ms_last_sent_(0), high_priority_packets_(new paced_sender::PacketList), @@ -172,11 +190,13 @@ bool PacedSender::Enabled() const { return enabled_; } -void PacedSender::UpdateBitrate(int max_bitrate_kbps, +void PacedSender::UpdateBitrate(int bitrate_kbps, + int max_bitrate_kbps, int min_bitrate_kbps) { CriticalSectionScoped cs(critsect_.get()); media_budget_->set_target_rate_kbps(max_bitrate_kbps); padding_budget_->set_target_rate_kbps(min_bitrate_kbps); + bitrate_bps_ = 1000 * bitrate_kbps; } bool PacedSender::SendPacket(Priority priority, uint32_t ssrc, @@ -187,6 +207,12 @@ bool PacedSender::SendPacket(Priority priority, uint32_t ssrc, if (!enabled_) { return true; // We can send now. } + // Enable probing if the probing experiment is enabled. + if (!prober_->IsProbing() && ProbingExperimentIsEnabled()) { + prober_->SetEnabled(true); + } + prober_->MaybeInitializeProbe(bitrate_bps_); + if (capture_time_ms < 0) { capture_time_ms = clock_->TimeInMilliseconds(); } @@ -244,12 +270,19 @@ int PacedSender::QueueInMs() const { return now_ms - oldest_packet_enqueue_time; } +size_t PacedSender::QueueSizePackets() const { + CriticalSectionScoped cs(critsect_.get()); + return low_priority_packets_->size() + normal_priority_packets_->size() + + high_priority_packets_->size(); +} + int32_t PacedSender::TimeUntilNextProcess() { CriticalSectionScoped cs(critsect_.get()); - int64_t elapsed_time_ms = (clock_->TimeInMicroseconds() - - time_last_update_us_ + 500) / 1000; - if (elapsed_time_ms <= 0) { - return kMinPacketLimitMs; + int64_t elapsed_time_us = clock_->TimeInMicroseconds() - time_last_update_us_; + int elapsed_time_ms = static_cast((elapsed_time_us + 500) / 1000); + if (prober_->IsProbing()) { + int next_probe = prober_->TimeUntilNextProbe(clock_->TimeInMilliseconds()); + return next_probe; } if (elapsed_time_ms >= kMinPacketLimitMs) { return 0; @@ -271,12 +304,15 @@ int32_t PacedSender::Process() { UpdateBytesPerInterval(delta_time_ms); } paced_sender::PacketList* packet_list; - while (ShouldSendNextPacket(&packet_list)) { + while (ShouldSendNextPacket(&packet_list, prober_->IsProbing())) { if (!SendPacketFromList(packet_list)) return 0; + // Send one packet per Process() call when probing, so that we have + // better control over the delta between packets. + if (prober_->IsProbing()) + return 0; } - if (high_priority_packets_->empty() && - normal_priority_packets_->empty() && + if (high_priority_packets_->empty() && normal_priority_packets_->empty() && low_priority_packets_->empty() && padding_budget_->bytes_remaining() > 0) { int padding_needed = padding_budget_->bytes_remaining(); @@ -325,12 +361,13 @@ void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) { padding_budget_->IncreaseBudget(delta_time_ms); } -bool PacedSender::ShouldSendNextPacket(paced_sender::PacketList** packet_list) { +bool PacedSender::ShouldSendNextPacket(paced_sender::PacketList** packet_list, + bool probe) { *packet_list = NULL; - if (media_budget_->bytes_remaining() <= 0) { + if (!probe && media_budget_->bytes_remaining() <= 0) { // All bytes consumed for this interval. // Check if we have not sent in a too long time. - if (clock_->TimeInMicroseconds() - time_last_send_us_ > + if (clock_->TimeInMicroseconds() - time_last_media_send_us_ > kMaxQueueTimeWithoutSendingUs) { if (!high_priority_packets_->empty()) { *packet_list = high_priority_packets_.get(); @@ -383,9 +420,14 @@ paced_sender::Packet PacedSender::GetNextPacketFromList( } void PacedSender::UpdateMediaBytesSent(int num_bytes) { - time_last_send_us_ = clock_->TimeInMicroseconds(); + prober_->PacketSent(clock_->TimeInMilliseconds(), num_bytes); + time_last_media_send_us_ = clock_->TimeInMicroseconds(); media_budget_->UseBudget(num_bytes); padding_budget_->UseBudget(num_bytes); } +bool PacedSender::ProbingExperimentIsEnabled() const { + return webrtc::field_trial::FindFullName("WebRTC-BitrateProbing") == + "Enabled"; +} } // namespace webrtc diff --git a/webrtc/modules/pacing/paced_sender_unittest.cc b/webrtc/modules/pacing/paced_sender_unittest.cc index 14dcdbc512..f8028a919e 100644 --- a/webrtc/modules/pacing/paced_sender_unittest.cc +++ b/webrtc/modules/pacing/paced_sender_unittest.cc @@ -8,9 +8,10 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include + #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" - #include "webrtc/modules/pacing/include/paced_sender.h" #include "webrtc/system_wrappers/interface/clock.h" @@ -26,8 +27,10 @@ static const float kPaceMultiplier = 1.5f; class MockPacedSenderCallback : public PacedSender::Callback { public: MOCK_METHOD4(TimeToSendPacket, - bool(uint32_t ssrc, uint16_t sequence_number, int64_t capture_time_ms, - bool retransmission)); + bool(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission)); MOCK_METHOD1(TimeToSendPadding, int(int bytes)); }; @@ -36,8 +39,10 @@ class PacedSenderPadding : public PacedSender::Callback { public: PacedSenderPadding() : padding_sent_(0) {} - bool TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number, - int64_t capture_time_ms, bool retransmission) { + bool TimeToSendPacket(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission) { return true; } @@ -54,24 +59,67 @@ class PacedSenderPadding : public PacedSender::Callback { int padding_sent_; }; +class PacedSenderProbing : public PacedSender::Callback { + public: + PacedSenderProbing(const std::list& expected_deltas, Clock* clock) + : prev_packet_time_ms_(-1), + expected_deltas_(expected_deltas), + packets_sent_(0), + clock_(clock) {} + + bool TimeToSendPacket(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission) { + ++packets_sent_; + EXPECT_FALSE(expected_deltas_.empty()); + if (expected_deltas_.empty()) + return false; + int64_t now_ms = clock_->TimeInMilliseconds(); + if (prev_packet_time_ms_ >= 0) { + EXPECT_EQ(expected_deltas_.front(), now_ms - prev_packet_time_ms_); + expected_deltas_.pop_front(); + } + prev_packet_time_ms_ = now_ms; + return true; + } + + int TimeToSendPadding(int bytes) { + EXPECT_TRUE(false); + return bytes; + } + + int packets_sent() const { return packets_sent_; } + + private: + int64_t prev_packet_time_ms_; + std::list expected_deltas_; + int packets_sent_; + Clock* clock_; +}; + class PacedSenderTest : public ::testing::Test { protected: PacedSenderTest() : clock_(123456) { srand(0); // Need to initialize PacedSender after we initialize clock. - send_bucket_.reset( - new PacedSender( - &clock_, &callback_, kPaceMultiplier * kTargetBitrate, 0)); + send_bucket_.reset(new PacedSender(&clock_, + &callback_, + kTargetBitrate, + kPaceMultiplier * kTargetBitrate, + 0)); } void SendAndExpectPacket(PacedSender::Priority priority, - uint32_t ssrc, uint16_t sequence_number, - int64_t capture_time_ms, int size, + uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + int size, bool retransmission) { EXPECT_FALSE(send_bucket_->SendPacket(priority, ssrc, sequence_number, capture_time_ms, size, retransmission)); - EXPECT_CALL(callback_, TimeToSendPacket( - ssrc, sequence_number, capture_time_ms, false)) + EXPECT_CALL(callback_, + TimeToSendPacket(ssrc, sequence_number, capture_time_ms, false)) .Times(1) .WillRepeatedly(Return(true)); } @@ -85,12 +133,24 @@ TEST_F(PacedSenderTest, QueuePacket) { uint32_t ssrc = 12345; uint16_t sequence_number = 1234; // Due to the multiplicative factor we can send 3 packets not 2 packets. - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); int64_t queued_packet_timestamp = clock_.TimeInMilliseconds(); EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc, sequence_number, queued_packet_timestamp, 250, false)); @@ -101,16 +161,25 @@ TEST_F(PacedSenderTest, QueuePacket) { EXPECT_EQ(1, send_bucket_->TimeUntilNextProcess()); clock_.AdvanceTimeMilliseconds(1); EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess()); - EXPECT_CALL(callback_, TimeToSendPacket( - ssrc, sequence_number++, queued_packet_timestamp, false)) + EXPECT_CALL( + callback_, + TimeToSendPacket(ssrc, sequence_number++, queued_packet_timestamp, false)) .Times(1) .WillRepeatedly(Return(true)); send_bucket_->Process(); sequence_number++; - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, clock_.TimeInMilliseconds(), 250, false)); send_bucket_->Process(); @@ -122,8 +191,12 @@ TEST_F(PacedSenderTest, PaceQueuedPackets) { // Due to the multiplicative factor we can send 3 packets not 2 packets. for (int i = 0; i < 3; ++i) { - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); } for (int j = 0; j < 30; ++j) { EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc, @@ -134,8 +207,7 @@ TEST_F(PacedSenderTest, PaceQueuedPackets) { for (int k = 0; k < 10; ++k) { EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess()); clock_.AdvanceTimeMilliseconds(5); - EXPECT_CALL(callback_, - TimeToSendPacket(ssrc, _, _, false)) + EXPECT_CALL(callback_, TimeToSendPacket(ssrc, _, _, false)) .Times(3) .WillRepeatedly(Return(true)); EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess()); @@ -145,12 +217,24 @@ TEST_F(PacedSenderTest, PaceQueuedPackets) { clock_.AdvanceTimeMilliseconds(5); EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess()); EXPECT_EQ(0, send_bucket_->Process()); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc, sequence_number, clock_.TimeInMilliseconds(), 250, false)); send_bucket_->Process(); @@ -163,8 +247,12 @@ TEST_F(PacedSenderTest, PaceQueuedPacketsWithDuplicates) { // Due to the multiplicative factor we can send 3 packets not 2 packets. for (int i = 0; i < 3; ++i) { - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); } queued_sequence_number = sequence_number; @@ -182,9 +270,8 @@ TEST_F(PacedSenderTest, PaceQueuedPacketsWithDuplicates) { clock_.AdvanceTimeMilliseconds(5); for (int i = 0; i < 3; ++i) { - EXPECT_CALL(callback_, TimeToSendPacket(ssrc, queued_sequence_number++, - _, - false)) + EXPECT_CALL(callback_, + TimeToSendPacket(ssrc, queued_sequence_number++, _, false)) .Times(1) .WillRepeatedly(Return(true)); } @@ -195,12 +282,24 @@ TEST_F(PacedSenderTest, PaceQueuedPacketsWithDuplicates) { clock_.AdvanceTimeMilliseconds(5); EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess()); EXPECT_EQ(0, send_bucket_->Process()); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, clock_.TimeInMilliseconds(), 250, false)); send_bucket_->Process(); @@ -233,14 +332,27 @@ TEST_F(PacedSenderTest, Padding) { uint32_t ssrc = 12345; uint16_t sequence_number = 1234; - send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate); + send_bucket_->UpdateBitrate( + kTargetBitrate, kPaceMultiplier * kTargetBitrate, kTargetBitrate); // Due to the multiplicative factor we can send 3 packets not 2 packets. - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - clock_.TimeInMilliseconds(), 250, false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + 250, + false); // No padding is expected since we have sent too much already. EXPECT_CALL(callback_, TimeToSendPadding(_)).Times(0); EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess()); @@ -259,7 +371,8 @@ TEST_F(PacedSenderTest, Padding) { TEST_F(PacedSenderTest, NoPaddingWhenDisabled) { send_bucket_->SetStatus(false); - send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate); + send_bucket_->UpdateBitrate( + kTargetBitrate, kPaceMultiplier * kTargetBitrate, kTargetBitrate); // No padding is expected since the pacer is disabled. EXPECT_CALL(callback_, TimeToSendPadding(_)).Times(0); EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess()); @@ -279,11 +392,16 @@ TEST_F(PacedSenderTest, VerifyPaddingUpToBitrate) { int64_t capture_time_ms = 56789; const int kTimeStep = 5; const int64_t kBitrateWindow = 100; - send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate); + send_bucket_->UpdateBitrate( + kTargetBitrate, kPaceMultiplier * kTargetBitrate, kTargetBitrate); int64_t start_time = clock_.TimeInMilliseconds(); while (clock_.TimeInMilliseconds() - start_time < kBitrateWindow) { - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - capture_time_ms, 250, false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + capture_time_ms, + 250, + false); clock_.AdvanceTimeMilliseconds(kTimeStep); EXPECT_CALL(callback_, TimeToSendPadding(250)).Times(1). WillOnce(Return(250)); @@ -298,9 +416,10 @@ TEST_F(PacedSenderTest, VerifyAverageBitrateVaryingMediaPayload) { const int kTimeStep = 5; const int64_t kBitrateWindow = 10000; PacedSenderPadding callback; - send_bucket_.reset( - new PacedSender(&clock_, &callback, kPaceMultiplier * kTargetBitrate, 0)); - send_bucket_->UpdateBitrate(kPaceMultiplier * kTargetBitrate, kTargetBitrate); + send_bucket_.reset(new PacedSender( + &clock_, &callback, kTargetBitrate, kPaceMultiplier * kTargetBitrate, 0)); + send_bucket_->UpdateBitrate( + kTargetBitrate, kPaceMultiplier * kTargetBitrate, kTargetBitrate); int64_t start_time = clock_.TimeInMilliseconds(); int media_bytes = 0; while (clock_.TimeInMilliseconds() - start_time < kBitrateWindow) { @@ -324,12 +443,24 @@ TEST_F(PacedSenderTest, Priority) { int64_t capture_time_ms_low_priority = 1234567; // Due to the multiplicative factor we can send 3 packets not 2 packets. - SendAndExpectPacket(PacedSender::kLowPriority, ssrc, sequence_number++, - capture_time_ms, 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - capture_time_ms, 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - capture_time_ms, 250, false); + SendAndExpectPacket(PacedSender::kLowPriority, + ssrc, + sequence_number++, + capture_time_ms, + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + capture_time_ms, + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + capture_time_ms, + 250, + false); send_bucket_->Process(); // Expect normal and low priority to be queued and high to pass through. @@ -354,8 +485,9 @@ TEST_F(PacedSenderTest, Priority) { EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess()); EXPECT_EQ(0, send_bucket_->Process()); - EXPECT_CALL(callback_, TimeToSendPacket( - ssrc_low_priority, _, capture_time_ms_low_priority, false)) + EXPECT_CALL(callback_, + TimeToSendPacket( + ssrc_low_priority, _, capture_time_ms_low_priority, false)) .Times(1) .WillRepeatedly(Return(true)); @@ -374,12 +506,24 @@ TEST_F(PacedSenderTest, Pause) { EXPECT_EQ(0, send_bucket_->QueueInMs()); // Due to the multiplicative factor we can send 3 packets not 2 packets. - SendAndExpectPacket(PacedSender::kLowPriority, ssrc, sequence_number++, - capture_time_ms, 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - capture_time_ms, 250, false); - SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, - capture_time_ms, 250, false); + SendAndExpectPacket(PacedSender::kLowPriority, + ssrc, + sequence_number++, + capture_time_ms, + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + capture_time_ms, + 250, + false); + SendAndExpectPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + capture_time_ms, + 250, + false); send_bucket_->Process(); send_bucket_->Pause(); @@ -423,8 +567,7 @@ TEST_F(PacedSenderTest, Pause) { EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess()); EXPECT_EQ(0, send_bucket_->Process()); - EXPECT_CALL( - callback_, TimeToSendPacket(_, _, second_capture_time_ms, false)) + EXPECT_CALL(callback_, TimeToSendPacket(_, _, second_capture_time_ms, false)) .Times(1) .WillRepeatedly(Return(true)); EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess()); @@ -457,8 +600,8 @@ TEST_F(PacedSenderTest, ResendPacket) { EXPECT_EQ(clock_.TimeInMilliseconds() - capture_time_ms, send_bucket_->QueueInMs()); // Fails to send first packet so only one call. - EXPECT_CALL(callback_, TimeToSendPacket( - ssrc, sequence_number, capture_time_ms, false)) + EXPECT_CALL(callback_, + TimeToSendPacket(ssrc, sequence_number, capture_time_ms, false)) .Times(1) .WillOnce(Return(false)); clock_.AdvanceTimeMilliseconds(10000); @@ -469,12 +612,13 @@ TEST_F(PacedSenderTest, ResendPacket) { send_bucket_->QueueInMs()); // Fails to send second packet. - EXPECT_CALL(callback_, TimeToSendPacket( - ssrc, sequence_number, capture_time_ms, false)) + EXPECT_CALL(callback_, + TimeToSendPacket(ssrc, sequence_number, capture_time_ms, false)) .Times(1) .WillOnce(Return(true)); - EXPECT_CALL(callback_, TimeToSendPacket( - ssrc, sequence_number + 1, capture_time_ms + 1, false)) + EXPECT_CALL( + callback_, + TimeToSendPacket(ssrc, sequence_number + 1, capture_time_ms + 1, false)) .Times(1) .WillOnce(Return(false)); clock_.AdvanceTimeMilliseconds(10000); @@ -485,8 +629,9 @@ TEST_F(PacedSenderTest, ResendPacket) { send_bucket_->QueueInMs()); // Send second packet and queue becomes empty. - EXPECT_CALL(callback_, TimeToSendPacket( - ssrc, sequence_number + 1, capture_time_ms + 1, false)) + EXPECT_CALL( + callback_, + TimeToSendPacket(ssrc, sequence_number + 1, capture_time_ms + 1, false)) .Times(1) .WillOnce(Return(true)); clock_.AdvanceTimeMilliseconds(10000); @@ -499,7 +644,7 @@ TEST_F(PacedSenderTest, MaxQueueLength) { uint16_t sequence_number = 1234; EXPECT_EQ(0, send_bucket_->QueueInMs()); - send_bucket_->UpdateBitrate(kPaceMultiplier * 30, 0); + send_bucket_->UpdateBitrate(30, kPaceMultiplier * 30, 0); for (int i = 0; i < 30; ++i) { SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, @@ -529,7 +674,7 @@ TEST_F(PacedSenderTest, QueueTimeGrowsOverTime) { uint16_t sequence_number = 1234; EXPECT_EQ(0, send_bucket_->QueueInMs()); - send_bucket_->UpdateBitrate(kPaceMultiplier * 30, 0); + send_bucket_->UpdateBitrate(30, kPaceMultiplier * 30, 0); SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number, @@ -542,5 +687,56 @@ TEST_F(PacedSenderTest, QueueTimeGrowsOverTime) { send_bucket_->Process(); EXPECT_EQ(0, send_bucket_->QueueInMs()); } + +class ProbingPacedSender : public PacedSender { + public: + ProbingPacedSender(Clock* clock, + Callback* callback, + int bitrate_kbps, + int max_bitrate_kbps, + int min_bitrate_kbps) + : PacedSender(clock, + callback, + bitrate_kbps, + max_bitrate_kbps, + min_bitrate_kbps) {} + + virtual bool ProbingExperimentIsEnabled() const OVERRIDE { return true; } +}; + +TEST_F(PacedSenderTest, ProbingWithInitialFrame) { + const int kNumPackets = 15; + const int kPacketSize = 1200; + const int kInitialBitrateKbps = 300; + uint32_t ssrc = 12346; + uint16_t sequence_number = 1234; + const int expected_deltas[kNumPackets - 1] = { + 12, 12, 12, 12, 8, 8, 8, 8, 8, 5, 5, 5, 5, 5}; + std::list expected_deltas_list(expected_deltas, + expected_deltas + kNumPackets - 1); + PacedSenderProbing callback(expected_deltas_list, &clock_); + send_bucket_.reset( + new ProbingPacedSender(&clock_, + &callback, + kInitialBitrateKbps, + kPaceMultiplier * kInitialBitrateKbps, + 0)); + for (int i = 0; i < kNumPackets; ++i) { + EXPECT_FALSE(send_bucket_->SendPacket(PacedSender::kNormalPriority, + ssrc, + sequence_number++, + clock_.TimeInMilliseconds(), + kPacketSize, + false)); + } + while (callback.packets_sent() < kNumPackets) { + int time_until_process = send_bucket_->TimeUntilNextProcess(); + if (time_until_process <= 0) { + send_bucket_->Process(); + } else { + clock_.AdvanceTimeMilliseconds(time_until_process); + } + } +} } // namespace test } // namespace webrtc diff --git a/webrtc/modules/pacing/pacing.gypi b/webrtc/modules/pacing/pacing.gypi index 07b433808f..366845089f 100644 --- a/webrtc/modules/pacing/pacing.gypi +++ b/webrtc/modules/pacing/pacing.gypi @@ -16,6 +16,8 @@ ], 'sources': [ 'include/paced_sender.h', + 'bitrate_prober.cc', + 'bitrate_prober.h', 'paced_sender.cc', ], }, diff --git a/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc b/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc index 142de871cd..f47984c685 100644 --- a/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc +++ b/webrtc/modules/remote_bitrate_estimator/bwe_simulations.cc @@ -98,7 +98,7 @@ TEST_P(BweSimulation, Choke1000kbps500kbps1000kbps) { TEST_P(BweSimulation, PacerChoke1000kbps500kbps1000kbps) { VerboseLogging(true); - AdaptiveVideoSender source(0, NULL, 30, 300, 0, 0); + PeriodicKeyFrameSender source(0, NULL, 30, 300, 0, 0, 1000); PacedVideoSender sender(this, 300, &source); ChokeFilter filter(this); RateCounterFilter counter(this, "receiver_input"); @@ -111,9 +111,20 @@ TEST_P(BweSimulation, PacerChoke1000kbps500kbps1000kbps) { RunFor(60 * 1000); } +TEST_P(BweSimulation, PacerChoke10000kbps) { + VerboseLogging(true); + PeriodicKeyFrameSender source(0, NULL, 30, 300, 0, 0, 0); + PacedVideoSender sender(this, 300, &source); + ChokeFilter filter(this); + RateCounterFilter counter(this, "receiver_input"); + filter.SetCapacity(10000); + filter.SetMaxDelay(500); + RunFor(60 * 1000); +} + TEST_P(BweSimulation, PacerChoke200kbps30kbps200kbps) { VerboseLogging(true); - AdaptiveVideoSender source(0, NULL, 30, 300, 0, 0); + PeriodicKeyFrameSender source(0, NULL, 30, 300, 0, 0, 1000); PacedVideoSender sender(this, 300, &source); ChokeFilter filter(this); RateCounterFilter counter(this, "receiver_input"); @@ -151,6 +162,18 @@ TEST_P(BweSimulation, GoogleWifiTrace3Mbps) { RunFor(300 * 1000); } +TEST_P(BweSimulation, PacerGoogleWifiTrace3Mbps) { + VerboseLogging(true); + PeriodicKeyFrameSender source(0, NULL, 30, 300, 0, 0, 1000); + PacedVideoSender sender(this, 300, &source); + RateCounterFilter counter1(this, "sender_output"); + TraceBasedDeliveryFilter filter(this, "link_capacity"); + filter.SetMaxDelay(500); + RateCounterFilter counter2(this, "receiver_input"); + ASSERT_TRUE(filter.Init(test::ResourcePath("google-wifi-3mbps", "rx"))); + RunFor(300 * 1000); +} + class MultiFlowBweSimulation : public BweSimulation { public: MultiFlowBweSimulation() : BweSimulation() {} diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc index 194db4d3dc..f7a7197ebd 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.cc @@ -155,6 +155,7 @@ void Packet::set_send_time_us(int64_t send_time_us) { } void Packet::SetAbsSendTimeMs(int64_t abs_send_time_ms) { + header_.extension.hasAbsoluteSendTime = true; header_.extension.absoluteSendTime = ((static_cast(abs_send_time_ms * (1 << 18)) + 500) / 1000) & 0x00fffffful; } @@ -543,8 +544,11 @@ PacketSender::PacketSender(PacketProcessorListener* listener, } -VideoSender::VideoSender(int flow_id, PacketProcessorListener* listener, - float fps, uint32_t kbps, uint32_t ssrc, +VideoSender::VideoSender(int flow_id, + PacketProcessorListener* listener, + float fps, + uint32_t kbps, + uint32_t ssrc, float first_frame_offset) : PacketSender(listener, FlowIds(1, flow_id)), kMaxPayloadSizeBytes(1200), @@ -566,6 +570,15 @@ uint32_t VideoSender::GetCapacityKbps() const { return (bytes_per_second_ * 8) / 1000; } +uint32_t VideoSender::NextFrameSize() { + return frame_size_bytes_; +} + +uint32_t VideoSender::NextPacketSize(uint32_t frame_size, + uint32_t remaining_payload) { + return std::min(kMaxPayloadSizeBytes, remaining_payload); +} + void VideoSender::RunFor(int64_t time_ms, Packets* in_out) { assert(in_out); now_ms_ += time_ms; @@ -580,10 +593,12 @@ void VideoSender::RunFor(int64_t time_ms, Packets* in_out) { // one packet, we will see a number of equally sized packets followed by // one smaller at the tail. int64_t send_time_us = next_frame_ms_ * 1000.0; - uint32_t payload_size = frame_size_bytes_; + uint32_t frame_size = NextFrameSize(); + uint32_t payload_size = frame_size; + while (payload_size > 0) { ++prototype_header_.sequenceNumber; - uint32_t size = std::min(kMaxPayloadSizeBytes, payload_size); + uint32_t size = NextPacketSize(frame_size, payload_size); new_packets.push_back(Packet(flow_ids()[0], send_time_us, size, prototype_header_)); new_packets.back().SetAbsSendTimeMs(next_frame_ms_); @@ -601,13 +616,69 @@ AdaptiveVideoSender::AdaptiveVideoSender(int flow_id, uint32_t kbps, uint32_t ssrc, float first_frame_offset) - : VideoSender(flow_id, listener, fps, kbps, ssrc, first_frame_offset) {} + : VideoSender(flow_id, listener, fps, kbps, ssrc, first_frame_offset) { +} void AdaptiveVideoSender::GiveFeedback(const PacketSender::Feedback& feedback) { - bytes_per_second_ = feedback.estimated_bps / 8; + bytes_per_second_ = std::min(feedback.estimated_bps / 8, 2500000u / 8); frame_size_bytes_ = (bytes_per_second_ * frame_period_ms_ + 500) / 1000; } +PeriodicKeyFrameSender::PeriodicKeyFrameSender( + int flow_id, + PacketProcessorListener* listener, + float fps, + uint32_t kbps, + uint32_t ssrc, + float first_frame_offset, + int key_frame_interval) + : AdaptiveVideoSender(flow_id, + listener, + fps, + kbps, + ssrc, + first_frame_offset), + key_frame_interval_(key_frame_interval), + frame_counter_(0), + compensation_bytes_(0), + compensation_per_frame_(0) { +} + +uint32_t PeriodicKeyFrameSender::NextFrameSize() { + uint32_t payload_size = frame_size_bytes_; + if (frame_counter_ == 0) { + payload_size = kMaxPayloadSizeBytes * 12; + compensation_bytes_ = 4 * frame_size_bytes_; + compensation_per_frame_ = compensation_bytes_ / 30; + } else if (key_frame_interval_ > 0 && + (frame_counter_ % key_frame_interval_ == 0)) { + payload_size *= 5; + compensation_bytes_ = payload_size - frame_size_bytes_; + compensation_per_frame_ = compensation_bytes_ / 30; + } else if (compensation_bytes_ > 0) { + if (compensation_per_frame_ > static_cast(payload_size)) { + // Skip this frame. + compensation_bytes_ -= payload_size; + payload_size = 0; + } else { + payload_size -= compensation_per_frame_; + compensation_bytes_ -= compensation_per_frame_; + } + } + if (compensation_bytes_ < 0) + compensation_bytes_ = 0; + ++frame_counter_; + return payload_size; +} + +uint32_t PeriodicKeyFrameSender::NextPacketSize(uint32_t frame_size, + uint32_t remaining_payload) { + uint32_t fragments = + (frame_size + (kMaxPayloadSizeBytes - 1)) / kMaxPayloadSizeBytes; + uint32_t avg_size = (frame_size + fragments - 1) / fragments; + return std::min(avg_size, remaining_payload); +} + PacedVideoSender::PacedVideoSender(PacketProcessorListener* listener, uint32_t kbps, AdaptiveVideoSender* source) @@ -617,22 +688,40 @@ PacedVideoSender::PacedVideoSender(PacketProcessorListener* listener, : PacketSender(listener, source->flow_ids()), clock_(0), start_of_run_ms_(0), - pacer_(&clock_, this, PacedSender::kDefaultPaceMultiplier * kbps, 0), - source_(source) {} + pacer_(&clock_, this, kbps, PacedSender::kDefaultPaceMultiplier* kbps, 0), + source_(source) { +} void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) { start_of_run_ms_ = clock_.TimeInMilliseconds(); Packets generated_packets; source_->RunFor(time_ms, &generated_packets); - Packets::iterator it = generated_packets.begin(); // Run process periodically to allow the packets to be paced out. - const int kProcessIntervalMs = 10; - for (int64_t current_time = 0; current_time < time_ms; - current_time += kProcessIntervalMs) { - int64_t end_of_interval_us = - 1000 * (clock_.TimeInMilliseconds() + kProcessIntervalMs); - while (it != generated_packets.end() && - end_of_interval_us >= it->send_time_us()) { + int64_t end_time_ms = clock_.TimeInMilliseconds() + time_ms; + Packets::iterator it = generated_packets.begin(); + while (clock_.TimeInMilliseconds() <= end_time_ms) { + int time_until_process_ms = pacer_.TimeUntilNextProcess(); + if (time_until_process_ms < 0) + time_until_process_ms = 0; + int time_until_packet_ms = time_ms; + if (it != generated_packets.end()) + time_until_packet_ms = + (it->send_time_us() + 500) / 1000 - clock_.TimeInMilliseconds(); + assert(time_until_packet_ms >= 0); + int time_until_next_event_ms = time_until_packet_ms; + if (time_until_process_ms < time_until_packet_ms && + pacer_.QueueSizePackets() > 0) + time_until_next_event_ms = time_until_process_ms; + + if (clock_.TimeInMilliseconds() + time_until_next_event_ms > end_time_ms) { + clock_.AdvanceTimeMilliseconds(end_time_ms - clock_.TimeInMilliseconds()); + break; + } + clock_.AdvanceTimeMilliseconds(time_until_next_event_ms); + if (time_until_process_ms < time_until_packet_ms) { + // Time to process. + pacer_.Process(); + } else { // Time to send next packet to pacer. pacer_.SendPacket(PacedSender::kNormalPriority, it->header().ssrc, @@ -641,16 +730,14 @@ void PacedVideoSender::RunFor(int64_t time_ms, Packets* in_out) { it->payload_size(), false); pacer_queue_.push_back(*it); - const size_t kMaxPacerQueueSize = 1000; + const size_t kMaxPacerQueueSize = 10000; if (pacer_queue_.size() > kMaxPacerQueueSize) { pacer_queue_.pop_front(); } ++it; } - clock_.AdvanceTimeMilliseconds(kProcessIntervalMs); - pacer_.Process(); } - QueuePackets(in_out, (start_of_run_ms_ + time_ms) * 1000); + QueuePackets(in_out, end_time_ms * 1000); } void PacedVideoSender::QueuePackets(Packets* batch, @@ -673,7 +760,9 @@ void PacedVideoSender::QueuePackets(Packets* batch, void PacedVideoSender::GiveFeedback(const PacketSender::Feedback& feedback) { source_->GiveFeedback(feedback); pacer_.UpdateBitrate( - PacedSender::kDefaultPaceMultiplier * feedback.estimated_bps / 1000, 0); + feedback.estimated_bps / 1000, + PacedSender::kDefaultPaceMultiplier * feedback.estimated_bps / 1000, + 0); } bool PacedVideoSender::TimeToSendPacket(uint32_t ssrc, @@ -686,7 +775,7 @@ bool PacedVideoSender::TimeToSendPacket(uint32_t ssrc, int64_t pace_out_time_ms = clock_.TimeInMilliseconds(); // Make sure a packet is never paced out earlier than when it was put into // the pacer. - assert(1000 * pace_out_time_ms >= it->send_time_us()); + assert(pace_out_time_ms >= (it->send_time_us() + 500) / 1000); it->SetAbsSendTimeMs(pace_out_time_ms); it->set_send_time_us(1000 * pace_out_time_ms); queue_.push_back(*it); diff --git a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h index 0ab3b5f9db..60981976ae 100644 --- a/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h +++ b/webrtc/modules/remote_bitrate_estimator/test/bwe_test_framework.h @@ -387,8 +387,12 @@ class PacketSender : public PacketProcessor { class VideoSender : public PacketSender { public: - VideoSender(int flow_id, PacketProcessorListener* listener, float fps, - uint32_t kbps, uint32_t ssrc, float first_frame_offset); + VideoSender(int flow_id, + PacketProcessorListener* listener, + float fps, + uint32_t kbps, + uint32_t ssrc, + float first_frame_offset); virtual ~VideoSender() {} uint32_t max_payload_size_bytes() const { return kMaxPayloadSizeBytes; } @@ -399,6 +403,10 @@ class VideoSender : public PacketSender { virtual void RunFor(int64_t time_ms, Packets* in_out) OVERRIDE; protected: + virtual uint32_t NextFrameSize(); + virtual uint32_t NextPacketSize(uint32_t frame_size, + uint32_t remaining_payload); + const uint32_t kMaxPayloadSizeBytes; const uint32_t kTimestampBase; const double frame_period_ms_; @@ -427,6 +435,30 @@ class AdaptiveVideoSender : public VideoSender { DISALLOW_IMPLICIT_CONSTRUCTORS(AdaptiveVideoSender); }; +class PeriodicKeyFrameSender : public AdaptiveVideoSender { + public: + PeriodicKeyFrameSender(int flow_id, + PacketProcessorListener* listener, + float fps, + uint32_t kbps, + uint32_t ssrc, + float first_frame_offset, + int key_frame_interval); + virtual ~PeriodicKeyFrameSender() {} + + protected: + virtual uint32_t NextFrameSize() OVERRIDE; + virtual uint32_t NextPacketSize(uint32_t frame_size, + uint32_t remaining_payload) OVERRIDE; + + private: + int key_frame_interval_; + uint32_t frame_counter_; + int compensation_bytes_; + int compensation_per_frame_; + DISALLOW_IMPLICIT_CONSTRUCTORS(PeriodicKeyFrameSender); +}; + class PacedVideoSender : public PacketSender, public PacedSender::Callback { public: PacedVideoSender(PacketProcessorListener* listener, @@ -445,12 +477,28 @@ class PacedVideoSender : public PacketSender, public PacedSender::Callback { virtual int TimeToSendPadding(int bytes) OVERRIDE; private: + class ProbingPacedSender : public PacedSender { + public: + ProbingPacedSender(Clock* clock, + Callback* callback, + int bitrate_kbps, + int max_bitrate_kbps, + int min_bitrate_kbps) + : PacedSender(clock, + callback, + bitrate_kbps, + max_bitrate_kbps, + min_bitrate_kbps) {} + + virtual bool ProbingExperimentIsEnabled() const OVERRIDE { return true; } + }; + void QueuePackets(Packets* batch, int64_t end_of_batch_time_us); static const int64_t kInitialTimeMs = 0; SimulatedClock clock_; int64_t start_of_run_ms_; - PacedSender pacer_; + ProbingPacedSender pacer_; Packets pacer_queue_; Packets queue_; AdaptiveVideoSender* source_; diff --git a/webrtc/modules/video_coding/main/interface/video_coding_defines.h b/webrtc/modules/video_coding/main/interface/video_coding_defines.h index c5f93cb177..0919c892c1 100644 --- a/webrtc/modules/video_coding/main/interface/video_coding_defines.h +++ b/webrtc/modules/video_coding/main/interface/video_coding_defines.h @@ -42,6 +42,8 @@ namespace webrtc { #define VCM_I420_PAYLOAD_TYPE 124 #define VCM_H264_PAYLOAD_TYPE 127 +enum { kDefaultStartBitrateKbps = 300 }; + enum VCMVideoProtection { kProtectionNack, // Both send-side and receive-side kProtectionNackSender, // Send-side only diff --git a/webrtc/modules/video_coding/main/source/codec_database.cc b/webrtc/modules/video_coding/main/source/codec_database.cc index cd8f9d35f5..e99cc52880 100644 --- a/webrtc/modules/video_coding/main/source/codec_database.cc +++ b/webrtc/modules/video_coding/main/source/codec_database.cc @@ -114,7 +114,7 @@ bool VCMCodecDataBase::Codec(int list_id, settings->codecType = kVideoCodecVP8; // 96 to 127 dynamic payload types for video codecs. settings->plType = VCM_VP8_PAYLOAD_TYPE; - settings->startBitrate = 100; + settings->startBitrate = kDefaultStartBitrateKbps; settings->minBitrate = VCM_MIN_BITRATE; settings->maxBitrate = 0; settings->maxFramerate = VCM_DEFAULT_FRAME_RATE; @@ -132,7 +132,7 @@ bool VCMCodecDataBase::Codec(int list_id, settings->codecType = kVideoCodecH264; // 96 to 127 dynamic payload types for video codecs. settings->plType = VCM_H264_PAYLOAD_TYPE; - settings->startBitrate = 100; + settings->startBitrate = kDefaultStartBitrateKbps; settings->minBitrate = VCM_MIN_BITRATE; settings->maxBitrate = 0; settings->maxFramerate = VCM_DEFAULT_FRAME_RATE; diff --git a/webrtc/video_engine/vie_encoder.cc b/webrtc/video_engine/vie_encoder.cc index 0955066b11..26ad8acef4 100644 --- a/webrtc/video_engine/vie_encoder.cc +++ b/webrtc/video_engine/vie_encoder.cc @@ -109,8 +109,10 @@ class ViEPacedSenderCallback : public PacedSender::Callback { : owner_(owner) { } virtual ~ViEPacedSenderCallback() {} - virtual bool TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number, - int64_t capture_time_ms, bool retransmission) { + virtual bool TimeToSendPacket(uint32_t ssrc, + uint16_t sequence_number, + int64_t capture_time_ms, + bool retransmission) { return owner_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms, retransmission); } @@ -162,9 +164,12 @@ ViEEncoder::ViEEncoder(int32_t engine_id, default_rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(configuration)); bitrate_observer_.reset(new ViEBitrateObserver(this)); pacing_callback_.reset(new ViEPacedSenderCallback(this)); - paced_sender_.reset( - new PacedSender(Clock::GetRealTimeClock(), pacing_callback_.get(), - PacedSender::kDefaultInitialPaceKbps, 0)); + paced_sender_.reset(new PacedSender( + Clock::GetRealTimeClock(), + pacing_callback_.get(), + kDefaultStartBitrateKbps, + PacedSender::kDefaultPaceMultiplier * kDefaultStartBitrateKbps, + 0)); } bool ViEEncoder::Init() { @@ -368,6 +373,7 @@ int32_t ViEEncoder::SetEncoder(const webrtc::VideoCodec& video_codec) { pad_up_to_bitrate_kbps = min_transmit_bitrate_kbps_; paced_sender_->UpdateBitrate( + video_codec.startBitrate, PacedSender::kDefaultPaceMultiplier * video_codec.startBitrate, pad_up_to_bitrate_kbps); @@ -885,6 +891,7 @@ void ViEEncoder::OnNetworkChanged(const uint32_t bitrate_bps, pad_up_to_bitrate_kbps = bitrate_kbps; paced_sender_->UpdateBitrate( + bitrate_kbps, PacedSender::kDefaultPaceMultiplier * bitrate_kbps, pad_up_to_bitrate_kbps); default_rtp_rtcp_->SetTargetSendBitrate(stream_bitrates);