diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h index de5fcb2f5..85aa36f0e 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 @@ enum RTCPPacketType kRtcpSli = 0x4000, kRtcpRpsi = 0x8000, kRtcpRemb = 0x10000, - kRtcpTransmissionTimeOffset = 0x20000 + kRtcpTransmissionTimeOffset = 0x20000, + kRtcpXrReceiverReferenceTime = 0x40000, + kRtcpXrDlrrReportBlock = 0x80000 }; enum KeyFrameRequestMethod @@ -177,6 +179,13 @@ struct RTCPReportBlock { 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 ReportBlockList; class RtpData diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.cc index 0771eba81..25fa82c65 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 #include //memset +#include + #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 @@ RTCPReceiver::RTCPReceiver(const int32_t id, Clock* clock, _remoteSenderInfo(), _lastReceivedSRNTPsecs(0), _lastReceivedSRNTPfrac(0), + _lastReceivedXRNTPsecs(0), + _lastReceivedXRNTPfrac(0), _receivedInfoMap(), _packetTimeOutMS(0), _lastReceivedRrMs(0), @@ -259,6 +263,30 @@ RTCPReceiver::NTP(uint32_t *ReceivedNTPsecs, 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 @@ RTCPReceiver::IncomingRTCPPacket(RTCPPacketInformation& rtcpPacketInformation, 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 @@ void RTCPReceiver::HandleBYE(RTCPUtility::RTCPParserV2& rtcpParser) { 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 014323188..0b5c8f1ab 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h +++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver.h @@ -69,6 +69,8 @@ public: 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 @@ protected: 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 @@ protected: 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 _receivedReportBlockMap; diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_help.cc index 964512c4b..b86e5cc2d 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 @@ RTCPPacketInformation::RTCPPacketInformation() 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 85d3f5362..949beb9c7 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 @@ public: 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 b63f5ebb5..af969ded2 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 @@ class PacketBuilder { 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& remote_ssrc) { + ASSERT_LT(pos_ + 4 + static_cast(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 @@ class RtcpReceiverTest : public ::testing::Test { // 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 @@ class RtcpReceiverTest : public ::testing::Test { 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 @@ TEST_F(RtcpReceiverTest, InjectSrPacket) { 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 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 ssrcs; + ssrcs.insert(kSourceSsrc); + rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); + std::vector 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 ssrcs; + ssrcs.insert(kSourceSsrc); + rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); + std::vector 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 ssrcs; + ssrcs.insert(kSourceSsrc); + rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); + std::vector 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 ssrcs; + ssrcs.insert(kSourceSsrc); + rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); + std::vector 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 ssrcs; + ssrcs.insert(kSourceSsrc); + rtcp_receiver_->SetSsrcs(kSourceSsrc, ssrcs); + std::vector 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(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 6d81d9596..82bfdbbe8 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc @@ -77,6 +77,8 @@ RTCPSender::FeedbackState::FeedbackState(ModuleRtpRtcpImpl* module) 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 @@ RTCPSender::FeedbackState::FeedbackState() 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 @@ RTCPSender::RTCPSender(const int32_t id, _lastSendReport(), _lastRTCPTime(), + last_xr_rr_(), + _CSRCs(0), _CSRC(), _includeCSRCs(true), @@ -148,6 +153,8 @@ RTCPSender::RTCPSender(const int32_t id, _appName(), _appData(NULL), _appLength(0), + + xrSendReceiverReferenceTimeEnabled_(false), _xrSendVoIPMetric(false), _xrVoIPMetric(), _nackCount(0), @@ -222,12 +229,15 @@ RTCPSender::Init() } _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 @@ RTCPSender::SendTimeOfSendReport(const uint32_t sendReport) 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::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 @@ RTCPSender::BuildBYE(uint8_t* rtcpbuffer, int& pos) 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( + 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 @@ int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state, 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 @@ int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state, 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 @@ RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric) 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 909c15d23..106a78dda 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.h @@ -63,6 +63,9 @@ public: 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 @@ public: 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 @@ public: 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 @@ private: 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 @@ private: 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. + // . + std::map last_xr_rr_; + // send CSRCs uint8_t _CSRCs; uint32_t _CSRC[kRtpCsrcSize]; @@ -314,6 +333,9 @@ private: 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 d8d439037..45ef1ec64 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 @@ class RtcpSenderTest : public ::testing::Test { 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 @@ class RtcpSenderTest : public ::testing::Test { } OverUseDetectorOptions over_use_detector_options_; - Clock* system_clock_; + SimulatedClock clock_; scoped_ptr rtp_payload_registry_; scoped_ptr rtp_receiver_; ModuleRtpRtcpImpl* rtp_rtcp_impl_; @@ -397,6 +397,70 @@ TEST_F(RtcpSenderTest, TestCompound_NoRtpReceived) { 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 8a9e1c5e3..8ab783f13 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc @@ -15,8 +15,14 @@ #include // 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 @@ RTCPUtility::RTCPParserV2::Iterate() 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 @@ RTCPUtility::RTCPParserV2::IterateTopLevel() // Nothing supported found, continue to next block! break; } - return; } case PT_APP: @@ -229,6 +240,26 @@ RTCPUtility::RTCPParserV2::IterateTopLevel() } } +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() { @@ -833,7 +864,6 @@ RTCPUtility::RTCPParserV2::ParseBYEItem() bool RTCPUtility::RTCPParserV2::ParseXR() { const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData; - if (length < 8) { EndCurrentBlock(); @@ -847,8 +877,11 @@ bool RTCPUtility::RTCPParserV2::ParseXR() _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 @@ bool RTCPUtility::RTCPParserV2::ParseXR() : 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 @@ RTCPUtility::RTCPParserV2::ParseXRItem() | JB maximum | JB abs max | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ + bool RTCPUtility::RTCPParserV2::ParseXRVOIPMetricItem() { @@ -920,6 +1050,7 @@ RTCPUtility::RTCPParserV2::ParseXRVOIPMetricItem() if (length < 28) { + _state = State_TopLevel; EndCurrentBlock(); return false; } @@ -967,6 +1098,7 @@ RTCPUtility::RTCPParserV2::ParseXRVOIPMetricItem() _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 fa771ab93..c954f4479 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 @@ namespace RTCPUtility { // 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 @@ namespace RTCPUtility { RTCPPacketPSFBFIRItem FIRItem; RTCPPacketXR XR; + RTCPPacketXRReceiverReferenceTimeItem XRReceiverReferenceTimeItem; + RTCPPacketXRDLRRReportBlockItem XRDLRRReportBlockItem; RTCPPacketXRVOIPMetricItem XRVOIPMetricItem; RTCPPacketAPP APP; @@ -274,6 +291,10 @@ namespace RTCPUtility { kRtcpRtpfbSrReqCode, // RFC 3611 + kRtcpXrHeaderCode, + kRtcpXrReceiverReferenceTimeCode, + kRtcpXrDlrrReportBlockCode, + kRtcpXrDlrrReportBlockItemCode, kRtcpXrVoipMetricCode, kRtcpAppCode, @@ -353,6 +374,7 @@ namespace RTCPUtility { 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 @@ namespace RTCPUtility { void IteratePsfbAppItem(); void IteratePsfbREMBItem(); void IterateAppItem(); + void IterateXrItem(); + void IterateXrDlrrItem(); void Validate(); void EndCurrentBlock(); @@ -391,6 +415,8 @@ namespace RTCPUtility { 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 068b5cfe2..812f42734 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 @@ uint32_t ModuleRtpRtcpImpl::SendTimeOfSendReport( 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& nack_sequence_numbers) { if (!rtp_sender_.StorePackets() || @@ -1566,6 +1571,11 @@ int32_t ModuleRtpRtcpImpl::LastReceivedNTP( 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 ada2442fe..b97ef1a98 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 @@ class ModuleRtpRtcpImpl : public RtpRtcp { 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 @@ class ModuleRtpRtcpImpl : public RtpRtcp { 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;