Add TrySendPacket() method to RTP modules.

This method will be called when PacedSender is using the new code path
that directly owns the packets to be sent.

It can be seen as combining a few features of the old code path:
* It checks if this is the correct RTP module and then sends, without
  the need for PacketRouter to poll multiple methods for SSRC etc first.
* It partly corresponds to TimeToSendPacket(), but RTX encapsulation
  now happens pre-pacer and FEC does not need to have a packet history,
  so most of that method is not used.
* It implements most of PrepareAndSendPacket(), such as updating header
  extensions, reporting stats and of course forwards to Transport. It
  now also handles the history a bit differently, since media packets
  will only be stored for potential retransmission post-pacer.

Bug: webrtc:10633
Change-Id: Ie97952eeef6e56e462e115d67f7c7929f36c1817
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/142165
Commit-Queue: Erik Språng <sprang@webrtc.org>
Reviewed-by: Ilya Nikolaevskiy <ilnik@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28298}
diff --git a/modules/rtp_rtcp/include/rtp_rtcp.h b/modules/rtp_rtcp/include/rtp_rtcp.h
index 203871b..6734e6c 100644
--- a/modules/rtp_rtcp/include/rtp_rtcp.h
+++ b/modules/rtp_rtcp/include/rtp_rtcp.h
@@ -268,6 +268,12 @@
       bool retransmission,
       const PacedPacketInfo& pacing_info) = 0;
 
+  // Try to send the provided packet. Returns true iff packet matches any of
+  // the SSRCs for this module (media/rtx/fec etc) and was forwarded to the
+  // transport.
+  virtual bool TrySendPacket(RtpPacketToSend* packet,
+                             const PacedPacketInfo& pacing_info) = 0;
+
   virtual size_t TimeToSendPadding(size_t bytes,
                                    const PacedPacketInfo& pacing_info) = 0;
 
diff --git a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 0514507..2791d0e 100644
--- a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -11,6 +11,7 @@
 #ifndef MODULES_RTP_RTCP_MOCKS_MOCK_RTP_RTCP_H_
 #define MODULES_RTP_RTCP_MOCKS_MOCK_RTP_RTCP_H_
 
+#include <memory>
 #include <set>
 #include <string>
 #include <utility>
@@ -22,6 +23,7 @@
 #include "modules/rtp_rtcp/include/rtp_rtcp.h"
 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
 #include "rtc_base/checks.h"
 #include "test/gmock.h"
 
@@ -88,6 +90,9 @@
                                    int64_t capture_time_ms,
                                    bool retransmission,
                                    const PacedPacketInfo& pacing_info));
+  MOCK_METHOD2(TrySendPacket,
+               bool(RtpPacketToSend* packet,
+                    const PacedPacketInfo& pacing_info));
   MOCK_METHOD2(TimeToSendPadding,
                size_t(size_t bytes, const PacedPacketInfo& pacing_info));
   MOCK_METHOD2(RegisterRtcpObservers,
diff --git a/modules/rtp_rtcp/source/rtp_packet_to_send.h b/modules/rtp_rtcp/source/rtp_packet_to_send.h
index 8961284..1cbe7de 100644
--- a/modules/rtp_rtcp/source/rtp_packet_to_send.h
+++ b/modules/rtp_rtcp/source/rtp_packet_to_send.h
@@ -50,6 +50,21 @@
   void set_packet_type(Type type) { packet_type_ = type; }
   absl::optional<Type> packet_type() const { return packet_type_; }
 
+  // If this is a retransmission, indicates the sequence number of the original
+  // media packet that this packet represents. If RTX is used this will likely
+  // be different from SequenceNumber().
+  void set_retransmitted_sequence_number(uint16_t sequence_number) {
+    retransmitted_sequence_number_ = sequence_number;
+  }
+  absl::optional<uint16_t> retransmitted_sequence_number() {
+    return retransmitted_sequence_number_;
+  }
+
+  void set_allow_retransmission(bool allow_retransmission) {
+    allow_retransmission_ = allow_retransmission;
+  }
+  bool allow_retransmission() { return allow_retransmission_; }
+
   // Additional data bound to the RTP packet for use in application code,
   // outside of WebRTC.
   rtc::ArrayView<const uint8_t> application_data() const {
@@ -87,6 +102,8 @@
  private:
   int64_t capture_time_ms_ = 0;
   absl::optional<Type> packet_type_;
+  bool allow_retransmission_ = false;
+  absl::optional<uint16_t> retransmitted_sequence_number_;
   std::vector<uint8_t> application_data_;
 };
 
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 09e8c52..900599b 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -416,6 +416,11 @@
                                        retransmission, pacing_info);
 }
 
