Adds support for sending first set of packets at increasingly higher bitrates to probe the link and faster ramp up to a high bitrate.
Also wires up a finch experiment to control this. R=mflodman@webrtc.org Review URL: https://webrtc-codereview.appspot.com/30639004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7505 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@ -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_);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
source_set("pacing") {
|
||||
sources = [
|
||||
"include/paced_sender.h",
|
||||
"bitrate_prober.cc",
|
||||
"bitrate_prober.h",
|
||||
"paced_sender.cc",
|
||||
]
|
||||
|
||||
|
||||
120
webrtc/modules/pacing/bitrate_prober.cc
Normal file
120
webrtc/modules/pacing/bitrate_prober.cc
Normal file
@ -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 <assert.h>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#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<int>(1000ll * static_cast<int64_t>(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<int>::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
|
||||
57
webrtc/modules/pacing/bitrate_prober.h
Normal file
57
webrtc/modules/pacing/bitrate_prober.h
Normal file
@ -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 <cstddef>
|
||||
#include <list>
|
||||
|
||||
#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<int> probe_bitrates_;
|
||||
size_t packet_size_last_send_;
|
||||
int64_t time_last_send_ms_;
|
||||
};
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_PACING_BITRATE_PROBER_H_
|
||||
57
webrtc/modules/pacing/bitrate_prober_unittest.cc
Normal file
57
webrtc/modules/pacing/bitrate_prober_unittest.cc
Normal file
@ -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 <limits>
|
||||
|
||||
#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<int>::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<int>::max(), prober.TimeUntilNextProbe(now_ms));
|
||||
EXPECT_FALSE(prober.IsProbing());
|
||||
}
|
||||
} // namespace webrtc
|
||||
@ -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,
|
||||
|
||||
@ -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 <list>
|
||||
#include <set>
|
||||
@ -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<paced_sender::IntervalBudget> padding_budget_
|
||||
GUARDED_BY(critsect_);
|
||||
|
||||
scoped_ptr<BitrateProber> 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_
|
||||
|
||||
@ -16,8 +16,11 @@
|
||||
#include <set>
|
||||
|
||||
#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<uint32_t, std::set<uint16_t> >::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<int>((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
|
||||
|
||||
@ -8,9 +8,10 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
|
||||
#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<int>& 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<int> 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<int> 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
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
],
|
||||
'sources': [
|
||||
'include/paced_sender.h',
|
||||
'bitrate_prober.cc',
|
||||
'bitrate_prober.h',
|
||||
'paced_sender.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() {}
|
||||
|
||||
@ -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<int64_t>(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<int>(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);
|
||||
|
||||
@ -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_;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
Reference in New Issue
Block a user