Propagate estimated RTT from receivers to rtt observer.

BUG=1613
R=stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/3119004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5063 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
index 25fa82c..ddeedcc 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -50,6 +50,7 @@
     _lastReceivedSRNTPfrac(0),
     _lastReceivedXRNTPsecs(0),
     _lastReceivedXRNTPfrac(0),
+    xr_rr_rtt_ms_(0),
     _receivedInfoMap(),
     _packetTimeOutMS(0),
     _lastReceivedRrMs(0),
@@ -216,6 +217,17 @@
   return 0;
 }
 
+bool RTCPReceiver::GetAndResetXrRrRtt(uint16_t* rtt_ms) {
+  assert(rtt_ms);
+  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
+  if (xr_rr_rtt_ms_ == 0) {
+    return false;
+  }
+  *rtt_ms = xr_rr_rtt_ms_;
+  xr_rr_rtt_ms_ = 0;
+  return true;
+}
+
 uint16_t RTCPReceiver::RTT() const {
   CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
   if (!_receivedReportBlockMap.empty()) {
@@ -897,6 +909,7 @@
     delete cnameInfoIt->second;
     _receivedCnameMap.erase(cnameInfoIt);
   }
+  xr_rr_rtt_ms_ = 0;
   rtcpParser.Iterate();
 }
 
@@ -968,13 +981,13 @@
   }
 
   // The DelayLastRR field is in units of 1/65536 sec.
-// uint32_t delay_rr_ms =
-//    (((packet.XRDLRRReportBlockItem.DelayLastRR & 0x0000ffff) * 1000) >> 16) +
-//    (((packet.XRDLRRReportBlockItem.DelayLastRR & 0xffff0000) >> 16) * 1000);
+  uint32_t delay_rr_ms =
+      (((packet.XRDLRRReportBlockItem.DelayLastRR & 0x0000ffff) * 1000) >> 16) +
+      (((packet.XRDLRRReportBlockItem.DelayLastRR & 0xffff0000) >> 16) * 1000);
 
-  // TODO(asapersson): Not yet used.
-// int32_t rtt =_clock->CurrentNtpInMilliseconds() - delay_rr_ms - send_time_ms;
-// rtt = std::max(rtt, 1);
+  int32_t rtt = _clock->CurrentNtpInMilliseconds() - delay_rr_ms - send_time_ms;
+
+  xr_rr_rtt_ms_ = static_cast<uint16_t>(std::max(rtt, 1));
 
   rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpXrDlrrReportBlock;
 }
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
index 0b5c8f1..3da3445 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
@@ -86,6 +86,8 @@
 
     int32_t SenderInfoReceived(RTCPSenderInfo* senderInfo) const;
 
+    bool GetAndResetXrRrRtt(uint16_t* rtt_ms);
+
     // get statistics
     int32_t StatisticsReceived(
         std::vector<RTCPReportBlock>* receiveBlocks) const;
@@ -245,6 +247,8 @@
   // Time when the report was received.
   uint32_t _lastReceivedXRNTPsecs;
   uint32_t _lastReceivedXRNTPfrac;
+  // Estimated rtt, zero when there is no valid estimate.
+  uint16_t xr_rr_rtt_ms_;
 
   // Received report blocks.
   std::map<uint32_t, RTCPHelp::RTCPReportBlockInformation*>
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index af969de..c33cf23 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -459,6 +459,11 @@
   EXPECT_EQ(kNtpMid, RTCPUtility::MidNtp(kNtpSec, kNtpFrac));
 }
 
+TEST_F(RtcpReceiverTest, TestXrRrRttInitiallyFalse) {
+  uint16_t rtt_ms;
+  EXPECT_FALSE(rtcp_receiver_->GetAndResetXrRrRtt(&rtt_ms));
+}
+
 TEST_F(RtcpReceiverTest, LastReceivedXrReferenceTimeInfoInitiallyFalse) {
   RtcpReceiveTimeInfo info;
   EXPECT_FALSE(rtcp_receiver_->LastReceivedXrReferenceTimeInfo(&info));
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 812f427..3369b55 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -196,13 +196,12 @@
       default_instance = true;
   }
   if (!default_instance) {
+    bool process_rtt = now >= last_rtt_process_time_ + kRtpRtcpRttProcessTimeMs;
     if (rtcp_sender_.Sending()) {
       // Process RTT if we have received a receiver report and we haven't
       // processed RTT for at least |kRtpRtcpRttProcessTimeMs| milliseconds.
       if (rtcp_receiver_.LastReceivedReceiverReport() >
-          last_rtt_process_time_ && now >= last_rtt_process_time_ +
-          kRtpRtcpRttProcessTimeMs) {
-        last_rtt_process_time_ = now;
+          last_rtt_process_time_ && process_rtt) {
         std::vector<RTCPReportBlock> receive_blocks;
         rtcp_receiver_.StatisticsReceived(&receive_blocks);
         uint16_t max_rtt = 0;
@@ -237,7 +236,20 @@
           rtcp_sender_.SetTargetBitrate(target_bitrate);
         }
       }
+    } else {
+      // Report rtt from receiver.
+      if (process_rtt) {
+         uint16_t rtt_ms;
+         if (rtt_observer_ && rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)) {
+           rtt_observer_->OnRttUpdate(rtt_ms);
+         }
+      }
     }
