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;