Non-zero pacing debt should result in non-zero process time delta.
Bug: webrtc:11340
Change-Id: Ib5567ef03d324b44fd1c0f3f8265870acb710cc9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/259764
Reviewed-by: Emil Lundmark <lndmrk@webrtc.org>
Commit-Queue: Erik Språng <sprang@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#36616}
diff --git a/modules/pacing/pacing_controller.cc b/modules/pacing/pacing_controller.cc
index 5ef10db..f2895cf 100644
--- a/modules/pacing/pacing_controller.cc
+++ b/modules/pacing/pacing_controller.cc
@@ -366,6 +366,13 @@
RTC_DCHECK_GT(media_rate_, DataRate::Zero());
TimeDelta drain_time =
std::max(media_debt_ / media_rate_, padding_debt_ / padding_rate_);
+
+ if (drain_time.IsZero() &&
+ (!media_debt_.IsZero() || !padding_debt_.IsZero())) {
+ // We have a non-zero debt, but drain time is smaller than tick size of
+ // TimeDelta, round it up to the smallest possible non-zero delta.
+ drain_time = TimeDelta::Micros(1);
+ }
next_send_time = last_process_time_ + drain_time;
} else {
// Nothing to do.
diff --git a/modules/pacing/pacing_controller_unittest.cc b/modules/pacing/pacing_controller_unittest.cc
index 33592e3..27f0c46 100644
--- a/modules/pacing/pacing_controller_unittest.cc
+++ b/modules/pacing/pacing_controller_unittest.cc
@@ -2114,6 +2114,54 @@
pacer_->ProcessPackets();
}
+TEST_P(PacingControllerTest, HandlesSubMicrosecondSendIntervals) {
+ if (PeriodicProcess()) {
+ GTEST_SKIP() << "This test checks behavior when not using interval budget.";
+ }
+
+ static constexpr DataSize kPacketSize = DataSize::Bytes(1);
+ static constexpr TimeDelta kPacketSendTime = TimeDelta::Micros(1);
+
+ // Set pacing rate such that a packet is sent in 0.5us.
+ pacer_->SetPacingRates(/*pacing_rate=*/2 * kPacketSize / kPacketSendTime,
+ /*padding_rate=*/DataRate::Zero());
+
+ // Enqueue three packets, the first two should be sent immediately - the third
+ // should cause a non-zero delta to the next process time.
+ EXPECT_CALL(callback_, SendPacket).Times(2);
+ for (int i = 0; i < 3; ++i) {
+ Send(RtpPacketMediaType::kVideo, /*ssrc=*/12345, /*sequence_number=*/i,
+ clock_.TimeInMilliseconds(), kPacketSize.bytes());
+ }
+ pacer_->ProcessPackets();
+
+ EXPECT_GT(pacer_->NextSendTime(), clock_.CurrentTime());
+}
+
+TEST_P(PacingControllerTest, HandlesSubMicrosecondPaddingInterval) {
+ if (PeriodicProcess()) {
+ GTEST_SKIP() << "This test checks behavior when not using interval budget.";
+ }
+
+ static constexpr DataSize kPacketSize = DataSize::Bytes(1);
+ static constexpr TimeDelta kPacketSendTime = TimeDelta::Micros(1);
+
+ // Set both pacing and padding rates to 1 byte per 0.5us.
+ pacer_->SetPacingRates(/*pacing_rate=*/2 * kPacketSize / kPacketSendTime,
+ /*padding_rate=*/2 * kPacketSize / kPacketSendTime);
+
+ // Enqueue and send one packet.
+ EXPECT_CALL(callback_, SendPacket);
+ Send(RtpPacketMediaType::kVideo, /*ssrc=*/12345, /*sequence_number=*/1234,
+ clock_.TimeInMilliseconds(), kPacketSize.bytes());
+ pacer_->ProcessPackets();
+
+ // The padding debt is now 1 byte, and the pacing time for that is lower than
+ // the precision of a TimeStamp tick. Make sure the pacer still indicates a
+ // non-zero sleep time is needed until the next process.
+ EXPECT_GT(pacer_->NextSendTime(), clock_.CurrentTime());
+}
+
INSTANTIATE_TEST_SUITE_P(
WithAndWithoutIntervalBudget,
PacingControllerTest,