+
+    if (process_rtt) {
+      last_rtt_process_time_ = now;
+    }
+
     if (rtcp_sender_.TimeToSendRTCPReport()) {
       RTCPSender::FeedbackState feedback_state(this);
       rtcp_sender_.SendRTCP(feedback_state, kRtcpReport);
@@ -941,6 +953,12 @@
   return  rtcp_sender_.SetRTCPVoIPMetrics(voip_metric);
 }
 
+void ModuleRtpRtcpImpl::SetRtcpXrRrtrStatus(bool enable) {
+  WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
+               "SetRtcpXrRrtrStatus(%s)", enable ? "true" : "false");
+  return rtcp_sender_.SendRtcpXrReceiverReferenceTime(enable);
+}
+
 int32_t ModuleRtpRtcpImpl::DataCountersRTP(
     uint32_t* bytes_sent,
     uint32_t* packets_sent) const {
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index b97ef1a..c2fc498 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -255,6 +255,9 @@
   // (XR) VOIP metric.
   virtual int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) OVERRIDE;
 
+  // (XR) Receiver reference time report.
+  virtual void SetRtcpXrRrtrStatus(bool enable) OVERRIDE;
+
   // Audio part.
 
   // Set audio packet size, used to determine when it's time to send a DTMF
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
index f9add41..ff3c32e 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl_unittest.cc
@@ -18,6 +18,17 @@
 namespace webrtc {
 namespace {
 
+class RtcpRttStatsTestImpl : public RtcpRttObserver {
+ public:
+  RtcpRttStatsTestImpl() : rtt_ms_(0) {}
+  virtual ~RtcpRttStatsTestImpl() {}
+
+  virtual void OnRttUpdate(uint32_t rtt_ms) {
+    rtt_ms_ = rtt_ms;
+  }
+  uint32_t rtt_ms_;
+};
+
 class SendTransport : public Transport,
                       public NullRtpData {
  public:
@@ -59,6 +70,7 @@
     configuration.clock = &clock_;
     configuration.outgoing_transport = &transport_;
     configuration.receive_statistics = receive_statistics_.get();
+    configuration.rtt_observer = &rtt_stats_;
 
     rtp_rtcp_impl_.reset(new ModuleRtpRtcpImpl(configuration));
     transport_.SetRtpRtcpModule(rtp_rtcp_impl_.get());
@@ -68,6 +80,7 @@
   scoped_ptr<ReceiveStatistics> receive_statistics_;
   scoped_ptr<ModuleRtpRtcpImpl> rtp_rtcp_impl_;
   SendTransport transport_;
+  RtcpRttStatsTestImpl rtt_stats_;
 };
 
 TEST_F(RtpRtcpImplTest, Rtt) {
@@ -108,4 +121,25 @@
       rtp_rtcp_impl_->RTT(kSsrc + 1, &rtt, &avg_rtt, &min_rtt, &max_rtt));
 }
 
+TEST_F(RtpRtcpImplTest, RttForReceiverOnly) {
+  rtp_rtcp_impl_->SetRtcpXrRrtrStatus(true);
+  EXPECT_EQ(0, rtp_rtcp_impl_->SetSendingStatus(false));
+  EXPECT_EQ(0, rtp_rtcp_impl_->SetRTCPStatus(kRtcpCompound));
+  EXPECT_EQ(0, rtp_rtcp_impl_->SetSSRC(0x12345));
+
+  // A Receiver time reference report (RTRR) should be sent and received.
+  EXPECT_EQ(0, rtp_rtcp_impl_->SendRTCP(kRtcpReport));
+
+  // Send new RTRR. A response to the last RTRR should be sent.
+  clock_.AdvanceTimeMilliseconds(1000);
+  transport_.SimulateNetworkDelay(100, &clock_);
+  EXPECT_EQ(0, rtp_rtcp_impl_->SendRTCP(kRtcpReport));
+
+  // Verify RTT.
+  EXPECT_EQ(0U, rtt_stats_.rtt_ms_);
+
+  rtp_rtcp_impl_->Process();
+  EXPECT_EQ(100U, rtt_stats_.rtt_ms_);
+}
+
 }  // namespace webrtc