+bool ModuleRtpRtcpImpl::TrySendPacket(RtpPacketToSend* packet,
+                                      const PacedPacketInfo& pacing_info) {
+  return rtp_sender_->TrySendPacket(packet, pacing_info);
+}
+
 size_t ModuleRtpRtcpImpl::TimeToSendPadding(
     size_t bytes,
     const PacedPacketInfo& pacing_info) {
diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 817ec7a..38e1ede 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -29,6 +29,7 @@
 #include "modules/rtp_rtcp/source/rtcp_packet/tmmb_item.h"
 #include "modules/rtp_rtcp/source/rtcp_receiver.h"
 #include "modules/rtp_rtcp/source/rtcp_sender.h"
+#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
 #include "modules/rtp_rtcp/source/rtp_sender.h"
 #include "rtc_base/critical_section.h"
 #include "rtc_base/gtest_prod_util.h"
@@ -139,6 +140,9 @@
       bool retransmission,
       const PacedPacketInfo& pacing_info) override;
 
+  bool TrySendPacket(RtpPacketToSend* packet,
+                     const PacedPacketInfo& pacing_info) override;
+
   // Returns the number of padding bytes actually sent, which can be more or
   // less than |bytes|.
   size_t TimeToSendPadding(size_t bytes,
diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc
index b783859..2f23ddd 100644
--- a/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/modules/rtp_rtcp/source/rtp_sender.cc
@@ -571,6 +571,119 @@
              : RtpPacketSendResult::kTransportUnavailable;
 }
 
