Added support for sending and receiving RTCP XR packets:
- Receiver reference time report block
- DLRR report block (RFC3611).

BUG=1613
R=mflodman@webrtc.org, stefan@webrtc.org

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

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4898 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
index de5fcb2..85aa36f 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
@@ -96,7 +96,9 @@
     kRtcpSli            = 0x4000,
     kRtcpRpsi           = 0x8000,
     kRtcpRemb           = 0x10000,
-    kRtcpTransmissionTimeOffset = 0x20000
+    kRtcpTransmissionTimeOffset = 0x20000,
+    kRtcpXrReceiverReferenceTime = 0x40000,
+    kRtcpXrDlrrReportBlock = 0x80000
 };
 
 enum KeyFrameRequestMethod
@@ -177,6 +179,13 @@
   uint32_t delaySinceLastSR;
 };
 
+struct RtcpReceiveTimeInfo {
+  // Fields as described by RFC 3611 4.5.
+  uint32_t sourceSSRC;
+  uint32_t lastRR;
+  uint32_t delaySinceLastRR;
+};
+
 typedef std::list<RTCPReportBlock> ReportBlockList;
 
 class RtpData
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
index 0771eba..25fa82c 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc
@@ -13,6 +13,8 @@
 #include <assert.h> //assert
 #include <string.h> //memset
 
+#include <algorithm>
+
 #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
@@ -46,6 +48,8 @@
     _remoteSenderInfo(),
     _lastReceivedSRNTPsecs(0),
     _lastReceivedSRNTPfrac(0),
+    _lastReceivedXRNTPsecs(0),
+    _lastReceivedXRNTPfrac(0),
     _receivedInfoMap(),
     _packetTimeOutMS(0),
     _lastReceivedRrMs(0),
@@ -259,6 +263,30 @@
     return 0;
 }
 
+bool RTCPReceiver::LastReceivedXrReferenceTimeInfo(
+    RtcpReceiveTimeInfo* info) const {
+  assert(info);
+  CriticalSectionScoped lock(_criticalSectionRTCPReceiver);
+  if (_lastReceivedXRNTPsecs == 0 && _lastReceivedXRNTPfrac == 0) {
+    return false;
+  }
+
+  info->sourceSSRC = _remoteXRReceiveTimeInfo.sourceSSRC;
+  info->lastRR = _remoteXRReceiveTimeInfo.lastRR;
+
+  // Get the delay since last received report (RFC 3611).
+  uint32_t receive_time = RTCPUtility::MidNtp(_lastReceivedXRNTPsecs,
+                                              _lastReceivedXRNTPfrac);
+
+  uint32_t ntp_sec = 0;
+  uint32_t ntp_frac = 0;
+  _clock->CurrentNtp(ntp_sec, ntp_frac);
+  uint32_t now = RTCPUtility::MidNtp(ntp_sec, ntp_frac);
+
+  info->delaySinceLastRR = now - receive_time;
+  return true;
+}
+
 int32_t
 RTCPReceiver::SenderInfoReceived(RTCPSenderInfo* senderInfo) const
 {
@@ -316,6 +344,15 @@
         case RTCPUtility::kRtcpSdesCode:
             HandleSDES(*rtcpParser);
             break;
+        case RTCPUtility::kRtcpXrHeaderCode:
+            HandleXrHeader(*rtcpParser, rtcpPacketInformation);
+            break;
+        case RTCPUtility::kRtcpXrReceiverReferenceTimeCode:
+            HandleXrReceiveReferenceTime(*rtcpParser, rtcpPacketInformation);
+            break;
+        case RTCPUtility::kRtcpXrDlrrReportBlockCode:
+            HandleXrDlrrReportBlock(*rtcpParser, rtcpPacketInformation);
+            break;
         case RTCPUtility::kRtcpXrVoipMetricCode:
             HandleXRVOIPMetric(*rtcpParser, rtcpPacketInformation);
             break;
@@ -863,6 +900,85 @@
   rtcpParser.Iterate();
 }
 
+void RTCPReceiver::HandleXrHeader(
+    RTCPUtility::RTCPParserV2& parser,
+    RTCPPacketInformation& rtcpPacketInformation) {
+  const RTCPUtility::RTCPPacket& packet = parser.Packet();
+
+  rtcpPacketInformation.xr_originator_ssrc = packet.XR.OriginatorSSRC;
+
+  parser.Iterate();
+}
+
+void RTCPReceiver::HandleXrReceiveReferenceTime(
+    RTCPUtility::RTCPParserV2& parser,
+    RTCPPacketInformation& rtcpPacketInformation) {
+  const RTCPUtility::RTCPPacket& packet = parser.Packet();
+
+  _remoteXRReceiveTimeInfo.sourceSSRC =
+      rtcpPacketInformation.xr_originator_ssrc;
+
+  _remoteXRReceiveTimeInfo.lastRR = RTCPUtility::MidNtp(
+      packet.XRReceiverReferenceTimeItem.NTPMostSignificant,
+      packet.XRReceiverReferenceTimeItem.NTPLeastSignificant);
+
+  _clock->CurrentNtp(_lastReceivedXRNTPsecs, _lastReceivedXRNTPfrac);
+
+  rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpXrReceiverReferenceTime;
+
+  parser.Iterate();
+}
+
+void RTCPReceiver::HandleXrDlrrReportBlock(
+    RTCPUtility::RTCPParserV2& parser,
+    RTCPPacketInformation& rtcpPacketInformation) {
+  const RTCPUtility::RTCPPacket& packet = parser.Packet();
+  // Iterate through sub-block(s), if any.
+  RTCPUtility::RTCPPacketTypes packet_type = parser.Iterate();
+
+  while (packet_type == RTCPUtility::kRtcpXrDlrrReportBlockItemCode) {
+    HandleXrDlrrReportBlockItem(packet, rtcpPacketInformation);
+    packet_type = parser.Iterate();
+  }
+}
+
+void RTCPReceiver::HandleXrDlrrReportBlockItem(
+    const RTCPUtility::RTCPPacket& packet,
+    RTCPPacketInformation& rtcpPacketInformation) {
+  if (registered_ssrcs_.find(packet.XRDLRRReportBlockItem.SSRC) ==
+      registered_ssrcs_.end()) {
+    // Not to us.
+    return;
+  }
+
+  rtcpPacketInformation.xr_dlrr_item = true;
+
+  // To avoid problem with acquiring _criticalSectionRTCPSender while holding
+  // _criticalSectionRTCPReceiver.
+  _criticalSectionRTCPReceiver->Leave();
+
+  int64_t send_time_ms;
+  bool found = _rtpRtcp.SendTimeOfXrRrReport(
+      packet.XRDLRRReportBlockItem.LastRR, &send_time_ms);
+
+  _criticalSectionRTCPReceiver->Enter();
+
+  if (!found) {
+    return;
+  }
+
+  // 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);
+
+  // TODO(asapersson): Not yet used.
+// int32_t rtt =_clock->CurrentNtpInMilliseconds() - delay_rr_ms - send_time_ms;
+// rtt = std::max(rtt, 1);
+
+  rtcpPacketInformation.rtcpPacketTypeFlags |= kRtcpXrDlrrReportBlock;
+}
+
 // no need for critsect we have _criticalSectionRTCPReceiver
 void
 RTCPReceiver::HandleXRVOIPMetric(RTCPUtility::RTCPParserV2& rtcpParser,
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
index 0143231..0b5c8f1 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h
@@ -69,6 +69,8 @@
                 uint32_t *RTCPArrivalTimeFrac,
                 uint32_t *rtcp_timestamp) const;
 
