From c3cc375499b16d463346408dc62f73493b2ee4e5 Mon Sep 17 00:00:00 2001 From: "stefan@webrtc.org" Date: Tue, 4 Jun 2013 09:36:56 +0000 Subject: [PATCH] Add support for padding in pacer. This improves pacer-based padding by making sure it limits padding according to: - Never pad more than 800 kbps. - Padding + media should not go above a given target bitrate. Also adds appropriate unittests to make sure we reach the given targets. BUG=1837 R=mflodman@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1582005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4168 4adac7df-926f-26a2-2b94-8c16560cd09d --- webrtc/modules/pacing/include/paced_sender.h | 71 ++--- webrtc/modules/pacing/paced_sender.cc | 292 ++++++++++-------- .../modules/pacing/paced_sender_unittest.cc | 98 +++++- .../main/interface/video_coding.h | 2 +- webrtc/video_engine/vie_channel.cc | 6 +- webrtc/video_engine/vie_encoder.cc | 6 +- 6 files changed, 304 insertions(+), 171 deletions(-) diff --git a/webrtc/modules/pacing/include/paced_sender.h b/webrtc/modules/pacing/include/paced_sender.h index 837af27b20..0eeb9921a4 100644 --- a/webrtc/modules/pacing/include/paced_sender.h +++ b/webrtc/modules/pacing/include/paced_sender.h @@ -21,6 +21,11 @@ namespace webrtc { class CriticalSectionWrapper; +namespace paced_sender { +class IntervalBudget; +struct Packet; +class PacketList; +} // namespace paced_sender class PacedSender : public Module { public: @@ -40,7 +45,7 @@ class PacedSender : public Module { virtual void TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number, int64_t capture_time_ms) = 0; // Called when it's a good time to send a padding data. - virtual void TimeToSendPadding(int bytes) = 0; + virtual int TimeToSendPadding(int bytes) = 0; protected: virtual ~Callback() {} }; @@ -52,14 +57,19 @@ class PacedSender : public Module { // Enable/disable pacing. void SetStatus(bool enable); + bool Enabled() const; + // Temporarily pause all sending. void Pause(); // Resume sending packets. void Resume(); - // Current total estimated bitrate. - void UpdateBitrate(int target_bitrate_kbps); + // Set the pacing target bitrate and the bitrate up to which we are allowed to + // pad. We will send padding packets to increase the total bitrate until we + // reach |pad_up_to_bitrate_kbps|. If the media bitrate is above + // |pad_up_to_bitrate_kbps| no padding will be sent. + void UpdateBitrate(int target_bitrate_kbps, int pad_up_to_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. @@ -80,42 +90,13 @@ class PacedSender : public Module { virtual int32_t Process(); private: - struct Packet { - Packet(uint32_t ssrc, uint16_t seq_number, int64_t capture_time_ms, - int length_in_bytes) - : ssrc_(ssrc), - sequence_number_(seq_number), - capture_time_ms_(capture_time_ms), - bytes_(length_in_bytes) { - } - uint32_t ssrc_; - uint16_t sequence_number_; - int64_t capture_time_ms_; - int bytes_; - }; - - // STL list style class which prevents duplicates in the list. - class PacketList { - public: - PacketList() {}; - - bool empty() const; - Packet front() const; - void pop_front(); - void push_back(const Packet& packet); - - private: - std::list packet_list_; - std::set sequence_number_set_; - }; - // Checks if next packet in line can be transmitted. Returns true on success. bool GetNextPacket(uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms, Priority* priority, bool* last_packet); // Local helper function to GetNextPacket. - void GetNextPacketFromList(PacketList* list, + void GetNextPacketFromList(paced_sender::PacketList* packets, uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms, bool* last_packet); @@ -123,24 +104,32 @@ class PacedSender : public Module { void UpdateBytesPerInterval(uint32_t delta_time_in_ms); // Updates the buffers with the number of bytes that we sent. - void UpdateState(int num_bytes); + void UpdateMediaBytesSent(int num_bytes); Callback* callback_; const float pace_multiplier_; - bool enable_; + bool enabled_; bool paused_; scoped_ptr critsect_; - int target_bitrate_kbytes_per_s_; - int bytes_remaining_interval_; - int padding_bytes_remaining_interval_; + // This is the media budget, keeping track of how many bits of media + // we can pace out during the current interval. + scoped_ptr media_budget_; + // This is the padding budget, keeping track of how many bits of padding we're + // allowed to send out during the current interval. + scoped_ptr padding_budget_; + // Media and padding share this budget, therefore no padding will be sent if + // media uses all of this budget. This is used to avoid padding above a given + // bitrate. + scoped_ptr pad_up_to_bitrate_budget_; + TickTime time_last_update_; TickTime time_last_send_; int64_t capture_time_ms_last_queued_; int64_t capture_time_ms_last_sent_; - PacketList high_priority_packets_; - PacketList normal_priority_packets_; - PacketList low_priority_packets_; + scoped_ptr high_priority_packets_; + scoped_ptr normal_priority_packets_; + scoped_ptr low_priority_packets_; }; } // namespace webrtc #endif // WEBRTC_MODULES_PACED_SENDER_H_ diff --git a/webrtc/modules/pacing/paced_sender.cc b/webrtc/modules/pacing/paced_sender.cc index 3cee8e177d..16629ac57d 100644 --- a/webrtc/modules/pacing/paced_sender.cc +++ b/webrtc/modules/pacing/paced_sender.cc @@ -28,47 +28,115 @@ const int kMaxIntervalTimeMs = 30; // packets are sent, regardless of buffer state. In practice only in effect at // low bitrates (less than 320 kbits/s). const int kMaxQueueTimeWithoutSendingMs = 30; + +// Max padding bytes per second. +const int kMaxPaddingKbps = 800; + } // namespace namespace webrtc { -bool PacedSender::PacketList::empty() const { - return packet_list_.empty(); -} - -PacedSender::Packet PacedSender::PacketList::front() const { - return packet_list_.front(); -} - -void PacedSender::PacketList::pop_front() { - PacedSender::Packet& packet = packet_list_.front(); - uint16_t sequence_number = packet.sequence_number_; - packet_list_.pop_front(); - sequence_number_set_.erase(sequence_number); -} - -void PacedSender::PacketList::push_back(const PacedSender::Packet& packet) { - if (sequence_number_set_.find(packet.sequence_number_) == - sequence_number_set_.end()) { - // Don't insert duplicates. - packet_list_.push_back(packet); - sequence_number_set_.insert(packet.sequence_number_); +namespace paced_sender { +struct Packet { + Packet(uint32_t ssrc, uint16_t seq_number, int64_t capture_time_ms, + int length_in_bytes) + : ssrc_(ssrc), + sequence_number_(seq_number), + capture_time_ms_(capture_time_ms), + bytes_(length_in_bytes) { } -} + uint32_t ssrc_; + uint16_t sequence_number_; + int64_t capture_time_ms_; + int bytes_; +}; + +// STL list style class which prevents duplicates in the list. +class PacketList { + public: + PacketList() {}; + + bool empty() const { + return packet_list_.empty(); + } + + Packet front() const { + return packet_list_.front(); + } + + void pop_front() { + Packet& packet = packet_list_.front(); + uint16_t sequence_number = packet.sequence_number_; + packet_list_.pop_front(); + sequence_number_set_.erase(sequence_number); + } + + void push_back(const Packet& packet) { + if (sequence_number_set_.find(packet.sequence_number_) == + sequence_number_set_.end()) { + // Don't insert duplicates. + packet_list_.push_back(packet); + sequence_number_set_.insert(packet.sequence_number_); + } + } + + private: + std::list packet_list_; + std::set sequence_number_set_; +}; + +class IntervalBudget { + public: + explicit IntervalBudget(int initial_target_rate_kbps) + : target_rate_kbps_(initial_target_rate_kbps), + bytes_remaining_(0) {} + + void set_target_rate_kbps(int target_rate_kbps) { + target_rate_kbps_ = target_rate_kbps; + } + + void IncreaseBudget(int delta_time_ms) { + int bytes = target_rate_kbps_ * delta_time_ms / 8; + if (bytes_remaining_ < 0) { + // We overused last interval, compensate this interval. + bytes_remaining_ = bytes_remaining_ + bytes; + } else { + // If we underused last interval we can't use it this interval. + bytes_remaining_ = bytes; + } + } + + void UseBudget(int bytes) { + bytes_remaining_ = std::max(bytes_remaining_ - bytes, + -100 * target_rate_kbps_ / 8); + } + + int bytes_remaining() const { return bytes_remaining_; } + + private: + int target_rate_kbps_; + int bytes_remaining_; +}; +} // namespace paced_sender PacedSender::PacedSender(Callback* callback, int target_bitrate_kbps, float pace_multiplier) : callback_(callback), pace_multiplier_(pace_multiplier), - enable_(false), + enabled_(false), paused_(false), critsect_(CriticalSectionWrapper::CreateCriticalSection()), - target_bitrate_kbytes_per_s_(target_bitrate_kbps >> 3), // Divide by 8. - bytes_remaining_interval_(0), - padding_bytes_remaining_interval_(0), + media_budget_(new paced_sender::IntervalBudget( + pace_multiplier_ * target_bitrate_kbps)), + padding_budget_(new paced_sender::IntervalBudget(kMaxPaddingKbps)), + // No padding until UpdateBitrate is called. + pad_up_to_bitrate_budget_(new paced_sender::IntervalBudget(0)), time_last_update_(TickTime::Now()), capture_time_ms_last_queued_(0), - capture_time_ms_last_sent_(0) { + capture_time_ms_last_sent_(0), + high_priority_packets_(new paced_sender::PacketList), + normal_priority_packets_(new paced_sender::PacketList), + low_priority_packets_(new paced_sender::PacketList) { UpdateBytesPerInterval(kMinPacketLimitMs); } @@ -87,20 +155,27 @@ void PacedSender::Resume() { void PacedSender::SetStatus(bool enable) { CriticalSectionScoped cs(critsect_.get()); - enable_ = enable; + enabled_ = enable; } -void PacedSender::UpdateBitrate(int target_bitrate_kbps) { +bool PacedSender::Enabled() const { CriticalSectionScoped cs(critsect_.get()); - target_bitrate_kbytes_per_s_ = target_bitrate_kbps >> 3; // Divide by 8. + return enabled_; +} + +void PacedSender::UpdateBitrate(int target_bitrate_kbps, + int pad_up_to_bitrate_kbps) { + CriticalSectionScoped cs(critsect_.get()); + media_budget_->set_target_rate_kbps(pace_multiplier_ * target_bitrate_kbps); + pad_up_to_bitrate_budget_->set_target_rate_kbps(pad_up_to_bitrate_kbps); } bool PacedSender::SendPacket(Priority priority, uint32_t ssrc, uint16_t sequence_number, int64_t capture_time_ms, int bytes) { CriticalSectionScoped cs(critsect_.get()); - if (!enable_) { - UpdateState(bytes); + if (!enabled_) { + UpdateMediaBytesSent(bytes); return true; // We can send now. } if (capture_time_ms < 0) { @@ -110,8 +185,10 @@ bool PacedSender::SendPacket(Priority priority, uint32_t ssrc, // Queue all packets when we are paused. switch (priority) { case kHighPriority: - high_priority_packets_.push_back( - Packet(ssrc, sequence_number, capture_time_ms, bytes)); + high_priority_packets_->push_back(paced_sender::Packet(ssrc, + sequence_number, + capture_time_ms, + bytes)); break; case kNormalPriority: if (capture_time_ms > capture_time_ms_last_queued_) { @@ -122,50 +199,31 @@ bool PacedSender::SendPacket(Priority priority, uint32_t ssrc, case kLowPriority: // Queue the low priority packets in the normal priority queue when we // are paused to avoid starvation. - normal_priority_packets_.push_back( - Packet(ssrc, sequence_number, capture_time_ms, bytes)); + normal_priority_packets_->push_back(paced_sender::Packet( + ssrc, sequence_number, capture_time_ms, bytes)); break; } return false; } - + paced_sender::PacketList* packet_list; switch (priority) { case kHighPriority: - if (high_priority_packets_.empty() && - bytes_remaining_interval_ > 0) { - UpdateState(bytes); - return true; // We can send now. - } - high_priority_packets_.push_back( - Packet(ssrc, sequence_number, capture_time_ms, bytes)); - return false; + packet_list = high_priority_packets_.get(); + break; case kNormalPriority: - if (high_priority_packets_.empty() && - normal_priority_packets_.empty() && - bytes_remaining_interval_ > 0) { - UpdateState(bytes); - return true; // We can send now. - } - if (capture_time_ms > capture_time_ms_last_queued_) { - capture_time_ms_last_queued_ = capture_time_ms; - TRACE_EVENT_ASYNC_BEGIN1("webrtc_rtp", "PacedSend", capture_time_ms, - "capture_time_ms", capture_time_ms); - } - normal_priority_packets_.push_back( - Packet(ssrc, sequence_number, capture_time_ms, bytes)); - return false; + packet_list = normal_priority_packets_.get(); + break; case kLowPriority: - if (high_priority_packets_.empty() && - normal_priority_packets_.empty() && - low_priority_packets_.empty() && - bytes_remaining_interval_ > 0) { - UpdateState(bytes); - return true; // We can send now. - } - low_priority_packets_.push_back( - Packet(ssrc, sequence_number, capture_time_ms, bytes)); - return false; + packet_list = low_priority_packets_.get(); + break; } + if (packet_list->empty() && + media_budget_->bytes_remaining() > 0) { + UpdateMediaBytesSent(bytes); + return true; // We can send now. + } + packet_list->push_back(paced_sender::Packet(ssrc, sequence_number, + capture_time_ms, bytes)); return false; } @@ -173,20 +231,20 @@ int PacedSender::QueueInMs() const { CriticalSectionScoped cs(critsect_.get()); int64_t now_ms = TickTime::MillisecondTimestamp(); int64_t oldest_packet_capture_time = now_ms; - if (!high_priority_packets_.empty()) { + if (!high_priority_packets_->empty()) { oldest_packet_capture_time = std::min( oldest_packet_capture_time, - high_priority_packets_.front().capture_time_ms_); + high_priority_packets_->front().capture_time_ms_); } - if (!normal_priority_packets_.empty()) { + if (!normal_priority_packets_->empty()) { oldest_packet_capture_time = std::min( oldest_packet_capture_time, - normal_priority_packets_.front().capture_time_ms_); + normal_priority_packets_->front().capture_time_ms_); } - if (!low_priority_packets_.empty()) { + if (!low_priority_packets_->empty()) { oldest_packet_capture_time = std::min( oldest_packet_capture_time, - low_priority_packets_.front().capture_time_ms_); + low_priority_packets_->front().capture_time_ms_); } return now_ms - oldest_packet_capture_time; } @@ -231,15 +289,20 @@ int32_t PacedSender::Process() { callback_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms); critsect_->Enter(); } - if (high_priority_packets_.empty() && - normal_priority_packets_.empty() && - low_priority_packets_.empty() && - padding_bytes_remaining_interval_ > 0) { + if (high_priority_packets_->empty() && + normal_priority_packets_->empty() && + low_priority_packets_->empty() && + padding_budget_->bytes_remaining() > 0 && + pad_up_to_bitrate_budget_->bytes_remaining() > 0) { + int padding_needed = std::min( + padding_budget_->bytes_remaining(), + pad_up_to_bitrate_budget_->bytes_remaining()); critsect_->Leave(); - callback_->TimeToSendPadding(padding_bytes_remaining_interval_); + int bytes_sent = callback_->TimeToSendPadding(padding_needed); critsect_->Enter(); - padding_bytes_remaining_interval_ = 0; - bytes_remaining_interval_ -= padding_bytes_remaining_interval_; + media_budget_->UseBudget(bytes_sent); + padding_budget_->UseBudget(bytes_sent); + pad_up_to_bitrate_budget_->UseBudget(bytes_sent); } } return 0; @@ -247,87 +310,74 @@ int32_t PacedSender::Process() { // MUST have critsect_ when calling. void PacedSender::UpdateBytesPerInterval(uint32_t delta_time_ms) { - uint32_t bytes_per_interval = target_bitrate_kbytes_per_s_ * delta_time_ms; - - if (bytes_remaining_interval_ < 0) { - // We overused last interval, compensate this interval. - bytes_remaining_interval_ += pace_multiplier_ * bytes_per_interval; - } else { - // If we underused last interval we can't use it this interval. - bytes_remaining_interval_ = pace_multiplier_ * bytes_per_interval; - } - if (padding_bytes_remaining_interval_ < 0) { - // We overused last interval, compensate this interval. - padding_bytes_remaining_interval_ += bytes_per_interval; - } else { - // If we underused last interval we can't use it this interval. - padding_bytes_remaining_interval_ = bytes_per_interval; - } + media_budget_->IncreaseBudget(delta_time_ms); + padding_budget_->IncreaseBudget(delta_time_ms); + pad_up_to_bitrate_budget_->IncreaseBudget(delta_time_ms); } // MUST have critsect_ when calling. bool PacedSender::GetNextPacket(uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms, Priority* priority, bool* last_packet) { - if (bytes_remaining_interval_ <= 0) { + if (media_budget_->bytes_remaining() <= 0) { // All bytes consumed for this interval. // Check if we have not sent in a too long time. if ((TickTime::Now() - time_last_send_).Milliseconds() > kMaxQueueTimeWithoutSendingMs) { - if (!high_priority_packets_.empty()) { + if (!high_priority_packets_->empty()) { *priority = kHighPriority; - GetNextPacketFromList(&high_priority_packets_, ssrc, sequence_number, - capture_time_ms, last_packet); + GetNextPacketFromList(high_priority_packets_.get(), ssrc, + sequence_number, capture_time_ms, last_packet); return true; } - if (!normal_priority_packets_.empty()) { + if (!normal_priority_packets_->empty()) { *priority = kNormalPriority; - GetNextPacketFromList(&normal_priority_packets_, ssrc, sequence_number, - capture_time_ms, last_packet); + GetNextPacketFromList(normal_priority_packets_.get(), ssrc, + sequence_number, capture_time_ms, last_packet); return true; } } return false; } - if (!high_priority_packets_.empty()) { + if (!high_priority_packets_->empty()) { *priority = kHighPriority; - GetNextPacketFromList(&high_priority_packets_, ssrc, sequence_number, + GetNextPacketFromList(high_priority_packets_.get(), ssrc, sequence_number, capture_time_ms, last_packet); return true; } - if (!normal_priority_packets_.empty()) { + if (!normal_priority_packets_->empty()) { *priority = kNormalPriority; - GetNextPacketFromList(&normal_priority_packets_, ssrc, sequence_number, - capture_time_ms, last_packet); + GetNextPacketFromList(normal_priority_packets_.get(), ssrc, + sequence_number, capture_time_ms, last_packet); return true; } - if (!low_priority_packets_.empty()) { + if (!low_priority_packets_->empty()) { *priority = kLowPriority; - GetNextPacketFromList(&low_priority_packets_, ssrc, sequence_number, + GetNextPacketFromList(low_priority_packets_.get(), ssrc, sequence_number, capture_time_ms, last_packet); return true; } return false; } -void PacedSender::GetNextPacketFromList(PacketList* list, +void PacedSender::GetNextPacketFromList(paced_sender::PacketList* packets, uint32_t* ssrc, uint16_t* sequence_number, int64_t* capture_time_ms, bool* last_packet) { - Packet packet = list->front(); - UpdateState(packet.bytes_); + paced_sender::Packet packet = packets->front(); + UpdateMediaBytesSent(packet.bytes_); *sequence_number = packet.sequence_number_; *ssrc = packet.ssrc_; *capture_time_ms = packet.capture_time_ms_; - list->pop_front(); - *last_packet = list->empty() || - list->front().capture_time_ms_ > *capture_time_ms; + packets->pop_front(); + *last_packet = packets->empty() || + packets->front().capture_time_ms_ > *capture_time_ms; } // MUST have critsect_ when calling. -void PacedSender::UpdateState(int num_bytes) { +void PacedSender::UpdateMediaBytesSent(int num_bytes) { time_last_send_ = TickTime::Now(); - bytes_remaining_interval_ -= num_bytes; - padding_bytes_remaining_interval_ -= num_bytes; + media_budget_->UseBudget(num_bytes); + pad_up_to_bitrate_budget_->UseBudget(num_bytes); } } // namespace webrtc diff --git a/webrtc/modules/pacing/paced_sender_unittest.cc b/webrtc/modules/pacing/paced_sender_unittest.cc index 247366c6b5..49d18eef43 100644 --- a/webrtc/modules/pacing/paced_sender_unittest.cc +++ b/webrtc/modules/pacing/paced_sender_unittest.cc @@ -14,6 +14,7 @@ #include "webrtc/modules/pacing/include/paced_sender.h" using testing::_; +using testing::Return; namespace webrtc { namespace test { @@ -26,18 +27,41 @@ class MockPacedSenderCallback : public PacedSender::Callback { MOCK_METHOD3(TimeToSendPacket, void(uint32_t ssrc, uint16_t sequence_number, int64_t capture_time_ms)); MOCK_METHOD1(TimeToSendPadding, - void(int bytes)); + int(int bytes)); +}; + +class PacedSenderPadding : public PacedSender::Callback { + public: + PacedSenderPadding() : padding_sent_(0) {} + + void TimeToSendPacket(uint32_t ssrc, uint16_t sequence_number, + int64_t capture_time_ms) { + } + + int TimeToSendPadding(int bytes) { + const int kPaddingPacketSize = 224; + int num_packets = (bytes + kPaddingPacketSize - 1) / kPaddingPacketSize; + padding_sent_ += kPaddingPacketSize * num_packets; + return kPaddingPacketSize * num_packets; + } + + int padding_sent() { return padding_sent_; } + + private: + int padding_sent_; }; class PacedSenderTest : public ::testing::Test { protected: PacedSenderTest() { + srand(0); TickTime::UseFakeClock(123456); // Need to initialize PacedSender after we initialize clock. send_bucket_.reset(new PacedSender(&callback_, kTargetBitrate, kPaceMultiplier)); send_bucket_->SetStatus(true); } + MockPacedSenderCallback callback_; scoped_ptr send_bucket_; }; @@ -164,6 +188,7 @@ TEST_F(PacedSenderTest, Padding) { uint16_t sequence_number = 1234; int64_t capture_time_ms = 56789; + send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate); // Due to the multiplicative factor we can send 3 packets not 2 packets. EXPECT_TRUE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, capture_time_ms, 250)); @@ -171,7 +196,8 @@ TEST_F(PacedSenderTest, Padding) { sequence_number++, capture_time_ms, 250)); EXPECT_TRUE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, capture_time_ms, 250)); - EXPECT_CALL(callback_, TimeToSendPadding(250)).Times(1); + // No padding is expected since we have sent too much already. + EXPECT_CALL(callback_, TimeToSendPadding(_)).Times(0); EXPECT_CALL(callback_, TimeToSendPacket(ssrc, sequence_number, capture_time_ms)).Times(0); EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess()); @@ -179,13 +205,79 @@ TEST_F(PacedSenderTest, Padding) { EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess()); EXPECT_EQ(0, send_bucket_->Process()); - EXPECT_CALL(callback_, TimeToSendPadding(500)).Times(1); + // 5 milliseconds later we have enough budget to send some padding. + EXPECT_CALL(callback_, TimeToSendPadding(250)).Times(1). + WillOnce(Return(250)); EXPECT_EQ(5, send_bucket_->TimeUntilNextProcess()); TickTime::AdvanceFakeClock(5); EXPECT_EQ(0, send_bucket_->TimeUntilNextProcess()); EXPECT_EQ(0, send_bucket_->Process()); } +TEST_F(PacedSenderTest, VerifyPaddingUpToBitrate) { + uint32_t ssrc = 12345; + uint16_t sequence_number = 1234; + int64_t capture_time_ms = 56789; + const int kTimeStep = 5; + const int64_t kBitrateWindow = 100; + send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate); + int64_t start_time = TickTime::MillisecondTimestamp(); + while (TickTime::MillisecondTimestamp() - start_time < kBitrateWindow) { + EXPECT_TRUE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc, + sequence_number++, capture_time_ms, + 250)); + TickTime::AdvanceFakeClock(kTimeStep); + EXPECT_CALL(callback_, TimeToSendPadding(250)).Times(1). + WillOnce(Return(250)); + send_bucket_->Process(); + } +} + +TEST_F(PacedSenderTest, VerifyMaxPaddingBitrate) { + uint32_t ssrc = 12345; + uint16_t sequence_number = 1234; + int64_t capture_time_ms = 56789; + const int kTimeStep = 5; + const int64_t kBitrateWindow = 100; + const int kTargetBitrate = 1500; + send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate); + int64_t start_time = TickTime::MillisecondTimestamp(); + while (TickTime::MillisecondTimestamp() - start_time < kBitrateWindow) { + EXPECT_TRUE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc, + sequence_number++, capture_time_ms, + 250)); + TickTime::AdvanceFakeClock(kTimeStep); + EXPECT_CALL(callback_, TimeToSendPadding(500)).Times(1). + WillOnce(Return(250)); + send_bucket_->Process(); + } +} + +TEST_F(PacedSenderTest, VerifyAverageBitrateVaryingMediaPayload) { + uint32_t ssrc = 12345; + uint16_t sequence_number = 1234; + int64_t capture_time_ms = 56789; + const int kTimeStep = 5; + const int64_t kBitrateWindow = 10000; + PacedSenderPadding callback; + send_bucket_.reset(new PacedSender(&callback, kTargetBitrate, + kPaceMultiplier)); + send_bucket_->UpdateBitrate(kTargetBitrate, kTargetBitrate); + int64_t start_time = TickTime::MillisecondTimestamp(); + int media_bytes = 0; + while (TickTime::MillisecondTimestamp() - start_time < kBitrateWindow) { + int media_payload = rand() % 100 + 200; // [200, 300] bytes. + EXPECT_TRUE(send_bucket_->SendPacket(PacedSender::kNormalPriority, ssrc, + sequence_number++, capture_time_ms, + media_payload)); + media_bytes += media_payload; + TickTime::AdvanceFakeClock(kTimeStep); + send_bucket_->Process(); + } + EXPECT_NEAR(kTargetBitrate, 8 * (media_bytes + callback.padding_sent()) / + kBitrateWindow, 1); +} + TEST_F(PacedSenderTest, Priority) { uint32_t ssrc_low_priority = 12345; uint32_t ssrc = 12346; diff --git a/webrtc/modules/video_coding/main/interface/video_coding.h b/webrtc/modules/video_coding/main/interface/video_coding.h index a92d80b6b2..0198ca57d6 100644 --- a/webrtc/modules/video_coding/main/interface/video_coding.h +++ b/webrtc/modules/video_coding/main/interface/video_coding.h @@ -165,7 +165,7 @@ public: // < 0, on error. virtual int32_t CodecConfigParameters(uint8_t* buffer, int32_t size) = 0; - // API to get currently configured encoder target bitrate in kbit/s. + // API to get currently configured encoder target bitrate in bits/s. // // Return value : 0, on success. // < 0, on error. diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc index 1b52f9dfee..8506ea9cb3 100644 --- a/webrtc/video_engine/vie_channel.cc +++ b/webrtc/video_engine/vie_channel.cc @@ -942,8 +942,8 @@ int32_t ViEChannel::EnableKeyFrameRequestCallback(const bool enable) { } int32_t ViEChannel::SetSSRC(const uint32_t SSRC, - const StreamType usage, - const uint8_t simulcast_idx) { + const StreamType usage, + const uint8_t simulcast_idx) { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(engine_id_, channel_id_), @@ -973,7 +973,7 @@ int32_t ViEChannel::SetSSRC(const uint32_t SSRC, } int32_t ViEChannel::SetRemoteSSRCType(const StreamType usage, - const uint32_t SSRC) const { + const uint32_t SSRC) const { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(engine_id_, channel_id_), diff --git a/webrtc/video_engine/vie_encoder.cc b/webrtc/video_engine/vie_encoder.cc index 845dfb6f80..53c5d62411 100644 --- a/webrtc/video_engine/vie_encoder.cc +++ b/webrtc/video_engine/vie_encoder.cc @@ -10,6 +10,7 @@ #include "webrtc/video_engine/vie_encoder.h" +#include #include #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" @@ -91,8 +92,9 @@ class ViEPacedSenderCallback : public PacedSender::Callback { int64_t capture_time_ms) { owner_->TimeToSendPacket(ssrc, sequence_number, capture_time_ms); } - virtual void TimeToSendPadding(int /*bytes*/) { + virtual int TimeToSendPadding(int bytes) { // TODO(pwestin): Hook up this. + return 0; } private: ViEEncoder* owner_; @@ -1000,7 +1002,7 @@ void ViEEncoder::OnNetworkChanged(const uint32_t bitrate_bps, vcm_.SetChannelParameters(bitrate_bps, fraction_lost, round_trip_time_ms); int bitrate_kbps = bitrate_bps / 1000; - paced_sender_->UpdateBitrate(bitrate_kbps); + paced_sender_->UpdateBitrate(bitrate_kbps, 0); default_rtp_rtcp_->SetTargetSendBitrate(bitrate_bps); }