Add RtpPacketHistory::SetSendTime()

This method will be used instead of GetPacketAndSetSendTime() when the
new pacer code path is used, where the packet isn't stored in the
history during pacing.

Bug: webrtc:10633
Change-Id: Ie168125d949cef617ade3868a1858ed1dffe909c
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/140892
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28240}
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn
index b738624..b70ad72 100644
--- a/modules/rtp_rtcp/BUILD.gn
+++ b/modules/rtp_rtcp/BUILD.gn
@@ -206,6 +206,7 @@
     "..:module_fec_api",
     "../..:webrtc_common",
     "../../api:array_view",
+    "../../api:function_view",
     "../../api:libjingle_peerconnection_api",
     "../../api:rtp_headers",
     "../../api:scoped_refptr",
diff --git a/modules/rtp_rtcp/source/rtp_packet_history.cc b/modules/rtp_rtcp/source/rtp_packet_history.cc
index 0930b82..5336181 100644
--- a/modules/rtp_rtcp/source/rtp_packet_history.cc
+++ b/modules/rtp_rtcp/source/rtp_packet_history.cc
@@ -205,6 +205,71 @@
   return absl::make_unique<RtpPacketToSend>(*packet.packet_);
 }
 
+std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacketAndMarkAsPending(
+    uint16_t sequence_number) {
+  return GetPacketAndMarkAsPending(
+      sequence_number, [](const RtpPacketToSend& packet) {
+        return absl::make_unique<RtpPacketToSend>(packet);
+      });
+}
+
+std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacketAndMarkAsPending(
+    uint16_t sequence_number,
+    rtc::FunctionView<std::unique_ptr<RtpPacketToSend>(const RtpPacketToSend&)>
+        encapsulate) {
+  rtc::CritScope cs(&lock_);
+  if (mode_ == StorageMode::kDisabled) {
+    return nullptr;
+  }
+
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  StoredPacketIterator rtp_it = packet_history_.find(sequence_number);
+  if (rtp_it == packet_history_.end()) {
+    return nullptr;
+  }
+
+  StoredPacket& packet = rtp_it->second;
+  RTC_DCHECK(packet.storage_type() != StorageType::kDontRetransmit);
+
+  if (packet.pending_transmission_) {
+    // Packet already in pacer queue, ignore this request.
+    return nullptr;
+  }
+
+  if (!VerifyRtt(rtp_it->second, now_ms)) {
+    // Packet already resent within too short a time window, ignore.
+    return nullptr;
+  }
+
+  packet.pending_transmission_ = true;
+
+  // Copy and/or encapsulate packet.
+  return encapsulate(*packet.packet_);
+}
+
+void RtpPacketHistory::MarkPacketAsSent(uint16_t sequence_number) {
+  rtc::CritScope cs(&lock_);
+  if (mode_ == StorageMode::kDisabled) {
+    return;
+  }
+
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  StoredPacketIterator rtp_it = packet_history_.find(sequence_number);
+  if (rtp_it == packet_history_.end()) {
+    return;
+  }
+
+  StoredPacket& packet = rtp_it->second;
+  RTC_CHECK(packet.storage_type() != StorageType::kDontRetransmit);
+  RTC_DCHECK(packet.send_time_ms_);
+
+  // Update send-time, mark as no longer in pacer queue, and increment
+  // transmission count.
+  packet.send_time_ms_ = now_ms;
+  packet.pending_transmission_ = false;
+  packet.IncrementTimesRetransmitted(&padding_priority_);
+}
+
 absl::optional<RtpPacketHistory::PacketState> RtpPacketHistory::GetPacketState(
     uint16_t sequence_number) const {
   rtc::CritScope cs(&lock_);
diff --git a/modules/rtp_rtcp/source/rtp_packet_history.h b/modules/rtp_rtcp/source/rtp_packet_history.h
index 0246e8c..44ebf43 100644
--- a/modules/rtp_rtcp/source/rtp_packet_history.h
+++ b/modules/rtp_rtcp/source/rtp_packet_history.h
@@ -16,6 +16,7 @@
 #include <set>
 #include <vector>
 
+#include "api/function_view.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "rtc_base/constructor_magic.h"
 #include "rtc_base/critical_section.h"
@@ -82,6 +83,25 @@
   std::unique_ptr<RtpPacketToSend> GetPacketAndSetSendTime(
       uint16_t sequence_number);
 
+  // Gets stored RTP packet corresponding to the input |sequence number|.
+  // Returns nullptr if packet is not found or was (re)sent too recently.
+  // If a packet copy is returned, it will be marked as pending transmission but
+  // does not update send time, that must be done by MarkPacketAsSent().
+  std::unique_ptr<RtpPacketToSend> GetPacketAndMarkAsPending(
+      uint16_t sequence_number);
+
+  // In addition to getting packet and marking as sent, this method takes an
+  // encapsulator function that takes a reference to the packet and outputs a
+  // copy that may be wrapped in a container, eg RTX.
+  std::unique_ptr<RtpPacketToSend> GetPacketAndMarkAsPending(
+      uint16_t sequence_number,
+      rtc::FunctionView<std::unique_ptr<RtpPacketToSend>(
+          const RtpPacketToSend&)> encapsulate);
+
+  // Updates the send time for the given packet and increments the transmission
+  // counter. Marks the packet as no longer being in the pacer queue.
+  void MarkPacketAsSent(uint16_t sequence_number);
+
   // Similar to GetPacketAndSetSendTime(), but only returns a snapshot of the
   // current state for packet, and never updates internal state.
   absl::optional<PacketState> GetPacketState(uint16_t sequence_number) const;
diff --git a/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc
index 5074ac6..6a577fa 100644
--- a/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc
@@ -13,6 +13,7 @@
 #include <memory>
 #include <utility>
 
+#include "absl/memory/memory.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
 #include "system_wrappers/include/clock.h"
@@ -678,6 +679,61 @@
   EXPECT_FALSE(packet_state->pending_transmission);
 }
 