+// Called from pacer when we can send the packet.
+bool RTPSender::TrySendPacket(RtpPacketToSend* packet,
+                              const PacedPacketInfo& pacing_info) {
+  RTC_DCHECK(packet);
+
+  const uint32_t packet_ssrc = packet->Ssrc();
+  const auto packet_type = packet->packet_type();
+  RTC_DCHECK(packet_type.has_value());
+
+  PacketOptions options;
+  bool is_media = false;
+  bool is_rtx = false;
+  {
+    rtc::CritScope lock(&send_critsect_);
+    if (!sending_media_) {
+      return false;
+    }
+
+    switch (*packet_type) {
+      case RtpPacketToSend::Type::kAudio:
+      case RtpPacketToSend::Type::kVideo:
+        if (packet_ssrc != ssrc_) {
+          return false;
+        }
+        is_media = true;
+        break;
+      case RtpPacketToSend::Type::kRetransmission:
+      case RtpPacketToSend::Type::kPadding:
+        // Both padding and retransmission must be on either the media or the
+        // RTX stream.
+        if (packet_ssrc == ssrc_rtx_) {
+          is_rtx = true;
+        } else if (packet_ssrc != ssrc_) {
+          return false;
+        }
+        break;
+      case RtpPacketToSend::Type::kForwardErrorCorrection:
+        // FlexFEC is on separate SSRC, ULPFEC uses media SSRC.
+        if (packet_ssrc != ssrc_ && packet_ssrc != flexfec_ssrc_) {
+          return false;
+        }
+        break;
+    }
+
+    options.included_in_allocation = force_part_of_allocation_;
+  }
+
+  // Bug webrtc:7859. While FEC is invoked from rtp_sender_video, and not after
+  // the pacer, these modifications of the header below are happening after the
+  // FEC protection packets are calculated. This will corrupt recovered packets
+  // at the same place. It's not an issue for extensions, which are present in
+  // all the packets (their content just may be incorrect on recovered packets).
+  // 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.
+  int64_t now_ms = clock_->TimeInMilliseconds();
+  int64_t diff_ms = now_ms - packet->capture_time_ms();
+  packet->SetExtension<TransmissionOffset>(kTimestampTicksPerMs * diff_ms);
+  packet->SetExtension<AbsoluteSendTime>(AbsoluteSendTime::MsTo24Bits(now_ms));
+
+  if (packet->HasExtension<VideoTimingExtension>()) {
+    if (populate_network2_timestamp_) {
+      packet->set_network2_time_ms(now_ms);
+    } else {
+      packet->set_pacer_exit_time_ms(now_ms);
+    }
+  }
+
+  // Downstream code actually uses this flag to distinguish between media and
+  // everything else.
+  options.is_retransmit = !is_media;
+  if (auto packet_id = packet->GetExtension<TransportSequenceNumber>()) {
+    options.packet_id = *packet_id;
+    options.included_in_feedback = true;
+    options.included_in_allocation = true;
+    AddPacketToTransportFeedback(*packet_id, *packet, pacing_info);
+  }
+
+  options.application_data.assign(packet->application_data().begin(),
+                                  packet->application_data().end());
+
+  if (packet->packet_type() != RtpPacketToSend::Type::kPadding &&
+      packet->packet_type() != RtpPacketToSend::Type::kRetransmission) {
+    UpdateDelayStatistics(packet->capture_time_ms(), now_ms, packet_ssrc);
+    UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(),
+                       packet_ssrc);
+  }
+
+  const bool send_success = SendPacketToNetwork(*packet, options, pacing_info);
+
+  // Put packet in retransmission history or update pending status even if
+  // actual sending fails.
+  if (is_media && packet->allow_retransmission()) {
+    packet_history_.PutRtpPacket(absl::make_unique<RtpPacketToSend>(*packet),
+                                 StorageType::kAllowRetransmission, now_ms);
+  } else if (packet->retransmitted_sequence_number()) {
+    packet_history_.MarkPacketAsSent(*packet->retransmitted_sequence_number());
+  }
+
+  if (send_success) {
+    UpdateRtpStats(*packet, is_rtx,
+                   packet_type == RtpPacketToSend::Type::kRetransmission);
+
+    rtc::CritScope lock(&send_critsect_);
+    media_has_been_sent_ = true;
+  }
+
+  // Return true even if transport failed (will be handled by retransmissions
+  // instead in that case), so that PacketRouter does not have to iterate over
+  // all other RTP modules and fail to send there too.
+  return true;
+}
+
 bool RTPSender::PrepareAndSendPacket(std::unique_ptr<RtpPacketToSend> packet,
                                      bool send_over_rtx,
                                      bool is_retransmit,
@@ -632,7 +745,7 @@
                                   packet_to_send->application_data().end());
 
   if (!is_retransmit && !send_over_rtx) {
-    UpdateDelayStatistics(packet->capture_time_ms(), now_ms);
+    UpdateDelayStatistics(packet->capture_time_ms(), now_ms, packet->Ssrc());
     UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(),
                        packet->Ssrc());
   }
@@ -744,7 +857,7 @@
   options.application_data.assign(packet->application_data().begin(),
                                   packet->application_data().end());
 
-  UpdateDelayStatistics(packet->capture_time_ms(), now_ms);
+  UpdateDelayStatistics(packet->capture_time_ms(), now_ms, packet->Ssrc());
   UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(),
                      packet->Ssrc());
 
@@ -777,21 +890,16 @@
   }
 }
 
-void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) {
+void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms,
+                                      int64_t now_ms,
+                                      uint32_t ssrc) {
   if (!send_side_delay_observer_ || capture_time_ms <= 0)
     return;
 
-  uint32_t ssrc;
   int avg_delay_ms = 0;
   int max_delay_ms = 0;
   uint64_t total_packet_send_delay_ms = 0;
   {
-    rtc::CritScope lock(&send_critsect_);
-    if (!ssrc_)
-      return;
-    ssrc = *ssrc_;
-  }
-  {
     rtc::CritScope cs(&statistics_crit_);
     // Compute the max and average of the recent capture-to-send delays.
     // The time complexity of the current approach depends on the distribution
diff --git a/modules/rtp_rtcp/source/rtp_sender.h b/modules/rtp_rtcp/source/rtp_sender.h
index 3933ba3..94ef809 100644
--- a/modules/rtp_rtcp/source/rtp_sender.h
+++ b/modules/rtp_rtcp/source/rtp_sender.h
@@ -110,6 +110,8 @@
                                        int64_t capture_time_ms,
                                        bool retransmission,
                                        const PacedPacketInfo& pacing_info);
+  bool TrySendPacket(RtpPacketToSend* packet,
+                     const PacedPacketInfo& pacing_info);
   size_t TimeToSendPadding(size_t bytes, const PacedPacketInfo& pacing_info);
 
   // NACK.
@@ -204,7 +206,9 @@
                            const PacedPacketInfo& pacing_info);
 
   void RecomputeMaxSendDelay() RTC_EXCLUSIVE_LOCKS_REQUIRED(statistics_crit_);
