diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc index 123b68a10d..01085d1a33 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl2_unittest.cc @@ -47,11 +47,13 @@ namespace webrtc { namespace { constexpr uint32_t kSenderSsrc = 0x12345; constexpr uint32_t kReceiverSsrc = 0x23456; +constexpr uint32_t kRtxSenderSsrc = 0x12346; constexpr TimeDelta kOneWayNetworkDelay = TimeDelta::Millis(100); constexpr uint8_t kBaseLayerTid = 0; constexpr uint8_t kHigherLayerTid = 1; constexpr uint16_t kSequenceNumber = 100; constexpr uint8_t kPayloadType = 100; +constexpr uint8_t kRtxPayloadType = 98; constexpr int kWidth = 320; constexpr int kHeight = 100; constexpr int kCaptureTimeMsToRtpTimestamp = 90; // 90 kHz clock. @@ -264,7 +266,6 @@ class RtpRtcpModule : public RtcpPacketTypeCounterObserver, CreateModuleImpl(); } - private: void CreateModuleImpl() { RtpRtcpInterface::Configuration config; config.audio = false; @@ -275,6 +276,8 @@ class RtpRtcpModule : public RtcpPacketTypeCounterObserver, config.rtt_stats = &rtt_stats_; config.rtcp_report_interval_ms = rtcp_report_interval_.ms(); config.local_media_ssrc = is_sender_ ? kSenderSsrc : kReceiverSsrc; + config.rtx_send_ssrc = + is_sender_ ? absl::make_optional(kRtxSenderSsrc) : absl::nullopt; config.need_rtp_packet_infos = true; config.non_sender_rtt_measurement = true; config.field_trials = &trials_; @@ -285,6 +288,7 @@ class RtpRtcpModule : public RtcpPacketTypeCounterObserver, impl_->SetRTCPStatus(RtcpMode::kCompound); } + private: std::map counter_map_; absl::optional last_sent_packet_; VideoFecGenerator* fec_generator_ = nullptr; @@ -1075,6 +1079,99 @@ TEST_P(RtpRtcpImpl2Test, GeneratesUlpfec) { EXPECT_EQ(fec_packet.payload()[0], kUlpfecPayloadType); } +TEST_P(RtpRtcpImpl2Test, RtpStateReflectsCurrentState) { + // Verify that that each of the field of GetRtpState actually reflects + // the current state. + + // Current time will be used for `timestamp`, `capture_time_ms` and + // `last_timestamp_time_ms`. + const int64_t time_ms = time_controller_.GetClock()->TimeInMilliseconds(); + + // Use different than default sequence number to test `sequence_number`. + const uint16_t kSeq = kSequenceNumber + 123; + // Hard-coded value for `start_timestamp`. + const uint32_t kStartTimestamp = 3456; + const int64_t capture_time_ms = time_ms; + const uint32_t timestamp = capture_time_ms * kCaptureTimeMsToRtpTimestamp; + + sender_.impl_->SetSequenceNumber(kSeq - 1); + sender_.impl_->SetStartTimestamp(kStartTimestamp); + EXPECT_TRUE(SendFrame(&sender_, sender_video_.get(), kBaseLayerTid)); + + // Simulate an RTCP receiver report in order to populate `ssrc_has_acked`. + RTCPReportBlock ack; + ack.source_ssrc = kSenderSsrc; + ack.extended_highest_sequence_number = kSeq; + sender_.impl_->OnReceivedRtcpReportBlocks({ack}); + + RtpState state = sender_.impl_->GetRtpState(); + EXPECT_EQ(state.sequence_number, kSeq); + EXPECT_EQ(state.start_timestamp, kStartTimestamp); + EXPECT_EQ(state.timestamp, timestamp); + EXPECT_EQ(state.capture_time_ms, capture_time_ms); + EXPECT_EQ(state.last_timestamp_time_ms, time_ms); + EXPECT_EQ(state.ssrc_has_acked, true); + + // Reset sender, advance time, restore state. Directly observing state + // is not feasible, so just verify returned state matches what we set. + sender_.CreateModuleImpl(); + time_controller_.AdvanceTime(TimeDelta::Millis(10)); + sender_.impl_->SetRtpState(state); + + state = sender_.impl_->GetRtpState(); + EXPECT_EQ(state.sequence_number, kSeq); + EXPECT_EQ(state.start_timestamp, kStartTimestamp); + EXPECT_EQ(state.timestamp, timestamp); + EXPECT_EQ(state.capture_time_ms, capture_time_ms); + EXPECT_EQ(state.last_timestamp_time_ms, time_ms); + EXPECT_EQ(state.ssrc_has_acked, true); +} + +TEST_P(RtpRtcpImpl2Test, RtxRtpStateReflectsCurrentState) { + // Enable RTX. + sender_.impl_->SetStorePacketsStatus(/*enable=*/true, /*number_to_store=*/10); + sender_.impl_->SetRtxSendPayloadType(kRtxPayloadType, kPayloadType); + sender_.impl_->SetRtxSendStatus(kRtxRetransmitted | kRtxRedundantPayloads); + + // `start_timestamp` is the only timestamp populate in the RTX state. + const uint32_t kStartTimestamp = 3456; + sender_.impl_->SetStartTimestamp(kStartTimestamp); + + // Send a frame and ask for a retransmit of the last packet. Capture the RTX + // packet in order to verify RTX sequence number. + EXPECT_TRUE(SendFrame(&sender_, sender_video_.get(), kBaseLayerTid)); + time_controller_.AdvanceTime(TimeDelta::Millis(5)); + sender_.impl_->OnReceivedNack( + std::vector{sender_.transport_.last_packet_.SequenceNumber()}); + RtpPacketReceived& rtx_packet = sender_.transport_.last_packet_; + EXPECT_EQ(rtx_packet.Ssrc(), kRtxSenderSsrc); + + // Simulate an RTCP receiver report in order to populate `ssrc_has_acked`. + RTCPReportBlock ack; + ack.source_ssrc = kRtxSenderSsrc; + ack.extended_highest_sequence_number = rtx_packet.SequenceNumber(); + sender_.impl_->OnReceivedRtcpReportBlocks({ack}); + + RtpState rtp_state = sender_.impl_->GetRtpState(); + RtpState rtx_state = sender_.impl_->GetRtxState(); + EXPECT_EQ(rtx_state.start_timestamp, kStartTimestamp); + EXPECT_EQ(rtx_state.ssrc_has_acked, true); + EXPECT_EQ(rtx_state.sequence_number, rtx_packet.SequenceNumber() + 1); + + // Reset sender, advance time, restore state. Directly observing state + // is not feasible, so just verify returned state matches what we set. + // Needs SetRtpState() too in order to propagate start timestamp. + sender_.CreateModuleImpl(); + time_controller_.AdvanceTime(TimeDelta::Millis(10)); + sender_.impl_->SetRtpState(rtp_state); + sender_.impl_->SetRtxState(rtx_state); + + rtx_state = sender_.impl_->GetRtxState(); + EXPECT_EQ(rtx_state.start_timestamp, kStartTimestamp); + EXPECT_EQ(rtx_state.ssrc_has_acked, true); + EXPECT_EQ(rtx_state.sequence_number, rtx_packet.SequenceNumber() + 1); +} + INSTANTIATE_TEST_SUITE_P(WithAndWithoutOverhead, RtpRtcpImpl2Test, ::testing::Values(TestConfig{false},