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:
@@ -96,7 +96,9 @@ enum RTCPPacketType
|
|||||||
kRtcpSli = 0x4000,
|
kRtcpSli = 0x4000,
|
||||||
kRtcpRpsi = 0x8000,
|
kRtcpRpsi = 0x8000,
|
||||||
kRtcpRemb = 0x10000,
|
kRtcpRemb = 0x10000,
|
||||||
kRtcpTransmissionTimeOffset = 0x20000
|
kRtcpTransmissionTimeOffset = 0x20000,
|
||||||
|
kRtcpXrReceiverReferenceTime = 0x40000,
|
||||||
|
kRtcpXrDlrrReportBlock = 0x80000
|
||||||
};
|
};
|
||||||
|
|
||||||
enum KeyFrameRequestMethod
|
enum KeyFrameRequestMethod
|
||||||
@@ -177,6 +179,13 @@ struct RTCPReportBlock {
|
|||||||
uint32_t delaySinceLastSR;
|
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;
|
typedef std::list<RTCPReportBlock> ReportBlockList;
|
||||||
|
|
||||||
class RtpData
|
class RtpData
|
||||||
|
@@ -13,6 +13,8 @@
|
|||||||
#include <assert.h> //assert
|
#include <assert.h> //assert
|
||||||
#include <string.h> //memset
|
#include <string.h> //memset
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
|
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
|
||||||
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
|
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
|
||||||
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
|
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
|
||||||
@@ -46,6 +48,8 @@ RTCPReceiver::RTCPReceiver(const int32_t id, Clock* clock,
|
|||||||
_remoteSenderInfo(),
|
_remoteSenderInfo(),
|
||||||
_lastReceivedSRNTPsecs(0),
|
_lastReceivedSRNTPsecs(0),
|
||||||
_lastReceivedSRNTPfrac(0),
|
_lastReceivedSRNTPfrac(0),
|
||||||
|
_lastReceivedXRNTPsecs(0),
|
||||||
|
_lastReceivedXRNTPfrac(0),
|
||||||
_receivedInfoMap(),
|
_receivedInfoMap(),
|
||||||
_packetTimeOutMS(0),
|
_packetTimeOutMS(0),
|
||||||
_lastReceivedRrMs(0),
|
_lastReceivedRrMs(0),
|
||||||
@@ -259,6 +263,30 @@ RTCPReceiver::NTP(uint32_t *ReceivedNTPsecs,
|
|||||||
return 0;
|
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
|
int32_t
|
||||||
RTCPReceiver::SenderInfoReceived(RTCPSenderInfo* senderInfo) const
|
RTCPReceiver::SenderInfoReceived(RTCPSenderInfo* senderInfo) const
|
||||||
{
|
{
|
||||||
@@ -316,6 +344,15 @@ RTCPReceiver::IncomingRTCPPacket(RTCPPacketInformation& rtcpPacketInformation,
|
|||||||
case RTCPUtility::kRtcpSdesCode:
|
case RTCPUtility::kRtcpSdesCode:
|
||||||
HandleSDES(*rtcpParser);
|
HandleSDES(*rtcpParser);
|
||||||
break;
|
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:
|
case RTCPUtility::kRtcpXrVoipMetricCode:
|
||||||
HandleXRVOIPMetric(*rtcpParser, rtcpPacketInformation);
|
HandleXRVOIPMetric(*rtcpParser, rtcpPacketInformation);
|
||||||
break;
|
break;
|
||||||
@@ -863,6 +900,85 @@ void RTCPReceiver::HandleBYE(RTCPUtility::RTCPParserV2& rtcpParser) {
|
|||||||
rtcpParser.Iterate();
|
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
|
// no need for critsect we have _criticalSectionRTCPReceiver
|
||||||
void
|
void
|
||||||
RTCPReceiver::HandleXRVOIPMetric(RTCPUtility::RTCPParserV2& rtcpParser,
|
RTCPReceiver::HandleXRVOIPMetric(RTCPUtility::RTCPParserV2& rtcpParser,
|
||||||
|
@@ -69,6 +69,8 @@ public:
|
|||||||
uint32_t *RTCPArrivalTimeFrac,
|
uint32_t *RTCPArrivalTimeFrac,
|
||||||
uint32_t *rtcp_timestamp) const;
|
uint32_t *rtcp_timestamp) const;
|
||||||
|
|
||||||
|
bool LastReceivedXrReferenceTimeInfo(RtcpReceiveTimeInfo* info) const;
|
||||||
|
|
||||||
// get rtt
|
// get rtt
|
||||||
int32_t RTT(uint32_t remoteSSRC,
|
int32_t RTT(uint32_t remoteSSRC,
|
||||||
uint16_t* RTT,
|
uint16_t* RTT,
|
||||||
@@ -133,6 +135,21 @@ protected:
|
|||||||
|
|
||||||
void HandleSDESChunk(RTCPUtility::RTCPParserV2& rtcpParser);
|
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,
|
void HandleXRVOIPMetric(RTCPUtility::RTCPParserV2& rtcpParser,
|
||||||
RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
|
RTCPHelp::RTCPPacketInformation& rtcpPacketInformation);
|
||||||
|
|
||||||
@@ -223,6 +240,12 @@ protected:
|
|||||||
uint32_t _lastReceivedSRNTPsecs;
|
uint32_t _lastReceivedSRNTPsecs;
|
||||||
uint32_t _lastReceivedSRNTPfrac;
|
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.
|
// Received report blocks.
|
||||||
std::map<uint32_t, RTCPHelp::RTCPReportBlockInformation*>
|
std::map<uint32_t, RTCPHelp::RTCPReportBlockInformation*>
|
||||||
_receivedReportBlockMap;
|
_receivedReportBlockMap;
|
||||||
|
@@ -34,6 +34,8 @@ RTCPPacketInformation::RTCPPacketInformation()
|
|||||||
ntp_secs(0),
|
ntp_secs(0),
|
||||||
ntp_frac(0),
|
ntp_frac(0),
|
||||||
rtp_timestamp(0),
|
rtp_timestamp(0),
|
||||||
|
xr_originator_ssrc(0),
|
||||||
|
xr_dlrr_item(false),
|
||||||
VoIPMetric(NULL) {
|
VoIPMetric(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -80,6 +80,8 @@ public:
|
|||||||
uint32_t ntp_frac;
|
uint32_t ntp_frac;
|
||||||
uint32_t rtp_timestamp;
|
uint32_t rtp_timestamp;
|
||||||
|
|
||||||
|
uint32_t xr_originator_ssrc;
|
||||||
|
bool xr_dlrr_item;
|
||||||
RTCPVoIPMetric* VoIPMetric;
|
RTCPVoIPMetric* VoIPMetric;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -137,6 +137,44 @@ class PacketBuilder {
|
|||||||
Add32(0); // Delay since last SR.
|
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() {
|
const uint8_t* packet() {
|
||||||
PatchLengthField();
|
PatchLengthField();
|
||||||
return buffer_;
|
return buffer_;
|
||||||
@@ -228,7 +266,7 @@ class RtcpReceiverTest : public ::testing::Test {
|
|||||||
// Injects an RTCP packet into the receiver.
|
// Injects an RTCP packet into the receiver.
|
||||||
// Returns 0 for OK, non-0 for failure.
|
// Returns 0 for OK, non-0 for failure.
|
||||||
int InjectRtcpPacket(const uint8_t* packet,
|
int InjectRtcpPacket(const uint8_t* packet,
|
||||||
uint16_t packet_len) {
|
uint16_t packet_len) {
|
||||||
RTCPUtility::RTCPParserV2 rtcpParser(packet,
|
RTCPUtility::RTCPParserV2 rtcpParser(packet,
|
||||||
packet_len,
|
packet_len,
|
||||||
true); // Allow non-compound RTCP
|
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_secs = rtcpPacketInformation.ntp_secs;
|
||||||
rtcp_packet_info_.ntp_frac = rtcpPacketInformation.ntp_frac;
|
rtcp_packet_info_.ntp_frac = rtcpPacketInformation.ntp_frac;
|
||||||
rtcp_packet_info_.rtp_timestamp = rtcpPacketInformation.rtp_timestamp;
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,6 +329,165 @@ TEST_F(RtcpReceiverTest, InjectSrPacket) {
|
|||||||
kRtcpSr & rtcp_packet_info_.rtcpPacketTypeFlags);
|
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) {
|
TEST_F(RtcpReceiverTest, ReceiveReportTimeout) {
|
||||||
const uint32_t kSenderSsrc = 0x10203;
|
const uint32_t kSenderSsrc = 0x10203;
|
||||||
const uint32_t kSourceSsrc = 0x40506;
|
const uint32_t kSourceSsrc = 0x40506;
|
||||||
|
@@ -77,6 +77,8 @@ RTCPSender::FeedbackState::FeedbackState(ModuleRtpRtcpImpl* module)
|
|||||||
last_rr_ntp_frac = last_ntp_frac;
|
last_rr_ntp_frac = last_ntp_frac;
|
||||||
remote_sr = last_remote_sr;
|
remote_sr = last_remote_sr;
|
||||||
|
|
||||||
|
has_last_xr_rr = module->LastReceivedXrReferenceTimeInfo(&last_xr_rr);
|
||||||
|
|
||||||
uint32_t send_bitrate = 0, tmp;
|
uint32_t send_bitrate = 0, tmp;
|
||||||
module->BitrateSent(&send_bitrate, &tmp, &tmp, &tmp);
|
module->BitrateSent(&send_bitrate, &tmp, &tmp, &tmp);
|
||||||
this->send_bitrate = send_bitrate;
|
this->send_bitrate = send_bitrate;
|
||||||
@@ -90,7 +92,8 @@ RTCPSender::FeedbackState::FeedbackState()
|
|||||||
send_bitrate(0),
|
send_bitrate(0),
|
||||||
last_rr_ntp_secs(0),
|
last_rr_ntp_secs(0),
|
||||||
last_rr_ntp_frac(0),
|
last_rr_ntp_frac(0),
|
||||||
remote_sr(0) {}
|
remote_sr(0),
|
||||||
|
has_last_xr_rr(false) {}
|
||||||
|
|
||||||
RTCPSender::RTCPSender(const int32_t id,
|
RTCPSender::RTCPSender(const int32_t id,
|
||||||
const bool audio,
|
const bool audio,
|
||||||
@@ -128,6 +131,8 @@ RTCPSender::RTCPSender(const int32_t id,
|
|||||||
_lastSendReport(),
|
_lastSendReport(),
|
||||||
_lastRTCPTime(),
|
_lastRTCPTime(),
|
||||||
|
|
||||||
|
last_xr_rr_(),
|
||||||
|
|
||||||
_CSRCs(0),
|
_CSRCs(0),
|
||||||
_CSRC(),
|
_CSRC(),
|
||||||
_includeCSRCs(true),
|
_includeCSRCs(true),
|
||||||
@@ -148,6 +153,8 @@ RTCPSender::RTCPSender(const int32_t id,
|
|||||||
_appName(),
|
_appName(),
|
||||||
_appData(NULL),
|
_appData(NULL),
|
||||||
_appLength(0),
|
_appLength(0),
|
||||||
|
|
||||||
|
xrSendReceiverReferenceTimeEnabled_(false),
|
||||||
_xrSendVoIPMetric(false),
|
_xrSendVoIPMetric(false),
|
||||||
_xrVoIPMetric(),
|
_xrVoIPMetric(),
|
||||||
_nackCount(0),
|
_nackCount(0),
|
||||||
@@ -222,12 +229,15 @@ RTCPSender::Init()
|
|||||||
}
|
}
|
||||||
_appLength = 0;
|
_appLength = 0;
|
||||||
|
|
||||||
|
xrSendReceiverReferenceTimeEnabled_ = false;
|
||||||
|
|
||||||
_xrSendVoIPMetric = false;
|
_xrSendVoIPMetric = false;
|
||||||
|
|
||||||
memset(&_xrVoIPMetric, 0, sizeof(_xrVoIPMetric));
|
memset(&_xrVoIPMetric, 0, sizeof(_xrVoIPMetric));
|
||||||
memset(_CNAME, 0, sizeof(_CNAME));
|
memset(_CNAME, 0, sizeof(_CNAME));
|
||||||
memset(_lastSendReport, 0, sizeof(_lastSendReport));
|
memset(_lastSendReport, 0, sizeof(_lastSendReport));
|
||||||
memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
|
memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
|
||||||
|
last_xr_rr_.clear();
|
||||||
|
|
||||||
_nackCount = 0;
|
_nackCount = 0;
|
||||||
_pliCount = 0;
|
_pliCount = 0;
|
||||||
@@ -591,6 +601,21 @@ RTCPSender::SendTimeOfSendReport(const uint32_t sendReport)
|
|||||||
return 0;
|
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(
|
int32_t RTCPSender::AddExternalReportBlock(
|
||||||
uint32_t SSRC,
|
uint32_t SSRC,
|
||||||
const RTCPReportBlock* reportBlock) {
|
const RTCPReportBlock* reportBlock) {
|
||||||
@@ -1502,6 +1527,107 @@ RTCPSender::BuildBYE(uint8_t* rtcpbuffer, int& pos)
|
|||||||
return 0;
|
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
|
int32_t
|
||||||
RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, int& pos)
|
RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, int& pos)
|
||||||
{
|
{
|
||||||
@@ -1652,7 +1778,18 @@ int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state,
|
|||||||
rtcpPacketTypeFlags |= kRtcpTmmbn;
|
rtcpPacketTypeFlags |= kRtcpTmmbn;
|
||||||
_sendTMMBN = false;
|
_sendTMMBN = false;
|
||||||
}
|
}
|
||||||
|
if (xrSendReceiverReferenceTimeEnabled_ &&
|
||||||
|
(rtcpPacketTypeFlags & kRtcpReport))
|
||||||
|
{
|
||||||
|
if (!_sending)
|
||||||
|
{
|
||||||
|
rtcpPacketTypeFlags |= kRtcpXrReceiverReferenceTime;
|
||||||
|
}
|
||||||
|
if (feedback_state.has_last_xr_rr)
|
||||||
|
{
|
||||||
|
rtcpPacketTypeFlags |= kRtcpXrDlrrReportBlock;
|
||||||
|
}
|
||||||
|
}
|
||||||
if(_method == kRtcpCompound)
|
if(_method == kRtcpCompound)
|
||||||
{
|
{
|
||||||
if(_sending)
|
if(_sending)
|
||||||
@@ -1893,6 +2030,27 @@ int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state,
|
|||||||
return position;
|
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;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2020,6 +2178,11 @@ RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) {
|
||||||
|
CriticalSectionScoped lock(_criticalSectionRTCPSender);
|
||||||
|
xrSendReceiverReferenceTimeEnabled_ = enable;
|
||||||
|
}
|
||||||
|
|
||||||
// called under critsect _criticalSectionRTCPSender
|
// called under critsect _criticalSectionRTCPSender
|
||||||
int32_t RTCPSender::WriteAllReportBlocksToBuffer(
|
int32_t RTCPSender::WriteAllReportBlocksToBuffer(
|
||||||
uint8_t* rtcpbuffer,
|
uint8_t* rtcpbuffer,
|
||||||
|
@@ -63,6 +63,9 @@ public:
|
|||||||
uint32_t last_rr_ntp_frac;
|
uint32_t last_rr_ntp_frac;
|
||||||
uint32_t remote_sr;
|
uint32_t remote_sr;
|
||||||
|
|
||||||
|
bool has_last_xr_rr;
|
||||||
|
RtcpReceiveTimeInfo last_xr_rr;
|
||||||
|
|
||||||
// Used when generating TMMBR.
|
// Used when generating TMMBR.
|
||||||
ModuleRtpRtcpImpl* module;
|
ModuleRtpRtcpImpl* module;
|
||||||
};
|
};
|
||||||
@@ -107,6 +110,8 @@ public:
|
|||||||
|
|
||||||
uint32_t SendTimeOfSendReport(const uint32_t sendReport);
|
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;
|
bool TimeToSendRTCPReport(const bool sendKeyframeBeforeRTP = false) const;
|
||||||
|
|
||||||
uint32_t LastSendReport(uint32_t& lastRTCPTime);
|
uint32_t LastSendReport(uint32_t& lastRTCPTime);
|
||||||
@@ -164,6 +169,8 @@ public:
|
|||||||
|
|
||||||
int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric);
|
int32_t SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric);
|
||||||
|
|
||||||
|
void SendRtcpXrReceiverReferenceTime(bool enable);
|
||||||
|
|
||||||
int32_t SetCSRCs(const uint32_t arrOfCSRC[kRtpCsrcSize],
|
int32_t SetCSRCs(const uint32_t arrOfCSRC[kRtpCsrcSize],
|
||||||
const uint8_t arrLength);
|
const uint8_t arrLength);
|
||||||
|
|
||||||
@@ -250,6 +257,14 @@ private:
|
|||||||
const uint16_t* nackList,
|
const uint16_t* nackList,
|
||||||
std::string* nackString);
|
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:
|
private:
|
||||||
int32_t _id;
|
int32_t _id;
|
||||||
const bool _audio;
|
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 _lastSendReport[RTCP_NUMBER_OF_SR]; // allow packet loss and RTT above 1 sec
|
||||||
uint32_t _lastRTCPTime[RTCP_NUMBER_OF_SR];
|
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
|
// send CSRCs
|
||||||
uint8_t _CSRCs;
|
uint8_t _CSRCs;
|
||||||
uint32_t _CSRC[kRtpCsrcSize];
|
uint32_t _CSRC[kRtpCsrcSize];
|
||||||
@@ -314,6 +333,9 @@ private:
|
|||||||
uint8_t* _appData;
|
uint8_t* _appData;
|
||||||
uint16_t _appLength;
|
uint16_t _appLength;
|
||||||
|
|
||||||
|
// True if sending of XR Receiver reference time report is enabled.
|
||||||
|
bool xrSendReceiverReferenceTimeEnabled_;
|
||||||
|
|
||||||
// XR VoIP metric
|
// XR VoIP metric
|
||||||
bool _xrSendVoIPMetric;
|
bool _xrSendVoIPMetric;
|
||||||
RTCPVoIPMetric _xrVoIPMetric;
|
RTCPVoIPMetric _xrVoIPMetric;
|
||||||
|
@@ -274,30 +274,30 @@ class RtcpSenderTest : public ::testing::Test {
|
|||||||
protected:
|
protected:
|
||||||
RtcpSenderTest()
|
RtcpSenderTest()
|
||||||
: over_use_detector_options_(),
|
: over_use_detector_options_(),
|
||||||
system_clock_(Clock::GetRealTimeClock()),
|
clock_(1335900000),
|
||||||
rtp_payload_registry_(new RTPPayloadRegistry(
|
rtp_payload_registry_(new RTPPayloadRegistry(
|
||||||
0, RTPPayloadStrategy::CreateStrategy(false))),
|
0, RTPPayloadStrategy::CreateStrategy(false))),
|
||||||
remote_bitrate_observer_(),
|
remote_bitrate_observer_(),
|
||||||
remote_bitrate_estimator_(
|
remote_bitrate_estimator_(
|
||||||
RemoteBitrateEstimatorFactory().Create(
|
RemoteBitrateEstimatorFactory().Create(
|
||||||
&remote_bitrate_observer_,
|
&remote_bitrate_observer_,
|
||||||
system_clock_)),
|
&clock_)),
|
||||||
receive_statistics_(ReceiveStatistics::Create(system_clock_)) {
|
receive_statistics_(ReceiveStatistics::Create(&clock_)) {
|
||||||
test_transport_ = new TestTransport();
|
test_transport_ = new TestTransport();
|
||||||
|
|
||||||
RtpRtcp::Configuration configuration;
|
RtpRtcp::Configuration configuration;
|
||||||
configuration.id = 0;
|
configuration.id = 0;
|
||||||
configuration.audio = false;
|
configuration.audio = false;
|
||||||
configuration.clock = system_clock_;
|
configuration.clock = &clock_;
|
||||||
configuration.outgoing_transport = test_transport_;
|
configuration.outgoing_transport = test_transport_;
|
||||||
configuration.remote_bitrate_estimator = remote_bitrate_estimator_.get();
|
configuration.remote_bitrate_estimator = remote_bitrate_estimator_.get();
|
||||||
|
|
||||||
rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration);
|
rtp_rtcp_impl_ = new ModuleRtpRtcpImpl(configuration);
|
||||||
rtp_receiver_.reset(RtpReceiver::CreateVideoReceiver(
|
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_ =
|
rtcp_sender_ =
|
||||||
new RTCPSender(0, false, system_clock_, receive_statistics_.get());
|
new RTCPSender(0, false, &clock_, receive_statistics_.get());
|
||||||
rtcp_receiver_ = new RTCPReceiver(0, system_clock_, rtp_rtcp_impl_);
|
rtcp_receiver_ = new RTCPReceiver(0, &clock_, rtp_rtcp_impl_);
|
||||||
test_transport_->SetRTCPReceiver(rtcp_receiver_);
|
test_transport_->SetRTCPReceiver(rtcp_receiver_);
|
||||||
// Initialize
|
// Initialize
|
||||||
EXPECT_EQ(0, rtcp_sender_->Init());
|
EXPECT_EQ(0, rtcp_sender_->Init());
|
||||||
@@ -317,7 +317,7 @@ class RtcpSenderTest : public ::testing::Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OverUseDetectorOptions over_use_detector_options_;
|
OverUseDetectorOptions over_use_detector_options_;
|
||||||
Clock* system_clock_;
|
SimulatedClock clock_;
|
||||||
scoped_ptr<RTPPayloadRegistry> rtp_payload_registry_;
|
scoped_ptr<RTPPayloadRegistry> rtp_payload_registry_;
|
||||||
scoped_ptr<RtpReceiver> rtp_receiver_;
|
scoped_ptr<RtpReceiver> rtp_receiver_;
|
||||||
ModuleRtpRtcpImpl* rtp_rtcp_impl_;
|
ModuleRtpRtcpImpl* rtp_rtcp_impl_;
|
||||||
@@ -397,6 +397,70 @@ TEST_F(RtcpSenderTest, TestCompound_NoRtpReceived) {
|
|||||||
kRtcpTransmissionTimeOffset);
|
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
|
// 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 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
|
// to put an actual limit here. It's just information that no limit
|
||||||
|
@@ -15,8 +15,14 @@
|
|||||||
#include <string.h> // memcpy
|
#include <string.h> // memcpy
|
||||||
|
|
||||||
namespace webrtc {
|
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,
|
RTCPUtility::RTCPParserV2::RTCPParserV2(const uint8_t* rtcpData,
|
||||||
size_t rtcpDataLength,
|
size_t rtcpDataLength,
|
||||||
bool rtcpReducedSizeEnable)
|
bool rtcpReducedSizeEnable)
|
||||||
@@ -110,6 +116,12 @@ RTCPUtility::RTCPParserV2::Iterate()
|
|||||||
case State_PSFB_REMBItem:
|
case State_PSFB_REMBItem:
|
||||||
IteratePsfbREMBItem();
|
IteratePsfbREMBItem();
|
||||||
break;
|
break;
|
||||||
|
case State_XRItem:
|
||||||
|
IterateXrItem();
|
||||||
|
break;
|
||||||
|
case State_XR_DLLRItem:
|
||||||
|
IterateXrDlrrItem();
|
||||||
|
break;
|
||||||
case State_AppItem:
|
case State_AppItem:
|
||||||
IterateAppItem();
|
IterateAppItem();
|
||||||
break;
|
break;
|
||||||
@@ -198,7 +210,6 @@ RTCPUtility::RTCPParserV2::IterateTopLevel()
|
|||||||
// Nothing supported found, continue to next block!
|
// Nothing supported found, continue to next block!
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case PT_APP:
|
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
|
void
|
||||||
RTCPUtility::RTCPParserV2::IterateReportBlockItem()
|
RTCPUtility::RTCPParserV2::IterateReportBlockItem()
|
||||||
{
|
{
|
||||||
@@ -833,7 +864,6 @@ RTCPUtility::RTCPParserV2::ParseBYEItem()
|
|||||||
bool RTCPUtility::RTCPParserV2::ParseXR()
|
bool RTCPUtility::RTCPParserV2::ParseXR()
|
||||||
{
|
{
|
||||||
const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
|
const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
|
||||||
|
|
||||||
if (length < 8)
|
if (length < 8)
|
||||||
{
|
{
|
||||||
EndCurrentBlock();
|
EndCurrentBlock();
|
||||||
@@ -847,8 +877,11 @@ bool RTCPUtility::RTCPParserV2::ParseXR()
|
|||||||
_packet.XR.OriginatorSSRC += *_ptrRTCPData++ << 8;
|
_packet.XR.OriginatorSSRC += *_ptrRTCPData++ << 8;
|
||||||
_packet.XR.OriginatorSSRC += *_ptrRTCPData++;
|
_packet.XR.OriginatorSSRC += *_ptrRTCPData++;
|
||||||
|
|
||||||
return ParseXRItem();
|
_packetType = kRtcpXrHeaderCode;
|
||||||
|
_state = State_XRItem;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
0 1 2 3
|
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
|
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 :
|
: type-specific block contents :
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RTCPUtility::RTCPParserV2::ParseXRItem()
|
RTCPUtility::RTCPParserV2::ParseXRItem()
|
||||||
{
|
{
|
||||||
const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
|
const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
|
||||||
|
|
||||||
if (length < 4) //
|
if (length < 4) {
|
||||||
{
|
_state = State_TopLevel;
|
||||||
EndCurrentBlock();
|
EndCurrentBlock();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t blockType = *_ptrRTCPData++;
|
uint8_t blockType = *_ptrRTCPData++;
|
||||||
uint8_t typeSpecific = *_ptrRTCPData++;
|
_ptrRTCPData++; // Ignore reserved.
|
||||||
|
|
||||||
uint16_t blockLength = *_ptrRTCPData++ << 8;
|
uint16_t blockLength = *_ptrRTCPData++ << 8;
|
||||||
blockLength = *_ptrRTCPData++;
|
blockLength = *_ptrRTCPData++;
|
||||||
|
|
||||||
if(blockType == 7 && typeSpecific == 0)
|
if (blockType == 4 && blockLength == 2)
|
||||||
{
|
{
|
||||||
if(blockLength != 8)
|
return ParseXRReceiverReferenceTimeItem();
|
||||||
{
|
}
|
||||||
EndCurrentBlock();
|
else if (blockType == 5 && (blockLength % 3) == 0)
|
||||||
return false;
|
{
|
||||||
}
|
_packetType = kRtcpXrDlrrReportBlockCode;
|
||||||
return ParseXRVOIPMetricItem();
|
_state = State_XR_DLLRItem;
|
||||||
}else
|
_numberOfBlocks = blockLength / 3;
|
||||||
{
|
return true;
|
||||||
EndCurrentBlock();
|
}
|
||||||
return false;
|
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
|
0 1 2 3
|
||||||
@@ -913,6 +1042,7 @@ RTCPUtility::RTCPParserV2::ParseXRItem()
|
|||||||
| JB maximum | JB abs max |
|
| JB maximum | JB abs max |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
RTCPUtility::RTCPParserV2::ParseXRVOIPMetricItem()
|
RTCPUtility::RTCPParserV2::ParseXRVOIPMetricItem()
|
||||||
{
|
{
|
||||||
@@ -920,6 +1050,7 @@ RTCPUtility::RTCPParserV2::ParseXRVOIPMetricItem()
|
|||||||
|
|
||||||
if (length < 28)
|
if (length < 28)
|
||||||
{
|
{
|
||||||
|
_state = State_TopLevel;
|
||||||
EndCurrentBlock();
|
EndCurrentBlock();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -967,6 +1098,7 @@ RTCPUtility::RTCPParserV2::ParseXRVOIPMetricItem()
|
|||||||
_packet.XRVOIPMetricItem.JBabsMax = *_ptrRTCPData++ << 8;
|
_packet.XRVOIPMetricItem.JBabsMax = *_ptrRTCPData++ << 8;
|
||||||
_packet.XRVOIPMetricItem.JBabsMax += *_ptrRTCPData++;
|
_packet.XRVOIPMetricItem.JBabsMax += *_ptrRTCPData++;
|
||||||
|
|
||||||
|
_state = State_XRItem;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
namespace RTCPUtility {
|
namespace RTCPUtility {
|
||||||
|
uint32_t MidNtp(uint32_t ntp_sec, uint32_t ntp_frac);
|
||||||
|
|
||||||
// CNAME
|
// CNAME
|
||||||
struct RTCPCnameInformation
|
struct RTCPCnameInformation
|
||||||
{
|
{
|
||||||
@@ -74,6 +76,19 @@ namespace RTCPUtility {
|
|||||||
// RFC 3611
|
// RFC 3611
|
||||||
uint32_t OriginatorSSRC;
|
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
|
struct RTCPPacketXRVOIPMetricItem
|
||||||
{
|
{
|
||||||
// RFC 3611 4.7
|
// RFC 3611 4.7
|
||||||
@@ -228,6 +243,8 @@ namespace RTCPUtility {
|
|||||||
RTCPPacketPSFBFIRItem FIRItem;
|
RTCPPacketPSFBFIRItem FIRItem;
|
||||||
|
|
||||||
RTCPPacketXR XR;
|
RTCPPacketXR XR;
|
||||||
|
RTCPPacketXRReceiverReferenceTimeItem XRReceiverReferenceTimeItem;
|
||||||
|
RTCPPacketXRDLRRReportBlockItem XRDLRRReportBlockItem;
|
||||||
RTCPPacketXRVOIPMetricItem XRVOIPMetricItem;
|
RTCPPacketXRVOIPMetricItem XRVOIPMetricItem;
|
||||||
|
|
||||||
RTCPPacketAPP APP;
|
RTCPPacketAPP APP;
|
||||||
@@ -274,6 +291,10 @@ namespace RTCPUtility {
|
|||||||
kRtcpRtpfbSrReqCode,
|
kRtcpRtpfbSrReqCode,
|
||||||
|
|
||||||
// RFC 3611
|
// RFC 3611
|
||||||
|
kRtcpXrHeaderCode,
|
||||||
|
kRtcpXrReceiverReferenceTimeCode,
|
||||||
|
kRtcpXrDlrrReportBlockCode,
|
||||||
|
kRtcpXrDlrrReportBlockItemCode,
|
||||||
kRtcpXrVoipMetricCode,
|
kRtcpXrVoipMetricCode,
|
||||||
|
|
||||||
kRtcpAppCode,
|
kRtcpAppCode,
|
||||||
@@ -353,6 +374,7 @@ namespace RTCPUtility {
|
|||||||
State_PSFB_AppItem, // Application specific FCI item
|
State_PSFB_AppItem, // Application specific FCI item
|
||||||
State_PSFB_REMBItem, // Application specific REMB item
|
State_PSFB_REMBItem, // Application specific REMB item
|
||||||
State_XRItem,
|
State_XRItem,
|
||||||
|
State_XR_DLLRItem,
|
||||||
State_AppItem
|
State_AppItem
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -371,6 +393,8 @@ namespace RTCPUtility {
|
|||||||
void IteratePsfbAppItem();
|
void IteratePsfbAppItem();
|
||||||
void IteratePsfbREMBItem();
|
void IteratePsfbREMBItem();
|
||||||
void IterateAppItem();
|
void IterateAppItem();
|
||||||
|
void IterateXrItem();
|
||||||
|
void IterateXrDlrrItem();
|
||||||
|
|
||||||
void Validate();
|
void Validate();
|
||||||
void EndCurrentBlock();
|
void EndCurrentBlock();
|
||||||
@@ -391,6 +415,8 @@ namespace RTCPUtility {
|
|||||||
|
|
||||||
bool ParseXR();
|
bool ParseXR();
|
||||||
bool ParseXRItem();
|
bool ParseXRItem();
|
||||||
|
bool ParseXRReceiverReferenceTimeItem();
|
||||||
|
bool ParseXRDLRRReportBlockItem();
|
||||||
bool ParseXRVOIPMetricItem();
|
bool ParseXRVOIPMetricItem();
|
||||||
|
|
||||||
bool ParseFBCommon(const RTCPCommonHeader& header);
|
bool ParseFBCommon(const RTCPCommonHeader& header);
|
||||||
|
@@ -1536,6 +1536,11 @@ uint32_t ModuleRtpRtcpImpl::SendTimeOfSendReport(
|
|||||||
return rtcp_sender_.SendTimeOfSendReport(send_report);
|
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(
|
void ModuleRtpRtcpImpl::OnReceivedNACK(
|
||||||
const std::list<uint16_t>& nack_sequence_numbers) {
|
const std::list<uint16_t>& nack_sequence_numbers) {
|
||||||
if (!rtp_sender_.StorePackets() ||
|
if (!rtp_sender_.StorePackets() ||
|
||||||
@@ -1566,6 +1571,11 @@ int32_t ModuleRtpRtcpImpl::LastReceivedNTP(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ModuleRtpRtcpImpl::LastReceivedXrReferenceTimeInfo(
|
||||||
|
RtcpReceiveTimeInfo* info) const {
|
||||||
|
return rtcp_receiver_.LastReceivedXrReferenceTimeInfo(info);
|
||||||
|
}
|
||||||
|
|
||||||
bool ModuleRtpRtcpImpl::UpdateRTCPReceiveInformationTimers() {
|
bool ModuleRtpRtcpImpl::UpdateRTCPReceiveInformationTimers() {
|
||||||
// If this returns true this channel has timed out.
|
// If this returns true this channel has timed out.
|
||||||
// Periodically check if this is true and if so call UpdateTMMBR.
|
// Periodically check if this is true and if so call UpdateTMMBR.
|
||||||
|
@@ -324,6 +324,8 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
|
|||||||
uint32_t& NTPfrac,
|
uint32_t& NTPfrac,
|
||||||
uint32_t& remote_sr);
|
uint32_t& remote_sr);
|
||||||
|
|
||||||
|
virtual bool LastReceivedXrReferenceTimeInfo(RtcpReceiveTimeInfo* info) const;
|
||||||
|
|
||||||
virtual int32_t BoundingSet(bool& tmmbr_owner, TMMBRSet*& bounding_set_rec);
|
virtual int32_t BoundingSet(bool& tmmbr_owner, TMMBRSet*& bounding_set_rec);
|
||||||
|
|
||||||
virtual void BitrateSent(uint32_t* total_rate,
|
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 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.
|
// Good state of RTP receiver inform sender.
|
||||||
virtual int32_t SendRTCPReferencePictureSelection(
|
virtual int32_t SendRTCPReferencePictureSelection(
|
||||||
const uint64_t picture_id) OVERRIDE;
|
const uint64_t picture_id) OVERRIDE;
|
||||||
|
Reference in New Issue
Block a user