Wire up new PacedSender code path.
This CL makes the new code path for paced sending functionally complete.
By default, the field trial WebRTC-Pacer-ReferencePackets is Enabled,
meaning that there is no behavior change unless the field trial is
forced to Disabled. This is done in tests, and can be done on the
command line for manual testing.
Bug: webrtc:10633
Change-Id: I0d66c94ef83b5847dee437a785018f09ba3f828d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/144050
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Åsa Persson <asapersson@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28497}
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 21b85a1..aaf1822 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -409,8 +409,9 @@
return rtp_sender_->TimeToSendPadding(bytes, pacing_info);
}
-void ModuleRtpRtcpImpl::GeneratePadding(size_t target_size_bytes) {
- rtp_sender_->GeneratePadding(target_size_bytes);
+std::vector<std::unique_ptr<RtpPacketToSend>>
+ModuleRtpRtcpImpl::GeneratePadding(size_t target_size_bytes) {
+ return rtp_sender_->GeneratePadding(target_size_bytes);
}
size_t ModuleRtpRtcpImpl::MaxRtpPacketSize() const {
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 60ac5fd..e22126c 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -148,7 +148,8 @@
size_t TimeToSendPadding(size_t bytes,
const PacedPacketInfo& pacing_info) override;
- void GeneratePadding(size_t target_size_bytes) override;
+ std::vector<std::unique_ptr<RtpPacketToSend>> GeneratePadding(
+ size_t target_size_bytes) override;
// RTCP part.
diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc
index a932fab..0fa719e 100644
--- a/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/modules/rtp_rtcp/source/rtp_sender.cc
@@ -195,6 +195,9 @@
config.field_trials)),
payload_padding_prefer_useful_packets_(
!IsDisabled("WebRTC-PayloadPadding-UseMostUsefulPacket",
+ config.field_trials)),
+ pacer_legacy_packet_referencing_(
+ !IsDisabled("WebRTC-Pacer-LegacyPacketReferencing",
config.field_trials)) {
// This random initialization is not intended to be cryptographic strong.
timestamp_offset_ = random_.Rand<uint32_t>();
@@ -283,6 +286,9 @@
.find("Enabled") == 0),
payload_padding_prefer_useful_packets_(
field_trials.Lookup("WebRTC-PayloadPadding-UseMostUsefulPacket")
+ .find("Disabled") != 0),
+ pacer_legacy_packet_referencing_(
+ field_trials.Lookup("WebRTC-Pacer-LegacyPacketReferencing")
.find("Disabled") != 0) {
// This random initialization is not intended to be cryptographic strong.
timestamp_offset_ = random_.Rand<uint32_t>();
@@ -592,31 +598,67 @@
}
const int32_t packet_size = static_cast<int32_t>(stored_packet->packet_size);
-
- // Skip retransmission rate check if not configured.
- if (retransmission_rate_limiter_) {
- // Check if we're overusing retransmission bitrate.
- // TODO(sprang): Add histograms for nack success or failure reasons.
- if (!retransmission_rate_limiter_->TryUseRate(packet_size)) {
- return -1;
- }
- }
+ const bool rtx = (RtxStatus() & kRtxRetransmitted) > 0;
if (paced_sender_) {
- // Mark packet as being in pacer queue again, to prevent duplicates.
- if (!packet_history_.SetPendingTransmission(packet_id)) {
- // Packet has already been removed from history, return early.
- return 0;
+ if (pacer_legacy_packet_referencing_) {
+ // Check if we're overusing retransmission bitrate.
+ // TODO(sprang): Add histograms for nack success or failure reasons.
+ if (retransmission_rate_limiter_ &&
+ !retransmission_rate_limiter_->TryUseRate(packet_size)) {
+ return -1;
+ }
+
+ // Mark packet as being in pacer queue again, to prevent duplicates.
+ if (!packet_history_.SetPendingTransmission(packet_id)) {
+ // Packet has already been removed from history, return early.
+ return 0;
+ }
+
+ paced_sender_->InsertPacket(
+ RtpPacketSender::kNormalPriority, stored_packet->ssrc,
+ stored_packet->rtp_sequence_number, stored_packet->capture_time_ms,
+ stored_packet->packet_size, true);
+ } else {
+ std::unique_ptr<RtpPacketToSend> packet =
+ packet_history_.GetPacketAndMarkAsPending(
+ packet_id, [&](const RtpPacketToSend& stored_packet) {
+ // Check if we're overusing retransmission bitrate.
+ // TODO(sprang): Add histograms for nack success or failure
+ // reasons.
+ std::unique_ptr<RtpPacketToSend> retransmit_packet;
+ if (retransmission_rate_limiter_ &&
+ !retransmission_rate_limiter_->TryUseRate(packet_size)) {
+ return retransmit_packet;
+ }
+ if (rtx) {
+ retransmit_packet = BuildRtxPacket(stored_packet);
+ } else {
+ retransmit_packet =
+ absl::make_unique<RtpPacketToSend>(stored_packet);
+ }
+ retransmit_packet->set_retransmitted_sequence_number(
+ stored_packet.SequenceNumber());
+ return retransmit_packet;
+ });
+ if (!packet) {
+ return -1;
+ }
+ packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
+ paced_sender_->EnqueuePacket(std::move(packet));
}
- paced_sender_->InsertPacket(
- RtpPacketSender::kNormalPriority, stored_packet->ssrc,
- stored_packet->rtp_sequence_number, stored_packet->capture_time_ms,
- stored_packet->packet_size, true);
-
return packet_size;
}
+ // TODO(sprang): Replace this whole code-path with a pass-through pacer.
+ // Check if we're overusing retransmission bitrate.
+ // TODO(sprang): Add histograms for nack success or failure reasons.
+ if (retransmission_rate_limiter_ &&
+ !retransmission_rate_limiter_->TryUseRate(packet_size)) {
+ return -1;
+ }
+
std::unique_ptr<RtpPacketToSend> packet =
packet_history_.GetPacketAndSetSendTime(packet_id);
if (!packet) {
@@ -624,7 +666,6 @@
return 0;
}
- const bool rtx = (RtxStatus() & kRtxRetransmitted) > 0;
if (!PrepareAndSendPacket(std::move(packet), rtx, true, PacedPacketInfo()))
return -1;
@@ -926,15 +967,18 @@
return bytes_sent;
}
-void RTPSender::GeneratePadding(size_t target_size_bytes) {
+std::vector<std::unique_ptr<RtpPacketToSend>> RTPSender::GeneratePadding(
+ size_t target_size_bytes) {
// This method does not actually send packets, it just generates
// them and puts them in the pacer queue. Since this should incur
// low overhead, keep the lock for the scope of the method in order
// to make the code more readable.
rtc::CritScope lock(&send_critsect_);
- if (!sending_media_)
- return;
+ if (!sending_media_) {
+ return {};
+ }
+ std::vector<std::unique_ptr<RtpPacketToSend>> padding_packets;
size_t bytes_left = target_size_bytes;
if ((rtx_ & kRtxRedundantPayloads) != 0) {
while (bytes_left >= 0) {
@@ -953,7 +997,7 @@
bytes_left -= std::min(bytes_left, packet->payload_size());
packet->set_packet_type(RtpPacketToSend::Type::kPadding);
- paced_sender_->EnqueuePacket(std::move(packet));
+ padding_packets.push_back(std::move(packet));
}
}
@@ -1022,10 +1066,15 @@
padding_packet->SetPayloadType(rtx_payload_type_map_.begin()->second);
}
+ if (rtp_header_extension_map_.IsRegistered(TransportSequenceNumber::kId)) {
+ padding_packet->ReserveExtension<TransportSequenceNumber>();
+ }
padding_packet->SetPadding(padding_bytes_in_packet);
bytes_left -= std::min(bytes_left, padding_bytes_in_packet);
- paced_sender_->EnqueuePacket(std::move(padding_packet));
+ padding_packets.push_back(std::move(padding_packet));
}
+
+ return padding_packets;
}
bool RTPSender::SendToNetwork(std::unique_ptr<RtpPacketToSend> packet,
@@ -1040,18 +1089,28 @@
size_t packet_size =
send_side_bwe_with_overhead_ ? packet->size() : packet->payload_size();
auto packet_type = packet->packet_type();
- RTC_DCHECK(packet_type.has_value());
- if (ssrc == FlexfecSsrc()) {
- // Store FlexFEC packets in the history here, so they can be found
- // when the pacer calls TimeToSendPacket.
- flexfec_packet_history_.PutRtpPacket(std::move(packet), storage,
- absl::nullopt);
+ RTC_CHECK(packet_type) << "Packet type must be set before sending.";
+
+ if (pacer_legacy_packet_referencing_) {
+ // If |pacer_reference_packets_| then pacer needs to find the packet in
+ // the history when it is time to send, so move packet there.
+ if (ssrc == FlexfecSsrc()) {
+ // Store FlexFEC packets in a separate history since they are on a
+ // separate SSRC.
+ flexfec_packet_history_.PutRtpPacket(std::move(packet), storage,
+ absl::nullopt);
+ } else {
+ packet_history_.PutRtpPacket(std::move(packet), storage, absl::nullopt);
+ }
+
+ paced_sender_->InsertPacket(PacketTypeToPriority(*packet_type), ssrc,
+ seq_no, capture_time_ms, packet_size, false);
} else {
- packet_history_.PutRtpPacket(std::move(packet), storage, absl::nullopt);
+ packet->set_allow_retransmission(storage ==
+ StorageType::kAllowRetransmission);
+ paced_sender_->EnqueuePacket(std::move(packet));
}
- paced_sender_->InsertPacket(PacketTypeToPriority(*packet_type), ssrc,
- seq_no, capture_time_ms, packet_size, false);
return true;
}
diff --git a/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h
index c191694..8e50575 100644
--- a/modules/rtp_rtcp/source/rtp_sender.h
+++ b/modules/rtp_rtcp/source/rtp_sender.h
@@ -119,7 +119,8 @@
bool TrySendPacket(RtpPacketToSend* packet,
const PacedPacketInfo& pacing_info);
size_t TimeToSendPadding(size_t bytes, const PacedPacketInfo& pacing_info);
- void GeneratePadding(size_t target_size_bytes);
+ std::vector<std::unique_ptr<RtpPacketToSend>> GeneratePadding(
+ size_t target_size_bytes);
// NACK.
void OnReceivedNack(const std::vector<uint16_t>& nack_sequence_numbers,
@@ -322,6 +323,11 @@
// packet_history_.GetBestFittingPacket() in TrySendRedundantPayloads().
const bool payload_padding_prefer_useful_packets_;
+ // If true, PacedSender should only reference packets as in legacy mode.
+ // If false, PacedSender may have direct ownership of RtpPacketToSend objects.
+ // Defaults to true, will be changed to default false soon.
+ const bool pacer_legacy_packet_referencing_;
+
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RTPSender);
};
diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index dad0d74..02462b4 100644
--- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -142,6 +142,27 @@
return value == arg->GetType();
}
+struct TestConfig {
+ TestConfig(bool with_overhead, bool pacer_references_packets)
+ : with_overhead(with_overhead),
+ pacer_references_packets(pacer_references_packets) {}
+ bool with_overhead = false;
+ bool pacer_references_packets = false;
+};
+
+std::string ToFieldTrialString(TestConfig config) {
+ std::string field_trials;
+ if (config.with_overhead) {
+ field_trials += "WebRTC-SendSideBwe-WithOverhead/Enabled/";
+ }
+ if (config.pacer_references_packets) {
+ field_trials += "WebRTC-Pacer-LegacyPacketReferencing/Enabled/";
+ } else {
+ field_trials += "WebRTC-Pacer-LegacyPacketReferencing/Disabled/";
+ }
+ return field_trials;
+}
+
} // namespace
class MockRtpPacketPacer : public RtpPacketPacer {
@@ -188,7 +209,7 @@
MOCK_METHOD1(OnOverheadChanged, void(size_t overhead_bytes_per_packet));
};
-class RtpSenderTest : public ::testing::TestWithParam<bool> {
+class RtpSenderTest : public ::testing::TestWithParam<TestConfig> {
protected:
RtpSenderTest()
: fake_clock_(kStartTime),
@@ -206,8 +227,7 @@
rtp_sender_(),
transport_(),
kMarkerBit(true),
- field_trials_(GetParam() ? "WebRTC-SendSideBwe-WithOverhead/Enabled/"
- : "") {}
+ field_trials_(ToFieldTrialString(GetParam())) {}
void SetUp() override { SetUpRtpSender(true, false); }
@@ -255,21 +275,23 @@
return packet;
}
- void SendPacket(int64_t capture_time_ms, int payload_length) {
+ std::unique_ptr<RtpPacketToSend> SendPacket(int64_t capture_time_ms,
+ int payload_length) {
uint32_t timestamp = capture_time_ms * 90;
auto packet =
BuildRtpPacket(kPayload, kMarkerBit, timestamp, capture_time_ms);
packet->AllocatePayload(payload_length);
// Packet should be stored in a send bucket.
- EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
- kAllowRetransmission,
- RtpPacketSender::kNormalPriority));
+ EXPECT_TRUE(rtp_sender_->SendToNetwork(
+ absl::make_unique<RtpPacketToSend>(*packet), kAllowRetransmission,
+ RtpPacketSender::kNormalPriority));
+ return packet;
}
- void SendGenericPacket() {
+ std::unique_ptr<RtpPacketToSend> SendGenericPacket() {
const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds();
- SendPacket(kCaptureTimeMs, sizeof(kPayloadData));
+ return SendPacket(kCaptureTimeMs, sizeof(kPayloadData));
}
};
@@ -429,8 +451,9 @@
.WillOnce(Return(kTransportSequenceNumber));
const size_t expected_bytes =
- GetParam() ? sizeof(kPayloadData) + kRtpOverheadBytesPerPacket
- : sizeof(kPayloadData);
+ GetParam().with_overhead
+ ? sizeof(kPayloadData) + kRtpOverheadBytesPerPacket
+ : sizeof(kPayloadData);
EXPECT_CALL(feedback_observer_,
OnAddPacket(AllOf(
@@ -658,9 +681,6 @@
kRtpExtensionTransportSequenceNumber,
kTransportSequenceNumberExtensionId));
- EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _));
- EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
- .WillOnce(Return(kTransportSequenceNumber));
EXPECT_CALL(send_packet_observer_,
OnSendPacket(kTransportSequenceNumber, _, _))
.Times(1);
@@ -674,10 +694,26 @@
Field(&RtpPacketSendInfo::pacing_info, PacedPacketInfo()))))
.Times(1);
- SendGenericPacket();
- rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
- fake_clock_.TimeInMilliseconds(), false,
- PacedPacketInfo());
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _));
+ SendGenericPacket();
+ EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
+ .WillOnce(Return(kTransportSequenceNumber));
+ rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
+ fake_clock_.TimeInMilliseconds(), false,
+ PacedPacketInfo());
+ } else {
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(AllOf(
+ Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)),
+ Pointee(Property(&RtpPacketToSend::SequenceNumber, kSeqNum)))));
+ auto packet = SendGenericPacket();
+ packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+ // Transport sequence number is set by PacketRouter, before TrySendPacket().
+ packet->SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ }
const auto& packet = transport_.last_sent_packet();
uint16_t transport_seq_no;
@@ -702,17 +738,26 @@
size_t packet_size = packet->size();
const int kStoredTimeInMs = 100;
- {
+ if (GetParam().pacer_references_packets) {
EXPECT_CALL(
mock_paced_sender_,
InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, _, _, _, _));
EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
kAllowRetransmission,
RtpPacketSender::kNormalPriority));
+ fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+ rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
+ PacedPacketInfo());
+ } else {
+ packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc))));
+ EXPECT_TRUE(rtp_sender_->SendToNetwork(
+ absl::make_unique<RtpPacketToSend>(*packet), kAllowRetransmission));
+ fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
}
- fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
- rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
- PacedPacketInfo());
EXPECT_EQ(1, transport_.packets_sent());
EXPECT_EQ(packet_size, transport_.last_sent_packet().size());
@@ -740,17 +785,29 @@
size_t packet_size = packet->size();
const int kStoredTimeInMs = 100;
- {
+
+ if (GetParam().pacer_references_packets) {
EXPECT_CALL(
mock_paced_sender_,
InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, _, _, _, _));
EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
kAllowRetransmission,
RtpPacketSender::kNormalPriority));
+ fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+ rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
+ PacedPacketInfo());
+ } else {
+ packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc))));
+ EXPECT_TRUE(rtp_sender_->SendToNetwork(
+ absl::make_unique<RtpPacketToSend>(*packet), kAllowRetransmission,
+ RtpPacketSender::kNormalPriority));
+ fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
}
- fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
- rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
- PacedPacketInfo());
+
EXPECT_EQ(1, transport_.packets_sent());
EXPECT_EQ(packet_size, transport_.last_sent_packet().size());
@@ -787,8 +844,6 @@
}
TEST_P(RtpSenderTest, TrafficSmoothingWithExtensions) {
- EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority,
- kSsrc, kSeqNum, _, _, _));
EXPECT_CALL(mock_rtc_event_log_,
LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)));
@@ -804,18 +859,32 @@
BuildRtpPacket(kPayload, kMarkerBit, kTimestamp, capture_time_ms);
size_t packet_size = packet->size();
- // Packet should be stored in a send bucket.
- EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
- kAllowRetransmission,
- RtpPacketSender::kNormalPriority));
-
- EXPECT_EQ(0, transport_.packets_sent());
-
const int kStoredTimeInMs = 100;
- fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
-
- rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
- PacedPacketInfo());
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_,
+ InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, kSeqNum,
+ _, _, _));
+ // Packet should be stored in a send bucket.
+ EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
+ kAllowRetransmission,
+ RtpPacketSender::kNormalPriority));
+ EXPECT_EQ(0, transport_.packets_sent());
+ fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+ rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
+ PacedPacketInfo());
+ } else {
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(AllOf(
+ Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)),
+ Pointee(Property(&RtpPacketToSend::SequenceNumber, kSeqNum)))));
+ packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+ EXPECT_TRUE(rtp_sender_->SendToNetwork(
+ absl::make_unique<RtpPacketToSend>(*packet), kAllowRetransmission));
+ EXPECT_EQ(0, transport_.packets_sent());
+ fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ }
// Process send bucket. Packet should now be sent.
EXPECT_EQ(1, transport_.packets_sent());
@@ -832,8 +901,6 @@
}
TEST_P(RtpSenderTest, TrafficSmoothingRetransmits) {
- EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority,
- kSsrc, kSeqNum, _, _, _));
EXPECT_CALL(mock_rtc_event_log_,
LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)));
@@ -850,28 +917,60 @@
size_t packet_size = packet->size();
// Packet should be stored in a send bucket.
- EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
- kAllowRetransmission,
- RtpPacketSender::kNormalPriority));
- // Immediately process send bucket and send packet.
- rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
- PacedPacketInfo());
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_,
+ InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, kSeqNum,
+ _, _, _));
+ EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
+ kAllowRetransmission,
+ RtpPacketSender::kNormalPriority));
+ // Immediately process send bucket and send packet.
+ rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
+ PacedPacketInfo());
+ } else {
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(AllOf(
+ Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)),
+ Pointee(Property(&RtpPacketToSend::SequenceNumber, kSeqNum)))));
+ packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+ packet->set_allow_retransmission(true);
+ EXPECT_TRUE(rtp_sender_->SendToNetwork(
+ absl::make_unique<RtpPacketToSend>(*packet), kAllowRetransmission));
+ // Immediately process send bucket and send packet.
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ }
+
EXPECT_EQ(1, transport_.packets_sent());
// Retransmit packet.
const int kStoredTimeInMs = 100;
fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
- EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority,
- kSsrc, kSeqNum, _, _, _));
EXPECT_CALL(mock_rtc_event_log_,
LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)));
-
- EXPECT_EQ(static_cast<int>(packet_size), rtp_sender_->ReSendPacket(kSeqNum));
- EXPECT_EQ(1, transport_.packets_sent());
-
- rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, false,
- PacedPacketInfo());
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_,
+ InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, kSeqNum,
+ _, _, _));
+ EXPECT_EQ(static_cast<int>(packet_size),
+ rtp_sender_->ReSendPacket(kSeqNum));
+ EXPECT_EQ(1, transport_.packets_sent());
+ rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum, capture_time_ms, true,
+ PacedPacketInfo());
+ } else {
+ packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
+ packet->set_retransmitted_sequence_number(kSeqNum);
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(AllOf(
+ Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)),
+ Pointee(Property(&RtpPacketToSend::SequenceNumber, kSeqNum)))));
+ EXPECT_EQ(static_cast<int>(packet_size),
+ rtp_sender_->ReSendPacket(kSeqNum));
+ EXPECT_EQ(1, transport_.packets_sent());
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ }
// Process send bucket. Packet should now be sent.
EXPECT_EQ(2, transport_.packets_sent());
@@ -891,8 +990,6 @@
// 1 more regular packet.
TEST_P(RtpSenderTest, SendPadding) {
// Make all (non-padding) packets go to send queue.
- EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority,
- kSsrc, kSeqNum, _, _, _));
EXPECT_CALL(mock_rtc_event_log_,
LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
.Times(1 + 4 + 1);
@@ -918,19 +1015,37 @@
BuildRtpPacket(kPayload, kMarkerBit, timestamp, capture_time_ms);
const uint32_t media_packet_timestamp = timestamp;
size_t packet_size = packet->size();
+ int total_packets_sent = 0;
+ const int kStoredTimeInMs = 100;
// Packet should be stored in a send bucket.
- EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
- kAllowRetransmission,
- RtpPacketSender::kNormalPriority));
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_,
+ InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, kSeqNum,
+ _, _, _));
+ EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
+ kAllowRetransmission,
+ RtpPacketSender::kNormalPriority));
+ EXPECT_EQ(total_packets_sent, transport_.packets_sent());
+ fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+ rtp_sender_->TimeToSendPacket(kSsrc, seq_num++, capture_time_ms, false,
+ PacedPacketInfo());
+ } else {
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(AllOf(
+ Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)),
+ Pointee(Property(&RtpPacketToSend::SequenceNumber, kSeqNum)))));
+ packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+ packet->set_allow_retransmission(true);
+ EXPECT_TRUE(rtp_sender_->SendToNetwork(
+ absl::make_unique<RtpPacketToSend>(*packet), kAllowRetransmission));
+ EXPECT_EQ(total_packets_sent, transport_.packets_sent());
+ fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ ++seq_num;
+ }
- int total_packets_sent = 0;
- EXPECT_EQ(total_packets_sent, transport_.packets_sent());
-
- const int kStoredTimeInMs = 100;
- fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs);
- rtp_sender_->TimeToSendPacket(kSsrc, seq_num++, capture_time_ms, false,
- PacedPacketInfo());
// Packet should now be sent. This test doesn't verify the regular video
// packet, since it is tested in another test.
EXPECT_EQ(++total_packets_sent, transport_.packets_sent());
@@ -972,16 +1087,28 @@
packet = BuildRtpPacket(kPayload, kMarkerBit, timestamp, capture_time_ms);
packet_size = packet->size();
- EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kNormalPriority,
- kSsrc, seq_num, _, _, _));
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_,
+ InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, seq_num,
+ _, _, _));
+ // Packet should be stored in a send bucket.
+ EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
+ kAllowRetransmission,
+ RtpPacketSender::kNormalPriority));
+ rtp_sender_->TimeToSendPacket(kSsrc, seq_num, capture_time_ms, false,
+ PacedPacketInfo());
+ } else {
+ packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(AllOf(
+ Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)),
+ Pointee(Property(&RtpPacketToSend::SequenceNumber, seq_num)))));
+ EXPECT_TRUE(rtp_sender_->SendToNetwork(
+ absl::make_unique<RtpPacketToSend>(*packet), kAllowRetransmission));
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ }
- // Packet should be stored in a send bucket.
- EXPECT_TRUE(rtp_sender_->SendToNetwork(std::move(packet),
- kAllowRetransmission,
- RtpPacketSender::kNormalPriority));
-
- rtp_sender_->TimeToSendPacket(kSsrc, seq_num, capture_time_ms, false,
- PacedPacketInfo());
// Process send bucket.
EXPECT_EQ(++total_packets_sent, transport_.packets_sent());
EXPECT_EQ(packet_size, transport_.last_sent_packet().size());
@@ -1006,16 +1133,28 @@
EXPECT_CALL(send_packet_observer_,
OnSendPacket(kTransportSequenceNumber, _, _))
.Times(1);
- EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
- .WillOnce(Return(kTransportSequenceNumber));
- EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
- .Times(1);
- SendGenericPacket(); // Packet passed to pacer.
- const bool kIsRetransmit = false;
- rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
- fake_clock_.TimeInMilliseconds(), kIsRetransmit,
- PacedPacketInfo());
+ if (GetParam().pacer_references_packets) {
+ const bool kIsRetransmit = false;
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _));
+ SendGenericPacket(); // Packet passed to pacer.
+ EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
+ .WillOnce(::testing::Return(kTransportSequenceNumber));
+ rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
+ fake_clock_.TimeInMilliseconds(),
+ kIsRetransmit, PacedPacketInfo());
+ } else {
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(AllOf(
+ Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)),
+ Pointee(Property(&RtpPacketToSend::SequenceNumber, kSeqNum)))));
+ auto packet = SendGenericPacket();
+ packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+ packet->SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ }
+
EXPECT_EQ(1, transport_.packets_sent());
}
@@ -1026,21 +1165,41 @@
rtp_sender_->SetStorePacketsStatus(true, 10);
EXPECT_CALL(send_packet_observer_, OnSendPacket(_, _, _)).Times(0);
- EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
- .WillOnce(Return(kTransportSequenceNumber));
- EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
- .Times(1);
- SendGenericPacket(); // Packet passed to pacer.
- const bool kIsRetransmit = true;
- rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
- fake_clock_.TimeInMilliseconds(), kIsRetransmit,
- PacedPacketInfo());
+ if (GetParam().pacer_references_packets) {
+ const bool kIsRetransmit = true;
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _));
+ SendGenericPacket(); // Packet passed to pacer.
+ EXPECT_CALL(seq_num_allocator_, AllocateSequenceNumber())
+ .WillOnce(Return(kTransportSequenceNumber));
+ rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
+ fake_clock_.TimeInMilliseconds(),
+ kIsRetransmit, PacedPacketInfo());
+ } else {
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(AllOf(
+ Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)),
+ Pointee(Property(&RtpPacketToSend::SequenceNumber, kSeqNum)))));
+ auto packet = SendGenericPacket();
+ packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
+ packet->SetExtension<TransportSequenceNumber>(kTransportSequenceNumber);
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ }
+
EXPECT_EQ(1, transport_.packets_sent());
EXPECT_TRUE(transport_.last_options_.is_retransmit);
}
TEST_P(RtpSenderTest, OnSendPacketNotUpdatedWithoutSeqNumAllocator) {
+ if (!GetParam().pacer_references_packets) {
+ // When PacedSender owns packets, there is no
+ // TransportSequenceNumberAllocator callback, so this test does not make any
+ // sense.
+ // TODO(bugs.webrtc.org/10633): Remove this test once old code is gone.
+ return;
+ }
+
RtpRtcp::Configuration config;
config.clock = &fake_clock_;
config.outgoing_transport = &transport_;
@@ -1058,20 +1217,26 @@
rtp_sender_->SetStorePacketsStatus(true, 10);
EXPECT_CALL(send_packet_observer_, OnSendPacket(_, _, _)).Times(0);
- EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _))
- .Times(1);
- SendGenericPacket(); // Packet passed to pacer.
const bool kIsRetransmit = false;
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, kSeqNum, _, _, _));
+ SendGenericPacket(); // Packet passed to pacer.
rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
fake_clock_.TimeInMilliseconds(), kIsRetransmit,
PacedPacketInfo());
+
EXPECT_EQ(1, transport_.packets_sent());
}
// TODO(bugs.webrtc.org/8975): Remove this test when non-useful padding is
// removed.
TEST_P(RtpSenderTest, SendRedundantPayloads) {
+ if (!GetParam().pacer_references_packets) {
+ // If PacedSender owns the RTP packets, GeneratePadding() family of methods
+ // will be called instead and this test makes no sense.
+ return;
+ }
+
test::ScopedFieldTrials field_trials(
"WebRTC-PayloadPadding-UseMostUsefulPacket/Disabled/");
MockTransport transport;
@@ -1103,9 +1268,6 @@
const size_t kPayloadSizes[kNumPayloadSizes] = {500, 550, 600, 650, 700,
750, 800, 850, 900, 950};
// Expect all packets go through the pacer.
- EXPECT_CALL(mock_paced_sender_,
- InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, _, _, _, _))
- .Times(kNumPayloadSizes);
EXPECT_CALL(mock_rtc_event_log_,
LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
.Times(kNumPayloadSizes);
@@ -1113,10 +1275,27 @@
// Send 10 packets of increasing size.
for (size_t i = 0; i < kNumPayloadSizes; ++i) {
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
- EXPECT_CALL(transport, SendRtp(_, _, _)).WillOnce(Return(true));
- SendPacket(capture_time_ms, kPayloadSizes[i]);
- rtp_sender_->TimeToSendPacket(kSsrc, seq_num++, capture_time_ms, false,
- PacedPacketInfo());
+
+ EXPECT_CALL(transport, SendRtp(_, _, _)).WillOnce(::testing::Return(true));
+
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, seq_num, _, _, _));
+ SendPacket(capture_time_ms, kPayloadSizes[i]);
+ rtp_sender_->TimeToSendPacket(kSsrc, seq_num,
+ fake_clock_.TimeInMilliseconds(), false,
+ PacedPacketInfo());
+ } else {
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(AllOf(
+ Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)),
+ Pointee(Property(&RtpPacketToSend::SequenceNumber, seq_num)))));
+ auto packet = SendPacket(capture_time_ms, kPayloadSizes[i]);
+ packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ }
+
+ ++seq_num;
fake_clock_.AdvanceTimeMilliseconds(33);
}
@@ -1153,6 +1332,12 @@
}
TEST_P(RtpSenderTest, SendRedundantPayloadsUsefulPadding) {
+ if (!GetParam().pacer_references_packets) {
+ // If PacedSender owns the RTP packets, GeneratePadding() family of methods
+ // will be called instead and this test makes no sense.
+ return;
+ }
+
test::ScopedFieldTrials field_trials(
"WebRTC-PayloadPadding-UseMostUsefulPacket/Enabled/");
MockTransport transport;
@@ -1184,22 +1369,34 @@
const size_t kPayloadSizes[kNumPayloadSizes] = {500, 550, 600, 650, 700,
750, 800, 850, 900, 950};
// Expect all packets go through the pacer.
- EXPECT_CALL(mock_paced_sender_,
- InsertPacket(RtpPacketSender::kNormalPriority, kSsrc, _, _, _, _))
- .Times(kNumPayloadSizes);
EXPECT_CALL(mock_rtc_event_log_,
LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
.Times(kNumPayloadSizes);
// Send 10 packets of increasing size.
- EXPECT_CALL(transport, SendRtp)
- .Times(kNumPayloadSizes)
- .WillRepeatedly(Return(true));
for (size_t i = 0; i < kNumPayloadSizes; ++i) {
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
- SendPacket(capture_time_ms, kPayloadSizes[i]);
- rtp_sender_->TimeToSendPacket(kSsrc, seq_num++, capture_time_ms, false,
- PacedPacketInfo());
+
+ EXPECT_CALL(transport, SendRtp(_, _, _)).WillOnce(::testing::Return(true));
+
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(_, kSsrc, seq_num, _, _, _));
+ SendPacket(capture_time_ms, kPayloadSizes[i]);
+ rtp_sender_->TimeToSendPacket(kSsrc, seq_num,
+ fake_clock_.TimeInMilliseconds(), false,
+ PacedPacketInfo());
+ } else {
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(AllOf(
+ Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)),
+ Pointee(Property(&RtpPacketToSend::SequenceNumber, seq_num)))));
+ auto packet = SendPacket(capture_time_ms, kPayloadSizes[i]);
+ packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+ rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo());
+ }
+
+ ++seq_num;
fake_clock_.AdvanceTimeMilliseconds(33);
}
@@ -1341,30 +1538,60 @@
params.fec_mask_type = kFecMaskRandom;
rtp_sender_video.SetFecParameters(params, params);
- EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
- kSsrc, kSeqNum, _, _, false));
uint16_t flexfec_seq_num;
- EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
- kFlexFecSsrc, _, _, _, false))
- .WillOnce(SaveArg<2>(&flexfec_seq_num));
-
RTPVideoHeader video_header;
- EXPECT_TRUE(rtp_sender_video.SendVideo(
- VideoFrameType::kVideoFrameKey, kMediaPayloadType, kTimestamp,
- fake_clock_.TimeInMilliseconds(), kPayloadData, sizeof(kPayloadData),
- nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
- EXPECT_CALL(mock_rtc_event_log_,
- LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
- .Times(2);
- EXPECT_EQ(RtpPacketSendResult::kSuccess,
- rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
- fake_clock_.TimeInMilliseconds(),
- false, PacedPacketInfo()));
- EXPECT_EQ(RtpPacketSendResult::kSuccess,
- rtp_sender_->TimeToSendPacket(kFlexFecSsrc, flexfec_seq_num,
- fake_clock_.TimeInMilliseconds(),
- false, PacedPacketInfo()));
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
+ kSsrc, kSeqNum, _, _, false));
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
+ kFlexFecSsrc, _, _, _, false))
+ .WillOnce(::testing::SaveArg<2>(&flexfec_seq_num));
+
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
+ VideoFrameType::kVideoFrameKey, kMediaPayloadType, kTimestamp,
+ fake_clock_.TimeInMilliseconds(), kPayloadData, sizeof(kPayloadData),
+ nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
+
+ EXPECT_EQ(RtpPacketSendResult::kSuccess,
+ rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
+ fake_clock_.TimeInMilliseconds(),
+ false, PacedPacketInfo()));
+ EXPECT_EQ(RtpPacketSendResult::kSuccess,
+ rtp_sender_->TimeToSendPacket(kFlexFecSsrc, flexfec_seq_num,
+ fake_clock_.TimeInMilliseconds(),
+ false, PacedPacketInfo()));
+ } else {
+ std::unique_ptr<RtpPacketToSend> media_packet;
+ std::unique_ptr<RtpPacketToSend> fec_packet;
+
+ EXPECT_CALL(mock_paced_sender_, EnqueuePacket)
+ .Times(2)
+ .WillRepeatedly([&](std::unique_ptr<RtpPacketToSend> packet) {
+ if (packet->packet_type() == RtpPacketToSend::Type::kVideo) {
+ EXPECT_EQ(packet->Ssrc(), kSsrc);
+ EXPECT_EQ(packet->SequenceNumber(), kSeqNum);
+ media_packet = std::move(packet);
+ } else {
+ EXPECT_EQ(packet->packet_type(),
+ RtpPacketToSend::Type::kForwardErrorCorrection);
+ EXPECT_EQ(packet->Ssrc(), kFlexFecSsrc);
+ fec_packet = std::move(packet);
+ }
+ });
+
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
+ VideoFrameType::kVideoFrameKey, kMediaPayloadType, kTimestamp,
+ fake_clock_.TimeInMilliseconds(), kPayloadData, sizeof(kPayloadData),
+ nullptr, &video_header, kDefaultExpectedRetransmissionTimeMs));
+ ASSERT_TRUE(media_packet != nullptr);
+ ASSERT_TRUE(fec_packet != nullptr);
+
+ flexfec_seq_num = fec_packet->SequenceNumber();
+ rtp_sender_->TrySendPacket(media_packet.get(), PacedPacketInfo());
+ rtp_sender_->TrySendPacket(fec_packet.get(), PacedPacketInfo());
+ }
+
ASSERT_EQ(2, transport_.packets_sent());
const RtpPacketReceived& media_packet = transport_.sent_packets_[0];
EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType());
@@ -1376,14 +1603,180 @@
EXPECT_EQ(kFlexFecSsrc, flexfec_packet.Ssrc());
}
+// TODO(ilnik): because of webrtc:7859. Once FEC moved below pacer, this test
+// should be removed.
+TEST_P(RtpSenderTest, NoFlexfecForTimingFrames) {
+ constexpr uint32_t kTimestamp = 1234;
+ const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds();
+ constexpr int kMediaPayloadType = 127;
+ constexpr int kFlexfecPayloadType = 118;
+ const std::vector<RtpExtension> kNoRtpExtensions;
+ const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
+
+ FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexFecSsrc, kSsrc, kNoMid,
+ kNoRtpExtensions, kNoRtpExtensionSizes,
+ nullptr /* rtp_state */, &fake_clock_);
+
+ // Reset |rtp_sender_| to use FlexFEC.
+ rtp_sender_.reset(new RTPSender(
+ false, &fake_clock_, &transport_, &mock_paced_sender_,
+ flexfec_sender.ssrc(), &seq_num_allocator_, nullptr, nullptr, nullptr,
+ &mock_rtc_event_log_, &send_packet_observer_,
+ &retransmission_rate_limiter_, nullptr, false, nullptr, false, false,
+ FieldTrialBasedConfig()));
+ rtp_sender_->SetSSRC(kSsrc);
+ rtp_sender_->SetSequenceNumber(kSeqNum);
+ rtp_sender_->SetStorePacketsStatus(true, 10);
+
+ PlayoutDelayOracle playout_delay_oracle;
+ RTPSenderVideo rtp_sender_video(
+ &fake_clock_, rtp_sender_.get(), &flexfec_sender, &playout_delay_oracle,
+ nullptr, false, false, FieldTrialBasedConfig());
+ rtp_sender_video.RegisterPayloadType(kMediaPayloadType, "GENERIC",
+ /*raw_payload=*/false);
+
+ // Need extension to be registered for timing frames to be sent.
+ ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+ kRtpExtensionVideoTiming, kVideoTimingExtensionId));
+
+ // Parameters selected to generate a single FEC packet per media packet.
+ FecProtectionParams params;
+ params.fec_rate = 15;
+ params.max_fec_frames = 1;
+ params.fec_mask_type = kFecMaskRandom;
+ rtp_sender_video.SetFecParameters(params, params);
+
+ RTPVideoHeader video_header;
+ video_header.video_timing.flags = VideoSendTiming::kTriggeredByTimer;
+
+ EXPECT_CALL(mock_rtc_event_log_,
+ LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
+ .Times(1);
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
+ kSsrc, kSeqNum, _, _, false));
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
+ kFlexFecSsrc, _, _, _, false))
+ .Times(0); // Not called because packet should not be protected.
+
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
+ VideoFrameType::kVideoFrameKey, kMediaPayloadType, kTimestamp,
+ kCaptureTimeMs, kPayloadData, sizeof(kPayloadData), nullptr,
+ &video_header, kDefaultExpectedRetransmissionTimeMs));
+
+ EXPECT_EQ(RtpPacketSendResult::kSuccess,
+ rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum,
+ fake_clock_.TimeInMilliseconds(),
+ false, PacedPacketInfo()));
+ } else {
+ std::unique_ptr<RtpPacketToSend> rtp_packet;
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(AllOf(
+ Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)),
+ Pointee(Property(&RtpPacketToSend::SequenceNumber, kSeqNum)))))
+ .WillOnce([&rtp_packet](std::unique_ptr<RtpPacketToSend> packet) {
+ rtp_packet = std::move(packet);
+ });
+
+ EXPECT_CALL(
+ mock_paced_sender_,
+ EnqueuePacket(Pointee(Property(&RtpPacketToSend::Ssrc, kFlexFecSsrc))))
+ .Times(0); // Not called because packet should not be protected.
+
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
+ VideoFrameType::kVideoFrameKey, kMediaPayloadType, kTimestamp,
+ kCaptureTimeMs, kPayloadData, sizeof(kPayloadData), nullptr,
+ &video_header, kDefaultExpectedRetransmissionTimeMs));
+
+ EXPECT_TRUE(
+ rtp_sender_->TrySendPacket(rtp_packet.get(), PacedPacketInfo()));
+ }
+
+ ASSERT_EQ(1, transport_.packets_sent());
+ const RtpPacketReceived& media_packet = transport_.sent_packets_[0];
+ EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType());
+ EXPECT_EQ(kSeqNum, media_packet.SequenceNumber());
+ EXPECT_EQ(kSsrc, media_packet.Ssrc());
+
+ // Now try to send not a timing frame.
+ uint16_t flexfec_seq_num;
+
+ EXPECT_CALL(mock_rtc_event_log_,
+ LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing)))
+ .Times(2);
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(RtpPacketSender::kLowPriority,
+ kFlexFecSsrc, _, _, _, false))
+ .WillOnce(::testing::SaveArg<2>(&flexfec_seq_num));
+ EXPECT_CALL(mock_paced_sender_,
+ InsertPacket(RtpPacketSender::kLowPriority, kSsrc, kSeqNum + 1,
+ _, _, false));
+ video_header.video_timing.flags = VideoSendTiming::kInvalid;
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
+ VideoFrameType::kVideoFrameKey, kMediaPayloadType, kTimestamp + 1,
+ kCaptureTimeMs + 1, kPayloadData, sizeof(kPayloadData), nullptr,
+ &video_header, kDefaultExpectedRetransmissionTimeMs));
+
+ EXPECT_EQ(RtpPacketSendResult::kSuccess,
+ rtp_sender_->TimeToSendPacket(kSsrc, kSeqNum + 1,
+ fake_clock_.TimeInMilliseconds(),
+ false, PacedPacketInfo()));
+ EXPECT_EQ(RtpPacketSendResult::kSuccess,
+ rtp_sender_->TimeToSendPacket(kFlexFecSsrc, flexfec_seq_num,
+ fake_clock_.TimeInMilliseconds(),
+ false, PacedPacketInfo()));
+ } else {
+ std::unique_ptr<RtpPacketToSend> media_packet;
+ std::unique_ptr<RtpPacketToSend> fec_packet;
+
+ EXPECT_CALL(mock_paced_sender_, EnqueuePacket)
+ .Times(2)
+ .WillRepeatedly([&](std::unique_ptr<RtpPacketToSend> packet) {
+ if (packet->packet_type() == RtpPacketToSend::Type::kVideo) {
+ EXPECT_EQ(packet->Ssrc(), kSsrc);
+ EXPECT_EQ(packet->SequenceNumber(), kSeqNum + 1);
+ media_packet = std::move(packet);
+ } else {
+ EXPECT_EQ(packet->packet_type(),
+ RtpPacketToSend::Type::kForwardErrorCorrection);
+ EXPECT_EQ(packet->Ssrc(), kFlexFecSsrc);
+ fec_packet = std::move(packet);
+ }
+ });
+
+ video_header.video_timing.flags = VideoSendTiming::kInvalid;
+ EXPECT_TRUE(rtp_sender_video.SendVideo(
+ VideoFrameType::kVideoFrameKey, kMediaPayloadType, kTimestamp + 1,
+ kCaptureTimeMs + 1, kPayloadData, sizeof(kPayloadData), nullptr,
+ &video_header, kDefaultExpectedRetransmissionTimeMs));
+
+ ASSERT_TRUE(media_packet != nullptr);
+ ASSERT_TRUE(fec_packet != nullptr);
+
+ flexfec_seq_num = fec_packet->SequenceNumber();
+ rtp_sender_->TrySendPacket(media_packet.get(), PacedPacketInfo());
+ rtp_sender_->TrySendPacket(fec_packet.get(), PacedPacketInfo());
+ }
+
+ ASSERT_EQ(3, transport_.packets_sent());
+ const RtpPacketReceived& media_packet2 = transport_.sent_packets_[1];
+ EXPECT_EQ(kMediaPayloadType, media_packet2.PayloadType());
+ EXPECT_EQ(kSeqNum + 1, media_packet2.SequenceNumber());
+ EXPECT_EQ(kSsrc, media_packet2.Ssrc());
+ const RtpPacketReceived& flexfec_packet = transport_.sent_packets_[2];
+ EXPECT_EQ(kFlexfecPayloadType, flexfec_packet.PayloadType());
+ EXPECT_EQ(flexfec_seq_num, flexfec_packet.SequenceNumber());
+ EXPECT_EQ(kFlexFecSsrc, flexfec_packet.Ssrc());
+}
+
TEST_P(RtpSenderTestWithoutPacer, SendFlexfecPackets) {
constexpr uint32_t kTimestamp = 1234;
constexpr int kMediaPayloadType = 127;
constexpr int kFlexfecPayloadType = 118;
- constexpr uint32_t kFlexfecSsrc = 5678;
const std::vector<RtpExtension> kNoRtpExtensions;
const std::vector<RtpExtensionSize> kNoRtpExtensionSizes;
- FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexfecSsrc, kSsrc, kNoMid,
+ FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexFecSsrc, kSsrc, kNoMid,
kNoRtpExtensions, kNoRtpExtensionSizes,
nullptr /* rtp_state */, &fake_clock_);
@@ -1430,7 +1823,7 @@
EXPECT_EQ(kSsrc, media_packet.Ssrc());
const RtpPacketReceived& flexfec_packet = transport_.sent_packets_[1];
EXPECT_EQ(kFlexfecPayloadType, flexfec_packet.PayloadType());
- EXPECT_EQ(kFlexfecSsrc, flexfec_packet.Ssrc());
+ EXPECT_EQ(kFlexFecSsrc, flexfec_packet.Ssrc());
}
// Test that the MID header extension is included on sent packets when
@@ -1550,8 +1943,13 @@
constexpr size_t kNumMediaPackets = 10;
constexpr size_t kNumFecPackets = kNumMediaPackets;
constexpr int64_t kTimeBetweenPacketsMs = 10;
- EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, false))
- .Times(kNumMediaPackets + kNumFecPackets);
+ if (GetParam().pacer_references_packets) {
+ EXPECT_CALL(mock_paced_sender_, InsertPacket(_, _, _, _, _, false))
+ .Times(kNumMediaPackets + kNumFecPackets);
+ } else {
+ EXPECT_CALL(mock_paced_sender_, EnqueuePacket)
+ .Times(kNumMediaPackets + kNumFecPackets);
+ }
for (size_t i = 0; i < kNumMediaPackets; ++i) {
RTPVideoHeader video_header;
@@ -2166,26 +2564,33 @@
// Generated padding has large enough budget that the video packet should be
// retransmitted as padding.
- EXPECT_CALL(mock_paced_sender_,
- EnqueuePacket(AllOf(
- Pointee(Property(&RtpPacketToSend::packet_type,
- RtpPacketToSend::Type::kPadding)),
- Pointee(Property(&RtpPacketToSend::Ssrc, kRtxSsrc)),
- Pointee(Property(&RtpPacketToSend::payload_size,
- kPayloadPacketSize + kRtxHeaderSize)))))
- .Times(1);
- rtp_sender_->GeneratePadding(kPayloadPacketSize + kRtxHeaderSize);
+ std::vector<std::unique_ptr<RtpPacketToSend>> generated_packets =
+ rtp_sender_->GeneratePadding(kPayloadPacketSize + kRtxHeaderSize);
+ ASSERT_EQ(generated_packets.size(), 1u);
+ auto& padding_packet = generated_packets.front();
+ EXPECT_EQ(padding_packet->packet_type(), RtpPacketToSend::Type::kPadding);
+ EXPECT_EQ(padding_packet->Ssrc(), kRtxSsrc);
+ EXPECT_EQ(padding_packet->payload_size(),
+ kPayloadPacketSize + kRtxHeaderSize);
// Not enough budged for payload padding, use plain padding instead.
- EXPECT_CALL(mock_paced_sender_,
- EnqueuePacket(AllOf(
- Pointee(Property(&RtpPacketToSend::packet_type,
- RtpPacketToSend::Type::kPadding)),
- Pointee(Property(&RtpPacketToSend::Ssrc, kRtxSsrc)),
- Pointee(Property(&RtpPacketToSend::payload_size, 0)),
- Pointee(Property(&RtpPacketToSend::padding_size, Gt(0u))))))
- .Times((kPayloadPacketSize + kMaxPaddingSize - 1) / kMaxPaddingSize);
- rtp_sender_->GeneratePadding(kPayloadPacketSize + kRtxHeaderSize - 1);
+ const size_t kPaddingBytesRequested = kPayloadPacketSize + kRtxHeaderSize - 1;
+ const size_t kExpectedNumPaddingPackets =
+ (kPaddingBytesRequested + kMaxPaddingSize - 1) / kMaxPaddingSize;
+
+ size_t padding_bytes_generated = 0;
+ generated_packets = rtp_sender_->GeneratePadding(kPaddingBytesRequested);
+ EXPECT_EQ(generated_packets.size(), kExpectedNumPaddingPackets);
+ for (auto& packet : generated_packets) {
+ EXPECT_EQ(packet->packet_type(), RtpPacketToSend::Type::kPadding);
+ EXPECT_EQ(packet->Ssrc(), kRtxSsrc);
+ EXPECT_EQ(packet->payload_size(), 0u);
+ EXPECT_GT(packet->padding_size(), 0u);
+ padding_bytes_generated += packet->padding_size();
+ }
+
+ EXPECT_EQ(padding_bytes_generated,
+ kExpectedNumPaddingPackets * kMaxPaddingSize);
}
TEST_P(RtpSenderTest, GeneratePaddingCreatesPurePaddingWithoutRtx) {
@@ -2209,24 +2614,32 @@
const size_t kPaddingBytesRequested = kPayloadPacketSize + kRtxHeaderSize;
const size_t kExpectedNumPaddingPackets =
(kPaddingBytesRequested + kMaxPaddingSize - 1) / kMaxPaddingSize;
- size_t padding_bytes_sent = 0;
- EXPECT_CALL(mock_paced_sender_, EnqueuePacket)
- .WillRepeatedly([&](std::unique_ptr<RtpPacketToSend> packet) {
- EXPECT_EQ(packet->packet_type(), RtpPacketToSend::Type::kPadding);
- EXPECT_EQ(packet->Ssrc(), kSsrc);
- EXPECT_EQ(packet->payload_size(), 0u);
- EXPECT_GT(packet->padding_size(), 0u);
- padding_bytes_sent += packet->padding_size();
- });
- rtp_sender_->GeneratePadding(kPaddingBytesRequested);
- EXPECT_EQ(padding_bytes_sent, kExpectedNumPaddingPackets * kMaxPaddingSize);
+ size_t padding_bytes_generated = 0;
+ std::vector<std::unique_ptr<RtpPacketToSend>> padding_packets =
+ rtp_sender_->GeneratePadding(kPaddingBytesRequested);
+ EXPECT_EQ(padding_packets.size(), kExpectedNumPaddingPackets);
+ for (auto& packet : padding_packets) {
+ EXPECT_EQ(packet->packet_type(), RtpPacketToSend::Type::kPadding);
+ EXPECT_EQ(packet->Ssrc(), kSsrc);
+ EXPECT_EQ(packet->payload_size(), 0u);
+ EXPECT_GT(packet->padding_size(), 0u);
+ padding_bytes_generated += packet->padding_size();
+ }
+
+ EXPECT_EQ(padding_bytes_generated,
+ kExpectedNumPaddingPackets * kMaxPaddingSize);
}
INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead,
RtpSenderTest,
- ::testing::Bool());
+ ::testing::Values(TestConfig{false, false},
+ TestConfig{false, true},
+ TestConfig{true, false},
+ TestConfig{true, true}));
+
INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead,
RtpSenderTestWithoutPacer,
- ::testing::Bool());
+ ::testing::Values(TestConfig{false, false},
+ TestConfig{true, false}));
} // namespace webrtc