Make it possible to enable/disable receive-side RTT with a setter.

This will allow us to enable receive-side RTT without having to recreate all AudioReceiveStream objects.

Bug: webrtc:12951
Change-Id: I1227297ec4ebeea9ba15fe2ed904349829b2e669
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/225262
Commit-Queue: Ivo Creusen <ivoc@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Jakob Ivarsson <jakobi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34464}
diff --git a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index a7707ec..59b8cf1 100644
--- a/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -66,6 +66,7 @@
   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 3ab78df..a8e1dc5 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -303,6 +303,11 @@
   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 fa9f367..206b63a 100644
--- a/modules/rtp_rtcp/source/rtcp_receiver.h
+++ b/modules/rtp_rtcp/source/rtcp_receiver.h
@@ -108,6 +108,7 @@
               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 @@
       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 3065534..e61ae64 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 <memory>
+#include <set>
 #include <utility>
 
 #include "api/array_view.h"
@@ -939,6 +940,64 @@
   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 8f5e3b1..7f5e327 100644
--- a/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -231,6 +231,11 @@
   }
 }
 
+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 2d1c7da..133eb83 100644
--- a/modules/rtp_rtcp/source/rtcp_sender.h
+++ b/modules/rtp_rtcp/source/rtcp_sender.h
@@ -118,7 +118,8 @@
                         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 @@
   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 347be79..d05d8d6 100644
--- a/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
+++ b/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
@@ -531,6 +531,35 @@
   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 b0e0b41..932a02d 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -97,6 +97,8 @@
   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 7fae1e3..c6d1977 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl2.cc
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl2.cc
@@ -103,14 +103,11 @@
   // 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 @@
   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 @@
   absl::optional<TimeDelta> 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 0ad4955..0440879 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_impl2.h
+++ b/modules/rtp_rtcp/source/rtp_rtcp_impl2.h
@@ -104,6 +104,8 @@
   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 dd5744e..5961b3d 100644
--- a/modules/rtp_rtcp/source/rtp_rtcp_interface.h
+++ b/modules/rtp_rtcp/source/rtp_rtcp_interface.h
@@ -237,6 +237,9 @@
   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;