-  void UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms);
+  void UpdateDelayStatistics(int64_t capture_time_ms,
+                             int64_t now_ms,
+                             uint32_t ssrc);
   void UpdateOnSendPacket(int packet_id,
                           int64_t capture_time_ms,
                           uint32_t ssrc);
diff --git a/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
index 944ec07..c492b81 100644
--- a/modules/rtp_rtcp/source/rtp_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/rtp_sender_unittest.cc
@@ -60,6 +60,8 @@
 const uint32_t kTimestamp = 10;
 const uint16_t kSeqNum = 33;
 const uint32_t kSsrc = 725242;
+const uint32_t kRtxSsrc = 12345;
+const uint32_t kFlexFecSsrc = 45678;
 const uint16_t kTransportSequenceNumber = 0xaabbu;
 const uint64_t kStartTime = 123456789;
 const size_t kMaxPaddingSize = 224u;
@@ -74,7 +76,9 @@
 using ::testing::ElementsAreArray;
 using ::testing::Field;
 using ::testing::Invoke;
+using ::testing::NiceMock;
 using ::testing::SizeIs;
+using ::testing::StrictMock;
 
 uint64_t ConvertMsToAbsSendTime(int64_t time_ms) {
   return (((time_ms << 18) + 500) / 1000) & 0x00ffffff;
@@ -192,22 +196,22 @@
   void SetUpRtpSender(bool pacer, bool populate_network2) {
     rtp_sender_.reset(new RTPSender(
         false, &fake_clock_, &transport_, pacer ? &mock_paced_sender_ : nullptr,
-        absl::nullopt, &seq_num_allocator_, nullptr, nullptr, nullptr,
+        kFlexFecSsrc, &seq_num_allocator_, nullptr, nullptr, nullptr,
         &mock_rtc_event_log_, &send_packet_observer_,
         &retransmission_rate_limiter_, nullptr, populate_network2, nullptr,
         false, false, FieldTrialBasedConfig()));
     rtp_sender_->SetSequenceNumber(kSeqNum);
     rtp_sender_->SetTimestampOffset(0);
     rtp_sender_->SetSSRC(kSsrc);
+    rtp_sender_->SetRtxSsrc(kRtxSsrc);
   }
 
   SimulatedClock fake_clock_;
-  ::testing::NiceMock<MockRtcEventLog> mock_rtc_event_log_;
+  NiceMock<MockRtcEventLog> mock_rtc_event_log_;
   MockRtpPacketSender mock_paced_sender_;
-  ::testing::StrictMock<MockTransportSequenceNumberAllocator>
-      seq_num_allocator_;
-  ::testing::StrictMock<MockSendPacketObserver> send_packet_observer_;
-  ::testing::StrictMock<MockTransportFeedbackObserver> feedback_observer_;
+  StrictMock<MockTransportSequenceNumberAllocator> seq_num_allocator_;
+  StrictMock<MockSendPacketObserver> send_packet_observer_;
+  StrictMock<MockTransportFeedbackObserver> feedback_observer_;
   RateLimiter retransmission_rate_limiter_;
   std::unique_ptr<RTPSender> rtp_sender_;
   LoopbackTransportTest transport_;
@@ -378,7 +382,7 @@
 TEST_P(RtpSenderTestWithoutPacer,
        TransportFeedbackObserverGetsCorrectByteCount) {
   constexpr int kRtpOverheadBytesPerPacket = 12 + 8;
-  ::testing::NiceMock<MockOverheadObserver> mock_overhead_observer;
+  NiceMock<MockOverheadObserver> mock_overhead_observer;
   rtp_sender_.reset(
       new RTPSender(false, &fake_clock_, &transport_, nullptr, absl::nullopt,
                     &seq_num_allocator_, &feedback_observer_, nullptr, nullptr,
@@ -506,7 +510,7 @@
 }
 
 TEST_P(RtpSenderTestWithoutPacer, OnSendSideDelayUpdated) {
-  ::testing::StrictMock<MockSendSideDelayObserver> send_side_delay_observer_;
+  StrictMock<MockSendSideDelayObserver> send_side_delay_observer_;
   rtp_sender_.reset(
       new RTPSender(false, &fake_clock_, &transport_, nullptr, absl::nullopt,
                     nullptr, nullptr, nullptr, &send_side_delay_observer_,
@@ -1444,7 +1448,7 @@
   rtp_sender_->SetSendingMediaStatus(true);
 
   rtp_sender_->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads);
-  rtp_sender_->SetRtxSsrc(1234);
+  rtp_sender_->SetRtxSsrc(kRtxSsrc);
   rtp_sender_->SetRtxPayloadType(kRtxPayload, kPayload);
 
   rtp_sender_->SetStorePacketsStatus(true, 10);
@@ -1723,7 +1727,7 @@
   // XXX const char* kPayloadName = "GENERIC";
   const uint8_t kPayloadType = 127;
   rtp_sender_->SetSSRC(1234);
-  rtp_sender_->SetRtxSsrc(4321);
+  rtp_sender_->SetRtxSsrc(kRtxSsrc);
   rtp_sender_->SetRtxPayloadType(kPayloadType - 1, kPayloadType);
   rtp_sender_->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads);
 
@@ -1827,6 +1831,277 @@
   SendGenericPacket();
 }
 
+TEST_P(RtpSenderTest, TrySendPacketMatchesVideo) {
+  std::unique_ptr<RtpPacketToSend> packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+
+  // Verify not sent with wrong SSRC.
+  packet->SetSsrc(kSsrc + 1);
+  EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  // Verify sent with correct SSRC.
+  packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->SetSsrc(kSsrc);
+  packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+}
+
+TEST_P(RtpSenderTest, TrySendPacketMatchesAudio) {
+  std::unique_ptr<RtpPacketToSend> packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->set_packet_type(RtpPacketToSend::Type::kAudio);
+
+  // Verify not sent with wrong SSRC.
+  packet->SetSsrc(kSsrc + 1);
+  EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  // Verify sent with correct SSRC.
+  packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->SetSsrc(kSsrc);
+  packet->set_packet_type(RtpPacketToSend::Type::kAudio);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+}
+
+TEST_P(RtpSenderTest, TrySendPacketMatchesRetransmissions) {
+  std::unique_ptr<RtpPacketToSend> packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
+
+  // Verify not sent with wrong SSRC.
+  packet->SetSsrc(kSsrc + 1);
+  EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  // Verify sent with correct SSRC (non-RTX).
+  packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->SetSsrc(kSsrc);
+  packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  // RTX retransmission.
+  packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->SetSsrc(kRtxSsrc);
+  packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+}
+
+TEST_P(RtpSenderTest, TrySendPacketMatchesPadding) {
+  std::unique_ptr<RtpPacketToSend> packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->set_packet_type(RtpPacketToSend::Type::kPadding);
+
+  // Verify not sent with wrong SSRC.
+  packet->SetSsrc(kSsrc + 1);
+  EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  // Verify sent with correct SSRC (non-RTX).
+  packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->SetSsrc(kSsrc);
+  packet->set_packet_type(RtpPacketToSend::Type::kPadding);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  // RTX padding.
+  packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->SetSsrc(kRtxSsrc);
+  packet->set_packet_type(RtpPacketToSend::Type::kPadding);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+}
+
+TEST_P(RtpSenderTest, TrySendPacketMatchesFlexfec) {
+  std::unique_ptr<RtpPacketToSend> packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection);
+
+  // Verify not sent with wrong SSRC.
+  packet->SetSsrc(kSsrc + 1);
+  EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  // Verify sent with correct SSRC.
+  packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->SetSsrc(kFlexFecSsrc);
+  packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+}
+
+TEST_P(RtpSenderTest, TrySendPacketMatchesUlpfec) {
+  std::unique_ptr<RtpPacketToSend> packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection);
+
+  // Verify not sent with wrong SSRC.
+  packet->SetSsrc(kSsrc + 1);
+  EXPECT_FALSE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  // Verify sent with correct SSRC.
+  packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->SetSsrc(kSsrc);
+  packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+}
+
+TEST_P(RtpSenderTest, TrySendPacketHandlesRetransmissionHistory) {
+  rtp_sender_->SetStorePacketsStatus(true, 10);
+
+  // Build a media packet and send it.
+  std::unique_ptr<RtpPacketToSend> packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  const uint16_t media_sequence_number = packet->SequenceNumber();
+  packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+  packet->set_allow_retransmission(true);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  // Simulate retransmission request.
+  fake_clock_.AdvanceTimeMilliseconds(30);
+  EXPECT_GT(rtp_sender_->ReSendPacket(media_sequence_number), 0);
+
+  // Packet already pending, retransmission not allowed.
+  fake_clock_.AdvanceTimeMilliseconds(30);
+  EXPECT_EQ(rtp_sender_->ReSendPacket(media_sequence_number), 0);
+
+  // Packet exiting pacer, mark as not longer pending.
+  packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  EXPECT_NE(packet->SequenceNumber(), media_sequence_number);
+  packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
+  packet->SetSsrc(kRtxSsrc);
+  packet->set_retransmitted_sequence_number(media_sequence_number);
+  packet->set_allow_retransmission(false);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  // Retransmissions allowed again.
+  fake_clock_.AdvanceTimeMilliseconds(30);
+  EXPECT_GT(rtp_sender_->ReSendPacket(media_sequence_number), 0);
+
+  // Retransmission of RTX packet should not be allowed.
+  EXPECT_EQ(rtp_sender_->ReSendPacket(packet->SequenceNumber()), 0);
+}
+
+TEST_P(RtpSenderTest, TrySendPacketUpdatesExtensions) {
+  ASSERT_EQ(rtp_sender_->RegisterRtpHeaderExtension(
+                kRtpExtensionTransmissionTimeOffset,
+                kTransmissionTimeOffsetExtensionId),
+            0);
+  ASSERT_EQ(rtp_sender_->RegisterRtpHeaderExtension(
+                kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId),
+            0);
+  ASSERT_EQ(rtp_sender_->RegisterRtpHeaderExtension(kRtpExtensionVideoTiming,
+                                                    kVideoTimingExtensionId),
+            0);
+
+  std::unique_ptr<RtpPacketToSend> packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->set_packetization_finish_time_ms(fake_clock_.TimeInMilliseconds());
+
+  const int32_t kDiffMs = 10;
+  fake_clock_.AdvanceTimeMilliseconds(kDiffMs);
+
+  packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  const RtpPacketReceived& received_packet = transport_.last_sent_packet();
+
+  EXPECT_EQ(received_packet.GetExtension<TransmissionOffset>(), kDiffMs * 90);
+
+  EXPECT_EQ(received_packet.GetExtension<AbsoluteSendTime>(),
+            AbsoluteSendTime::MsTo24Bits(fake_clock_.TimeInMilliseconds()));
+
+  VideoSendTiming timing;
+  EXPECT_TRUE(received_packet.GetExtension<VideoTimingExtension>(&timing));
+  EXPECT_EQ(timing.pacer_exit_delta_ms, kDiffMs);
+}
+
+TEST_P(RtpSenderTest, TrySendPacketSetsPacketOptions) {
+  const uint16_t kPacketId = 42;
+  ASSERT_EQ(rtp_sender_->RegisterRtpHeaderExtension(
+                kRtpExtensionTransportSequenceNumber,
+                kTransportSequenceNumberExtensionId),
+            0);
+  std::unique_ptr<RtpPacketToSend> packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->SetExtension<TransportSequenceNumber>(kPacketId);
+
+  packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+  EXPECT_CALL(send_packet_observer_, OnSendPacket);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+
+  EXPECT_EQ(transport_.last_options_.packet_id, kPacketId);
+  EXPECT_TRUE(transport_.last_options_.included_in_allocation);
+  EXPECT_TRUE(transport_.last_options_.included_in_feedback);
+  EXPECT_FALSE(transport_.last_options_.is_retransmit);
+
+  // Send another packet as retransmission, verify options are populated.
+  packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  packet->SetExtension<TransportSequenceNumber>(kPacketId + 1);
+  packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(packet.get(), PacedPacketInfo()));
+  EXPECT_TRUE(transport_.last_options_.is_retransmit);
+}
+
+TEST_P(RtpSenderTest, TrySendPacketUpdatesStats) {
+  const size_t kPayloadSize = 1000;
+
+  StrictMock<MockSendSideDelayObserver> send_side_delay_observer;
+  rtp_sender_.reset(new RTPSender(
+      false, &fake_clock_, &transport_, nullptr, kFlexFecSsrc, nullptr, nullptr,
+      nullptr, &send_side_delay_observer, &mock_rtc_event_log_,
+      &send_packet_observer_, nullptr, nullptr, false, nullptr, false, false,
+      FieldTrialBasedConfig()));
+  rtp_sender_->SetSSRC(kSsrc);
+  rtp_sender_->SetRtxSsrc(kRtxSsrc);
+  ASSERT_EQ(0, rtp_sender_->RegisterRtpHeaderExtension(
+                   kRtpExtensionTransportSequenceNumber,
+                   kTransportSequenceNumberExtensionId));
+
+  const int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
+
+  std::unique_ptr<RtpPacketToSend> video_packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  video_packet->set_packet_type(RtpPacketToSend::Type::kVideo);
+  video_packet->SetPayloadSize(kPayloadSize);
+  video_packet->SetExtension<TransportSequenceNumber>(1);
+
+  std::unique_ptr<RtpPacketToSend> rtx_packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  rtx_packet->SetSsrc(kRtxSsrc);
+  rtx_packet->set_packet_type(RtpPacketToSend::Type::kRetransmission);
+  rtx_packet->SetPayloadSize(kPayloadSize);
+  rtx_packet->SetExtension<TransportSequenceNumber>(2);
+
+  std::unique_ptr<RtpPacketToSend> fec_packet =
+      BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds());
+  fec_packet->SetSsrc(kFlexFecSsrc);
+  fec_packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection);
+  fec_packet->SetPayloadSize(kPayloadSize);
+  fec_packet->SetExtension<TransportSequenceNumber>(3);
+
+  const int64_t kDiffMs = 25;
+  fake_clock_.AdvanceTimeMilliseconds(kDiffMs);
+
+  EXPECT_CALL(send_side_delay_observer,
+              SendSideDelayUpdated(kDiffMs, kDiffMs, kDiffMs, kSsrc));
+  EXPECT_CALL(
+      send_side_delay_observer,
+      SendSideDelayUpdated(kDiffMs, kDiffMs, 2 * kDiffMs, kFlexFecSsrc));
+
+  EXPECT_CALL(send_packet_observer_, OnSendPacket(1, capture_time_ms, kSsrc));
+  EXPECT_TRUE(
+      rtp_sender_->TrySendPacket(video_packet.get(), PacedPacketInfo()));
+
+  // Send packet observer not called for padding/retransmissions.
+  EXPECT_CALL(send_packet_observer_, OnSendPacket(2, _, _)).Times(0);
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(rtx_packet.get(), PacedPacketInfo()));
+
+  EXPECT_CALL(send_packet_observer_,
+              OnSendPacket(3, capture_time_ms, kFlexFecSsrc));
+  EXPECT_TRUE(rtp_sender_->TrySendPacket(fec_packet.get(), PacedPacketInfo()));
+
+  StreamDataCounters rtp_stats;
+  StreamDataCounters rtx_stats;
+  rtp_sender_->GetDataCounters(&rtp_stats, &rtx_stats);
+  EXPECT_EQ(rtp_stats.transmitted.packets, 2u);
+  EXPECT_EQ(rtp_stats.fec.packets, 1u);
+  EXPECT_EQ(rtx_stats.retransmitted.packets, 1u);
+}
+
 INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead,
                          RtpSenderTest,
                          ::testing::Bool());