+   bool LastReceivedXrReferenceTimeInfo(RtcpReceiveTimeInfo* info) const;
+
     // get rtt
     int32_t RTT(uint32_t remoteSSRC,
                 uint16_t* RTT,
@@ -133,6 +135,21 @@
 
     void HandleSDESChunk(RTCPUtility::RTCPParserV2& rtcpParser);
 
+    void HandleXrHeader(RTCPUtility::RTCPParserV2& parser,
+                        RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
+
+    void HandleXrReceiveReferenceTime(
+        RTCPUtility::RTCPParserV2& parser,
+        RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
+
+    void HandleXrDlrrReportBlock(
+        RTCPUtility::RTCPParserV2& parser,
+        RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
+
+    void HandleXrDlrrReportBlockItem(
+        const RTCPUtility::RTCPPacket& packet,
+        RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
+
     void HandleXRVOIPMetric(RTCPUtility::RTCPParserV2& rtcpParser,
                             RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
 
@@ -223,6 +240,12 @@
   uint32_t _lastReceivedSRNTPsecs;
   uint32_t _lastReceivedSRNTPfrac;
 
+  // Received XR receive time report.
+  RtcpReceiveTimeInfo _remoteXRReceiveTimeInfo;
+  // Time when the report was received.
+  uint32_t _lastReceivedXRNTPsecs;
+  uint32_t _lastReceivedXRNTPfrac;
+
   // Received report blocks.
   std::map<uint32_t, RTCPHelp::RTCPReportBlockInformation*>
       _receivedReportBlockMap;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc
index 964512c..b86e5cc 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc
@@ -34,6 +34,8 @@
       ntp_secs(0),
       ntp_frac(0),
       rtp_timestamp(0),
+      xr_originator_ssrc(0),
+      xr_dlrr_item(false),
       VoIPMetric(NULL) {
 }
 
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.h b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.h
index 85d3f53..949beb9 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.h
@@ -80,6 +80,8 @@
     uint32_t ntp_frac;
     uint32_t rtp_timestamp;
 
+    uint32_t xr_originator_ssrc;
+    bool xr_dlrr_item;
     RTCPVoIPMetric*  VoIPMetric;
 
 private:
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
index b63f5eb..af969de 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc
@@ -137,6 +137,44 @@
     Add32(0);  // Delay since last SR.
   }
 
+  void AddXrHeader(uint32_t sender_ssrc) {
+    AddRtcpHeader(207, 0);
+    Add32(sender_ssrc);
+  }
+
+  void AddXrReceiverReferenceTimeBlock(uint32_t ntp_sec, uint32_t ntp_frac) {
+    Add8(4);                   // Block type.
+    Add8(0);                   // Reserved.
+    Add16(2);                  // Length.
+    Add64(ntp_sec, ntp_frac);  // NTP timestamp.
+  }
+
+  void AddXrDlrrBlock(std::vector<uint32_t>& remote_ssrc) {
+    ASSERT_LT(pos_ + 4 + static_cast<int>(remote_ssrc.size())*4,
+        kMaxPacketSize-1) << "Max buffer size reached.";
+    Add8(5);                      // Block type.
+    Add8(0);                      // Reserved.
+    Add16(remote_ssrc.size() * 3);  // Length.
+    for (size_t i = 0; i < remote_ssrc.size(); ++i) {
+      Add32(remote_ssrc.at(i));   // Receiver SSRC.
+      Add32(0x10203);             // Last RR.
+      Add32(0x40506);             // Delay since last RR.
+    }
+  }
+
+  void AddXrVoipBlock(uint32_t remote_ssrc, uint8_t loss) {
+    Add8(7);             // Block type.
+    Add8(0);             // Reserved.
+    Add16(8);            // Length.
+    Add32(remote_ssrc);  // Receiver SSRC.
+    Add8(loss);          // Loss rate.
+    Add8(0);             // Remaining statistics (RFC 3611) are set to zero.
+    Add16(0);
+    Add64(0, 0);
+    Add64(0, 0);
+    Add64(0, 0);
+  }
+
   const uint8_t* packet() {
     PatchLengthField();
     return buffer_;
@@ -228,7 +266,7 @@
   // Injects an RTCP packet into the receiver.
   // Returns 0 for OK, non-0 for failure.
   int InjectRtcpPacket(const uint8_t* packet,
-                        uint16_t packet_len) {
+                       uint16_t packet_len) {
     RTCPUtility::RTCPParserV2 rtcpParser(packet,
                                          packet_len,
                                          true);  // Allow non-compound RTCP
@@ -255,6 +293,10 @@
     rtcp_packet_info_.ntp_secs = rtcpPacketInformation.ntp_secs;
     rtcp_packet_info_.ntp_frac = rtcpPacketInformation.ntp_frac;
     rtcp_packet_info_.rtp_timestamp = rtcpPacketInformation.rtp_timestamp;
+    rtcp_packet_info_.xr_dlrr_item = rtcpPacketInformation.xr_dlrr_item;
+    if (rtcpPacketInformation.VoIPMetric) {
+      rtcp_packet_info_.AddVoIPMetric(rtcpPacketInformation.VoIPMetric);
+    }
     return result;
   }
 
@@ -287,6 +329,165 @@
             kRtcpSr & rtcp_packet_info_.rtcpPacketTypeFlags);
 }
 
+TEST_F(RtcpReceiverTest, XrPacketWithZeroReportBlocksIgnored) {
+  PacketBuilder p;
+  p.AddXrHeader(0x2345);
+  EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length()));
+  EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags);
+}
+
+TEST_F(RtcpReceiverTest, InjectXrVoipPacket) {
+  const uint32_t kSourceSsrc = 0x123456;
+  std::set<uint32_t> ssrcs;
+  ssrcs.insert(kSourceSsrc);
+  rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs);
+
+  const uint8_t kLossRate = 123;
+  PacketBuilder p;
+  p.AddXrHeader(0x2345);
+  p.AddXrVoipBlock(kSourceSsrc, kLossRate);
+  EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length()));
+  ASSERT_TRUE(rtcp_packet_info_.VoIPMetric != NULL);
+  EXPECT_EQ(kLossRate, rtcp_packet_info_.VoIPMetric->lossRate);
+  EXPECT_EQ(kRtcpXrVoipMetric, rtcp_packet_info_.rtcpPacketTypeFlags);
+}
+
+TEST_F(RtcpReceiverTest, InjectXrReceiverReferenceTimePacket) {
+  PacketBuilder p;
+  p.AddXrHeader(0x2345);
+  p.AddXrReceiverReferenceTimeBlock(0x10203, 0x40506);
+  EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length()));
+  EXPECT_EQ(kRtcpXrReceiverReferenceTime,
+            rtcp_packet_info_.rtcpPacketTypeFlags);
+}
+
+TEST_F(RtcpReceiverTest, InjectXrDlrrPacketWithNoSubBlock) {
+  const uint32_t kSourceSsrc = 0x123456;
+  std::set<uint32_t> ssrcs;
+  ssrcs.insert(kSourceSsrc);
+  rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs);
+  std::vector<uint32_t> remote_ssrcs;
+
+  PacketBuilder p;
+  p.AddXrHeader(0x2345);
+  p.AddXrDlrrBlock(remote_ssrcs);
+  EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length()));
+  EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags);
+  EXPECT_FALSE(rtcp_packet_info_.xr_dlrr_item);
+}
+
+TEST_F(RtcpReceiverTest, XrDlrrPacketNotToUsIgnored) {
+  const uint32_t kSourceSsrc = 0x123456;
+  std::set<uint32_t> ssrcs;
+  ssrcs.insert(kSourceSsrc);
+  rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs);
+  std::vector<uint32_t> remote_ssrcs;
+  remote_ssrcs.push_back(kSourceSsrc+1);
+
+  PacketBuilder p;
+  p.AddXrHeader(0x2345);
+  p.AddXrDlrrBlock(remote_ssrcs);
+  EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length()));
+  EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags);
+  EXPECT_FALSE(rtcp_packet_info_.xr_dlrr_item);
+}
+
+TEST_F(RtcpReceiverTest, InjectXrDlrrPacketWithSubBlock) {
+  const uint32_t kSourceSsrc = 0x123456;
+  std::set<uint32_t> ssrcs;
+  ssrcs.insert(kSourceSsrc);
+  rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs);
+  std::vector<uint32_t> remote_ssrcs;
+  remote_ssrcs.push_back(kSourceSsrc);
+
+  PacketBuilder p;
+  p.AddXrHeader(0x2345);
+  p.AddXrDlrrBlock(remote_ssrcs);
+  EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length()));
+  // The parser should note the DLRR report block item, but not flag the packet
+  // since the RTT is not estimated.
+  EXPECT_TRUE(rtcp_packet_info_.xr_dlrr_item);
+}
+
+TEST_F(RtcpReceiverTest, InjectXrDlrrPacketWithMultipleSubBlocks) {
+  const uint32_t kSourceSsrc = 0x123456;
+  std::set<uint32_t> ssrcs;
+  ssrcs.insert(kSourceSsrc);
+  rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs);
+  std::vector<uint32_t> remote_ssrcs;
+  remote_ssrcs.push_back(kSourceSsrc+2);
+  remote_ssrcs.push_back(kSourceSsrc+1);
+  remote_ssrcs.push_back(kSourceSsrc);
+
+  PacketBuilder p;
+  p.AddXrHeader(0x2345);
+  p.AddXrDlrrBlock(remote_ssrcs);
+  EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length()));
+  // The parser should note the DLRR report block item, but not flag the packet
+  // since the RTT is not estimated.
+  EXPECT_TRUE(rtcp_packet_info_.xr_dlrr_item);
+}
+
+TEST_F(RtcpReceiverTest, InjectXrPacketWithMultipleReportBlocks) {
+  const uint8_t kLossRate = 123;
+  const uint32_t kSourceSsrc = 0x123456;
+  std::set<uint32_t> ssrcs;
+  ssrcs.insert(kSourceSsrc);
+  rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs);
+  std::vector<uint32_t> remote_ssrcs;
+  remote_ssrcs.push_back(kSourceSsrc);
+
+  PacketBuilder p;
+  p.AddXrHeader(0x2345);
+  p.AddXrDlrrBlock(remote_ssrcs);
+  p.AddXrVoipBlock(kSourceSsrc, kLossRate);
+  p.AddXrReceiverReferenceTimeBlock(0x10203, 0x40506);
+
+  EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length()));
+  EXPECT_EQ(static_cast<unsigned int>(kRtcpXrReceiverReferenceTime +
+                                      kRtcpXrVoipMetric),
+            rtcp_packet_info_.rtcpPacketTypeFlags);
+  // The parser should note the DLRR report block item, but not flag the packet
+  // since the RTT is not estimated.
+  EXPECT_TRUE(rtcp_packet_info_.xr_dlrr_item);
+}
+
+TEST(RtcpUtilityTest, MidNtp) {
+  const uint32_t kNtpSec = 0x12345678;
+  const uint32_t kNtpFrac = 0x23456789;
+  const uint32_t kNtpMid = 0x56782345;
+  EXPECT_EQ(kNtpMid, RTCPUtility::MidNtp(kNtpSec, kNtpFrac));
+}
+
+TEST_F(RtcpReceiverTest, LastReceivedXrReferenceTimeInfoInitiallyFalse) {
+  RtcpReceiveTimeInfo info;
+  EXPECT_FALSE(rtcp_receiver_->LastReceivedXrReferenceTimeInfo(&info));
+}
+
+TEST_F(RtcpReceiverTest, GetLastReceivedXrReferenceTimeInfo) {
+  const uint32_t kSenderSsrc = 0x123456;
+  const uint32_t kNtpSec = 0x10203;
+  const uint32_t kNtpFrac = 0x40506;
+  const uint32_t kNtpMid = RTCPUtility::MidNtp(kNtpSec, kNtpFrac);
+
+  PacketBuilder p;
+  p.AddXrHeader(kSenderSsrc);
+  p.AddXrReceiverReferenceTimeBlock(kNtpSec, kNtpFrac);
+  EXPECT_EQ(0, InjectRtcpPacket(p.packet(), p.length()));
+  EXPECT_EQ(kRtcpXrReceiverReferenceTime,
+      rtcp_packet_info_.rtcpPacketTypeFlags);
+
+  RtcpReceiveTimeInfo info;
+  EXPECT_TRUE(rtcp_receiver_->LastReceivedXrReferenceTimeInfo(&info));
+  EXPECT_EQ(kSenderSsrc, info.sourceSSRC);
+  EXPECT_EQ(kNtpMid, info.lastRR);
+  EXPECT_EQ(0U, info.delaySinceLastRR);
+
+  system_clock_.AdvanceTimeMilliseconds(1000);
+  EXPECT_TRUE(rtcp_receiver_->LastReceivedXrReferenceTimeInfo(&info));
+  EXPECT_EQ(65536U, info.delaySinceLastRR);
+}
+
 TEST_F(RtcpReceiverTest, ReceiveReportTimeout) {
   const uint32_t kSenderSsrc = 0x10203;
   const uint32_t kSourceSsrc = 0x40506;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
index 6d81d95..82bfdbb 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc
@@ -77,6 +77,8 @@
   last_rr_ntp_frac = last_ntp_frac;
   remote_sr = last_remote_sr;
 
+  has_last_xr_rr = module->LastReceivedXrReferenceTimeInfo(&last_xr_rr);
+
   uint32_t send_bitrate = 0, tmp;
   module->BitrateSent(&send_bitrate, &tmp, &tmp, &tmp);
   this->send_bitrate = send_bitrate;
@@ -90,7 +92,8 @@
       send_bitrate(0),
       last_rr_ntp_secs(0),
       last_rr_ntp_frac(0),
-      remote_sr(0) {}
+      remote_sr(0),
+      has_last_xr_rr(false) {}
 
 RTCPSender::RTCPSender(const int32_t id,
                        const bool audio,
@@ -128,6 +131,8 @@
     _lastSendReport(),
     _lastRTCPTime(),
 
+    last_xr_rr_(),
+
     _CSRCs(0),
     _CSRC(),
     _includeCSRCs(true),
@@ -148,6 +153,8 @@
     _appName(),
     _appData(NULL),
     _appLength(0),
+
+    xrSendReceiverReferenceTimeEnabled_(false),
     _xrSendVoIPMetric(false),
     _xrVoIPMetric(),
     _nackCount(0),
@@ -222,12 +229,15 @@
     }
     _appLength = 0;
 
+    xrSendReceiverReferenceTimeEnabled_ = false;
+
     _xrSendVoIPMetric = false;
 
     memset(&_xrVoIPMetric, 0, sizeof(_xrVoIPMetric));
     memset(_CNAME, 0, sizeof(_CNAME));
     memset(_lastSendReport, 0, sizeof(_lastSendReport));
     memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
+    last_xr_rr_.clear();
 
     _nackCount = 0;
     _pliCount = 0;
@@ -591,6 +601,21 @@
     return 0;
 }
 
