Adds trial to always send padding packets when not sending video.

This can be used to avoid getting stuck in a state where the encoder
is paused due to low bandwidth estimate which means no additional
feedback is received to update the bandwidth estimate. This could
happen if feedback packets are lost.

Bug: webrtc:8415
Change-Id: I59cd60c0277e8b31a6b911b25e8e488af9008fc2
Reviewed-on: https://webrtc-review.googlesource.com/80880
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23632}
This commit is contained in:
Sebastian Jansson 2018-06-15 14:46:11 +02:00 committed by Commit Bot
parent fc50110df6
commit c235a8d2bb
3 changed files with 73 additions and 14 deletions

View File

@ -63,6 +63,8 @@ PacedSender::PacedSender(const Clock* clock,
: clock_(clock),
packet_sender_(packet_sender),
alr_detector_(rtc::MakeUnique<AlrDetector>(event_log)),
send_padding_if_silent_(
field_trial::IsEnabled("WebRTC-Pacer-PadInSilence")),
paused_(false),
media_budget_(rtc::MakeUnique<IntervalBudget>(0)),
padding_budget_(rtc::MakeUnique<IntervalBudget>(0)),
@ -263,11 +265,9 @@ void PacedSender::Process() {
<< kMaxElapsedTimeMs << " ms";
elapsed_time_ms = kMaxElapsedTimeMs;
}
// When congested we send a padding packet every 500 ms to ensure we won't get
// stuck in the congested state due to no feedback being received.
// TODO(srte): Stop sending packet in paused state when pause is no longer
// used for congestion windows.
if (paused_ || Congested()) {
if (send_padding_if_silent_ || paused_ || Congested()) {
// We send a padding packet every 500 ms to ensure we won't get stuck in
// congested state due to no feedback being received.
int64_t elapsed_since_last_send_us = now_us - last_send_time_us_;
if (elapsed_since_last_send_us >= kCongestedPacketIntervalMs * 1000) {
// We can not send padding unless a normal packet has first been sent. If
@ -277,13 +277,13 @@ void PacedSender::Process() {
size_t bytes_sent = SendPadding(1, pacing_info);
alr_detector_->OnBytesSent(bytes_sent, elapsed_time_ms);
}
last_send_time_us_ = clock_->TimeInMicroseconds();
}
return;
}
if (paused_)
return;
int target_bitrate_kbps = pacing_bitrate_kbps_;
if (elapsed_time_ms > 0) {
int target_bitrate_kbps = pacing_bitrate_kbps_;
size_t queue_size_bytes = packets_->SizeInBytes();
if (queue_size_bytes > 0) {
// Assuming equal size packets and input/output rate, the average packet
@ -302,8 +302,6 @@ void PacedSender::Process() {
UpdateBudgetWithElapsedTime(elapsed_time_ms);
}
last_send_time_us_ = clock_->TimeInMicroseconds();
bool is_probing = prober_->IsProbing();
PacedPacketInfo pacing_info;
size_t bytes_sent = 0;
@ -314,7 +312,7 @@ void PacedSender::Process() {
}
// The paused state is checked in the loop since SendPacket leaves the
// critical section allowing the paused state to be changed from other code.
while (!packets_->Empty() && !paused_ && !Congested()) {
while (!packets_->Empty() && !paused_) {
// Since we need to release the lock in order to send, we first pop the
// element from the priority queue but keep it in storage, so that we can
// reinsert it if send fails.
@ -362,8 +360,9 @@ void PacedSender::ProcessThreadAttached(ProcessThread* process_thread) {
bool PacedSender::SendPacket(const PacketQueueInterface::Packet& packet,
const PacedPacketInfo& pacing_info) {
RTC_DCHECK(!paused_);
if (media_budget_->bytes_remaining() == 0 &&
pacing_info.probe_cluster_id == PacedPacketInfo::kNotAProbe) {
if (Congested() ||
(media_budget_->bytes_remaining() == 0 &&
pacing_info.probe_cluster_id == PacedPacketInfo::kNotAProbe)) {
return false;
}
@ -383,6 +382,7 @@ bool PacedSender::SendPacket(const PacketQueueInterface::Packet& packet,
// and we probably don't want to update the budget in such cases.
// https://bugs.chromium.org/p/webrtc/issues/detail?id=8052
UpdateBudgetWithBytesSent(packet.bytes);
last_send_time_us_ = clock_->TimeInMicroseconds();
}
}
@ -400,6 +400,7 @@ size_t PacedSender::SendPadding(size_t padding_needed,
if (bytes_sent > 0) {
UpdateBudgetWithBytesSent(bytes_sent);
}
last_send_time_us_ = clock_->TimeInMicroseconds();
return bytes_sent;
}

View File

@ -162,7 +162,7 @@ class PacedSender : public Pacer {
const Clock* const clock_;
PacketSender* const packet_sender_;
const std::unique_ptr<AlrDetector> alr_detector_ RTC_PT_GUARDED_BY(critsect_);
const bool send_padding_if_silent_;
rtc::CriticalSection critsect_;
bool paused_ RTC_GUARDED_BY(critsect_);
// This is the media budget, keeping track of how many bits of media

View File

@ -141,6 +141,64 @@ class PacedSenderTest : public testing::TestWithParam<std::string> {
std::unique_ptr<PacedSender> send_bucket_;
};
class PacedSenderFieldTrialTest : public testing::Test {
protected:
struct MediaStream {
const RtpPacketSender::Priority priority;
const uint32_t ssrc;
const size_t packet_size;
uint16_t seq_num;
};
const int kProcessIntervalsPerSecond = 1000 / 5;
PacedSenderFieldTrialTest() : clock_(123456) {}
void InsertPacket(PacedSender* pacer, MediaStream* stream) {
pacer->InsertPacket(stream->priority, stream->ssrc, stream->seq_num++,
clock_.TimeInMilliseconds(), stream->packet_size,
false);
}
void ProcessNext(PacedSender* pacer) {
clock_.AdvanceTimeMilliseconds(5);
pacer->Process();
}
MediaStream audio{/*priority*/ PacedSender::kHighPriority,
/*ssrc*/ 3333, /*packet_size*/ 100, /*seq_num*/ 1000};
MediaStream video{/*priority*/ PacedSender::kNormalPriority,
/*ssrc*/ 4444, /*packet_size*/ 1000, /*seq_num*/ 1000};
SimulatedClock clock_;
MockPacedSenderCallback callback_;
};
TEST_F(PacedSenderFieldTrialTest, DefaultNoPaddingInSilence) {
PacedSender pacer(&clock_, &callback_, nullptr);
pacer.SetPacingRates(kTargetBitrateBps, 0);
// Video packet to reset last send time and provide padding data.
InsertPacket(&pacer, &video);
EXPECT_CALL(callback_, TimeToSendPacket).WillOnce(Return(true));
clock_.AdvanceTimeMilliseconds(5);
pacer.Process();
EXPECT_CALL(callback_, TimeToSendPadding).Times(0);
// Waiting 500 ms should not trigger sending of padding.
clock_.AdvanceTimeMilliseconds(500);
pacer.Process();
}
TEST_F(PacedSenderFieldTrialTest, PaddingInSilenceWithTrial) {
ScopedFieldTrials trial("WebRTC-Pacer-PadInSilence/Enabled/");
PacedSender pacer(&clock_, &callback_, nullptr);
pacer.SetPacingRates(kTargetBitrateBps, 0);
// Video packet to reset last send time and provide padding data.
InsertPacket(&pacer, &video);
EXPECT_CALL(callback_, TimeToSendPacket).WillOnce(Return(true));
clock_.AdvanceTimeMilliseconds(5);
pacer.Process();
EXPECT_CALL(callback_, TimeToSendPadding).WillOnce(Return(1000));
// Waiting 500 ms should trigger sending of padding.
clock_.AdvanceTimeMilliseconds(500);
pacer.Process();
}
TEST_F(PacedSenderTest, FirstSentPacketTimeIsSet) {
uint16_t sequence_number = 1234;
const uint32_t kSsrc = 12345;