diff --git a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h index a7707ecc19..59b8cf19b8 100644 --- a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h +++ b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h @@ -66,6 +66,7 @@ class MockRtpRtcpInterface : public RtpRtcpInterface { MOCK_METHOD(void, SetSequenceNumber, (uint16_t seq), (override)); MOCK_METHOD(void, SetRtpState, (const RtpState& rtp_state), (override)); MOCK_METHOD(void, SetRtxState, (const RtpState& rtp_state), (override)); + MOCK_METHOD(void, SetNonSenderRttMeasurement, (bool enabled), (override)); MOCK_METHOD(RtpState, GetRtpState, (), (const, override)); MOCK_METHOD(RtpState, GetRtxState, (), (const, override)); MOCK_METHOD(uint32_t, SSRC, (), (const, override)); diff --git a/modules/rtp_rtcp/source/rtcp_receiver.cc b/modules/rtp_rtcp/source/rtcp_receiver.cc index 3ab78df17c..a8e1dc5f07 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver.cc @@ -303,6 +303,11 @@ int32_t RTCPReceiver::RTT(uint32_t remote_ssrc, return 0; } +void RTCPReceiver::SetNonSenderRttMeasurement(bool enabled) { + MutexLock lock(&rtcp_receiver_lock_); + xr_rrtr_status_ = enabled; +} + bool RTCPReceiver::GetAndResetXrRrRtt(int64_t* rtt_ms) { RTC_DCHECK(rtt_ms); MutexLock lock(&rtcp_receiver_lock_); diff --git a/modules/rtp_rtcp/source/rtcp_receiver.h b/modules/rtp_rtcp/source/rtcp_receiver.h index fa9f367c9e..206b63ae8f 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver.h +++ b/modules/rtp_rtcp/source/rtcp_receiver.h @@ -108,6 +108,7 @@ class RTCPReceiver final { int64_t* min_rtt_ms, int64_t* max_rtt_ms) const; + void SetNonSenderRttMeasurement(bool enabled); bool GetAndResetXrRrRtt(int64_t* rtt_ms); // Called once per second on the worker thread to do rtt calculations. @@ -371,7 +372,7 @@ class RTCPReceiver final { received_rrtrs_ssrc_it_ RTC_GUARDED_BY(rtcp_receiver_lock_); // Estimated rtt, zero when there is no valid estimate. - const bool xr_rrtr_status_; + bool xr_rrtr_status_ RTC_GUARDED_BY(rtcp_receiver_lock_); int64_t xr_rr_rtt_ms_; int64_t oldest_tmmbr_info_ms_ RTC_GUARDED_BY(rtcp_receiver_lock_); diff --git a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc index 3065534108..e61ae648c3 100644 --- a/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc +++ b/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc @@ -11,6 +11,7 @@ #include "modules/rtp_rtcp/source/rtcp_receiver.h" #include +#include #include #include "api/array_view.h" @@ -939,6 +940,64 @@ TEST(RtcpReceiverTest, RttCalculatedAfterExtendedReportsDlrr) { EXPECT_NEAR(kRttMs, rtt_ms, 1); } +// Same test as above but enables receive-side RTT using the setter instead of +// the config struct. +TEST(RtcpReceiverTest, SetterEnablesReceiverRtt) { + ReceiverMocks mocks; + auto config = DefaultConfiguration(&mocks); + config.non_sender_rtt_measurement = false; + RTCPReceiver receiver(config, &mocks.rtp_rtcp_impl); + receiver.SetRemoteSSRC(kSenderSsrc); + receiver.SetNonSenderRttMeasurement(true); + + Random rand(0x0123456789abcdef); + const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000); + const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); + const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + NtpTime now = mocks.clock.CurrentNtpTime(); + uint32_t sent_ntp = CompactNtp(now); + mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, sent_ntp, kDelayNtp)); + + receiver.IncomingPacket(xr.Build()); + + int64_t rtt_ms = 0; + EXPECT_TRUE(receiver.GetAndResetXrRrRtt(&rtt_ms)); + EXPECT_NEAR(rtt_ms, kRttMs, 1); +} + +// Same test as above but disables receive-side RTT using the setter instead of +// the config struct. +TEST(RtcpReceiverTest, DoesntCalculateRttOnReceivedDlrr) { + ReceiverMocks mocks; + auto config = DefaultConfiguration(&mocks); + config.non_sender_rtt_measurement = true; + RTCPReceiver receiver(config, &mocks.rtp_rtcp_impl); + receiver.SetRemoteSSRC(kSenderSsrc); + receiver.SetNonSenderRttMeasurement(false); + + Random rand(0x0123456789abcdef); + const int64_t kRttMs = rand.Rand(1, 9 * 3600 * 1000); + const uint32_t kDelayNtp = rand.Rand(0, 0x7fffffff); + const int64_t kDelayMs = CompactNtpRttToMs(kDelayNtp); + NtpTime now = mocks.clock.CurrentNtpTime(); + uint32_t sent_ntp = CompactNtp(now); + mocks.clock.AdvanceTimeMilliseconds(kRttMs + kDelayMs); + + rtcp::ExtendedReports xr; + xr.SetSenderSsrc(kSenderSsrc); + xr.AddDlrrItem(ReceiveTimeInfo(kReceiverMainSsrc, sent_ntp, kDelayNtp)); + + receiver.IncomingPacket(xr.Build()); + + // We expect that no RTT is available (because receive-side RTT was disabled). + int64_t rtt_ms = 0; + EXPECT_FALSE(receiver.GetAndResetXrRrRtt(&rtt_ms)); +} + TEST(RtcpReceiverTest, XrDlrrCalculatesNegativeRttAsOne) { ReceiverMocks mocks; auto config = DefaultConfiguration(&mocks); diff --git a/modules/rtp_rtcp/source/rtcp_sender.cc b/modules/rtp_rtcp/source/rtcp_sender.cc index 8f5e3b104c..7f5e327de1 100644 --- a/modules/rtp_rtcp/source/rtcp_sender.cc +++ b/modules/rtp_rtcp/source/rtcp_sender.cc @@ -231,6 +231,11 @@ void RTCPSender::SetSendingStatus(const FeedbackState& feedback_state, } } +void RTCPSender::SetNonSenderRttMeasurement(bool enabled) { + MutexLock lock(&mutex_rtcp_sender_); + xr_send_receiver_reference_time_enabled_ = enabled; +} + int32_t RTCPSender::SendLossNotification(const FeedbackState& feedback_state, uint16_t last_decoded_seq_num, uint16_t last_received_seq_num, diff --git a/modules/rtp_rtcp/source/rtcp_sender.h b/modules/rtp_rtcp/source/rtcp_sender.h index 2d1c7da0fc..133eb8342b 100644 --- a/modules/rtp_rtcp/source/rtcp_sender.h +++ b/modules/rtp_rtcp/source/rtcp_sender.h @@ -118,7 +118,8 @@ class RTCPSender final { bool enabled) RTC_LOCKS_EXCLUDED(mutex_rtcp_sender_); // combine the functions - int32_t SetNackStatus(bool enable) RTC_LOCKS_EXCLUDED(mutex_rtcp_sender_); + void SetNonSenderRttMeasurement(bool enabled) + RTC_LOCKS_EXCLUDED(mutex_rtcp_sender_); void SetTimestampOffset(uint32_t timestamp_offset) RTC_LOCKS_EXCLUDED(mutex_rtcp_sender_); @@ -282,7 +283,8 @@ class RTCPSender final { size_t max_packet_size_ RTC_GUARDED_BY(mutex_rtcp_sender_); // True if sending of XR Receiver reference time report is enabled. - const bool xr_send_receiver_reference_time_enabled_; + bool xr_send_receiver_reference_time_enabled_ + RTC_GUARDED_BY(mutex_rtcp_sender_); RtcpPacketTypeCounterObserver* const packet_type_counter_observer_; RtcpPacketTypeCounter packet_type_counter_ RTC_GUARDED_BY(mutex_rtcp_sender_); diff --git a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc index 347be79398..d05d8d6dd5 100644 --- a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc +++ b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc @@ -531,6 +531,35 @@ TEST_F(RtcpSenderTest, SendXrWithRrtr) { EXPECT_EQ(ntp, parser()->xr()->rrtr()->ntp()); } +// Same test as above, but enable Rrtr with the setter. +TEST_F(RtcpSenderTest, SendXrWithRrtrUsingSetter) { + RTCPSender::Configuration config = GetDefaultConfig(); + config.non_sender_rtt_measurement = false; + auto rtcp_sender = CreateRtcpSender(config); + rtcp_sender->SetNonSenderRttMeasurement(true); + rtcp_sender->SetRTCPStatus(RtcpMode::kCompound); + rtcp_sender->SetSendingStatus(feedback_state(), false); + NtpTime ntp = clock_.CurrentNtpTime(); + EXPECT_EQ(0, rtcp_sender->SendRTCP(feedback_state(), kRtcpReport)); + EXPECT_EQ(1, parser()->xr()->num_packets()); + EXPECT_EQ(kSenderSsrc, parser()->xr()->sender_ssrc()); + EXPECT_FALSE(parser()->xr()->dlrr()); + ASSERT_TRUE(parser()->xr()->rrtr()); + EXPECT_EQ(ntp, parser()->xr()->rrtr()->ntp()); +} + +// Same test as above, but disable Rrtr with the setter. +TEST_F(RtcpSenderTest, SendsNoRrtrUsingSetter) { + RTCPSender::Configuration config = GetDefaultConfig(); + config.non_sender_rtt_measurement = true; + auto rtcp_sender = CreateRtcpSender(config); + rtcp_sender->SetNonSenderRttMeasurement(false); + rtcp_sender->SetRTCPStatus(RtcpMode::kCompound); + rtcp_sender->SetSendingStatus(feedback_state(), false); + EXPECT_EQ(0, rtcp_sender->SendRTCP(feedback_state(), kRtcpReport)); + EXPECT_EQ(0, parser()->xr()->num_packets()); +} + TEST_F(RtcpSenderTest, TestNoXrRrtrSentIfSending) { RTCPSender::Configuration config = GetDefaultConfig(); config.non_sender_rtt_measurement = true; diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/modules/rtp_rtcp/source/rtp_rtcp_impl.h index b0e0b41c48..932a02d521 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -97,6 +97,8 @@ class ModuleRtpRtcpImpl : public RtpRtcp, public RTCPReceiver::ModuleRtpRtcp { RtpState GetRtpState() const override; RtpState GetRtxState() const override; + void SetNonSenderRttMeasurement(bool enabled) override {} + uint32_t SSRC() const override { return rtcp_sender_.SSRC(); } void SetRid(const std::string& rid) override; diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl2.cc b/modules/rtp_rtcp/source/rtp_rtcp_impl2.cc index 7fae1e3bd0..c6d19775f2 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl2.cc +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl2.cc @@ -103,14 +103,11 @@ ModuleRtpRtcpImpl2::ModuleRtpRtcpImpl2(const Configuration& configuration) // webrtc::VideoSendStream::Config::Rtp::kDefaultMaxPacketSize. const size_t kTcpOverIpv4HeaderSize = 40; SetMaxRtpPacketSize(IP_PACKET_SIZE - kTcpOverIpv4HeaderSize); - - if (rtt_stats_) { - rtt_update_task_ = RepeatingTaskHandle::DelayedStart( - worker_queue_, kRttUpdateInterval, [this]() { - PeriodicUpdate(); - return kRttUpdateInterval; - }); - } + rtt_update_task_ = RepeatingTaskHandle::DelayedStart( + worker_queue_, kRttUpdateInterval, [this]() { + PeriodicUpdate(); + return kRttUpdateInterval; + }); } ModuleRtpRtcpImpl2::~ModuleRtpRtcpImpl2() { @@ -204,6 +201,11 @@ RtpState ModuleRtpRtcpImpl2::GetRtxState() const { return rtp_sender_->packet_generator.GetRtxRtpState(); } +void ModuleRtpRtcpImpl2::SetNonSenderRttMeasurement(bool enabled) { + rtcp_sender_.SetNonSenderRttMeasurement(enabled); + rtcp_receiver_.SetNonSenderRttMeasurement(enabled); +} + uint32_t ModuleRtpRtcpImpl2::local_media_ssrc() const { RTC_DCHECK_RUN_ON(&packet_sequence_checker_); RTC_DCHECK_EQ(rtcp_receiver_.local_media_ssrc(), rtcp_sender_.SSRC()); @@ -739,7 +741,9 @@ void ModuleRtpRtcpImpl2::PeriodicUpdate() { absl::optional rtt = rtcp_receiver_.OnPeriodicRttUpdate(check_since, rtcp_sender_.Sending()); if (rtt) { - rtt_stats_->OnRttUpdate(rtt->ms()); + if (rtt_stats_) { + rtt_stats_->OnRttUpdate(rtt->ms()); + } set_rtt_ms(rtt->ms()); } } diff --git a/modules/rtp_rtcp/source/rtp_rtcp_impl2.h b/modules/rtp_rtcp/source/rtp_rtcp_impl2.h index 0ad495593d..0440879e12 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_impl2.h +++ b/modules/rtp_rtcp/source/rtp_rtcp_impl2.h @@ -104,6 +104,8 @@ class ModuleRtpRtcpImpl2 final : public RtpRtcpInterface, RtpState GetRtpState() const override; RtpState GetRtxState() const override; + void SetNonSenderRttMeasurement(bool enabled) override; + uint32_t SSRC() const override { return rtcp_sender_.SSRC(); } // Semantically identical to `SSRC()` but must be called on the packet diff --git a/modules/rtp_rtcp/source/rtp_rtcp_interface.h b/modules/rtp_rtcp/source/rtp_rtcp_interface.h index dd5744ec54..5961b3d787 100644 --- a/modules/rtp_rtcp/source/rtp_rtcp_interface.h +++ b/modules/rtp_rtcp/source/rtp_rtcp_interface.h @@ -237,6 +237,9 @@ class RtpRtcpInterface : public RtcpFeedbackSenderInterface { virtual RtpState GetRtpState() const = 0; virtual RtpState GetRtxState() const = 0; + // This can be used to enable/disable receive-side RTT. + virtual void SetNonSenderRttMeasurement(bool enabled) = 0; + // Returns SSRC. virtual uint32_t SSRC() const = 0;