Skip network transmission in RtpSenderEgress for untransmitted packets. When packet->allow_sending() is false, skip adding send-time header extensions and skip transmitting to the network transport, but still store the packet in RtpPacketHistory if it is marked as retransmittable. Bug: webrtc:564720400 Change-Id: Ie627f5b44d34b6eb44b481212e4c95094928f2f4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/505760 Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> Commit-Queue: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/main@{#48752}
diff --git a/modules/rtp_rtcp/BUILD.gn b/modules/rtp_rtcp/BUILD.gn index b871280..542331a 100644 --- a/modules/rtp_rtcp/BUILD.gn +++ b/modules/rtp_rtcp/BUILD.gn
@@ -376,6 +376,7 @@ "../../rtc_base:timeutils", "../../rtc_base/containers:flat_map", "../../rtc_base/experiments:field_trial_parser", + "../../rtc_base/experiments:retransmit_flushed_packets_settings", "../../rtc_base/synchronization:mutex", "../../rtc_base/system:no_unique_address", "../../rtc_base/task_utils:repeating_task",
diff --git a/modules/rtp_rtcp/source/rtp_packet_history.cc b/modules/rtp_rtcp/source/rtp_packet_history.cc index f215424..5cda7d6 100644 --- a/modules/rtp_rtcp/source/rtp_packet_history.cc +++ b/modules/rtp_rtcp/source/rtp_packet_history.cc
@@ -42,12 +42,12 @@ RtpPacketHistory::StoredPacket::StoredPacket( std::unique_ptr<RtpPacketToSend> packet, Timestamp send_time, - uint64_t insert_order) + uint64_t insert_order, + Timestamp earliest_allowed_retransmission) : packet_(std::move(packet)), - pending_transmission_(false), + earliest_allowed_retransmission_(earliest_allowed_retransmission), send_time_(send_time), - insert_order_(insert_order), - times_retransmitted_(0) {} + insert_order_(insert_order) {} RtpPacketHistory::StoredPacket::StoredPacket(StoredPacket&&) = default; RtpPacketHistory::StoredPacket& RtpPacketHistory::StoredPacket::operator=( @@ -62,6 +62,7 @@ PaddingMode padding_mode) : clock_(&env.clock()), padding_mode_(padding_mode), + retransmit_flushed_packets_settings_(env.field_trials()), number_to_store_(0), mode_(StorageMode::kDisabled), rtt_(TimeDelta::MinusInfinity()), @@ -109,6 +110,13 @@ RTC_DCHECK(packet->allow_retransmission()); CullOldPackets(); + Timestamp earliest_allowed_retransmission = Timestamp::MinusInfinity(); + if (!packet->allow_sending()) { + TimeDelta rtt = rtt_ >= TimeDelta::Zero() ? rtt_ : kDefaultRtt; + earliest_allowed_retransmission = + send_time + retransmit_flushed_packets_settings_.rtt_multiplier() * rtt; + } + // Store packet. const uint16_t rtp_seq_no = packet->SequenceNumber(); int packet_index = GetPacketIndex(rtp_seq_no); @@ -146,7 +154,8 @@ } packet_history_[packet_index] = - StoredPacket(std::move(packet), send_time, packets_inserted_++); + StoredPacket(std::move(packet), send_time, packets_inserted_++, + earliest_allowed_retransmission); } std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacketAndMarkAsPending( @@ -186,6 +195,7 @@ encapsulate(*packet->packet_); if (encapsulated_packet) { packet->pending_transmission_ = true; + encapsulated_packet->set_allow_sending(true); } return encapsulated_packet; @@ -234,8 +244,11 @@ bool RtpPacketHistory::VerifyRtt( const RtpPacketHistory::StoredPacket& packet) const { - if (packet.times_retransmitted() > 0 && - clock_->CurrentTime() - packet.send_time() < rtt_) { + const Timestamp now = clock_->CurrentTime(); + if (now < packet.earliest_allowed_retransmission()) { + return false; + } + if (packet.times_retransmitted() > 0 && now - packet.send_time() < rtt_) { // This packet has already been retransmitted once, and the time since // that even is lower than on RTT. Ignore request as this packet is // likely already in the network pipe. @@ -261,7 +274,12 @@ } if (padding_mode_ == PaddingMode::kRecentLargePacket && large_payload_packet_) { - return encapsulate(*large_payload_packet_); + std::unique_ptr<RtpPacketToSend> padding_packet = + encapsulate(*large_payload_packet_); + if (padding_packet != nullptr) { + padding_packet->set_allow_sending(true); + } + return padding_packet; } StoredPacket* best_packet = nullptr; @@ -293,6 +311,7 @@ return nullptr; } + padding_packet->set_allow_sending(true); best_packet->set_send_time(clock_->CurrentTime()); best_packet->IncrementTimesRetransmitted(); return padding_packet;
diff --git a/modules/rtp_rtcp/source/rtp_packet_history.h b/modules/rtp_rtcp/source/rtp_packet_history.h index 9a8c882..c49766e 100644 --- a/modules/rtp_rtcp/source/rtp_packet_history.h +++ b/modules/rtp_rtcp/source/rtp_packet_history.h
@@ -24,6 +24,7 @@ #include "api/units/timestamp.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" +#include "rtc_base/experiments/retransmit_flushed_packets_settings.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/thread_annotations.h" @@ -55,6 +56,9 @@ static constexpr int kMinPacketDurationRtt = 3; // With kStoreAndCull, always remove packets after 3x max(1000ms, 3x rtt). static constexpr int kPacketCullingDelayFactor = 3; + // Default RTT used when calculating earliest allowed retransmission for + // packets not allowed sending if no RTT has been set yet. + static constexpr TimeDelta kDefaultRtt = TimeDelta::Millis(200); RtpPacketHistory(const Environment& env, PaddingMode padding_mode); @@ -128,7 +132,8 @@ StoredPacket() = default; StoredPacket(std::unique_ptr<RtpPacketToSend> packet, Timestamp send_time, - uint64_t insert_order); + uint64_t insert_order, + Timestamp earliest_allowed_retransmission); StoredPacket(StoredPacket&&); StoredPacket& operator=(StoredPacket&&); ~StoredPacket(); @@ -141,21 +146,27 @@ Timestamp send_time() const { return send_time_; } void set_send_time(Timestamp value) { send_time_ = value; } + Timestamp earliest_allowed_retransmission() const { + return earliest_allowed_retransmission_; + } + // The actual packet. std::unique_ptr<RtpPacketToSend> packet_; // True if the packet is currently in the pacer queue pending transmission. - bool pending_transmission_; + bool pending_transmission_ = false; private: + // Do not restrict retransmission by default. + Timestamp earliest_allowed_retransmission_ = Timestamp::MinusInfinity(); Timestamp send_time_ = Timestamp::Zero(); // Unique number per StoredPacket, incremented by one for each added // packet. Used to sort on insert order. - uint64_t insert_order_; + uint64_t insert_order_ = 0; // Number of times RE-transmitted, ie excluding the first transmission. - size_t times_retransmitted_; + size_t times_retransmitted_ = 0; }; // Helper method to check if packet has too recently been sent. @@ -174,6 +185,9 @@ Clock* const clock_; const PaddingMode padding_mode_; + // TODO(bugs.webrtc.org/564720400): Either remove or make permanent once + // experiment is concluded. + const RetransmitFlushedPacketsSettings retransmit_flushed_packets_settings_; mutable Mutex lock_; size_t number_to_store_ RTC_GUARDED_BY(lock_); StorageMode mode_ RTC_GUARDED_BY(lock_);
diff --git a/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc index a265483..453bffd1 100644 --- a/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_packet_history_unittest.cc
@@ -41,6 +41,8 @@ using StorageMode = RtpPacketHistory::StorageMode; using ::testing::AllOf; +using ::testing::IsNull; +using ::testing::NotNull; using ::testing::Pointee; using ::testing::Property; @@ -723,4 +725,97 @@ Pointee(Property(&RtpPacketToSend::SequenceNumber, sequence_number))); } +TEST_P(RtpPacketHistoryTest, + DisallowsRetransmissionOfPacketNotAllowedSendingBeforeMultiplierRtt) { + constexpr TimeDelta kRtt = TimeDelta::Millis(100); + hist_.SetStorePacketsStatus(RtpPacketHistory::StorageMode::kStoreAndCull, 10); + hist_.SetRtt(kRtt); + + Timestamp now = fake_clock_.CurrentTime(); + std::unique_ptr<RtpPacketToSend> packet = CreatePacket(kStartSeqNum); + packet->set_allow_sending(false); + hist_.PutRtpPacket(std::move(packet), now); + + fake_clock_.AdvanceTime(2 * kRtt - TimeDelta::Millis(1)); + EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum)); + EXPECT_THAT(hist_.GetPacketAndMarkAsPending(kStartSeqNum), IsNull()); +} + +TEST_P(RtpPacketHistoryTest, + AllowsRetransmissionOfPacketNotAllowedSendingAtMultiplierRtt) { + constexpr TimeDelta kRtt = TimeDelta::Millis(100); + hist_.SetStorePacketsStatus(RtpPacketHistory::StorageMode::kStoreAndCull, 10); + hist_.SetRtt(kRtt); + + Timestamp now = fake_clock_.CurrentTime(); + std::unique_ptr<RtpPacketToSend> packet = CreatePacket(kStartSeqNum); + packet->set_allow_sending(false); + hist_.PutRtpPacket(std::move(packet), now); + + fake_clock_.AdvanceTime(2 * kRtt); + EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum)); + std::unique_ptr<RtpPacketToSend> retransmitted_packet = + hist_.GetPacketAndMarkAsPending(kStartSeqNum); + ASSERT_THAT(retransmitted_packet, NotNull()); + EXPECT_EQ(retransmitted_packet->SequenceNumber(), kStartSeqNum); + EXPECT_TRUE(retransmitted_packet->allow_sending()); +} + +TEST_P(RtpPacketHistoryTest, PacketNotAllowedSendingUsesDefaultRttIfNoneSet) { + hist_.SetStorePacketsStatus(RtpPacketHistory::StorageMode::kStoreAndCull, 10); + + Timestamp now = fake_clock_.CurrentTime(); + std::unique_ptr<RtpPacketToSend> packet = CreatePacket(kStartSeqNum); + packet->set_allow_sending(false); + hist_.PutRtpPacket(std::move(packet), now); + + // Before 2 * kDefaultRtt (400ms), retransmission is not allowed. + fake_clock_.AdvanceTime(2 * RtpPacketHistory::kDefaultRtt - + TimeDelta::Millis(1)); + EXPECT_FALSE(hist_.GetPacketState(kStartSeqNum)); + EXPECT_THAT(hist_.GetPacketAndMarkAsPending(kStartSeqNum), IsNull()); + + // At/after 2 * kDefaultRtt, retransmission is allowed. + fake_clock_.AdvanceTime(TimeDelta::Millis(1)); + EXPECT_TRUE(hist_.GetPacketState(kStartSeqNum)); + std::unique_ptr<RtpPacketToSend> default_rtt_packet = + hist_.GetPacketAndMarkAsPending(kStartSeqNum); + ASSERT_THAT(default_rtt_packet, NotNull()); + EXPECT_EQ(default_rtt_packet->SequenceNumber(), kStartSeqNum); + EXPECT_TRUE(default_rtt_packet->allow_sending()); +} + +TEST_P(RtpPacketHistoryTest, + PacketNotAllowedSendingRespectsCustomRttMultiplier) { + constexpr TimeDelta kRtt = TimeDelta::Millis(100); + Environment env = CreateTestEnvironment({ + .field_trials = + "WebRTC-RetransmitFlushedPackets/Enabled,rtt_multiplier:3.0/", + .time = &fake_clock_, + }); + RtpPacketHistory history(env, GetParam()); + history.SetStorePacketsStatus(RtpPacketHistory::StorageMode::kStoreAndCull, + 10); + history.SetRtt(kRtt); + + Timestamp now = fake_clock_.CurrentTime(); + std::unique_ptr<RtpPacketToSend> packet = CreatePacket(kStartSeqNum); + packet->set_allow_sending(false); + history.PutRtpPacket(std::move(packet), now); + + // Before 3 * RTT (300ms), retransmission is not allowed. + fake_clock_.AdvanceTime(3 * kRtt - TimeDelta::Millis(1)); + EXPECT_FALSE(history.GetPacketState(kStartSeqNum)); + EXPECT_THAT(history.GetPacketAndMarkAsPending(kStartSeqNum), IsNull()); + + // At 3 * RTT, retransmission is allowed. + fake_clock_.AdvanceTime(TimeDelta::Millis(1)); + EXPECT_TRUE(history.GetPacketState(kStartSeqNum)); + std::unique_ptr<RtpPacketToSend> custom_multiplier_packet = + history.GetPacketAndMarkAsPending(kStartSeqNum); + ASSERT_THAT(custom_multiplier_packet, NotNull()); + EXPECT_EQ(custom_multiplier_packet->SequenceNumber(), kStartSeqNum); + EXPECT_TRUE(custom_multiplier_packet->allow_sending()); +} + } // namespace webrtc
diff --git a/modules/rtp_rtcp/source/rtp_sender_egress.cc b/modules/rtp_rtcp/source/rtp_sender_egress.cc index d4d39c2..8feb4f1 100644 --- a/modules/rtp_rtcp/source/rtp_sender_egress.cc +++ b/modules/rtp_rtcp/source/rtp_sender_egress.cc
@@ -49,6 +49,11 @@ constexpr TimeDelta kBitrateStatisticsWindow = TimeDelta::Seconds(1); constexpr size_t kRtpSequenceNumberMapMaxEntries = 1 << 13; constexpr TimeDelta kUpdateInterval = kBitrateStatisticsWindow; + +bool IsMediaPacket(std::optional<RtpPacketMediaType> packet_type) { + return packet_type == RtpPacketMediaType::kVideo || + packet_type == RtpPacketMediaType::kAudio; +} } // namespace RtpSenderEgress::NonPacedPacketSender::NonPacedPacketSender( @@ -93,12 +98,10 @@ if (packet->Ssrc() != sender_->FlexFecSsrc()) { sequencer_->Sequence(*packet); } - if (!packet->SetExtension<TransportSequenceNumber>( - ++transport_sequence_number_)) { + if (packet->allow_sending() && !packet->SetExtension<TransportSequenceNumber>( + ++transport_sequence_number_)) { --transport_sequence_number_; } - packet->ReserveExtension<TransmissionOffset>(); - packet->ReserveExtension<AbsoluteSendTime>(); } RtpSenderEgress::RtpSenderEgress(const Environment& env, @@ -220,35 +223,45 @@ // In case of VideoTimingExtension, since it's present not in every packet, // data after rtp header may be corrupted if these packets are protected by // the FEC. - if (packet->HasExtension<TransmissionOffset>() && - packet->capture_time() > Timestamp::Zero()) { - TimeDelta diff = now - packet->capture_time(); - packet->SetExtension<TransmissionOffset>(kTimestampTicksPerMs * diff.ms()); - } - if (packet->HasExtension<AbsoluteSendTime>()) { - packet->SetExtension<AbsoluteSendTime>(AbsoluteSendTime::To24Bits( - env_.clock().ConvertTimestampToNtpTime(now))); - } - if (packet->HasExtension<TransportSequenceNumber>() && - packet->transport_sequence_number()) { - packet->SetExtension<TransportSequenceNumber>( - *packet->transport_sequence_number() & 0xFFFF); - } - - if (packet->HasExtension<VideoTimingExtension>()) { - if (populate_network2_timestamp_) { - packet->set_network2_time(now); - } else { - packet->set_pacer_exit_time(now); + if (packet->allow_sending()) { + if (packet->HasExtension<TransmissionOffset>() && + packet->capture_time() > Timestamp::Zero()) { + TimeDelta diff = now - packet->capture_time(); + packet->SetExtension<TransmissionOffset>(kTimestampTicksPerMs * + diff.ms()); } - } + if (packet->HasExtension<AbsoluteSendTime>()) { + packet->SetExtension<AbsoluteSendTime>(AbsoluteSendTime::To24Bits( + env_.clock().ConvertTimestampToNtpTime(now))); + } + if (packet->HasExtension<TransportSequenceNumber>() && + packet->transport_sequence_number()) { + packet->SetExtension<TransportSequenceNumber>( + *packet->transport_sequence_number() & 0xFFFF); + } - auto compound_packet = - Packet{.rtp_packet = std::move(packet), .info = pacing_info, .now = now}; - if (enable_send_packet_batching_ && !is_audio_) { - packets_to_send_.push_back(std::move(compound_packet)); - } else { - CompleteSendPacket(compound_packet, false); + if (packet->HasExtension<VideoTimingExtension>()) { + if (populate_network2_timestamp_) { + packet->set_network2_time(now); + } else { + packet->set_pacer_exit_time(now); + } + } + + auto compound_packet = Packet{ + .rtp_packet = std::move(packet), .info = pacing_info, .now = now}; + if (enable_send_packet_batching_ && !is_audio_) { + packets_to_send_.push_back(std::move(compound_packet)); + } else { + CompleteSendPacket(compound_packet, false); + } + } else if (IsMediaPacket(packet->packet_type()) && + packet->allow_retransmission()) { + // TODO(bugs.webrtc.org/564720400): Either remove or make permanent skipping + // network transmission if allow_sending is false. + // + // Packet should not be sent, just put it in the packet history. + packet_history_->PutRtpPacket(std::move(packet), now); } } @@ -265,11 +278,11 @@ RTC_DCHECK_RUN_ON(worker_queue_); auto& [packet, pacing_info, now] = compound_packet; RTC_CHECK(packet); + RTC_DCHECK(packet->allow_sending()); PacketOptions options; options.included_in_allocation = force_part_of_allocation_; - options.is_media = packet->packet_type() == RtpPacketMediaType::kAudio || - packet->packet_type() == RtpPacketMediaType::kVideo; + options.is_media = IsMediaPacket(packet->packet_type()); // Set Packet id from transport sequence number header extension if it is // used. The source of the header extension is
diff --git a/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc index 68476ca..676cef0 100644 --- a/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_sender_egress_unittest.cc
@@ -17,6 +17,7 @@ #include <optional> #include <span> #include <utility> +#include <vector> #include "api/call/transport.h" #include "api/environment/environment.h" @@ -29,6 +30,7 @@ #include "modules/rtp_rtcp/include/flexfec_sender.h" #include "modules/rtp_rtcp/include/rtp_header_extension_map.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "modules/rtp_rtcp/source/packet_sequencer.h" #include "modules/rtp_rtcp/source/rtp_header_extension_size.h" #include "modules/rtp_rtcp/source/rtp_header_extensions.h" #include "modules/rtp_rtcp/source/rtp_packet_history.h" @@ -49,7 +51,9 @@ using ::testing::Eq; using ::testing::Field; using ::testing::InSequence; +using ::testing::IsNull; using ::testing::NiceMock; +using ::testing::NotNull; constexpr Timestamp kStartTime = Timestamp::Millis(123456789); constexpr int kDefaultPayloadType = 100; @@ -510,6 +514,140 @@ EXPECT_TRUE(packet_history_.GetPacketState(packet_sequence_number)); } +TEST_F(RtpSenderEgressTest, PacketWithAllowSendingFalseNotSentToNetwork) { + std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress(); + + std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket(); + packet->set_allow_retransmission(true); + packet->set_allow_sending(false); + + // Transport and observer should NOT receive the packet. + EXPECT_CALL(transport_, SentRtp).Times(0); + EXPECT_CALL(send_packet_observer_, OnSendPacket).Times(0); + + sender->SendPacket(std::move(packet), PacedPacketInfo()); + + EXPECT_FALSE(transport_.last_packet().has_value()); +} + +TEST_F(RtpSenderEgressTest, + PacketWithAllowSendingFalseStoredInHistoryWithDelayedRetransmission) { + std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress(); + const TimeDelta kRtt = TimeDelta::Millis(100); + packet_history_.SetRtt(kRtt); + packet_history_.SetStorePacketsStatus( + RtpPacketHistory::StorageMode::kStoreAndCull, 10); + + std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket(); + packet->set_allow_retransmission(true); + packet->set_allow_sending(false); + packet->set_transport_sequence_number(42); + const uint16_t packet_sequence_number = packet->SequenceNumber(); + + sender->SendPacket(std::move(packet), PacedPacketInfo()); + + // Before 2 * RTT, retransmission is not allowed. + time_controller_.AdvanceTime(2 * kRtt - TimeDelta::Millis(1)); + EXPECT_FALSE(packet_history_.GetPacketState(packet_sequence_number)); + EXPECT_THAT(packet_history_.GetPacketAndMarkAsPending(packet_sequence_number), + IsNull()); + + // At/after 2 * RTT, retransmission IS allowed. + time_controller_.AdvanceTime(TimeDelta::Millis(1)); + EXPECT_TRUE(packet_history_.GetPacketState(packet_sequence_number)); + std::unique_ptr<RtpPacketToSend> retransmit = + packet_history_.GetPacketAndMarkAsPending(packet_sequence_number); + ASSERT_THAT(retransmit, NotNull()); + EXPECT_THAT(retransmit->SequenceNumber(), packet_sequence_number); + EXPECT_THAT(retransmit->allow_sending(), true); + EXPECT_THAT(retransmit->HasExtension<AbsoluteSendTime>(), false); + EXPECT_THAT(retransmit->HasExtension<TransportSequenceNumber>(), false); + + // Send the retransmitted packet and verify it is sent to the network. + retransmit->set_packet_type(RtpPacketMediaType::kRetransmission); + retransmit->set_retransmitted_sequence_number(packet_sequence_number); + EXPECT_CALL(transport_, SentRtp); + sender->SendPacket(std::move(retransmit), PacedPacketInfo()); + EXPECT_TRUE(transport_.last_packet().has_value()); +} + +TEST_F(RtpSenderEgressTest, + PacketWithAllowSendingFalseUsesDefaultRttIfNoneSet) { + std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress(); + packet_history_.SetStorePacketsStatus( + RtpPacketHistory::StorageMode::kStoreAndCull, 10); + + std::unique_ptr<RtpPacketToSend> packet = BuildRtpPacket(); + packet->set_allow_retransmission(true); + packet->set_allow_sending(false); + const uint16_t packet_sequence_number = packet->SequenceNumber(); + + sender->SendPacket(std::move(packet), PacedPacketInfo()); + + // Before 2 * kDefaultRtt (400ms), retransmission is not allowed. + time_controller_.AdvanceTime(2 * RtpPacketHistory::kDefaultRtt - + TimeDelta::Millis(1)); + EXPECT_FALSE(packet_history_.GetPacketState(packet_sequence_number)); + EXPECT_THAT(packet_history_.GetPacketAndMarkAsPending(packet_sequence_number), + IsNull()); + + // At/after 2 * kDefaultRtt, retransmission is allowed. + time_controller_.AdvanceTime(TimeDelta::Millis(1)); + std::unique_ptr<RtpPacketToSend> retransmitted_packet = + packet_history_.GetPacketAndMarkAsPending(packet_sequence_number); + ASSERT_THAT(retransmitted_packet, NotNull()); + EXPECT_EQ(retransmitted_packet->SequenceNumber(), packet_sequence_number); + EXPECT_TRUE(retransmitted_packet->allow_sending()); +} + +TEST_F( + RtpSenderEgressTest, + NonPacedPacketSenderDoesNotIncrementTransportSeqWhenAllowSendingIsFalse) { + header_extensions_.RegisterByUri(kTransportSequenceNumberExtensionId, + TransportSequenceNumber::Uri()); + std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress(); + packet_history_.SetStorePacketsStatus( + RtpPacketHistory::StorageMode::kStoreAndCull, 10); + + PacketSequencer sequencer(kSsrc, kRtxSsrc, + /*require_marker_before_media_padding=*/false, + &env_.clock()); + sequencer.set_media_sequence_number(kStartSequenceNumber); + RtpSenderEgress::NonPacedPacketSender non_paced_sender( + *time_controller_.GetMainThread(), sender.get(), &sequencer); + + std::unique_ptr<RtpPacketToSend> untransmitted_packet = BuildRtpPacket(); + untransmitted_packet->set_allow_retransmission(true); + untransmitted_packet->set_allow_sending(false); + + EXPECT_CALL(transport_, SentRtp).Times(0); + std::vector<std::unique_ptr<RtpPacketToSend>> packets; + packets.push_back(std::move(untransmitted_packet)); + non_paced_sender.EnqueuePackets(std::move(packets)); + + time_controller_.AdvanceTime(2 * RtpPacketHistory::kDefaultRtt); + std::unique_ptr<RtpPacketToSend> stored_packet = + packet_history_.GetPacketAndMarkAsPending(kStartSequenceNumber); + ASSERT_THAT(stored_packet, NotNull()); + + // Enqueue a normal packet and verify the transport sequence number starts at + // 1 (was not incremented for the untransmitted packet). + std::unique_ptr<RtpPacketToSend> transmitted_packet = BuildRtpPacket(); + transmitted_packet->set_allow_sending(true); + + EXPECT_CALL(transport_, SentRtp); + packets.clear(); + packets.push_back(std::move(transmitted_packet)); + non_paced_sender.EnqueuePackets(std::move(packets)); + + ASSERT_TRUE(transport_.last_packet().has_value()); + EXPECT_EQ(transport_.last_packet()->packet.SequenceNumber(), + kStartSequenceNumber + 1); + EXPECT_EQ( + transport_.last_packet()->packet.GetExtension<TransportSequenceNumber>(), + 1u); +} + TEST_F(RtpSenderEgressTest, DoesNotPutNonMediaInHistory) { std::unique_ptr<RtpSenderEgress> sender = CreateRtpSenderEgress(); packet_history_.SetStorePacketsStatus(