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
This commit is contained in:
stefan@webrtc.org 2013-06-04 09:36:56 +00:00
parent c69ae69d0b
commit c3cc375499
6 changed files with 304 additions and 171 deletions

View File

@ -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> packet_list_;
std::set<uint16_t> 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<CriticalSectionWrapper> 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<paced_sender::IntervalBudget> 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<paced_sender::IntervalBudget> 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<paced_sender::IntervalBudget> 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<paced_sender::PacketList> high_priority_packets_;
scoped_ptr<paced_sender::PacketList> normal_priority_packets_;
scoped_ptr<paced_sender::PacketList> low_priority_packets_;
};
} // namespace webrtc
#endif // WEBRTC_MODULES_PACED_SENDER_H_

View File

@ -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> packet_list_;
std::set<uint16_t> 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

View File

@ -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<PacedSender> 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;

View File

@ -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.

View File

@ -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_),

View File

@ -10,6 +10,7 @@
#include "webrtc/video_engine/vie_encoder.h"
#include <algorithm>
#include <cassert>
#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);
}