/* * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "modules/rtp_rtcp/source/rtp_sender.h" #include #include #include "api/rtc_event_log/rtc_event.h" #include "api/transport/field_trial_based_config.h" #include "api/video/video_codec_constants.h" #include "api/video/video_timing.h" #include "logging/rtc_event_log/mock/mock_rtc_event_log.h" #include "modules/rtp_rtcp/include/rtp_cvo.h" #include "modules/rtp_rtcp/include/rtp_header_extension_map.h" #include "modules/rtp_rtcp/include/rtp_packet_sender.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_format_video_generic.h" #include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor.h" #include "modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.h" #include "modules/rtp_rtcp/source/rtp_header_extensions.h" #include "modules/rtp_rtcp/source/rtp_packet_received.h" #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" #include "modules/rtp_rtcp/source/rtp_sender_egress.h" #include "modules/rtp_rtcp/source/rtp_sender_video.h" #include "modules/rtp_rtcp/source/rtp_utility.h" #include "rtc_base/arraysize.h" #include "rtc_base/rate_limiter.h" #include "test/field_trial.h" #include "test/gmock.h" #include "test/gtest.h" #include "test/mock_transport.h" #include "test/rtp_header_parser.h" namespace webrtc { namespace { enum : int { // The first valid value is 1. kAbsoluteSendTimeExtensionId = 1, kAudioLevelExtensionId, kGenericDescriptorId00, kGenericDescriptorId01, kMidExtensionId, kRepairedRidExtensionId, kRidExtensionId, kTransmissionTimeOffsetExtensionId, kTransportSequenceNumberExtensionId, kVideoRotationExtensionId, kVideoTimingExtensionId, }; const int kPayload = 100; const int kRtxPayload = 98; 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 = 1; const uint64_t kStartTime = 123456789; const size_t kMaxPaddingSize = 224u; const uint8_t kPayloadData[] = {47, 11, 32, 93, 89}; const int64_t kDefaultExpectedRetransmissionTimeMs = 125; const char kNoRid[] = ""; const char kNoMid[] = ""; using ::testing::_; using ::testing::AllOf; using ::testing::Contains; using ::testing::ElementsAreArray; using ::testing::Field; using ::testing::NiceMock; using ::testing::Pointee; using ::testing::Property; using ::testing::Return; using ::testing::StrictMock; uint64_t ConvertMsToAbsSendTime(int64_t time_ms) { return (((time_ms << 18) + 500) / 1000) & 0x00ffffff; } class LoopbackTransportTest : public webrtc::Transport { public: LoopbackTransportTest() : total_bytes_sent_(0) { receivers_extensions_.Register( kTransmissionTimeOffsetExtensionId); receivers_extensions_.Register( kAbsoluteSendTimeExtensionId); receivers_extensions_.Register( kTransportSequenceNumberExtensionId); receivers_extensions_.Register(kVideoRotationExtensionId); receivers_extensions_.Register(kAudioLevelExtensionId); receivers_extensions_.Register( kVideoTimingExtensionId); receivers_extensions_.Register(kMidExtensionId); receivers_extensions_.Register( kGenericDescriptorId00); receivers_extensions_.Register( kGenericDescriptorId01); receivers_extensions_.Register(kRidExtensionId); receivers_extensions_.Register( kRepairedRidExtensionId); } bool SendRtp(const uint8_t* data, size_t len, const PacketOptions& options) override { last_options_ = options; total_bytes_sent_ += len; sent_packets_.push_back(RtpPacketReceived(&receivers_extensions_)); EXPECT_TRUE(sent_packets_.back().Parse(data, len)); return true; } bool SendRtcp(const uint8_t* data, size_t len) override { return false; } const RtpPacketReceived& last_sent_packet() { return sent_packets_.back(); } int packets_sent() { return sent_packets_.size(); } size_t total_bytes_sent_; PacketOptions last_options_; std::vector sent_packets_; private: RtpHeaderExtensionMap receivers_extensions_; }; MATCHER_P(SameRtcEventTypeAs, value, "") { return value == arg->GetType(); } struct TestConfig { explicit TestConfig(bool with_overhead) : with_overhead(with_overhead) {} bool with_overhead = false; }; std::string ToFieldTrialString(TestConfig config) { std::string field_trials; if (config.with_overhead) { field_trials += "WebRTC-SendSideBwe-WithOverhead/Enabled/"; } return field_trials; } class MockRtpPacketPacer : public RtpPacketSender { public: MockRtpPacketPacer() {} virtual ~MockRtpPacketPacer() {} MOCK_METHOD1(EnqueuePackets, void(std::vector>)); MOCK_METHOD2(CreateProbeCluster, void(int bitrate_bps, int cluster_id)); MOCK_METHOD0(Pause, void()); MOCK_METHOD0(Resume, void()); MOCK_METHOD1(SetCongestionWindow, void(absl::optional congestion_window_bytes)); MOCK_METHOD1(UpdateOutstandingData, void(int64_t outstanding_bytes)); MOCK_METHOD1(SetAccountForAudioPackets, void(bool account_for_audio)); }; class MockSendSideDelayObserver : public SendSideDelayObserver { public: MOCK_METHOD4(SendSideDelayUpdated, void(int, int, uint64_t, uint32_t)); }; class MockSendPacketObserver : public SendPacketObserver { public: MOCK_METHOD3(OnSendPacket, void(uint16_t, int64_t, uint32_t)); }; class MockTransportFeedbackObserver : public TransportFeedbackObserver { public: MOCK_METHOD1(OnAddPacket, void(const RtpPacketSendInfo&)); MOCK_METHOD1(OnTransportFeedback, void(const rtcp::TransportFeedback&)); }; class MockOverheadObserver : public OverheadObserver { public: MOCK_METHOD1(OnOverheadChanged, void(size_t overhead_bytes_per_packet)); }; class StreamDataTestCallback : public StreamDataCountersCallback { public: StreamDataTestCallback() : StreamDataCountersCallback(), ssrc_(0), counters_() {} ~StreamDataTestCallback() override = default; void DataCountersUpdated(const StreamDataCounters& counters, uint32_t ssrc) override { ssrc_ = ssrc; counters_ = counters; } uint32_t ssrc_; StreamDataCounters counters_; void MatchPacketCounter(const RtpPacketCounter& expected, const RtpPacketCounter& actual) { EXPECT_EQ(expected.payload_bytes, actual.payload_bytes); EXPECT_EQ(expected.header_bytes, actual.header_bytes); EXPECT_EQ(expected.padding_bytes, actual.padding_bytes); EXPECT_EQ(expected.packets, actual.packets); } void Matches(uint32_t ssrc, const StreamDataCounters& counters) { EXPECT_EQ(ssrc, ssrc_); MatchPacketCounter(counters.transmitted, counters_.transmitted); MatchPacketCounter(counters.retransmitted, counters_.retransmitted); EXPECT_EQ(counters.fec.packets, counters_.fec.packets); } }; // Mimics ModuleRtpRtcp::RtpSenderContext. // TODO(sprang): Split up unit tests and test these components individually // wherever possible. struct RtpSenderContext { explicit RtpSenderContext(const RtpRtcp::Configuration& config) : packet_history_(config.clock), packet_sender_(config, &packet_history_), non_paced_sender_(&packet_sender_), packet_generator_( config, &packet_history_, config.paced_sender ? config.paced_sender : &non_paced_sender_) {} RtpPacketHistory packet_history_; RtpSenderEgress packet_sender_; RtpSenderEgress::NonPacedPacketSender non_paced_sender_; RTPSender packet_generator_; }; } // namespace class RtpSenderTest : public ::testing::TestWithParam { protected: RtpSenderTest() : fake_clock_(kStartTime), retransmission_rate_limiter_(&fake_clock_, 1000), flexfec_sender_(0, kFlexFecSsrc, kSsrc, "", std::vector(), std::vector(), nullptr, &fake_clock_), kMarkerBit(true), field_trials_(ToFieldTrialString(GetParam())) {} void SetUp() override { SetUpRtpSender(true, false); } RTPSender* rtp_sender() { RTC_DCHECK(rtp_sender_context_); return &rtp_sender_context_->packet_generator_; } RtpSenderEgress* rtp_egress() { RTC_DCHECK(rtp_sender_context_); return &rtp_sender_context_->packet_sender_; } void SetUpRtpSender(bool pacer, bool populate_network2) { RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.local_media_ssrc = kSsrc; config.rtx_send_ssrc = kRtxSsrc; config.flexfec_sender = &flexfec_sender_; config.event_log = &mock_rtc_event_log_; config.send_packet_observer = &send_packet_observer_; config.retransmission_rate_limiter = &retransmission_rate_limiter_; config.paced_sender = pacer ? &mock_paced_sender_ : nullptr; config.populate_network2_timestamp = populate_network2; config.rtp_stats_callback = &rtp_stats_callback_; rtp_sender_context_ = std::make_unique(config); rtp_sender()->SetSequenceNumber(kSeqNum); rtp_sender()->SetTimestampOffset(0); } SimulatedClock fake_clock_; NiceMock mock_rtc_event_log_; MockRtpPacketPacer mock_paced_sender_; StrictMock send_packet_observer_; StrictMock feedback_observer_; RateLimiter retransmission_rate_limiter_; FlexfecSender flexfec_sender_; std::unique_ptr rtp_sender_context_; LoopbackTransportTest transport_; const bool kMarkerBit; test::ScopedFieldTrials field_trials_; StreamDataTestCallback rtp_stats_callback_; std::unique_ptr BuildRtpPacket(int payload_type, bool marker_bit, uint32_t timestamp, int64_t capture_time_ms) { auto packet = rtp_sender()->AllocatePacket(); packet->SetPayloadType(payload_type); packet->set_packet_type(RtpPacketToSend::Type::kVideo); packet->SetMarker(marker_bit); packet->SetTimestamp(timestamp); packet->set_capture_time_ms(capture_time_ms); EXPECT_TRUE(rtp_sender()->AssignSequenceNumber(packet.get())); return packet; } std::unique_ptr 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->set_allow_retransmission(true); // Packet should be stored in a send bucket. EXPECT_TRUE(rtp_sender()->SendToNetwork( std::make_unique(*packet))); return packet; } std::unique_ptr SendGenericPacket() { const int64_t kCaptureTimeMs = fake_clock_.TimeInMilliseconds(); return SendPacket(kCaptureTimeMs, sizeof(kPayloadData)); } size_t GenerateAndSendPadding(size_t target_size_bytes) { size_t generated_bytes = 0; for (auto& packet : rtp_sender()->GeneratePadding(target_size_bytes, true)) { generated_bytes += packet->payload_size() + packet->padding_size(); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); } return generated_bytes; } // The following are helpers for configuring the RTPSender. They must be // called before sending any packets. // Enable the retransmission stream with sizable packet storage. void EnableRtx() { // RTX needs to be able to read the source packets from the packet store. // Pick a number of packets to store big enough for any unit test. constexpr uint16_t kNumberOfPacketsToStore = 100; rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, kNumberOfPacketsToStore); rtp_sender()->SetRtxPayloadType(kRtxPayload, kPayload); rtp_sender()->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads); } // Enable sending of the MID header extension for both the primary SSRC and // the RTX SSRC. void EnableMidSending(const std::string& mid) { rtp_sender()->RegisterRtpHeaderExtension(kRtpExtensionMid, kMidExtensionId); rtp_sender()->SetMid(mid); } // Enable sending of the RSID header extension for the primary SSRC and the // RRSID header extension for the RTX SSRC. void EnableRidSending(const std::string& rid) { rtp_sender()->RegisterRtpHeaderExtension(kRtpExtensionRtpStreamId, kRidExtensionId); rtp_sender()->RegisterRtpHeaderExtension(kRtpExtensionRepairedRtpStreamId, kRepairedRidExtensionId); rtp_sender()->SetRid(rid); } }; // TODO(pbos): Move tests over from WithoutPacer to RtpSenderTest as this is our // default code path. class RtpSenderTestWithoutPacer : public RtpSenderTest { public: void SetUp() override { SetUpRtpSender(false, false); } }; TEST_P(RtpSenderTestWithoutPacer, AllocatePacketSetCsrc) { // Configure rtp_sender with csrc. std::vector csrcs; csrcs.push_back(0x23456789); rtp_sender()->SetCsrcs(csrcs); auto packet = rtp_sender()->AllocatePacket(); ASSERT_TRUE(packet); EXPECT_EQ(rtp_sender()->SSRC(), packet->Ssrc()); EXPECT_EQ(csrcs, packet->Csrcs()); } TEST_P(RtpSenderTestWithoutPacer, AllocatePacketReserveExtensions) { // Configure rtp_sender with extensions. ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionAudioLevel, kAudioLevelExtensionId)); ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId)); ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionVideoRotation, kVideoRotationExtensionId)); auto packet = rtp_sender()->AllocatePacket(); ASSERT_TRUE(packet); // Preallocate BWE extensions RtpSender set itself. EXPECT_TRUE(packet->HasExtension()); EXPECT_TRUE(packet->HasExtension()); EXPECT_TRUE(packet->HasExtension()); // Do not allocate media specific extensions. EXPECT_FALSE(packet->HasExtension()); EXPECT_FALSE(packet->HasExtension()); } TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberAdvanceSequenceNumber) { auto packet = rtp_sender()->AllocatePacket(); ASSERT_TRUE(packet); const uint16_t sequence_number = rtp_sender()->SequenceNumber(); EXPECT_TRUE(rtp_sender()->AssignSequenceNumber(packet.get())); EXPECT_EQ(sequence_number, packet->SequenceNumber()); EXPECT_EQ(sequence_number + 1, rtp_sender()->SequenceNumber()); } TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberFailsOnNotSending) { auto packet = rtp_sender()->AllocatePacket(); ASSERT_TRUE(packet); rtp_sender()->SetSendingMediaStatus(false); EXPECT_FALSE(rtp_sender()->AssignSequenceNumber(packet.get())); } TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberMayAllowPaddingOnVideo) { constexpr size_t kPaddingSize = 100; auto packet = rtp_sender()->AllocatePacket(); ASSERT_TRUE(packet); ASSERT_TRUE(rtp_sender()->GeneratePadding(kPaddingSize, true).empty()); packet->SetMarker(false); ASSERT_TRUE(rtp_sender()->AssignSequenceNumber(packet.get())); // Packet without marker bit doesn't allow padding on video stream. ASSERT_TRUE(rtp_sender()->GeneratePadding(kPaddingSize, true).empty()); packet->SetMarker(true); ASSERT_TRUE(rtp_sender()->AssignSequenceNumber(packet.get())); // Packet with marker bit allows send padding. ASSERT_FALSE(rtp_sender()->GeneratePadding(kPaddingSize, true).empty()); } TEST_P(RtpSenderTest, AssignSequenceNumberAllowsPaddingOnAudio) { MockTransport transport; RtpRtcp::Configuration config; config.audio = true; config.clock = &fake_clock_; config.outgoing_transport = &transport; config.paced_sender = &mock_paced_sender_; config.local_media_ssrc = kSsrc; config.event_log = &mock_rtc_event_log_; config.retransmission_rate_limiter = &retransmission_rate_limiter_; rtp_sender_context_ = std::make_unique(config); rtp_sender()->SetTimestampOffset(0); std::unique_ptr audio_packet = rtp_sender()->AllocatePacket(); // Padding on audio stream allowed regardless of marker in the last packet. audio_packet->SetMarker(false); audio_packet->SetPayloadType(kPayload); rtp_sender()->AssignSequenceNumber(audio_packet.get()); const size_t kPaddingSize = 59; EXPECT_CALL(transport, SendRtp(_, kPaddingSize + kRtpHeaderSize, _)) .WillOnce(Return(true)); EXPECT_EQ(kPaddingSize, GenerateAndSendPadding(kPaddingSize)); // Requested padding size is too small, will send a larger one. const size_t kMinPaddingSize = 50; EXPECT_CALL(transport, SendRtp(_, kMinPaddingSize + kRtpHeaderSize, _)) .WillOnce(Return(true)); EXPECT_EQ(kMinPaddingSize, GenerateAndSendPadding(kMinPaddingSize - 5)); } TEST_P(RtpSenderTestWithoutPacer, AssignSequenceNumberSetPaddingTimestamps) { constexpr size_t kPaddingSize = 100; auto packet = rtp_sender()->AllocatePacket(); ASSERT_TRUE(packet); packet->SetMarker(true); packet->SetTimestamp(kTimestamp); ASSERT_TRUE(rtp_sender()->AssignSequenceNumber(packet.get())); auto padding_packets = rtp_sender()->GeneratePadding(kPaddingSize, true); ASSERT_EQ(1u, padding_packets.size()); // Verify padding packet timestamp. EXPECT_EQ(kTimestamp, padding_packets[0]->Timestamp()); } TEST_P(RtpSenderTestWithoutPacer, TransportFeedbackObserverGetsCorrectByteCount) { constexpr int kRtpOverheadBytesPerPacket = 12 + 8; NiceMock mock_overhead_observer; RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.local_media_ssrc = kSsrc; config.transport_feedback_callback = &feedback_observer_; config.event_log = &mock_rtc_event_log_; config.retransmission_rate_limiter = &retransmission_rate_limiter_; config.overhead_observer = &mock_overhead_observer; rtp_sender_context_ = std::make_unique(config); EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId)); const size_t expected_bytes = GetParam().with_overhead ? sizeof(kPayloadData) + kRtpOverheadBytesPerPacket : sizeof(kPayloadData); EXPECT_CALL(feedback_observer_, OnAddPacket(AllOf( Field(&RtpPacketSendInfo::ssrc, rtp_sender()->SSRC()), Field(&RtpPacketSendInfo::transport_sequence_number, kTransportSequenceNumber), Field(&RtpPacketSendInfo::rtp_sequence_number, rtp_sender()->SequenceNumber()), Field(&RtpPacketSendInfo::length, expected_bytes), Field(&RtpPacketSendInfo::pacing_info, PacedPacketInfo())))) .Times(1); EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(kRtpOverheadBytesPerPacket)) .Times(1); SendGenericPacket(); } TEST_P(RtpSenderTestWithoutPacer, SendsPacketsWithTransportSequenceNumber) { RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.local_media_ssrc = kSsrc; config.transport_feedback_callback = &feedback_observer_; config.event_log = &mock_rtc_event_log_; config.send_packet_observer = &send_packet_observer_; config.retransmission_rate_limiter = &retransmission_rate_limiter_; rtp_sender_context_ = std::make_unique(config); EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId)); EXPECT_CALL(send_packet_observer_, OnSendPacket(kTransportSequenceNumber, _, _)) .Times(1); EXPECT_CALL(feedback_observer_, OnAddPacket(AllOf( Field(&RtpPacketSendInfo::ssrc, rtp_sender()->SSRC()), Field(&RtpPacketSendInfo::transport_sequence_number, kTransportSequenceNumber), Field(&RtpPacketSendInfo::rtp_sequence_number, rtp_sender()->SequenceNumber()), Field(&RtpPacketSendInfo::pacing_info, PacedPacketInfo())))) .Times(1); SendGenericPacket(); const auto& packet = transport_.last_sent_packet(); uint16_t transport_seq_no; ASSERT_TRUE(packet.GetExtension(&transport_seq_no)); EXPECT_EQ(kTransportSequenceNumber, transport_seq_no); EXPECT_EQ(transport_.last_options_.packet_id, transport_seq_no); EXPECT_TRUE(transport_.last_options_.included_in_allocation); } TEST_P(RtpSenderTestWithoutPacer, PacketOptionsNoRetransmission) { RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.local_media_ssrc = kSsrc; config.transport_feedback_callback = &feedback_observer_; config.event_log = &mock_rtc_event_log_; config.send_packet_observer = &send_packet_observer_; config.retransmission_rate_limiter = &retransmission_rate_limiter_; rtp_sender_context_ = std::make_unique(config); SendGenericPacket(); EXPECT_FALSE(transport_.last_options_.is_retransmit); } TEST_P(RtpSenderTestWithoutPacer, SetsIncludedInFeedbackWhenTransportSequenceNumberExtensionIsRegistered) { SetUpRtpSender(false, false); rtp_sender()->RegisterRtpHeaderExtension(kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId); EXPECT_CALL(send_packet_observer_, OnSendPacket).Times(1); SendGenericPacket(); EXPECT_TRUE(transport_.last_options_.included_in_feedback); } TEST_P( RtpSenderTestWithoutPacer, SetsIncludedInAllocationWhenTransportSequenceNumberExtensionIsRegistered) { SetUpRtpSender(false, false); rtp_sender()->RegisterRtpHeaderExtension(kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId); EXPECT_CALL(send_packet_observer_, OnSendPacket).Times(1); SendGenericPacket(); EXPECT_TRUE(transport_.last_options_.included_in_allocation); } TEST_P(RtpSenderTestWithoutPacer, SetsIncludedInAllocationWhenForcedAsPartOfAllocation) { SetUpRtpSender(false, false); rtp_egress()->ForceIncludeSendPacketsInAllocation(true); SendGenericPacket(); EXPECT_FALSE(transport_.last_options_.included_in_feedback); EXPECT_TRUE(transport_.last_options_.included_in_allocation); } TEST_P(RtpSenderTestWithoutPacer, DoesnSetIncludedInAllocationByDefault) { SetUpRtpSender(false, false); SendGenericPacket(); EXPECT_FALSE(transport_.last_options_.included_in_feedback); EXPECT_FALSE(transport_.last_options_.included_in_allocation); } TEST_P(RtpSenderTestWithoutPacer, OnSendSideDelayUpdated) { StrictMock send_side_delay_observer_; RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.local_media_ssrc = kSsrc; config.send_side_delay_observer = &send_side_delay_observer_; config.event_log = &mock_rtc_event_log_; rtp_sender_context_ = std::make_unique(config); PlayoutDelayOracle playout_delay_oracle; FieldTrialBasedConfig field_trials; RTPSenderVideo::Config video_config; video_config.clock = &fake_clock_; video_config.rtp_sender = rtp_sender(); video_config.playout_delay_oracle = &playout_delay_oracle; video_config.field_trials = &field_trials; RTPSenderVideo rtp_sender_video(video_config); const uint8_t kPayloadType = 127; const absl::optional kCodecType = VideoCodecType::kVideoCodecGeneric; const uint32_t kCaptureTimeMsToRtpTimestamp = 90; // 90 kHz clock RTPVideoHeader video_header; // Send packet with 10 ms send-side delay. The average, max and total should // be 10 ms. EXPECT_CALL(send_side_delay_observer_, SendSideDelayUpdated(10, 10, 10, kSsrc)) .Times(1); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); fake_clock_.AdvanceTimeMilliseconds(10); video_header.frame_type = VideoFrameType::kVideoFrameKey; EXPECT_TRUE(rtp_sender_video.SendVideo( kPayloadType, kCodecType, capture_time_ms * kCaptureTimeMsToRtpTimestamp, capture_time_ms, kPayloadData, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); // Send another packet with 20 ms delay. The average, max and total should be // 15, 20 and 30 ms respectively. EXPECT_CALL(send_side_delay_observer_, SendSideDelayUpdated(15, 20, 30, kSsrc)) .Times(1); fake_clock_.AdvanceTimeMilliseconds(10); video_header.frame_type = VideoFrameType::kVideoFrameKey; EXPECT_TRUE(rtp_sender_video.SendVideo( kPayloadType, kCodecType, capture_time_ms * kCaptureTimeMsToRtpTimestamp, capture_time_ms, kPayloadData, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); // Send another packet at the same time, which replaces the last packet. // Since this packet has 0 ms delay, the average is now 5 ms and max is 10 ms. // The total counter stays the same though. // TODO(terelius): Is is not clear that this is the right behavior. EXPECT_CALL(send_side_delay_observer_, SendSideDelayUpdated(5, 10, 30, kSsrc)) .Times(1); capture_time_ms = fake_clock_.TimeInMilliseconds(); video_header.frame_type = VideoFrameType::kVideoFrameKey; EXPECT_TRUE(rtp_sender_video.SendVideo( kPayloadType, kCodecType, capture_time_ms * kCaptureTimeMsToRtpTimestamp, capture_time_ms, kPayloadData, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); // Send a packet 1 second later. The earlier packets should have timed // out, so both max and average should be the delay of this packet. The total // keeps increasing. fake_clock_.AdvanceTimeMilliseconds(1000); capture_time_ms = fake_clock_.TimeInMilliseconds(); fake_clock_.AdvanceTimeMilliseconds(1); EXPECT_CALL(send_side_delay_observer_, SendSideDelayUpdated(1, 1, 31, kSsrc)) .Times(1); video_header.frame_type = VideoFrameType::kVideoFrameKey; EXPECT_TRUE(rtp_sender_video.SendVideo( kPayloadType, kCodecType, capture_time_ms * kCaptureTimeMsToRtpTimestamp, capture_time_ms, kPayloadData, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); } TEST_P(RtpSenderTestWithoutPacer, OnSendPacketUpdated) { EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId)); EXPECT_CALL(send_packet_observer_, OnSendPacket(kTransportSequenceNumber, _, _)) .Times(1); SendGenericPacket(); } TEST_P(RtpSenderTest, SendsPacketsWithTransportSequenceNumber) { RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.paced_sender = &mock_paced_sender_; config.local_media_ssrc = kSsrc; config.transport_feedback_callback = &feedback_observer_; config.event_log = &mock_rtc_event_log_; config.send_packet_observer = &send_packet_observer_; config.retransmission_rate_limiter = &retransmission_rate_limiter_; rtp_sender_context_ = std::make_unique(config); rtp_sender()->SetSequenceNumber(kSeqNum); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId)); EXPECT_CALL(send_packet_observer_, OnSendPacket(kTransportSequenceNumber, _, _)) .Times(1); EXPECT_CALL(feedback_observer_, OnAddPacket(AllOf( Field(&RtpPacketSendInfo::ssrc, rtp_sender()->SSRC()), Field(&RtpPacketSendInfo::transport_sequence_number, kTransportSequenceNumber), Field(&RtpPacketSendInfo::rtp_sequence_number, rtp_sender()->SequenceNumber()), Field(&RtpPacketSendInfo::pacing_info, PacedPacketInfo())))) .Times(1); EXPECT_CALL( mock_paced_sender_, EnqueuePackets(Contains(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 SendPacket(). packet->SetExtension(kTransportSequenceNumber); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); uint16_t transport_seq_no; EXPECT_TRUE( transport_.last_sent_packet().GetExtension( &transport_seq_no)); EXPECT_EQ(kTransportSequenceNumber, transport_seq_no); EXPECT_EQ(transport_.last_options_.packet_id, transport_seq_no); } TEST_P(RtpSenderTest, WritesPacerExitToTimingExtension) { rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionVideoTiming, kVideoTimingExtensionId)); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); auto packet = rtp_sender()->AllocatePacket(); packet->SetPayloadType(kPayload); packet->SetMarker(true); packet->SetTimestamp(kTimestamp); packet->set_capture_time_ms(capture_time_ms); const VideoSendTiming kVideoTiming = {0u, 0u, 0u, 0u, 0u, 0u, true}; packet->SetExtension(kVideoTiming); EXPECT_TRUE(rtp_sender()->AssignSequenceNumber(packet.get())); size_t packet_size = packet->size(); const int kStoredTimeInMs = 100; packet->set_packet_type(RtpPacketToSend::Type::kVideo); packet->set_allow_retransmission(true); EXPECT_CALL(mock_paced_sender_, EnqueuePackets(Contains(Pointee(Property( &RtpPacketToSend::Ssrc, kSsrc))))); EXPECT_TRUE( rtp_sender()->SendToNetwork(std::make_unique(*packet))); fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(1, transport_.packets_sent()); EXPECT_EQ(packet_size, transport_.last_sent_packet().size()); VideoSendTiming video_timing; EXPECT_TRUE(transport_.last_sent_packet().GetExtension( &video_timing)); EXPECT_EQ(kStoredTimeInMs, video_timing.pacer_exit_delta_ms); } TEST_P(RtpSenderTest, WritesNetwork2ToTimingExtensionWithPacer) { SetUpRtpSender(/*pacer=*/true, /*populate_network2=*/true); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionVideoTiming, kVideoTimingExtensionId)); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); auto packet = rtp_sender()->AllocatePacket(); packet->SetPayloadType(kPayload); packet->SetMarker(true); packet->SetTimestamp(kTimestamp); packet->set_capture_time_ms(capture_time_ms); const uint16_t kPacerExitMs = 1234u; const VideoSendTiming kVideoTiming = {0u, 0u, 0u, kPacerExitMs, 0u, 0u, true}; packet->SetExtension(kVideoTiming); EXPECT_TRUE(rtp_sender()->AssignSequenceNumber(packet.get())); size_t packet_size = packet->size(); const int kStoredTimeInMs = 100; packet->set_packet_type(RtpPacketToSend::Type::kVideo); packet->set_allow_retransmission(true); EXPECT_CALL(mock_paced_sender_, EnqueuePackets(Contains(Pointee(Property( &RtpPacketToSend::Ssrc, kSsrc))))); EXPECT_TRUE(rtp_sender()->SendToNetwork( std::make_unique(*packet))); fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(1, transport_.packets_sent()); EXPECT_EQ(packet_size, transport_.last_sent_packet().size()); VideoSendTiming video_timing; EXPECT_TRUE( transport_.last_sent_packet().GetExtension( &video_timing)); EXPECT_EQ(kStoredTimeInMs, video_timing.network2_timestamp_delta_ms); EXPECT_EQ(kPacerExitMs, video_timing.pacer_exit_delta_ms); } TEST_P(RtpSenderTest, WritesNetwork2ToTimingExtensionWithoutPacer) { SetUpRtpSender(/*pacer=*/false, /*populate_network2=*/true); EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionVideoTiming, kVideoTimingExtensionId)); auto packet = rtp_sender()->AllocatePacket(); packet->SetMarker(true); packet->set_capture_time_ms(fake_clock_.TimeInMilliseconds()); const VideoSendTiming kVideoTiming = {0u, 0u, 0u, 0u, 0u, 0u, true}; packet->SetExtension(kVideoTiming); packet->set_allow_retransmission(true); EXPECT_TRUE(rtp_sender()->AssignSequenceNumber(packet.get())); packet->set_packet_type(RtpPacketToSend::Type::kVideo); const int kPropagateTimeMs = 10; fake_clock_.AdvanceTimeMilliseconds(kPropagateTimeMs); EXPECT_TRUE(rtp_sender()->SendToNetwork(std::move(packet))); EXPECT_EQ(1, transport_.packets_sent()); absl::optional video_timing = transport_.last_sent_packet().GetExtension(); ASSERT_TRUE(video_timing); EXPECT_EQ(kPropagateTimeMs, video_timing->network2_timestamp_delta_ms); } TEST_P(RtpSenderTest, TrafficSmoothingWithExtensions) { EXPECT_CALL(mock_rtc_event_log_, LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); auto packet = BuildRtpPacket(kPayload, kMarkerBit, kTimestamp, capture_time_ms); size_t packet_size = packet->size(); const int kStoredTimeInMs = 100; EXPECT_CALL( mock_paced_sender_, EnqueuePackets(Contains(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(std::make_unique(*packet))); EXPECT_EQ(0, transport_.packets_sent()); fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); // Process send bucket. Packet should now be sent. EXPECT_EQ(1, transport_.packets_sent()); EXPECT_EQ(packet_size, transport_.last_sent_packet().size()); webrtc::RTPHeader rtp_header; transport_.last_sent_packet().GetHeader(&rtp_header); // Verify transmission time offset. EXPECT_EQ(kStoredTimeInMs * 90, rtp_header.extension.transmissionTimeOffset); uint64_t expected_send_time = ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); } TEST_P(RtpSenderTest, TrafficSmoothingRetransmits) { EXPECT_CALL(mock_rtc_event_log_, LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); auto packet = BuildRtpPacket(kPayload, kMarkerBit, kTimestamp, capture_time_ms); size_t packet_size = packet->size(); // Packet should be stored in a send bucket. EXPECT_CALL( mock_paced_sender_, EnqueuePackets(Contains(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(std::make_unique(*packet))); // Immediately process send bucket and send packet. rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(1, transport_.packets_sent()); // Retransmit packet. const int kStoredTimeInMs = 100; fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); EXPECT_CALL(mock_rtc_event_log_, LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))); packet->set_packet_type(RtpPacketToSend::Type::kRetransmission); packet->set_retransmitted_sequence_number(kSeqNum); EXPECT_CALL( mock_paced_sender_, EnqueuePackets(Contains(AllOf( Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)), Pointee(Property(&RtpPacketToSend::SequenceNumber, kSeqNum)))))); EXPECT_EQ(static_cast(packet_size), rtp_sender()->ReSendPacket(kSeqNum)); EXPECT_EQ(1, transport_.packets_sent()); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); // Process send bucket. Packet should now be sent. EXPECT_EQ(2, transport_.packets_sent()); EXPECT_EQ(packet_size, transport_.last_sent_packet().size()); webrtc::RTPHeader rtp_header; transport_.last_sent_packet().GetHeader(&rtp_header); // Verify transmission time offset. EXPECT_EQ(kStoredTimeInMs * 90, rtp_header.extension.transmissionTimeOffset); uint64_t expected_send_time = ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); } // This test sends 1 regular video packet, then 4 padding packets, and then // 1 more regular packet. TEST_P(RtpSenderTest, SendPadding) { // Make all (non-padding) packets go to send queue. EXPECT_CALL(mock_rtc_event_log_, LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))) .Times(1 + 4 + 1); uint16_t seq_num = kSeqNum; uint32_t timestamp = kTimestamp; rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); size_t rtp_header_len = kRtpHeaderSize; EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); rtp_header_len += 4; // 4 bytes extension. EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); rtp_header_len += 4; // 4 bytes extension. rtp_header_len += 4; // 4 extra bytes common to all extension headers. webrtc::RTPHeader rtp_header; int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); auto packet = 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_CALL( mock_paced_sender_, EnqueuePackets(Contains(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(std::make_unique(*packet))); EXPECT_EQ(total_packets_sent, transport_.packets_sent()); fake_clock_.AdvanceTimeMilliseconds(kStoredTimeInMs); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); ++seq_num; // 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()); timestamp += 90 * kStoredTimeInMs; // Send padding 4 times, waiting 50 ms between each. for (int i = 0; i < 4; ++i) { const int kPaddingPeriodMs = 50; const size_t kPaddingBytes = 100; const size_t kMaxPaddingLength = 224; // Value taken from rtp_sender.cc. // Padding will be forced to full packets. EXPECT_EQ(kMaxPaddingLength, GenerateAndSendPadding(kPaddingBytes)); // Process send bucket. Padding should now be sent. EXPECT_EQ(++total_packets_sent, transport_.packets_sent()); EXPECT_EQ(kMaxPaddingLength + rtp_header_len, transport_.last_sent_packet().size()); transport_.last_sent_packet().GetHeader(&rtp_header); EXPECT_EQ(kMaxPaddingLength, rtp_header.paddingLength); // Verify sequence number and timestamp. The timestamp should be the same // as the last media packet. EXPECT_EQ(seq_num++, rtp_header.sequenceNumber); EXPECT_EQ(media_packet_timestamp, rtp_header.timestamp); // Verify transmission time offset. int offset = timestamp - media_packet_timestamp; EXPECT_EQ(offset, rtp_header.extension.transmissionTimeOffset); uint64_t expected_send_time = ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); fake_clock_.AdvanceTimeMilliseconds(kPaddingPeriodMs); timestamp += 90 * kPaddingPeriodMs; } // Send a regular video packet again. capture_time_ms = fake_clock_.TimeInMilliseconds(); packet = BuildRtpPacket(kPayload, kMarkerBit, timestamp, capture_time_ms); packet_size = packet->size(); packet->set_packet_type(RtpPacketToSend::Type::kVideo); packet->set_allow_retransmission(true); EXPECT_CALL( mock_paced_sender_, EnqueuePackets(Contains(AllOf( Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)), Pointee(Property(&RtpPacketToSend::SequenceNumber, seq_num)))))); EXPECT_TRUE(rtp_sender()->SendToNetwork( std::make_unique(*packet))); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); // Process send bucket. EXPECT_EQ(++total_packets_sent, transport_.packets_sent()); EXPECT_EQ(packet_size, transport_.last_sent_packet().size()); transport_.last_sent_packet().GetHeader(&rtp_header); // Verify sequence number and timestamp. EXPECT_EQ(seq_num, rtp_header.sequenceNumber); EXPECT_EQ(timestamp, rtp_header.timestamp); // Verify transmission time offset. This packet is sent without delay. EXPECT_EQ(0, rtp_header.extension.transmissionTimeOffset); uint64_t expected_send_time = ConvertMsToAbsSendTime(fake_clock_.TimeInMilliseconds()); EXPECT_EQ(expected_send_time, rtp_header.extension.absoluteSendTime); } TEST_P(RtpSenderTest, OnSendPacketUpdated) { EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId)); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); EXPECT_CALL(send_packet_observer_, OnSendPacket(kTransportSequenceNumber, _, _)) .Times(1); EXPECT_CALL( mock_paced_sender_, EnqueuePackets(Contains(AllOf( Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)), Pointee(Property(&RtpPacketToSend::SequenceNumber, kSeqNum)))))); auto packet = SendGenericPacket(); packet->set_packet_type(RtpPacketToSend::Type::kVideo); packet->SetExtension(kTransportSequenceNumber); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(1, transport_.packets_sent()); } TEST_P(RtpSenderTest, OnSendPacketNotUpdatedForRetransmits) { EXPECT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId)); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); EXPECT_CALL(send_packet_observer_, OnSendPacket(_, _, _)).Times(0); EXPECT_CALL( mock_paced_sender_, EnqueuePackets(Contains(AllOf( Pointee(Property(&RtpPacketToSend::Ssrc, kSsrc)), Pointee(Property(&RtpPacketToSend::SequenceNumber, kSeqNum)))))); auto packet = SendGenericPacket(); packet->set_packet_type(RtpPacketToSend::Type::kRetransmission); packet->SetExtension(kTransportSequenceNumber); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(1, transport_.packets_sent()); EXPECT_TRUE(transport_.last_options_.is_retransmit); } TEST_P(RtpSenderTestWithoutPacer, SendGenericVideo) { const uint8_t kPayloadType = 127; const VideoCodecType kCodecType = VideoCodecType::kVideoCodecGeneric; PlayoutDelayOracle playout_delay_oracle; FieldTrialBasedConfig field_trials; RTPSenderVideo::Config video_config; video_config.clock = &fake_clock_; video_config.rtp_sender = rtp_sender(); video_config.playout_delay_oracle = &playout_delay_oracle; video_config.field_trials = &field_trials; RTPSenderVideo rtp_sender_video(video_config); uint8_t payload[] = {47, 11, 32, 93, 89}; // Send keyframe RTPVideoHeader video_header; video_header.frame_type = VideoFrameType::kVideoFrameKey; ASSERT_TRUE(rtp_sender_video.SendVideo(kPayloadType, kCodecType, 1234, 4321, payload, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); auto sent_payload = transport_.last_sent_packet().payload(); uint8_t generic_header = sent_payload[0]; EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kKeyFrameBit); EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kFirstPacketBit); EXPECT_THAT(sent_payload.subview(1), ElementsAreArray(payload)); // Send delta frame payload[0] = 13; payload[1] = 42; payload[4] = 13; video_header.frame_type = VideoFrameType::kVideoFrameDelta; ASSERT_TRUE(rtp_sender_video.SendVideo(kPayloadType, kCodecType, 1234, 4321, payload, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); sent_payload = transport_.last_sent_packet().payload(); generic_header = sent_payload[0]; EXPECT_FALSE(generic_header & RtpFormatVideoGeneric::kKeyFrameBit); EXPECT_TRUE(generic_header & RtpFormatVideoGeneric::kFirstPacketBit); EXPECT_THAT(sent_payload.subview(1), ElementsAreArray(payload)); } TEST_P(RtpSenderTestWithoutPacer, SendRawVideo) { const uint8_t kPayloadType = 111; const uint8_t payload[] = {11, 22, 33, 44, 55}; PlayoutDelayOracle playout_delay_oracle; FieldTrialBasedConfig field_trials; RTPSenderVideo::Config video_config; video_config.clock = &fake_clock_; video_config.rtp_sender = rtp_sender(); video_config.playout_delay_oracle = &playout_delay_oracle; video_config.field_trials = &field_trials; RTPSenderVideo rtp_sender_video(video_config); // Send a frame. RTPVideoHeader video_header; video_header.frame_type = VideoFrameType::kVideoFrameKey; ASSERT_TRUE(rtp_sender_video.SendVideo(kPayloadType, absl::nullopt, 1234, 4321, payload, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); auto sent_payload = transport_.last_sent_packet().payload(); EXPECT_THAT(sent_payload, ElementsAreArray(payload)); } TEST_P(RtpSenderTest, SendFlexfecPackets) { constexpr uint32_t kTimestamp = 1234; constexpr int kMediaPayloadType = 127; constexpr VideoCodecType kCodecType = VideoCodecType::kVideoCodecGeneric; constexpr int kFlexfecPayloadType = 118; const std::vector kNoRtpExtensions; const std::vector kNoRtpExtensionSizes; FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexFecSsrc, kSsrc, kNoMid, kNoRtpExtensions, kNoRtpExtensionSizes, nullptr /* rtp_state */, &fake_clock_); // Reset |rtp_sender_| to use FlexFEC. RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.paced_sender = &mock_paced_sender_; config.local_media_ssrc = kSsrc; config.flexfec_sender = &flexfec_sender_; config.event_log = &mock_rtc_event_log_; config.send_packet_observer = &send_packet_observer_; config.retransmission_rate_limiter = &retransmission_rate_limiter_; rtp_sender_context_ = std::make_unique(config); rtp_sender()->SetSequenceNumber(kSeqNum); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); PlayoutDelayOracle playout_delay_oracle; FieldTrialBasedConfig field_trials; RTPSenderVideo::Config video_config; video_config.clock = &fake_clock_; video_config.rtp_sender = rtp_sender(); video_config.flexfec_sender = &flexfec_sender; video_config.playout_delay_oracle = &playout_delay_oracle; video_config.field_trials = &field_trials; RTPSenderVideo rtp_sender_video(video_config); // 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); uint16_t flexfec_seq_num; RTPVideoHeader video_header; std::unique_ptr media_packet; std::unique_ptr fec_packet; EXPECT_CALL(mock_paced_sender_, EnqueuePackets) .WillOnce([&](std::vector> packets) { for (auto& packet : packets) { 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); } } }); video_header.frame_type = VideoFrameType::kVideoFrameKey; EXPECT_TRUE(rtp_sender_video.SendVideo( kMediaPayloadType, kCodecType, kTimestamp, fake_clock_.TimeInMilliseconds(), kPayloadData, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); ASSERT_TRUE(media_packet != nullptr); ASSERT_TRUE(fec_packet != nullptr); flexfec_seq_num = fec_packet->SequenceNumber(); rtp_egress()->SendPacket(media_packet.get(), PacedPacketInfo()); rtp_egress()->SendPacket(fec_packet.get(), PacedPacketInfo()); ASSERT_EQ(2, transport_.packets_sent()); const RtpPacketReceived& sent_media_packet = transport_.sent_packets_[0]; EXPECT_EQ(kMediaPayloadType, sent_media_packet.PayloadType()); EXPECT_EQ(kSeqNum, sent_media_packet.SequenceNumber()); EXPECT_EQ(kSsrc, sent_media_packet.Ssrc()); const RtpPacketReceived& sent_flexfec_packet = transport_.sent_packets_[1]; EXPECT_EQ(kFlexfecPayloadType, sent_flexfec_packet.PayloadType()); EXPECT_EQ(flexfec_seq_num, sent_flexfec_packet.SequenceNumber()); EXPECT_EQ(kFlexFecSsrc, sent_flexfec_packet.Ssrc()); } TEST_P(RtpSenderTestWithoutPacer, SendFlexfecPackets) { constexpr uint32_t kTimestamp = 1234; constexpr int kMediaPayloadType = 127; constexpr VideoCodecType kCodecType = VideoCodecType::kVideoCodecGeneric; constexpr int kFlexfecPayloadType = 118; const std::vector kNoRtpExtensions; const std::vector kNoRtpExtensionSizes; FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexFecSsrc, kSsrc, kNoMid, kNoRtpExtensions, kNoRtpExtensionSizes, nullptr /* rtp_state */, &fake_clock_); // Reset |rtp_sender_| to use FlexFEC. RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.local_media_ssrc = kSsrc; config.flexfec_sender = &flexfec_sender; config.event_log = &mock_rtc_event_log_; config.send_packet_observer = &send_packet_observer_; config.retransmission_rate_limiter = &retransmission_rate_limiter_; rtp_sender_context_ = std::make_unique(config); rtp_sender()->SetSequenceNumber(kSeqNum); PlayoutDelayOracle playout_delay_oracle; FieldTrialBasedConfig field_trials; RTPSenderVideo::Config video_config; video_config.clock = &fake_clock_; video_config.rtp_sender = rtp_sender(); video_config.flexfec_sender = &flexfec_sender; video_config.playout_delay_oracle = &playout_delay_oracle; video_config.field_trials = &field_trials; RTPSenderVideo rtp_sender_video(video_config); // 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); EXPECT_CALL(mock_rtc_event_log_, LogProxy(SameRtcEventTypeAs(RtcEvent::Type::RtpPacketOutgoing))) .Times(2); RTPVideoHeader video_header; video_header.frame_type = VideoFrameType::kVideoFrameKey; EXPECT_TRUE(rtp_sender_video.SendVideo( kMediaPayloadType, kCodecType, kTimestamp, fake_clock_.TimeInMilliseconds(), kPayloadData, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); ASSERT_EQ(2, transport_.packets_sent()); const RtpPacketReceived& media_packet = transport_.sent_packets_[0]; EXPECT_EQ(kMediaPayloadType, media_packet.PayloadType()); 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()); } // Test that the MID header extension is included on sent packets when // configured. TEST_P(RtpSenderTestWithoutPacer, MidIncludedOnSentPackets) { const char kMid[] = "mid"; EnableMidSending(kMid); // Send a couple packets. SendGenericPacket(); SendGenericPacket(); // Expect both packets to have the MID set. ASSERT_EQ(2u, transport_.sent_packets_.size()); for (const RtpPacketReceived& packet : transport_.sent_packets_) { std::string mid; ASSERT_TRUE(packet.GetExtension(&mid)); EXPECT_EQ(kMid, mid); } } TEST_P(RtpSenderTestWithoutPacer, RidIncludedOnSentPackets) { const char kRid[] = "f"; EnableRidSending(kRid); SendGenericPacket(); ASSERT_EQ(1u, transport_.sent_packets_.size()); const RtpPacketReceived& packet = transport_.sent_packets_[0]; std::string rid; ASSERT_TRUE(packet.GetExtension(&rid)); EXPECT_EQ(kRid, rid); } TEST_P(RtpSenderTestWithoutPacer, RidIncludedOnRtxSentPackets) { const char kRid[] = "f"; EnableRtx(); EnableRidSending(kRid); SendGenericPacket(); ASSERT_EQ(1u, transport_.sent_packets_.size()); const RtpPacketReceived& packet = transport_.sent_packets_[0]; std::string rid; ASSERT_TRUE(packet.GetExtension(&rid)); EXPECT_EQ(kRid, rid); rid = kNoRid; EXPECT_FALSE(packet.HasExtension()); uint16_t packet_id = packet.SequenceNumber(); rtp_sender()->ReSendPacket(packet_id); ASSERT_EQ(2u, transport_.sent_packets_.size()); const RtpPacketReceived& rtx_packet = transport_.sent_packets_[1]; ASSERT_TRUE(rtx_packet.GetExtension(&rid)); EXPECT_EQ(kRid, rid); EXPECT_FALSE(rtx_packet.HasExtension()); } TEST_P(RtpSenderTestWithoutPacer, MidAndRidNotIncludedOnSentPacketsAfterAck) { const char kMid[] = "mid"; const char kRid[] = "f"; EnableMidSending(kMid); EnableRidSending(kRid); // This first packet should include both MID and RID. auto first_built_packet = SendGenericPacket(); rtp_sender()->OnReceivedAckOnSsrc(first_built_packet->SequenceNumber()); // The second packet should include neither since an ack was received. SendGenericPacket(); ASSERT_EQ(2u, transport_.sent_packets_.size()); const RtpPacketReceived& first_packet = transport_.sent_packets_[0]; std::string mid, rid; ASSERT_TRUE(first_packet.GetExtension(&mid)); EXPECT_EQ(kMid, mid); ASSERT_TRUE(first_packet.GetExtension(&rid)); EXPECT_EQ(kRid, rid); const RtpPacketReceived& second_packet = transport_.sent_packets_[1]; EXPECT_FALSE(second_packet.HasExtension()); EXPECT_FALSE(second_packet.HasExtension()); } // Test that the first RTX packet includes both MID and RRID even if the packet // being retransmitted did not have MID or RID. The MID and RID are needed on // the first packets for a given SSRC, and RTX packets are sent on a separate // SSRC. TEST_P(RtpSenderTestWithoutPacer, MidAndRidIncludedOnFirstRtxPacket) { const char kMid[] = "mid"; const char kRid[] = "f"; EnableRtx(); EnableMidSending(kMid); EnableRidSending(kRid); // This first packet will include both MID and RID. auto first_built_packet = SendGenericPacket(); rtp_sender()->OnReceivedAckOnSsrc(first_built_packet->SequenceNumber()); // The second packet will include neither since an ack was received. auto second_built_packet = SendGenericPacket(); // The first RTX packet should include MID and RRID. ASSERT_LT(0, rtp_sender()->ReSendPacket(second_built_packet->SequenceNumber())); ASSERT_EQ(3u, transport_.sent_packets_.size()); const RtpPacketReceived& rtx_packet = transport_.sent_packets_[2]; std::string mid, rrid; ASSERT_TRUE(rtx_packet.GetExtension(&mid)); EXPECT_EQ(kMid, mid); ASSERT_TRUE(rtx_packet.GetExtension(&rrid)); EXPECT_EQ(kRid, rrid); } // Test that the RTX packets sent after receving an ACK on the RTX SSRC does // not include either MID or RRID even if the packet being retransmitted did // had a MID or RID. TEST_P(RtpSenderTestWithoutPacer, MidAndRidNotIncludedOnRtxPacketsAfterAck) { const char kMid[] = "mid"; const char kRid[] = "f"; EnableRtx(); EnableMidSending(kMid); EnableRidSending(kRid); // This first packet will include both MID and RID. auto first_built_packet = SendGenericPacket(); rtp_sender()->OnReceivedAckOnSsrc(first_built_packet->SequenceNumber()); // The second packet will include neither since an ack was received. auto second_built_packet = SendGenericPacket(); // The first RTX packet will include MID and RRID. ASSERT_LT(0, rtp_sender()->ReSendPacket(second_built_packet->SequenceNumber())); ASSERT_EQ(3u, transport_.sent_packets_.size()); const RtpPacketReceived& first_rtx_packet = transport_.sent_packets_[2]; rtp_sender()->OnReceivedAckOnRtxSsrc(first_rtx_packet.SequenceNumber()); // The second and third RTX packets should not include MID nor RRID. ASSERT_LT(0, rtp_sender()->ReSendPacket(first_built_packet->SequenceNumber())); ASSERT_LT(0, rtp_sender()->ReSendPacket(second_built_packet->SequenceNumber())); ASSERT_EQ(5u, transport_.sent_packets_.size()); const RtpPacketReceived& second_rtx_packet = transport_.sent_packets_[3]; EXPECT_FALSE(second_rtx_packet.HasExtension()); EXPECT_FALSE(second_rtx_packet.HasExtension()); const RtpPacketReceived& third_rtx_packet = transport_.sent_packets_[4]; EXPECT_FALSE(third_rtx_packet.HasExtension()); EXPECT_FALSE(third_rtx_packet.HasExtension()); } // Test that if the RtpState indicates an ACK has been received on that SSRC // then neither the MID nor RID header extensions will be sent. TEST_P(RtpSenderTestWithoutPacer, MidAndRidNotIncludedOnSentPacketsAfterRtpStateRestored) { const char kMid[] = "mid"; const char kRid[] = "f"; EnableMidSending(kMid); EnableRidSending(kRid); RtpState state = rtp_sender()->GetRtpState(); EXPECT_FALSE(state.ssrc_has_acked); state.ssrc_has_acked = true; rtp_sender()->SetRtpState(state); SendGenericPacket(); ASSERT_EQ(1u, transport_.sent_packets_.size()); const RtpPacketReceived& packet = transport_.sent_packets_[0]; EXPECT_FALSE(packet.HasExtension()); EXPECT_FALSE(packet.HasExtension()); } // Test that if the RTX RtpState indicates an ACK has been received on that // RTX SSRC then neither the MID nor RRID header extensions will be sent on // RTX packets. TEST_P(RtpSenderTestWithoutPacer, MidAndRridNotIncludedOnRtxPacketsAfterRtpStateRestored) { const char kMid[] = "mid"; const char kRid[] = "f"; EnableRtx(); EnableMidSending(kMid); EnableRidSending(kRid); RtpState rtx_state = rtp_sender()->GetRtxRtpState(); EXPECT_FALSE(rtx_state.ssrc_has_acked); rtx_state.ssrc_has_acked = true; rtp_sender()->SetRtxRtpState(rtx_state); auto built_packet = SendGenericPacket(); ASSERT_LT(0, rtp_sender()->ReSendPacket(built_packet->SequenceNumber())); ASSERT_EQ(2u, transport_.sent_packets_.size()); const RtpPacketReceived& rtx_packet = transport_.sent_packets_[1]; EXPECT_FALSE(rtx_packet.HasExtension()); EXPECT_FALSE(rtx_packet.HasExtension()); } TEST_P(RtpSenderTest, FecOverheadRate) { constexpr uint32_t kTimestamp = 1234; constexpr int kMediaPayloadType = 127; constexpr VideoCodecType kCodecType = VideoCodecType::kVideoCodecGeneric; constexpr int kFlexfecPayloadType = 118; const std::vector kNoRtpExtensions; const std::vector kNoRtpExtensionSizes; FlexfecSender flexfec_sender(kFlexfecPayloadType, kFlexFecSsrc, kSsrc, kNoMid, kNoRtpExtensions, kNoRtpExtensionSizes, nullptr /* rtp_state */, &fake_clock_); // Reset |rtp_sender_| to use FlexFEC. RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.paced_sender = &mock_paced_sender_; config.local_media_ssrc = kSsrc; config.flexfec_sender = &flexfec_sender; config.event_log = &mock_rtc_event_log_; config.send_packet_observer = &send_packet_observer_; config.retransmission_rate_limiter = &retransmission_rate_limiter_; rtp_sender_context_ = std::make_unique(config); rtp_sender()->SetSequenceNumber(kSeqNum); PlayoutDelayOracle playout_delay_oracle; FieldTrialBasedConfig field_trials; RTPSenderVideo::Config video_config; video_config.clock = &fake_clock_; video_config.rtp_sender = rtp_sender(); video_config.flexfec_sender = &flexfec_sender; video_config.playout_delay_oracle = &playout_delay_oracle; video_config.field_trials = &field_trials; RTPSenderVideo rtp_sender_video(video_config); // 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); constexpr size_t kNumMediaPackets = 10; constexpr size_t kNumFecPackets = kNumMediaPackets; constexpr int64_t kTimeBetweenPacketsMs = 10; EXPECT_CALL(mock_paced_sender_, EnqueuePackets).Times(kNumMediaPackets); for (size_t i = 0; i < kNumMediaPackets; ++i) { RTPVideoHeader video_header; video_header.frame_type = VideoFrameType::kVideoFrameKey; EXPECT_TRUE(rtp_sender_video.SendVideo( kMediaPayloadType, kCodecType, kTimestamp, fake_clock_.TimeInMilliseconds(), kPayloadData, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); fake_clock_.AdvanceTimeMilliseconds(kTimeBetweenPacketsMs); } constexpr size_t kRtpHeaderLength = 12; constexpr size_t kFlexfecHeaderLength = 20; constexpr size_t kGenericCodecHeaderLength = 1; constexpr size_t kPayloadLength = sizeof(kPayloadData); constexpr size_t kPacketLength = kRtpHeaderLength + kFlexfecHeaderLength + kGenericCodecHeaderLength + kPayloadLength; EXPECT_NEAR(kNumFecPackets * kPacketLength * 8 / (kNumFecPackets * kTimeBetweenPacketsMs / 1000.0f), rtp_sender_video.FecOverheadRate(), 500); } TEST_P(RtpSenderTest, BitrateCallbacks) { class TestCallback : public BitrateStatisticsObserver { public: TestCallback() : BitrateStatisticsObserver(), num_calls_(0), ssrc_(0), total_bitrate_(0), retransmit_bitrate_(0) {} ~TestCallback() override = default; void Notify(uint32_t total_bitrate, uint32_t retransmit_bitrate, uint32_t ssrc) override { ++num_calls_; ssrc_ = ssrc; total_bitrate_ = total_bitrate; retransmit_bitrate_ = retransmit_bitrate; } uint32_t num_calls_; uint32_t ssrc_; uint32_t total_bitrate_; uint32_t retransmit_bitrate_; } callback; RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.local_media_ssrc = kSsrc; config.send_bitrate_observer = &callback; config.retransmission_rate_limiter = &retransmission_rate_limiter_; rtp_sender_context_ = std::make_unique(config); PlayoutDelayOracle playout_delay_oracle; FieldTrialBasedConfig field_trials; RTPSenderVideo::Config video_config; video_config.clock = &fake_clock_; video_config.rtp_sender = rtp_sender(); video_config.playout_delay_oracle = &playout_delay_oracle; video_config.field_trials = &field_trials; RTPSenderVideo rtp_sender_video(video_config); const VideoCodecType kCodecType = VideoCodecType::kVideoCodecGeneric; const uint8_t kPayloadType = 127; // Simulate kNumPackets sent with kPacketInterval ms intervals, with the // number of packets selected so that we fill (but don't overflow) the one // second averaging window. const uint32_t kWindowSizeMs = 1000; const uint32_t kPacketInterval = 20; const uint32_t kNumPackets = (kWindowSizeMs - kPacketInterval) / kPacketInterval; // Overhead = 12 bytes RTP header + 1 byte generic header. const uint32_t kPacketOverhead = 13; uint8_t payload[] = {47, 11, 32, 93, 89}; rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 1); uint32_t ssrc = rtp_sender()->SSRC(); // Initial process call so we get a new time window. rtp_egress()->ProcessBitrateAndNotifyObservers(); // Send a few frames. RTPVideoHeader video_header; for (uint32_t i = 0; i < kNumPackets; ++i) { video_header.frame_type = VideoFrameType::kVideoFrameKey; ASSERT_TRUE(rtp_sender_video.SendVideo( kPayloadType, kCodecType, 1234, 4321, payload, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); fake_clock_.AdvanceTimeMilliseconds(kPacketInterval); } rtp_egress()->ProcessBitrateAndNotifyObservers(); // We get one call for every stats updated, thus two calls since both the // stream stats and the retransmit stats are updated once. EXPECT_EQ(2u, callback.num_calls_); EXPECT_EQ(ssrc, callback.ssrc_); const uint32_t kTotalPacketSize = kPacketOverhead + sizeof(payload); // Bitrate measured over delta between last and first timestamp, plus one. const uint32_t kExpectedWindowMs = kNumPackets * kPacketInterval + 1; const uint32_t kExpectedBitsAccumulated = kTotalPacketSize * kNumPackets * 8; const uint32_t kExpectedRateBps = (kExpectedBitsAccumulated * 1000 + (kExpectedWindowMs / 2)) / kExpectedWindowMs; EXPECT_EQ(kExpectedRateBps, callback.total_bitrate_); } TEST_P(RtpSenderTestWithoutPacer, StreamDataCountersCallbacks) { const uint8_t kPayloadType = 127; const VideoCodecType kCodecType = VideoCodecType::kVideoCodecGeneric; PlayoutDelayOracle playout_delay_oracle; FieldTrialBasedConfig field_trials; RTPSenderVideo::Config video_config; video_config.clock = &fake_clock_; video_config.rtp_sender = rtp_sender(); video_config.playout_delay_oracle = &playout_delay_oracle; video_config.field_trials = &field_trials; RTPSenderVideo rtp_sender_video(video_config); uint8_t payload[] = {47, 11, 32, 93, 89}; rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 1); uint32_t ssrc = rtp_sender()->SSRC(); // Send a frame. RTPVideoHeader video_header; video_header.frame_type = VideoFrameType::kVideoFrameKey; ASSERT_TRUE(rtp_sender_video.SendVideo(kPayloadType, kCodecType, 1234, 4321, payload, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); StreamDataCounters expected; expected.transmitted.payload_bytes = 6; expected.transmitted.header_bytes = 12; expected.transmitted.padding_bytes = 0; expected.transmitted.packets = 1; expected.retransmitted.payload_bytes = 0; expected.retransmitted.header_bytes = 0; expected.retransmitted.padding_bytes = 0; expected.retransmitted.packets = 0; expected.fec.packets = 0; rtp_stats_callback_.Matches(ssrc, expected); // Retransmit a frame. uint16_t seqno = rtp_sender()->SequenceNumber() - 1; rtp_sender()->ReSendPacket(seqno); expected.transmitted.payload_bytes = 12; expected.transmitted.header_bytes = 24; expected.transmitted.packets = 2; expected.retransmitted.payload_bytes = 6; expected.retransmitted.header_bytes = 12; expected.retransmitted.padding_bytes = 0; expected.retransmitted.packets = 1; rtp_stats_callback_.Matches(ssrc, expected); // Send padding. GenerateAndSendPadding(kMaxPaddingSize); expected.transmitted.payload_bytes = 12; expected.transmitted.header_bytes = 36; expected.transmitted.padding_bytes = kMaxPaddingSize; expected.transmitted.packets = 3; rtp_stats_callback_.Matches(ssrc, expected); } TEST_P(RtpSenderTestWithoutPacer, StreamDataCountersCallbacksUlpfec) { const uint8_t kRedPayloadType = 96; const uint8_t kUlpfecPayloadType = 97; const uint8_t kPayloadType = 127; const VideoCodecType kCodecType = VideoCodecType::kVideoCodecGeneric; PlayoutDelayOracle playout_delay_oracle; FieldTrialBasedConfig field_trials; RTPSenderVideo::Config video_config; video_config.clock = &fake_clock_; video_config.rtp_sender = rtp_sender(); video_config.playout_delay_oracle = &playout_delay_oracle; video_config.field_trials = &field_trials; video_config.red_payload_type = kRedPayloadType; video_config.ulpfec_payload_type = kUlpfecPayloadType; RTPSenderVideo rtp_sender_video(video_config); uint8_t payload[] = {47, 11, 32, 93, 89}; rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 1); uint32_t ssrc = rtp_sender()->SSRC(); RTPVideoHeader video_header; StreamDataCounters expected; // Send ULPFEC. FecProtectionParams fec_params; fec_params.fec_mask_type = kFecMaskRandom; fec_params.fec_rate = 1; fec_params.max_fec_frames = 1; rtp_sender_video.SetFecParameters(fec_params, fec_params); video_header.frame_type = VideoFrameType::kVideoFrameDelta; ASSERT_TRUE(rtp_sender_video.SendVideo(kPayloadType, kCodecType, 1234, 4321, payload, nullptr, video_header, kDefaultExpectedRetransmissionTimeMs)); expected.transmitted.payload_bytes = 28; expected.transmitted.header_bytes = 24; expected.transmitted.packets = 2; expected.fec.packets = 1; rtp_stats_callback_.Matches(ssrc, expected); } TEST_P(RtpSenderTestWithoutPacer, BytesReportedCorrectly) { // XXX const char* kPayloadName = "GENERIC"; const uint8_t kPayloadType = 127; rtp_sender()->SetRtxPayloadType(kPayloadType - 1, kPayloadType); rtp_sender()->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads); SendGenericPacket(); // Will send 2 full-size padding packets. GenerateAndSendPadding(1); GenerateAndSendPadding(1); StreamDataCounters rtp_stats; StreamDataCounters rtx_stats; rtp_egress()->GetDataCounters(&rtp_stats, &rtx_stats); // Payload EXPECT_GT(rtp_stats.first_packet_time_ms, -1); EXPECT_EQ(rtp_stats.transmitted.payload_bytes, sizeof(kPayloadData)); EXPECT_EQ(rtp_stats.transmitted.header_bytes, 12u); EXPECT_EQ(rtp_stats.transmitted.padding_bytes, 0u); EXPECT_EQ(rtx_stats.transmitted.payload_bytes, 0u); EXPECT_EQ(rtx_stats.transmitted.header_bytes, 24u); EXPECT_EQ(rtx_stats.transmitted.padding_bytes, 2 * kMaxPaddingSize); EXPECT_EQ(rtp_stats.transmitted.TotalBytes(), rtp_stats.transmitted.payload_bytes + rtp_stats.transmitted.header_bytes + rtp_stats.transmitted.padding_bytes); EXPECT_EQ(rtx_stats.transmitted.TotalBytes(), rtx_stats.transmitted.payload_bytes + rtx_stats.transmitted.header_bytes + rtx_stats.transmitted.padding_bytes); EXPECT_EQ( transport_.total_bytes_sent_, rtp_stats.transmitted.TotalBytes() + rtx_stats.transmitted.TotalBytes()); } TEST_P(RtpSenderTestWithoutPacer, RespectsNackBitrateLimit) { const int32_t kPacketSize = 1400; const int32_t kNumPackets = 30; retransmission_rate_limiter_.SetMaxRate(kPacketSize * kNumPackets * 8); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, kNumPackets); const uint16_t kStartSequenceNumber = rtp_sender()->SequenceNumber(); std::vector sequence_numbers; for (int32_t i = 0; i < kNumPackets; ++i) { sequence_numbers.push_back(kStartSequenceNumber + i); fake_clock_.AdvanceTimeMilliseconds(1); SendPacket(fake_clock_.TimeInMilliseconds(), kPacketSize); } EXPECT_EQ(kNumPackets, transport_.packets_sent()); fake_clock_.AdvanceTimeMilliseconds(1000 - kNumPackets); // Resending should work - brings the bandwidth up to the limit. // NACK bitrate is capped to the same bitrate as the encoder, since the max // protection overhead is 50% (see MediaOptimization::SetTargetRates). rtp_sender()->OnReceivedNack(sequence_numbers, 0); EXPECT_EQ(kNumPackets * 2, transport_.packets_sent()); // Must be at least 5ms in between retransmission attempts. fake_clock_.AdvanceTimeMilliseconds(5); // Resending should not work, bandwidth exceeded. rtp_sender()->OnReceivedNack(sequence_numbers, 0); EXPECT_EQ(kNumPackets * 2, transport_.packets_sent()); } TEST_P(RtpSenderTest, OnOverheadChanged) { MockOverheadObserver mock_overhead_observer; RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.local_media_ssrc = kSsrc; config.retransmission_rate_limiter = &retransmission_rate_limiter_; config.overhead_observer = &mock_overhead_observer; rtp_sender_context_ = std::make_unique(config); // RTP overhead is 12B. EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(12)).Times(1); SendGenericPacket(); rtp_sender()->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId); // TransmissionTimeOffset extension has a size of 8B. // 12B + 8B = 20B EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(20)).Times(1); SendGenericPacket(); } TEST_P(RtpSenderTest, DoesNotUpdateOverheadOnEqualSize) { MockOverheadObserver mock_overhead_observer; RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.local_media_ssrc = kSsrc; config.retransmission_rate_limiter = &retransmission_rate_limiter_; config.overhead_observer = &mock_overhead_observer; rtp_sender_context_ = std::make_unique(config); EXPECT_CALL(mock_overhead_observer, OnOverheadChanged(_)).Times(1); SendGenericPacket(); SendGenericPacket(); } TEST_P(RtpSenderTest, SendPacketMatchesVideo) { std::unique_ptr packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->set_packet_type(RtpPacketToSend::Type::kVideo); // Verify sent with correct SSRC. packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->SetSsrc(kSsrc); packet->set_packet_type(RtpPacketToSend::Type::kVideo); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(transport_.packets_sent(), 1); } TEST_P(RtpSenderTest, SendPacketMatchesAudio) { std::unique_ptr packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->set_packet_type(RtpPacketToSend::Type::kAudio); // Verify sent with correct SSRC. packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->SetSsrc(kSsrc); packet->set_packet_type(RtpPacketToSend::Type::kAudio); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(transport_.packets_sent(), 1); } TEST_P(RtpSenderTest, SendPacketMatchesRetransmissions) { std::unique_ptr packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->set_packet_type(RtpPacketToSend::Type::kRetransmission); // 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); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(transport_.packets_sent(), 1); // RTX retransmission. packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->SetSsrc(kRtxSsrc); packet->set_packet_type(RtpPacketToSend::Type::kRetransmission); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(transport_.packets_sent(), 2); } TEST_P(RtpSenderTest, SendPacketMatchesPadding) { std::unique_ptr packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->set_packet_type(RtpPacketToSend::Type::kPadding); // 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); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(transport_.packets_sent(), 1); // RTX padding. packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->SetSsrc(kRtxSsrc); packet->set_packet_type(RtpPacketToSend::Type::kPadding); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(transport_.packets_sent(), 2); } TEST_P(RtpSenderTest, SendPacketMatchesFlexfec) { std::unique_ptr packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection); // Verify sent with correct SSRC. packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->SetSsrc(kFlexFecSsrc); packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(transport_.packets_sent(), 1); } TEST_P(RtpSenderTest, SendPacketMatchesUlpfec) { std::unique_ptr packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection); // Verify sent with correct SSRC. packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->SetSsrc(kSsrc); packet->set_packet_type(RtpPacketToSend::Type::kForwardErrorCorrection); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_EQ(transport_.packets_sent(), 1); } TEST_P(RtpSenderTest, SendPacketHandlesRetransmissionHistory) { rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); // Build a media packet and send it. std::unique_ptr 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); rtp_egress()->SendPacket(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); rtp_egress()->SendPacket(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, SendPacketUpdatesExtensions) { 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 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); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); const RtpPacketReceived& received_packet = transport_.last_sent_packet(); EXPECT_EQ(received_packet.GetExtension(), kDiffMs * 90); EXPECT_EQ(received_packet.GetExtension(), AbsoluteSendTime::MsTo24Bits(fake_clock_.TimeInMilliseconds())); VideoSendTiming timing; EXPECT_TRUE(received_packet.GetExtension(&timing)); EXPECT_EQ(timing.pacer_exit_delta_ms, kDiffMs); } TEST_P(RtpSenderTest, SendPacketSetsPacketOptions) { const uint16_t kPacketId = 42; ASSERT_EQ(rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId), 0); std::unique_ptr packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->SetExtension(kPacketId); packet->set_packet_type(RtpPacketToSend::Type::kVideo); EXPECT_CALL(send_packet_observer_, OnSendPacket); rtp_egress()->SendPacket(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(kPacketId + 1); packet->set_packet_type(RtpPacketToSend::Type::kRetransmission); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); EXPECT_TRUE(transport_.last_options_.is_retransmit); } TEST_P(RtpSenderTest, SendPacketUpdatesStats) { const size_t kPayloadSize = 1000; StrictMock send_side_delay_observer; RtpRtcp::Configuration config; config.clock = &fake_clock_; config.outgoing_transport = &transport_; config.local_media_ssrc = kSsrc; config.rtx_send_ssrc = kRtxSsrc; config.flexfec_sender = &flexfec_sender_; config.send_side_delay_observer = &send_side_delay_observer; config.event_log = &mock_rtc_event_log_; config.send_packet_observer = &send_packet_observer_; rtp_sender_context_ = std::make_unique(config); ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId)); const int64_t capture_time_ms = fake_clock_.TimeInMilliseconds(); std::unique_ptr video_packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); video_packet->set_packet_type(RtpPacketToSend::Type::kVideo); video_packet->SetPayloadSize(kPayloadSize); video_packet->SetExtension(1); std::unique_ptr 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(2); std::unique_ptr 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(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)); rtp_egress()->SendPacket(video_packet.get(), PacedPacketInfo()); // Send packet observer not called for padding/retransmissions. EXPECT_CALL(send_packet_observer_, OnSendPacket(2, _, _)).Times(0); rtp_egress()->SendPacket(rtx_packet.get(), PacedPacketInfo()); EXPECT_CALL(send_packet_observer_, OnSendPacket(3, capture_time_ms, kFlexFecSsrc)); rtp_egress()->SendPacket(fec_packet.get(), PacedPacketInfo()); StreamDataCounters rtp_stats; StreamDataCounters rtx_stats; rtp_egress()->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); } TEST_P(RtpSenderTest, GeneratePaddingResendsOldPacketsWithRtx) { // Min requested size in order to use RTX payload. const size_t kMinPaddingSize = 50; rtp_sender()->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads); rtp_sender()->SetRtxPayloadType(kRtxPayload, kPayload); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 1); ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId)); const size_t kPayloadPacketSize = 1234; std::unique_ptr packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->set_allow_retransmission(true); packet->SetPayloadSize(kPayloadPacketSize); packet->set_packet_type(RtpPacketToSend::Type::kVideo); // Send a dummy video packet so it ends up in the packet history. EXPECT_CALL(send_packet_observer_, OnSendPacket).Times(1); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); // Generated padding has large enough budget that the video packet should be // retransmitted as padding. std::vector> generated_packets = rtp_sender()->GeneratePadding(kMinPaddingSize, true); 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); EXPECT_TRUE(padding_packet->IsExtensionReserved()); EXPECT_TRUE(padding_packet->IsExtensionReserved()); EXPECT_TRUE(padding_packet->IsExtensionReserved()); // Verify all header extensions are received. rtp_egress()->SendPacket(padding_packet.get(), PacedPacketInfo()); webrtc::RTPHeader rtp_header; transport_.last_sent_packet().GetHeader(&rtp_header); EXPECT_TRUE(rtp_header.extension.hasAbsoluteSendTime); EXPECT_TRUE(rtp_header.extension.hasTransmissionTimeOffset); EXPECT_TRUE(rtp_header.extension.hasTransportSequenceNumber); // Not enough budged for payload padding, use plain padding instead. const size_t kPaddingBytesRequested = kMinPaddingSize - 1; size_t padding_bytes_generated = 0; generated_packets = rtp_sender()->GeneratePadding(kPaddingBytesRequested, true); EXPECT_EQ(generated_packets.size(), 1u); 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_TRUE(packet->IsExtensionReserved()); EXPECT_TRUE(packet->IsExtensionReserved()); EXPECT_TRUE(packet->IsExtensionReserved()); // Verify all header extensions are received. rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); webrtc::RTPHeader rtp_header; transport_.last_sent_packet().GetHeader(&rtp_header); EXPECT_TRUE(rtp_header.extension.hasAbsoluteSendTime); EXPECT_TRUE(rtp_header.extension.hasTransmissionTimeOffset); EXPECT_TRUE(rtp_header.extension.hasTransportSequenceNumber); } EXPECT_EQ(padding_bytes_generated, kMaxPaddingSize); } TEST_P(RtpSenderTest, GeneratePaddingCreatesPurePaddingWithoutRtx) { rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 1); ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId)); ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionAbsoluteSendTime, kAbsoluteSendTimeExtensionId)); ASSERT_EQ(0, rtp_sender()->RegisterRtpHeaderExtension( kRtpExtensionTransportSequenceNumber, kTransportSequenceNumberExtensionId)); const size_t kPayloadPacketSize = 1234; // Send a dummy video packet so it ends up in the packet history. Since we // are not using RTX, it should never be used as padding. std::unique_ptr packet = BuildRtpPacket(kPayload, true, 0, fake_clock_.TimeInMilliseconds()); packet->set_allow_retransmission(true); packet->SetPayloadSize(kPayloadPacketSize); packet->set_packet_type(RtpPacketToSend::Type::kVideo); EXPECT_CALL(send_packet_observer_, OnSendPacket).Times(1); rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); // Payload padding not available without RTX, only generate plain padding on // the media SSRC. // Number of padding packets is the requested padding size divided by max // padding packet size, rounded up. Pure padding packets are always of the // maximum size. const size_t kPaddingBytesRequested = kPayloadPacketSize + kRtxHeaderSize; const size_t kExpectedNumPaddingPackets = (kPaddingBytesRequested + kMaxPaddingSize - 1) / kMaxPaddingSize; size_t padding_bytes_generated = 0; std::vector> padding_packets = rtp_sender()->GeneratePadding(kPaddingBytesRequested, true); 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_TRUE(packet->IsExtensionReserved()); EXPECT_TRUE(packet->IsExtensionReserved()); EXPECT_TRUE(packet->IsExtensionReserved()); // Verify all header extensions are received. rtp_egress()->SendPacket(packet.get(), PacedPacketInfo()); webrtc::RTPHeader rtp_header; transport_.last_sent_packet().GetHeader(&rtp_header); EXPECT_TRUE(rtp_header.extension.hasAbsoluteSendTime); EXPECT_TRUE(rtp_header.extension.hasTransmissionTimeOffset); EXPECT_TRUE(rtp_header.extension.hasTransportSequenceNumber); } EXPECT_EQ(padding_bytes_generated, kExpectedNumPaddingPackets * kMaxPaddingSize); } TEST_P(RtpSenderTest, SupportsPadding) { bool kSendingMediaStats[] = {true, false}; bool kEnableRedundantPayloads[] = {true, false}; RTPExtensionType kBweExtensionTypes[] = { kRtpExtensionTransportSequenceNumber, kRtpExtensionTransportSequenceNumber02, kRtpExtensionAbsoluteSendTime, kRtpExtensionTransmissionTimeOffset}; const int kExtensionsId = 7; for (bool sending_media : kSendingMediaStats) { rtp_sender()->SetSendingMediaStatus(sending_media); for (bool redundant_payloads : kEnableRedundantPayloads) { int rtx_mode = kRtxRetransmitted; if (redundant_payloads) { rtx_mode |= kRtxRedundantPayloads; } rtp_sender()->SetRtxStatus(rtx_mode); for (auto extension_type : kBweExtensionTypes) { EXPECT_FALSE(rtp_sender()->SupportsPadding()); rtp_sender()->RegisterRtpHeaderExtension(extension_type, kExtensionsId); if (!sending_media) { EXPECT_FALSE(rtp_sender()->SupportsPadding()); } else { EXPECT_TRUE(rtp_sender()->SupportsPadding()); if (redundant_payloads) { EXPECT_TRUE(rtp_sender()->SupportsRtxPayloadPadding()); } else { EXPECT_FALSE(rtp_sender()->SupportsRtxPayloadPadding()); } } rtp_sender()->DeregisterRtpHeaderExtension(extension_type); EXPECT_FALSE(rtp_sender()->SupportsPadding()); } } } } TEST_P(RtpSenderTest, SetsCaptureTimeAndPopulatesTransmissionOffset) { rtp_sender()->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset, kTransmissionTimeOffsetExtensionId); rtp_sender()->SetSendingMediaStatus(true); rtp_sender()->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads); rtp_sender()->SetRtxPayloadType(kRtxPayload, kPayload); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); const int64_t kMissingCaptureTimeMs = 0; const uint32_t kTimestampTicksPerMs = 90; const int64_t kOffsetMs = 10; auto packet = BuildRtpPacket(kPayload, kMarkerBit, fake_clock_.TimeInMilliseconds(), kMissingCaptureTimeMs); packet->set_packet_type(RtpPacketToSend::Type::kVideo); packet->ReserveExtension(); packet->AllocatePayload(sizeof(kPayloadData)); std::unique_ptr packet_to_pace; EXPECT_CALL(mock_paced_sender_, EnqueuePackets) .WillOnce([&](std::vector> packets) { EXPECT_EQ(packets.size(), 1u); EXPECT_GT(packets[0]->capture_time_ms(), 0); packet_to_pace = std::move(packets[0]); }); packet->set_allow_retransmission(true); EXPECT_TRUE(rtp_sender()->SendToNetwork(std::move(packet))); fake_clock_.AdvanceTimeMilliseconds(kOffsetMs); rtp_egress()->SendPacket(packet_to_pace.get(), PacedPacketInfo()); EXPECT_EQ(1, transport_.packets_sent()); absl::optional transmission_time_extension = transport_.sent_packets_.back().GetExtension(); ASSERT_TRUE(transmission_time_extension.has_value()); EXPECT_EQ(*transmission_time_extension, kOffsetMs * kTimestampTicksPerMs); // Retransmit packet. The RTX packet should get the same capture time as the // original packet, so offset is delta from original packet to now. fake_clock_.AdvanceTimeMilliseconds(kOffsetMs); std::unique_ptr rtx_packet_to_pace; EXPECT_CALL(mock_paced_sender_, EnqueuePackets) .WillOnce([&](std::vector> packets) { EXPECT_GT(packets[0]->capture_time_ms(), 0); rtx_packet_to_pace = std::move(packets[0]); }); EXPECT_GT(rtp_sender()->ReSendPacket(kSeqNum), 0); rtp_egress()->SendPacket(rtx_packet_to_pace.get(), PacedPacketInfo()); EXPECT_EQ(2, transport_.packets_sent()); transmission_time_extension = transport_.sent_packets_.back().GetExtension(); ASSERT_TRUE(transmission_time_extension.has_value()); EXPECT_EQ(*transmission_time_extension, 2 * kOffsetMs * kTimestampTicksPerMs); } TEST_P(RtpSenderTestWithoutPacer, ClearHistoryOnSequenceNumberCange) { const int64_t kRtt = 10; rtp_sender()->SetSendingMediaStatus(true); rtp_sender()->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads); rtp_sender()->SetRtxPayloadType(kRtxPayload, kPayload); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); rtp_sender_context_->packet_history_.SetRtt(kRtt); // Send a packet and record its sequence numbers. SendGenericPacket(); ASSERT_EQ(1u, transport_.sent_packets_.size()); const uint16_t packet_seqence_number = transport_.sent_packets_.back().SequenceNumber(); // Advance time and make sure it can be retransmitted, even if we try to set // the ssrc the what it already is. rtp_sender()->SetSequenceNumber(rtp_sender()->SequenceNumber()); fake_clock_.AdvanceTimeMilliseconds(kRtt); EXPECT_GT(rtp_sender()->ReSendPacket(packet_seqence_number), 0); // Change the sequence number, then move the time and try to retransmit again. // The old packet should now be gone. rtp_sender()->SetSequenceNumber(rtp_sender()->SequenceNumber() - 1); fake_clock_.AdvanceTimeMilliseconds(kRtt); EXPECT_EQ(rtp_sender()->ReSendPacket(packet_seqence_number), 0); } TEST_P(RtpSenderTest, IgnoresNackAfterDisablingMedia) { const int64_t kRtt = 10; rtp_sender()->SetSendingMediaStatus(true); rtp_sender()->SetRtxStatus(kRtxRetransmitted | kRtxRedundantPayloads); rtp_sender()->SetRtxPayloadType(kRtxPayload, kPayload); rtp_sender_context_->packet_history_.SetStorePacketsStatus( RtpPacketHistory::StorageMode::kStoreAndCull, 10); rtp_sender_context_->packet_history_.SetRtt(kRtt); // Send a packet so it is in the packet history. std::unique_ptr packet_to_pace; EXPECT_CALL(mock_paced_sender_, EnqueuePackets) .WillOnce([&](std::vector> packets) { packet_to_pace = std::move(packets[0]); }); SendGenericPacket(); rtp_egress()->SendPacket(packet_to_pace.get(), PacedPacketInfo()); ASSERT_EQ(1u, transport_.sent_packets_.size()); // Disable media sending and try to retransmit the packet, it should fail. rtp_sender()->SetSendingMediaStatus(false); fake_clock_.AdvanceTimeMilliseconds(kRtt); EXPECT_LT(rtp_sender()->ReSendPacket(kSeqNum), 0); } INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead, RtpSenderTest, ::testing::Values(TestConfig{false}, TestConfig{true})); INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead, RtpSenderTestWithoutPacer, ::testing::Values(TestConfig{false}, TestConfig{true})); } // namespace webrtc