+bool RTCPSender::SendTimeOfXrRrReport(uint32_t mid_ntp,
+                                      int64_t* time_ms) const {
+  CriticalSectionScoped lock(_criticalSectionRTCPSender);
+
+  if (last_xr_rr_.empty()) {
+    return false;
+  }
+  std::map<uint32_t, int64_t>::const_iterator it = last_xr_rr_.find(mid_ntp);
+  if (it == last_xr_rr_.end()) {
+    return false;
+  }
+  *time_ms = it->second;
+  return true;
+}
+
 int32_t RTCPSender::AddExternalReportBlock(
     uint32_t SSRC,
     const RTCPReportBlock* reportBlock) {
@@ -1502,6 +1527,107 @@
     return 0;
 }
 
+int32_t RTCPSender::BuildReceiverReferenceTime(uint8_t* buffer,
+                                               int& pos,
+                                               uint32_t ntp_sec,
+                                               uint32_t ntp_frac) {
+  const int kRrTimeBlockLength = 20;
+  if (pos + kRrTimeBlockLength >= IP_PACKET_SIZE) {
+    return -2;
+  }
+
+  if (last_xr_rr_.size() >= RTCP_NUMBER_OF_SR) {
+    last_xr_rr_.erase(last_xr_rr_.begin());
+  }
+  last_xr_rr_.insert(std::pair<uint32_t, int64_t>(
+      RTCPUtility::MidNtp(ntp_sec, ntp_frac),
+      Clock::NtpToMs(ntp_sec, ntp_frac)));
+
+  // Add XR header.
+  buffer[pos++] = 0x80;
+  buffer[pos++] = 207;
+  buffer[pos++] = 0;  // XR packet length.
+  buffer[pos++] = 4;  // XR packet length.
+
+  // Add our own SSRC.
+  ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, _SSRC);
+  pos += 4;
+
+  //    0                   1                   2                   3
+  //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  //   |     BT=4      |   reserved    |       block length = 2        |
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  //   |              NTP timestamp, most significant word             |
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  //   |             NTP timestamp, least significant word             |
+  //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  // Add Receiver Reference Time Report block.
+  buffer[pos++] = 4;  // BT.
+  buffer[pos++] = 0;  // Reserved.
+  buffer[pos++] = 0;  // Block length.
+  buffer[pos++] = 2;  // Block length.
+
+  // NTP timestamp.
+  ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, ntp_sec);
+  pos += 4;
+  ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, ntp_frac);
+  pos += 4;
+
+  return 0;
+}
+
+int32_t RTCPSender::BuildDlrr(uint8_t* buffer,
+                              int& pos,
+                              const RtcpReceiveTimeInfo& info) {
+  const int kDlrrBlockLength = 24;
+  if (pos + kDlrrBlockLength >= IP_PACKET_SIZE) {
+    return -2;
+  }
+
+  // Add XR header.
+  buffer[pos++] = 0x80;
+  buffer[pos++] = 207;
+  buffer[pos++] = 0;  // XR packet length.
+  buffer[pos++] = 5;  // XR packet length.
+
+  // Add our own SSRC.
+  ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, _SSRC);
+  pos += 4;
+
+  //   0                   1                   2                   3
+  //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  //  |     BT=5      |   reserved    |         block length          |
+  //  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+  //  |                 SSRC_1 (SSRC of first receiver)               | sub-
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
+  //  |                         last RR (LRR)                         |   1
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+  //  |                   delay since last RR (DLRR)                  |
+  //  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+  //  |                 SSRC_2 (SSRC of second receiver)              | sub-
+  //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
+  //  :                               ...                             :   2
+
+  // Add DLRR sub block.
+  buffer[pos++] = 5;  // BT.
+  buffer[pos++] = 0;  // Reserved.
+  buffer[pos++] = 0;  // Block length.
+  buffer[pos++] = 3;  // Block length.
+
+  // NTP timestamp.
+  ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, info.sourceSSRC);
+  pos += 4;
+  ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, info.lastRR);
+  pos += 4;
+  ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, info.delaySinceLastRR);
+  pos += 4;
+
+  return 0;
+}
+
 int32_t
 RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, int& pos)
 {
@@ -1652,7 +1778,18 @@
       rtcpPacketTypeFlags |= kRtcpTmmbn;
       _sendTMMBN = false;
   }