+TEST_F(RtpPacketHistoryTest, GetPacketAndSetSent) {
+  const int64_t kRttMs = RtpPacketHistory::kMinPacketDurationMs * 2;
+  hist_.SetRtt(kRttMs);
+
+  // Set size to remove old packets as soon as possible.
+  hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, 1);
+
+  // Add a sent packet to the history.
+  hist_.PutRtpPacket(CreateRtpPacket(kStartSeqNum), kAllowRetransmission,
+                     fake_clock_.TimeInMicroseconds());
+
+  // Retransmission request, first retransmission is allowed immediately.
+  EXPECT_TRUE(hist_.GetPacketAndMarkAsPending(kStartSeqNum));
+
+  // Packet not yet sent, new retransmission not allowed.
+  fake_clock_.AdvanceTimeMilliseconds(kRttMs);
+  EXPECT_FALSE(hist_.GetPacketAndMarkAsPending(kStartSeqNum));
+
+  // Mark as sent, but too early for retransmission.
+  hist_.MarkPacketAsSent(kStartSeqNum);
+  EXPECT_FALSE(hist_.GetPacketAndMarkAsPending(kStartSeqNum));
+
+  // Enough time has passed, retransmission is allowed again.
+  fake_clock_.AdvanceTimeMilliseconds(kRttMs);
+  EXPECT_TRUE(hist_.GetPacketAndMarkAsPending(kStartSeqNum));
+}
+
+TEST_F(RtpPacketHistoryTest, GetPacketWithEncapsulation) {
+  const uint32_t kSsrc = 92384762;
+  const int64_t kRttMs = RtpPacketHistory::kMinPacketDurationMs * 2;
+  hist_.SetRtt(kRttMs);
+
+  // Set size to remove old packets as soon as possible.
+  hist_.SetStorePacketsStatus(StorageMode::kStoreAndCull, 1);
+
+  // Add a sent packet to the history, with a set SSRC.
+  std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kStartSeqNum);
+  packet->SetSsrc(kSsrc);
+  hist_.PutRtpPacket(std::move(packet), kAllowRetransmission,
+                     fake_clock_.TimeInMicroseconds());
+
+  // Retransmission request, simulate an RTX-like encapsulation, were the packet
+  // is sent on a different SSRC.
+  std::unique_ptr<RtpPacketToSend> retransmit_packet =
+      hist_.GetPacketAndMarkAsPending(
+          kStartSeqNum, [](const RtpPacketToSend& packet) {
+            auto encapsulated_packet =
+                absl::make_unique<RtpPacketToSend>(packet);
+            encapsulated_packet->SetSsrc(packet.Ssrc() + 1);
+            return encapsulated_packet;
+          });
+  ASSERT_TRUE(retransmit_packet);
+  EXPECT_EQ(retransmit_packet->Ssrc(), kSsrc + 1);
+}
+
 TEST_F(RtpPacketHistoryTest, DontRemovePendingTransmissions) {
   const int64_t kRttMs = RtpPacketHistory::kMinPacketDurationMs * 2;
   const int64_t kPacketTimeoutMs =