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,