-
+  if (xrSendReceiverReferenceTimeEnabled_ &&
+      (rtcpPacketTypeFlags & kRtcpReport))
+  {
+      if (!_sending)
+      {
+          rtcpPacketTypeFlags |= kRtcpXrReceiverReferenceTime;
+      }
+      if (feedback_state.has_last_xr_rr)
+      {
+          rtcpPacketTypeFlags |= kRtcpXrDlrrReportBlock;
+      }
+  }
   if(_method == kRtcpCompound)
   {
       if(_sending)
@@ -1893,6 +2030,27 @@
         return position;
       }
   }
+  if (rtcpPacketTypeFlags & kRtcpXrReceiverReferenceTime)
+  {
+      buildVal = BuildReceiverReferenceTime(rtcp_buffer,
+                                            position,
+                                            NTPsec,
+                                            NTPfrac);
+      if (buildVal == -1) {
+        return -1;
+      } else if (buildVal == -2) {
+        return position;
+      }
+  }
+  if (rtcpPacketTypeFlags & kRtcpXrDlrrReportBlock)
+  {
+      buildVal = BuildDlrr(rtcp_buffer, position, feedback_state.last_xr_rr);
+      if (buildVal == -1) {
+        return -1;
+      } else if (buildVal == -2) {
+        return position;
+      }
+  }
   return position;
 }
 
