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 =