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
This commit is contained in:
asapersson@webrtc.org 2013-10-02 13:15:34 +00:00
parent c0167702d3
commit 8469f7b328
13 changed files with 814 additions and 40 deletions

View File

@ -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<RTCPReportBlock> ReportBlockList;
class RtpData

View File

@ -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 @@ 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,

View File

@ -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<uint32_t, RTCPHelp::RTCPReportBlockInformation*>
_receivedReportBlockMap;

View File

@ -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) {
}

View File

@ -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:

View File

@ -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<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 @@ 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<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;

View File

@ -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<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 @@ 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<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 @@ 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,

View File

@ -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.
// <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 @@ 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;

View File

@ -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<RTPPayloadRegistry> rtp_payload_registry_;
scoped_ptr<RtpReceiver> 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

View File

@ -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 @@ 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;
}

View File

@ -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);

View File

@ -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<uint16_t>& 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.

View File

@ -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;