@@ -2020,6 +2178,11 @@
     return 0;
 }
 
+void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) {
+  CriticalSectionScoped lock(_criticalSectionRTCPSender);
+  xrSendReceiverReferenceTimeEnabled_ = enable;
+}
+
 // called under critsect _criticalSectionRTCPSender
 int32_t RTCPSender::WriteAllReportBlocksToBuffer(
     uint8_t* rtcpbuffer,
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
index 909c15d..106a78d 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h
@@ -63,6 +63,9 @@
    uint32_t last_rr_ntp_frac;
    uint32_t remote_sr;
 
+   bool has_last_xr_rr;
+   RtcpReceiveTimeInfo last_xr_rr;
+
    // Used when generating TMMBR.
    ModuleRtpRtcpImpl* module;
  };
@@ -107,6 +110,8 @@
 
     uint32_t SendTimeOfSendReport(const uint32_t sendReport);
 
+    bool SendTimeOfXrRrReport(uint32_t mid_ntp, int64_t* time_ms) const;
+
     bool TimeToSendRTCPReport(const bool sendKeyframeBeforeRTP = false) const;
 
     uint32_t LastSendReport(uint32_t& lastRTCPTime);
@@ -164,6 +169,8 @@
 
     int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric);
 
+    void SendRtcpXrReceiverReferenceTime(bool enable);
+
     int32_t SetCSRCs(const uint32_t arrOfCSRC[kRtpCsrcSize],
                      const uint8_t arrLength);
 
@@ -250,6 +257,14 @@
                       const uint16_t* nackList,
                           std::string* nackString);
 
+    int32_t BuildReceiverReferenceTime(uint8_t* buffer,
+                                       int& pos,
+                                       uint32_t ntp_sec,
+                                       uint32_t ntp_frac);
+    int32_t BuildDlrr(uint8_t* buffer,
+                      int& pos,
+                      const RtcpReceiveTimeInfo& info);
+
 private:
     int32_t            _id;
     const bool               _audio;
@@ -289,6 +304,10 @@
     uint32_t        _lastSendReport[RTCP_NUMBER_OF_SR];  // allow packet loss and RTT above 1 sec
     uint32_t        _lastRTCPTime[RTCP_NUMBER_OF_SR];
 
+    // Sent XR receiver reference time report.
+    // <mid ntp (mid 32 bits of the 64 bits NTP timestamp), send time in ms>.
+    std::map<uint32_t, int64_t> last_xr_rr_;
+
     // send CSRCs
     uint8_t         _CSRCs;
     uint32_t        _CSRC[kRtpCsrcSize];
@@ -314,6 +333,9 @@
     uint8_t*       _appData;
     uint16_t       _appLength;
 
+    // True if sending of XR Receiver reference time report is enabled.
+    bool xrSendReceiverReferenceTimeEnabled_;
+
     // XR VoIP metric
     bool                _xrSendVoIPMetric;
     RTCPVoIPMetric      _xrVoIPMetric;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
index d8d4390..45ef1ec 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender_unittest.cc
@@ -274,30 +274,30 @@
  protected:
   RtcpSenderTest()
       : over_use_detector_options_(),
-        system_clock_(Clock::GetRealTimeClock()),
+        clock_(1335900000),
         rtp_payload_registry_(new RTPPayloadRegistry(
             0, RTPPayloadStrategy::CreateStrategy(false))),
         remote_bitrate_observer_(),
         remote_bitrate_estimator_(
             RemoteBitrateEstimatorFactory().Create(
                 &remote_bitrate_observer_,
-                system_clock_)),
-        receive_statistics_(ReceiveStatistics::Create(system_clock_)) {
+                &clock_)),
+        receive_statistics_(ReceiveStatistics::Create(&clock_)) {
     test_transport_ = new TestTransport();
 
     RtpRtcp::Configuration configuration;
     configuration.id = 0;
     configuration.audio = false;
-    configuration.clock = system_clock_;
+    configuration.clock = &clock_;
     configuration.outgoing_transport = test_transport_;
     configuration.remote_bitrate_estimator = remote_bitrate_estimator_.get();
 
     rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration);
     rtp_receiver_.reset(RtpReceiver::CreateVideoReceiver(
-        0, system_clock_, test_transport_, NULL, rtp_payload_registry_.get()));
+        0, &clock_, test_transport_, NULL, rtp_payload_registry_.get()));
     rtcp_sender_ =
-        new RTCPSender(0, false, system_clock_, receive_statistics_.get());
-    rtcp_receiver_ = new RTCPReceiver(0, system_clock_, rtp_rtcp_impl_);
+        new RTCPSender(0, false, &clock_, receive_statistics_.get());
+    rtcp_receiver_ = new RTCPReceiver(0, &clock_, rtp_rtcp_impl_);
     test_transport_->SetRTCPReceiver(rtcp_receiver_);
     // Initialize
     EXPECT_EQ(0, rtcp_sender_->Init());
@@ -317,7 +317,7 @@
   }
 
   OverUseDetectorOptions over_use_detector_options_;
-  Clock* system_clock_;
+  SimulatedClock clock_;
   scoped_ptr<RTPPayloadRegistry> rtp_payload_registry_;
   scoped_ptr<RtpReceiver> rtp_receiver_;
   ModuleRtpRtcpImpl* rtp_rtcp_impl_;
@@ -397,6 +397,70 @@
       kRtcpTransmissionTimeOffset);
 }
 
+TEST_F(RtcpSenderTest, TestXrReceiverReferenceTime) {
+  EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound));
+  RTCPSender::FeedbackState feedback_state(rtp_rtcp_impl_);
+  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state, false));
+  rtcp_sender_->SendRtcpXrReceiverReferenceTime(true);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport));
+
+  EXPECT_TRUE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags &
+      kRtcpXrReceiverReferenceTime);
+}
+
+TEST_F(RtcpSenderTest, TestNoXrReceiverReferenceTimeIfSending) {
+  EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound));
+  RTCPSender::FeedbackState feedback_state(rtp_rtcp_impl_);
+  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state, true));
+  rtcp_sender_->SendRtcpXrReceiverReferenceTime(true);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport));
+
+  EXPECT_FALSE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags &
+      kRtcpXrReceiverReferenceTime);
+}
+
+TEST_F(RtcpSenderTest, TestNoXrReceiverReferenceTimeIfNotEnabled) {
+  EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound));
+  RTCPSender::FeedbackState feedback_state(rtp_rtcp_impl_);
+  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state, false));
+  rtcp_sender_->SendRtcpXrReceiverReferenceTime(false);
+  EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport));
+
+  EXPECT_FALSE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags &
+      kRtcpXrReceiverReferenceTime);
+}
+
+TEST_F(RtcpSenderTest, TestSendTimeOfXrRrReport) {
+  EXPECT_EQ(0, rtcp_sender_->SetRTCPStatus(kRtcpCompound));
+  RTCPSender::FeedbackState feedback_state(rtp_rtcp_impl_);
+  EXPECT_EQ(0, rtcp_sender_->SetSendingStatus(feedback_state, false));
+  rtcp_sender_->SendRtcpXrReceiverReferenceTime(true);
+  uint32_t ntp_sec;
+  uint32_t ntp_frac;
+  clock_.CurrentNtp(ntp_sec, ntp_frac);
+  uint32_t initial_mid_ntp = RTCPUtility::MidNtp(ntp_sec, ntp_frac);
+
+  // No packet sent.
+  int64_t time_ms;
+  EXPECT_FALSE(rtcp_sender_->SendTimeOfXrRrReport(initial_mid_ntp, &time_ms));
+
+  // Send XR RR packets.
+  for (int i = 0; i <= RTCP_NUMBER_OF_SR; ++i) {
+    EXPECT_EQ(0, rtcp_sender_->SendRTCP(feedback_state, kRtcpReport));
+    EXPECT_TRUE(test_transport_->rtcp_packet_info_.rtcpPacketTypeFlags &
+        kRtcpXrReceiverReferenceTime);
+
+    clock_.CurrentNtp(ntp_sec, ntp_frac);
+    uint32_t mid_ntp = RTCPUtility::MidNtp(ntp_sec, ntp_frac);
+    EXPECT_TRUE(rtcp_sender_->SendTimeOfXrRrReport(mid_ntp, &time_ms));
+    EXPECT_EQ(clock_.CurrentNtpInMilliseconds(), time_ms);
+    clock_.AdvanceTimeMilliseconds(1000);
+  }
+
+  // The first report should no longer be stored.
+  EXPECT_FALSE(rtcp_sender_->SendTimeOfXrRrReport(initial_mid_ntp, &time_ms));
+}
+
 // This test is written to verify actual behaviour. It does not seem
 // to make much sense to send an empty TMMBN, since there is no place
 // to put an actual limit here. It's just information that no limit
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc b/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
index 8a9e1c5..8ab783f 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
@@ -15,8 +15,14 @@
 #include <string.h> // memcpy
 
 namespace webrtc {
-// RTCPParserV2 : currently read only
 
+namespace RTCPUtility {
+uint32_t MidNtp(uint32_t ntp_sec, uint32_t ntp_frac) {
+  return (ntp_sec << 16) + (ntp_frac >> 16);
+}  // end RTCPUtility
+}
+
+// RTCPParserV2 : currently read only
 RTCPUtility::RTCPParserV2::RTCPParserV2(const uint8_t* rtcpData,
                                         size_t rtcpDataLength,
                                         bool rtcpReducedSizeEnable)
@@ -110,6 +116,12 @@
         case State_PSFB_REMBItem:
             IteratePsfbREMBItem();
             break;
+        case State_XRItem:
+            IterateXrItem();
+            break;
+        case State_XR_DLLRItem:
+            IterateXrDlrrItem();
+            break;
         case State_AppItem:
             IterateAppItem();
             break;
@@ -198,7 +210,6 @@
                 // Nothing supported found, continue to next block!
                 break;
             }
-
             return;
         }
         case PT_APP:
@@ -230,6 +241,26 @@
 }
 
 void
+RTCPUtility::RTCPParserV2::IterateXrItem()
+{
+    const bool success = ParseXRItem();
+    if (!success)
+    {
+        Iterate();
+    }
+}
+
+void
+RTCPUtility::RTCPParserV2::IterateXrDlrrItem()
+{
+    const bool success = ParseXRDLRRReportBlockItem();
+    if (!success)
+    {
+        Iterate();
+    }
+}
+
+void
 RTCPUtility::RTCPParserV2::IterateReportBlockItem()
 {
     const bool success = ParseReportBlockItem();
@@ -833,7 +864,6 @@
 bool RTCPUtility::RTCPParserV2::ParseXR()
 {
     const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
-
     if (length < 8)
     {
         EndCurrentBlock();
@@ -847,8 +877,11 @@
     _packet.XR.OriginatorSSRC += *_ptrRTCPData++ << 8;
     _packet.XR.OriginatorSSRC += *_ptrRTCPData++;
 
-    return ParseXRItem();
+    _packetType = kRtcpXrHeaderCode;
+    _state = State_XRItem;
+    return true;
 }
+
 /*
     0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
@@ -858,37 +891,133 @@
     :             type-specific block contents                      :
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
-
 bool
 RTCPUtility::RTCPParserV2::ParseXRItem()
 {
-    const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
+  const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
 
-    if (length < 4) //
-    {
-        EndCurrentBlock();
-        return false;
-    }
+  if (length < 4) {
+    _state = State_TopLevel;
+    EndCurrentBlock();
+    return false;
+  }
 
-    uint8_t blockType = *_ptrRTCPData++;
-    uint8_t typeSpecific = *_ptrRTCPData++;
+  uint8_t blockType = *_ptrRTCPData++;
+  _ptrRTCPData++;  // Ignore reserved.
 
-    uint16_t blockLength = *_ptrRTCPData++ << 8;
-    blockLength = *_ptrRTCPData++;
+  uint16_t blockLength = *_ptrRTCPData++ << 8;
+  blockLength = *_ptrRTCPData++;
 
-    if(blockType == 7 && typeSpecific == 0)
-    {
-        if(blockLength != 8)
-        {
-            EndCurrentBlock();
-            return false;
-        }
-        return ParseXRVOIPMetricItem();
-    }else
-    {
-        EndCurrentBlock();
-        return false;
-    }
+  if (blockType == 4 && blockLength == 2)
+  {
+    return ParseXRReceiverReferenceTimeItem();
+  }
+  else if (blockType == 5 && (blockLength % 3) == 0)
+  {
+    _packetType = kRtcpXrDlrrReportBlockCode;
+    _state = State_XR_DLLRItem;
+    _numberOfBlocks = blockLength / 3;
+    return true;
+  }
+  else if (blockType == 7 && blockLength == 8)
+  {
+    return ParseXRVOIPMetricItem();
+  }
+
+  // Not supported.
+  _state = State_TopLevel;
+  EndCurrentBlock();
+  return false;
+}
+
+/*  0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |     BT=4      |   reserved    |       block length = 2        |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |              NTP timestamp, most significant word             |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |             NTP timestamp, least significant word             |
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+bool RTCPUtility::RTCPParserV2::ParseXRReceiverReferenceTimeItem() {
+  const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
+  if (length < 8) {
+    _state = State_TopLevel;
+    EndCurrentBlock();
+    return false;
+  }
+
+  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant =
+      *_ptrRTCPData++ << 24;
+  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant +=
+      *_ptrRTCPData++ << 16;
+  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant +=
+      *_ptrRTCPData++ << 8;
+  _packet.XRReceiverReferenceTimeItem.NTPMostSignificant += *_ptrRTCPData++;
+
+  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant =
+      *_ptrRTCPData++ << 24;
+  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant +=
+      *_ptrRTCPData++ << 16;
+  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant +=
+      *_ptrRTCPData++ << 8;
+  _packet.XRReceiverReferenceTimeItem.NTPLeastSignificant += *_ptrRTCPData++;
+
+  _packetType = kRtcpXrReceiverReferenceTimeCode;
+  _state = State_XRItem;
+  return true;
+}
+
+/*  0                   1                   2                   3
+    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |     BT=5      |   reserved    |         block length          |
+   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+   |                 SSRC_1 (SSRC of first receiver)               | sub-
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
+   |                         last RR (LRR)                         |   1
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+   |                   delay since last RR (DLRR)                  |
+   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+   |                 SSRC_2 (SSRC of second receiver)              | sub-
+   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
+   :                               ...                             :   2
+   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+*/
+
+bool RTCPUtility::RTCPParserV2::ParseXRDLRRReportBlockItem() {
+  const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
+  if (_numberOfBlocks == 0) {
+    _state = State_XRItem;
+    return false;
+  }
+  if (length < 12) {
+    _state = State_TopLevel;
+    EndCurrentBlock();
+    return false;
+  }
+
+  _packet.XRDLRRReportBlockItem.SSRC = *_ptrRTCPData++ << 24;
+  _packet.XRDLRRReportBlockItem.SSRC += *_ptrRTCPData++ << 16;
+  _packet.XRDLRRReportBlockItem.SSRC += *_ptrRTCPData++ << 8;
+  _packet.XRDLRRReportBlockItem.SSRC += *_ptrRTCPData++;
+
+  _packet.XRDLRRReportBlockItem.LastRR = *_ptrRTCPData++ << 24;
+  _packet.XRDLRRReportBlockItem.LastRR += *_ptrRTCPData++ << 16;
+  _packet.XRDLRRReportBlockItem.LastRR += *_ptrRTCPData++ << 8;
+  _packet.XRDLRRReportBlockItem.LastRR += *_ptrRTCPData++;
+
+  _packet.XRDLRRReportBlockItem.DelayLastRR = *_ptrRTCPData++ << 24;
+  _packet.XRDLRRReportBlockItem.DelayLastRR += *_ptrRTCPData++ << 16;
+  _packet.XRDLRRReportBlockItem.DelayLastRR += *_ptrRTCPData++ << 8;
+  _packet.XRDLRRReportBlockItem.DelayLastRR += *_ptrRTCPData++;
+
+  _packetType = kRtcpXrDlrrReportBlockItemCode;
+  --_numberOfBlocks;
+  _state = State_XR_DLLRItem;
+  return true;
 }
 /*
  0                   1                   2                   3
@@ -913,6 +1042,7 @@
    |          JB maximum           |          JB abs max           |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 */
+
 bool
 RTCPUtility::RTCPParserV2::ParseXRVOIPMetricItem()
 {
@@ -920,6 +1050,7 @@
 
     if (length < 28)
     {
+        _state = State_TopLevel;
         EndCurrentBlock();
         return false;
     }
@@ -967,6 +1098,7 @@
     _packet.XRVOIPMetricItem.JBabsMax = *_ptrRTCPData++ << 8;
     _packet.XRVOIPMetricItem.JBabsMax += *_ptrRTCPData++;
 
+    _state = State_XRItem;
     return true;
 }
 
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility.h b/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
index fa771ab..c954f44 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
@@ -19,6 +19,8 @@
 
 namespace webrtc {
 namespace RTCPUtility {
+    uint32_t MidNtp(uint32_t ntp_sec, uint32_t ntp_frac);
+
     // CNAME
     struct RTCPCnameInformation
     {
@@ -74,6 +76,19 @@
         // RFC 3611
         uint32_t OriginatorSSRC;
     };
+    struct RTCPPacketXRReceiverReferenceTimeItem
+    {
+        // RFC 3611 4.4
+        uint32_t NTPMostSignificant;
+        uint32_t NTPLeastSignificant;
+    };
+    struct RTCPPacketXRDLRRReportBlockItem
+    {
+        // RFC 3611 4.5
+        uint32_t SSRC;
+        uint32_t LastRR;
+        uint32_t DelayLastRR;
+    };
     struct RTCPPacketXRVOIPMetricItem
     {
         // RFC 3611 4.7
@@ -228,6 +243,8 @@
         RTCPPacketPSFBFIRItem     FIRItem;
 
         RTCPPacketXR               XR;
+        RTCPPacketXRReceiverReferenceTimeItem XRReceiverReferenceTimeItem;
+        RTCPPacketXRDLRRReportBlockItem XRDLRRReportBlockItem;
         RTCPPacketXRVOIPMetricItem XRVOIPMetricItem;
 
         RTCPPacketAPP             APP;
@@ -274,6 +291,10 @@
         kRtcpRtpfbSrReqCode,
 
         // RFC 3611
+        kRtcpXrHeaderCode,
+        kRtcpXrReceiverReferenceTimeCode,
+        kRtcpXrDlrrReportBlockCode,
+        kRtcpXrDlrrReportBlockItemCode,
         kRtcpXrVoipMetricCode,
 
         kRtcpAppCode,
@@ -353,6 +374,7 @@
             State_PSFB_AppItem,    // Application specific FCI item
             State_PSFB_REMBItem,   // Application specific REMB item
             State_XRItem,
+            State_XR_DLLRItem,
             State_AppItem
         };
 
@@ -371,6 +393,8 @@
         void IteratePsfbAppItem();
         void IteratePsfbREMBItem();
         void IterateAppItem();
+        void IterateXrItem();
+        void IterateXrDlrrItem();
 
         void Validate();
         void EndCurrentBlock();
@@ -391,6 +415,8 @@
 
         bool ParseXR();
         bool ParseXRItem();
+        bool ParseXRReceiverReferenceTimeItem();
+        bool ParseXRDLRRReportBlockItem();
         bool ParseXRVOIPMetricItem();
 
         bool ParseFBCommon(const RTCPCommonHeader& header);
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index 068b5cf..812f427 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -1536,6 +1536,11 @@
   return rtcp_sender_.SendTimeOfSendReport(send_report);
 }
 
+bool ModuleRtpRtcpImpl::SendTimeOfXrRrReport(
+    uint32_t mid_ntp, int64_t* time_ms) const {
+  return rtcp_sender_.SendTimeOfXrRrReport(mid_ntp, time_ms);
+}
+
 void ModuleRtpRtcpImpl::OnReceivedNACK(
     const std::list<uint16_t>& nack_sequence_numbers) {
   if (!rtp_sender_.StorePackets() ||
@@ -1566,6 +1571,11 @@
   return 0;
 }
 
+bool ModuleRtpRtcpImpl::LastReceivedXrReferenceTimeInfo(
+    RtcpReceiveTimeInfo* info) const {
+  return rtcp_receiver_.LastReceivedXrReferenceTimeInfo(info);
+}
+
 bool ModuleRtpRtcpImpl::UpdateRTCPReceiveInformationTimers() {
   // If this returns true this channel has timed out.
   // Periodically check if this is true and if so call UpdateTMMBR.
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index ada2442..b97ef1a 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -324,6 +324,8 @@
                                   uint32_t& NTPfrac,
                                   uint32_t& remote_sr);
 
+  virtual bool LastReceivedXrReferenceTimeInfo(RtcpReceiveTimeInfo* info) const;
+
   virtual int32_t BoundingSet(bool& tmmbr_owner, TMMBRSet*& bounding_set_rec);
 
   virtual void BitrateSent(uint32_t* total_rate,
@@ -333,6 +335,8 @@
 
   virtual uint32_t SendTimeOfSendReport(const uint32_t send_report);
 
+  virtual bool SendTimeOfXrRrReport(uint32_t mid_ntp, int64_t* time_ms) const;
+
   // Good state of RTP receiver inform sender.
   virtual int32_t SendRTCPReferencePictureSelection(
       const uint64_t picture_id) OVERRIDE;