rtcp::ExtenededReports packet class got Parse function

BUG=webrtc:5260
R=åsapersson

Review URL: https://codereview.webrtc.org/1557593002

Cr-Commit-Position: refs/heads/master@{#11428}
This commit is contained in:
danilchap 2016-01-29 11:26:14 -08:00 committed by Commit bot
parent ff63ed2888
commit de13882d94
5 changed files with 491 additions and 316 deletions

View File

@ -14,16 +14,10 @@
#include "webrtc/base/logging.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
using webrtc::RTCPUtility::PT_XR;
using webrtc::RTCPUtility::RTCPPacketXR;
using webrtc::RTCPUtility::RtcpCommonHeader;
namespace webrtc {
namespace rtcp {
namespace {
void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
ByteWriter<uint32_t>::WriteBigEndian(buffer + *offset, value);
*offset += 4;
}
// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
//
// Format for XR packets:
@ -37,23 +31,106 @@ void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : report blocks :
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
void CreateXrHeader(const RTCPPacketXR& header,
uint8_t* buffer,
size_t* pos) {
AssignUWord32(buffer, pos, header.OriginatorSSRC);
//
// Extended report block:
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | Block Type | reserved | block length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : type-specific block contents :
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ExtendedReports::ExtendedReports() : sender_ssrc_(0) {}
ExtendedReports::~ExtendedReports() {}
bool ExtendedReports::Parse(const RtcpCommonHeader& header,
const uint8_t* payload) {
RTC_CHECK(header.packet_type == kPacketType);
if (header.payload_size_bytes < kXrBaseLength) {
LOG(LS_WARNING) << "Packet is too small to be an ExtendedReports packet.";
return false;
}
sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(payload);
rrtr_blocks_.clear();
dlrr_blocks_.clear();
voip_metric_blocks_.clear();
const uint8_t* current_block = payload + kXrBaseLength;
const uint8_t* const packet_end = payload + header.payload_size_bytes;
const size_t kBlockHeaderSizeBytes = 4;
while (current_block + kBlockHeaderSizeBytes <= packet_end) {
uint8_t block_type = ByteReader<uint8_t>::ReadBigEndian(current_block);
uint16_t block_length =
ByteReader<uint16_t>::ReadBigEndian(current_block + 2);
const uint8_t* next_block =
current_block + kBlockHeaderSizeBytes + block_length * 4;
if (next_block > packet_end) {
LOG(LS_WARNING) << "Report block in extended report packet is too big.";
return false;
}
switch (block_type) {
case Rrtr::kBlockType:
ParseRrtrBlock(current_block, block_length);
break;
case Dlrr::kBlockType:
ParseDlrrBlock(current_block, block_length);
break;
case VoipMetric::kBlockType:
ParseVoipMetricBlock(current_block, block_length);
break;
default:
// Unknown block, ignore.
LOG(LS_WARNING) << "Unknown extended report block type " << block_type;
break;
}
current_block = next_block;
}
return true;
}
bool ExtendedReports::WithRrtr(const Rrtr& rrtr) {
if (rrtr_blocks_.size() >= kMaxNumberOfRrtrBlocks) {
LOG(LS_WARNING) << "Max RRTR blocks reached.";
return false;
}
rrtr_blocks_.push_back(rrtr);
return true;
}
bool ExtendedReports::WithDlrr(const Dlrr& dlrr) {
if (dlrr_blocks_.size() >= kMaxNumberOfDlrrBlocks) {
LOG(LS_WARNING) << "Max DLRR blocks reached.";
return false;
}
dlrr_blocks_.push_back(dlrr);
return true;
}
bool ExtendedReports::WithVoipMetric(const VoipMetric& voip_metric) {
if (voip_metric_blocks_.size() >= kMaxNumberOfVoipMetricBlocks) {
LOG(LS_WARNING) << "Max Voip Metric blocks reached.";
return false;
}
voip_metric_blocks_.push_back(voip_metric);
return true;
}
} // namespace
bool ExtendedReports::Create(uint8_t* packet,
size_t* index,
size_t max_length,
RtcpPacket::PacketReadyCallback* callback) const {
size_t* index,
size_t max_length,
RtcpPacket::PacketReadyCallback* callback) const {
while (*index + BlockLength() > max_length) {
if (!OnBufferFull(packet, index, callback))
return false;
}
CreateHeader(0U, PT_XR, HeaderLength(), packet, index);
CreateXrHeader(xr_header_, packet, index);
size_t index_end = *index + BlockLength();
const uint8_t kReserved = 0;
CreateHeader(kReserved, kPacketType, HeaderLength(), packet, index);
ByteWriter<uint32_t>::WriteBigEndian(packet + *index, sender_ssrc_);
*index += sizeof(uint32_t);
for (const Rrtr& block : rrtr_blocks_) {
block.Create(packet + *index);
*index += Rrtr::kLength;
@ -66,36 +143,7 @@ bool ExtendedReports::Create(uint8_t* packet,
block.Create(packet + *index);
*index += VoipMetric::kLength;
}
return true;
}
bool ExtendedReports::WithRrtr(Rrtr* rrtr) {
RTC_DCHECK(rrtr);
if (rrtr_blocks_.size() >= kMaxNumberOfRrtrBlocks) {
LOG(LS_WARNING) << "Max RRTR blocks reached.";
return false;
}
rrtr_blocks_.push_back(*rrtr);
return true;
}
bool ExtendedReports::WithDlrr(Dlrr* dlrr) {
RTC_DCHECK(dlrr);
if (dlrr_blocks_.size() >= kMaxNumberOfDlrrBlocks) {
LOG(LS_WARNING) << "Max DLRR blocks reached.";
return false;
}
dlrr_blocks_.push_back(*dlrr);
return true;
}
bool ExtendedReports::WithVoipMetric(VoipMetric* voip_metric) {
assert(voip_metric);
if (voip_metric_blocks_.size() >= kMaxNumberOfVoipMetricBlocks) {
LOG(LS_WARNING) << "Max Voip Metric blocks reached.";
return false;
}
voip_metric_blocks_.push_back(*voip_metric);
RTC_CHECK_EQ(*index, index_end);
return true;
}
@ -107,5 +155,34 @@ size_t ExtendedReports::DlrrLength() const {
return length;
}
void ExtendedReports::ParseRrtrBlock(const uint8_t* block,
uint16_t block_length) {
if (block_length != Rrtr::kBlockLength) {
LOG(LS_WARNING) << "Incorrect rrtr block size " << block_length
<< " Should be " << Rrtr::kBlockLength;
return;
}
rrtr_blocks_.push_back(Rrtr());
rrtr_blocks_.back().Parse(block);
}
void ExtendedReports::ParseDlrrBlock(const uint8_t* block,
uint16_t block_length) {
dlrr_blocks_.push_back(Dlrr());
if (!dlrr_blocks_.back().Parse(block, block_length)) {
dlrr_blocks_.pop_back();
}
}
void ExtendedReports::ParseVoipMetricBlock(const uint8_t* block,
uint16_t block_length) {
if (block_length != VoipMetric::kBlockLength) {
LOG(LS_WARNING) << "Incorrect voip metric block size " << block_length
<< " Should be " << VoipMetric::kBlockLength;
return;
}
voip_metric_blocks_.push_back(VoipMetric());
voip_metric_blocks_.back().Parse(block);
}
} // namespace rtcp
} // namespace webrtc

View File

@ -25,21 +25,28 @@ namespace rtcp {
// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
class ExtendedReports : public RtcpPacket {
public:
typedef std::vector<RTCPUtility::RTCPPacketXRDLRRReportBlockItem> DlrrBlock;
ExtendedReports() : RtcpPacket() {
memset(&xr_header_, 0, sizeof(xr_header_));
}
static const uint8_t kPacketType = 207;
virtual ~ExtendedReports() {}
ExtendedReports();
~ExtendedReports() override;
void From(uint32_t ssrc) {
xr_header_.OriginatorSSRC = ssrc;
}
// Parse assumes header is already parsed and validated.
bool Parse(const RTCPUtility::RtcpCommonHeader& header,
const uint8_t* payload); // Size of the payload is in the header.
void From(uint32_t ssrc) { sender_ssrc_ = ssrc; }
// Max 50 items of each of {Rrtr, Dlrr, VoipMetric} allowed per Xr.
bool WithRrtr(Rrtr* rrtr);
bool WithDlrr(Dlrr* dlrr);
bool WithVoipMetric(VoipMetric* voip_metric);
bool WithRrtr(const Rrtr& rrtr);
bool WithDlrr(const Dlrr& dlrr);
bool WithVoipMetric(const VoipMetric& voip_metric);
uint32_t sender_ssrc() const { return sender_ssrc_; }
const std::vector<Rrtr>& rrtrs() const { return rrtr_blocks_; }
const std::vector<Dlrr>& dlrrs() const { return dlrr_blocks_; }
const std::vector<VoipMetric>& voip_metrics() const {
return voip_metric_blocks_;
}
protected:
bool Create(uint8_t* packet,
@ -48,31 +55,33 @@ class ExtendedReports : public RtcpPacket {
RtcpPacket::PacketReadyCallback* callback) const override;
private:
static const int kMaxNumberOfRrtrBlocks = 50;
static const int kMaxNumberOfDlrrBlocks = 50;
static const int kMaxNumberOfVoipMetricBlocks = 50;
static const size_t kMaxNumberOfRrtrBlocks = 50;
static const size_t kMaxNumberOfDlrrBlocks = 50;
static const size_t kMaxNumberOfVoipMetricBlocks = 50;
static const size_t kXrBaseLength = 4;
size_t BlockLength() const {
const size_t kXrHeaderLength = 8;
return kXrHeaderLength + RrtrLength() + DlrrLength() + VoipMetricLength();
size_t BlockLength() const override {
return kHeaderLength + kXrBaseLength + RrtrLength() + DlrrLength() +
VoipMetricLength();
}
size_t RrtrLength() const { return Rrtr::kLength * rrtr_blocks_.size(); }
size_t DlrrLength() const;
size_t VoipMetricLength() const {
return VoipMetric::kLength * voip_metric_blocks_.size();
}
RTCPUtility::RTCPPacketXR xr_header_;
void ParseRrtrBlock(const uint8_t* block, uint16_t block_length);
void ParseDlrrBlock(const uint8_t* block, uint16_t block_length);
void ParseVoipMetricBlock(const uint8_t* block, uint16_t block_length);
uint32_t sender_ssrc_;
std::vector<Rrtr> rrtr_blocks_;
std::vector<Dlrr> dlrr_blocks_;
std::vector<VoipMetric> voip_metric_blocks_;
RTC_DISALLOW_COPY_AND_ASSIGN(ExtendedReports);
};
} // namespace rtcp
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_REPORTS_H_

View File

@ -12,253 +12,342 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/test/rtcp_packet_parser.h"
#include "webrtc/base/random.h"
using testing::ElementsAre;
using testing::ElementsAreArray;
using testing::IsEmpty;
using testing::make_tuple;
using webrtc::rtcp::Dlrr;
using webrtc::rtcp::ExtendedReports;
using webrtc::rtcp::RawPacket;
using webrtc::rtcp::ReceiveTimeInfo;
using webrtc::rtcp::Rrtr;
using webrtc::rtcp::VoipMetric;
using webrtc::test::RtcpPacketParser;
using webrtc::RTCPUtility::RtcpCommonHeader;
using webrtc::RTCPUtility::RtcpParseCommonHeader;
namespace webrtc {
// Define comparision operators that shouldn't be needed in production,
// but make testing matches more clear.
bool operator==(const RTCPVoIPMetric& metric1, const RTCPVoIPMetric& metric2) {
return metric1.lossRate == metric2.lossRate &&
metric1.discardRate == metric2.discardRate &&
metric1.burstDensity == metric2.burstDensity &&
metric1.gapDensity == metric2.gapDensity &&
metric1.burstDuration == metric2.burstDuration &&
metric1.gapDuration == metric2.gapDuration &&
metric1.roundTripDelay == metric2.roundTripDelay &&
metric1.endSystemDelay == metric2.endSystemDelay &&
metric1.signalLevel == metric2.signalLevel &&
metric1.noiseLevel == metric2.noiseLevel &&
metric1.RERL == metric2.RERL &&
metric1.Gmin == metric2.Gmin &&
metric1.Rfactor == metric2.Rfactor &&
metric1.extRfactor == metric2.extRfactor &&
metric1.MOSLQ == metric2.MOSLQ &&
metric1.MOSCQ == metric2.MOSCQ &&
metric1.RXconfig == metric2.RXconfig &&
metric1.JBnominal == metric2.JBnominal &&
metric1.JBmax == metric2.JBmax &&
metric1.JBabsMax == metric2.JBabsMax;
}
namespace rtcp {
const uint32_t kSenderSsrc = 0x12345678;
const uint32_t kRemoteSsrc = 0x23456789;
TEST(RtcpPacketExtendedReportsTest, WithNoReportBlocks) {
ExtendedReports xr;
xr.From(kSenderSsrc);
rtc::scoped_ptr<RawPacket> packet(xr.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.xr_header()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
bool operator==(const Rrtr& rrtr1, const Rrtr& rrtr2) {
return rrtr1.ntp() == rrtr2.ntp();
}
TEST(RtcpPacketExtendedReportsTest, WithRrtr) {
Rrtr rrtr;
rrtr.WithNtp(NtpTime(0x11111111, 0x22222222));
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithRrtr(&rrtr));
rtc::scoped_ptr<RawPacket> packet(xr.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.xr_header()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
EXPECT_EQ(1, parser.rrtr()->num_packets());
EXPECT_EQ(0x11111111U, parser.rrtr()->NtpSec());
EXPECT_EQ(0x22222222U, parser.rrtr()->NtpFrac());
bool operator==(const ReceiveTimeInfo& time1, const ReceiveTimeInfo& time2) {
return time1.ssrc == time2.ssrc &&
time1.last_rr == time2.last_rr &&
time1.delay_since_last_rr == time2.delay_since_last_rr;
}
TEST(RtcpPacketExtendedReportsTest, WithTwoRrtrBlocks) {
Rrtr rrtr1;
rrtr1.WithNtp(NtpTime(0x11111111, 0x22222222));
Rrtr rrtr2;
rrtr2.WithNtp(NtpTime(0x33333333, 0x44444444));
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithRrtr(&rrtr1));
EXPECT_TRUE(xr.WithRrtr(&rrtr2));
rtc::scoped_ptr<RawPacket> packet(xr.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.xr_header()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
EXPECT_EQ(2, parser.rrtr()->num_packets());
EXPECT_EQ(0x33333333U, parser.rrtr()->NtpSec());
EXPECT_EQ(0x44444444U, parser.rrtr()->NtpFrac());
bool operator==(const Dlrr& dlrr1, const Dlrr& dlrr2) {
return dlrr1.sub_blocks() == dlrr2.sub_blocks();
}
TEST(RtcpPacketExtendedReportsTest, WithDlrrWithOneSubBlock) {
Dlrr dlrr;
EXPECT_TRUE(dlrr.WithDlrrItem(0x11111111, 0x22222222, 0x33333333));
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithDlrr(&dlrr));
rtc::scoped_ptr<RawPacket> packet(xr.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.xr_header()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
EXPECT_EQ(1, parser.dlrr()->num_packets());
EXPECT_EQ(1, parser.dlrr_items()->num_packets());
EXPECT_EQ(0x11111111U, parser.dlrr_items()->Ssrc(0));
EXPECT_EQ(0x22222222U, parser.dlrr_items()->LastRr(0));
EXPECT_EQ(0x33333333U, parser.dlrr_items()->DelayLastRr(0));
}
TEST(RtcpPacketExtendedReportsTest, WithDlrrWithTwoSubBlocks) {
Dlrr dlrr;
EXPECT_TRUE(dlrr.WithDlrrItem(0x11111111, 0x22222222, 0x33333333));
EXPECT_TRUE(dlrr.WithDlrrItem(0x44444444, 0x55555555, 0x66666666));
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithDlrr(&dlrr));
rtc::scoped_ptr<RawPacket> packet(xr.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.xr_header()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
EXPECT_EQ(1, parser.dlrr()->num_packets());
EXPECT_EQ(2, parser.dlrr_items()->num_packets());
EXPECT_EQ(0x11111111U, parser.dlrr_items()->Ssrc(0));
EXPECT_EQ(0x22222222U, parser.dlrr_items()->LastRr(0));
EXPECT_EQ(0x33333333U, parser.dlrr_items()->DelayLastRr(0));
EXPECT_EQ(0x44444444U, parser.dlrr_items()->Ssrc(1));
EXPECT_EQ(0x55555555U, parser.dlrr_items()->LastRr(1));
EXPECT_EQ(0x66666666U, parser.dlrr_items()->DelayLastRr(1));
}
TEST(RtcpPacketExtendedReportsTest, WithTwoDlrrBlocks) {
Dlrr dlrr1;
EXPECT_TRUE(dlrr1.WithDlrrItem(0x11111111, 0x22222222, 0x33333333));
Dlrr dlrr2;
EXPECT_TRUE(dlrr2.WithDlrrItem(0x44444444, 0x55555555, 0x66666666));
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithDlrr(&dlrr1));
EXPECT_TRUE(xr.WithDlrr(&dlrr2));
rtc::scoped_ptr<RawPacket> packet(xr.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.xr_header()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
EXPECT_EQ(2, parser.dlrr()->num_packets());
EXPECT_EQ(2, parser.dlrr_items()->num_packets());
EXPECT_EQ(0x11111111U, parser.dlrr_items()->Ssrc(0));
EXPECT_EQ(0x22222222U, parser.dlrr_items()->LastRr(0));
EXPECT_EQ(0x33333333U, parser.dlrr_items()->DelayLastRr(0));
EXPECT_EQ(0x44444444U, parser.dlrr_items()->Ssrc(1));
EXPECT_EQ(0x55555555U, parser.dlrr_items()->LastRr(1));
EXPECT_EQ(0x66666666U, parser.dlrr_items()->DelayLastRr(1));
}
TEST(RtcpPacketExtendedReportsTest, WithVoipMetric) {
RTCPVoIPMetric metric;
metric.lossRate = 1;
metric.discardRate = 2;
metric.burstDensity = 3;
metric.gapDensity = 4;
metric.burstDuration = 0x1111;
metric.gapDuration = 0x2222;
metric.roundTripDelay = 0x3333;
metric.endSystemDelay = 0x4444;
metric.signalLevel = 5;
metric.noiseLevel = 6;
metric.RERL = 7;
metric.Gmin = 8;
metric.Rfactor = 9;
metric.extRfactor = 10;
metric.MOSLQ = 11;
metric.MOSCQ = 12;
metric.RXconfig = 13;
metric.JBnominal = 0x5555;
metric.JBmax = 0x6666;
metric.JBabsMax = 0x7777;
VoipMetric metric_block;
metric_block.To(kRemoteSsrc);
metric_block.WithVoipMetric(metric);
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithVoipMetric(&metric_block));
rtc::scoped_ptr<RawPacket> packet(xr.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.xr_header()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
EXPECT_EQ(1, parser.voip_metric()->num_packets());
EXPECT_EQ(kRemoteSsrc, parser.voip_metric()->Ssrc());
EXPECT_EQ(1, parser.voip_metric()->LossRate());
EXPECT_EQ(2, parser.voip_metric()->DiscardRate());
EXPECT_EQ(3, parser.voip_metric()->BurstDensity());
EXPECT_EQ(4, parser.voip_metric()->GapDensity());
EXPECT_EQ(0x1111, parser.voip_metric()->BurstDuration());
EXPECT_EQ(0x2222, parser.voip_metric()->GapDuration());
EXPECT_EQ(0x3333, parser.voip_metric()->RoundTripDelay());
EXPECT_EQ(0x4444, parser.voip_metric()->EndSystemDelay());
EXPECT_EQ(5, parser.voip_metric()->SignalLevel());
EXPECT_EQ(6, parser.voip_metric()->NoiseLevel());
EXPECT_EQ(7, parser.voip_metric()->Rerl());
EXPECT_EQ(8, parser.voip_metric()->Gmin());
EXPECT_EQ(9, parser.voip_metric()->Rfactor());
EXPECT_EQ(10, parser.voip_metric()->ExtRfactor());
EXPECT_EQ(11, parser.voip_metric()->MosLq());
EXPECT_EQ(12, parser.voip_metric()->MosCq());
EXPECT_EQ(13, parser.voip_metric()->RxConfig());
EXPECT_EQ(0x5555, parser.voip_metric()->JbNominal());
EXPECT_EQ(0x6666, parser.voip_metric()->JbMax());
EXPECT_EQ(0x7777, parser.voip_metric()->JbAbsMax());
}
TEST(RtcpPacketExtendedReportsTest, WithMultipleReportBlocks) {
Rrtr rrtr;
Dlrr dlrr;
EXPECT_TRUE(dlrr.WithDlrrItem(1, 2, 3));
VoipMetric metric;
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithRrtr(&rrtr));
EXPECT_TRUE(xr.WithDlrr(&dlrr));
EXPECT_TRUE(xr.WithVoipMetric(&metric));
rtc::scoped_ptr<RawPacket> packet(xr.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.xr_header()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
EXPECT_EQ(1, parser.rrtr()->num_packets());
EXPECT_EQ(1, parser.dlrr()->num_packets());
EXPECT_EQ(1, parser.dlrr_items()->num_packets());
EXPECT_EQ(1, parser.voip_metric()->num_packets());
}
TEST(RtcpPacketExtendedReportsTest, DlrrWithoutItemNotIncludedInPacket) {
Rrtr rrtr;
Dlrr dlrr;
VoipMetric metric;
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithRrtr(&rrtr));
EXPECT_TRUE(xr.WithDlrr(&dlrr));
EXPECT_TRUE(xr.WithVoipMetric(&metric));
rtc::scoped_ptr<RawPacket> packet(xr.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.xr_header()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.xr_header()->Ssrc());
EXPECT_EQ(1, parser.rrtr()->num_packets());
EXPECT_EQ(0, parser.dlrr()->num_packets());
EXPECT_EQ(1, parser.voip_metric()->num_packets());
}
TEST(RtcpPacketExtendedReportsTest, WithTooManyBlocks) {
const int kMaxBlocks = 50;
ExtendedReports xr;
Rrtr rrtr;
for (int i = 0; i < kMaxBlocks; ++i)
EXPECT_TRUE(xr.WithRrtr(&rrtr));
EXPECT_FALSE(xr.WithRrtr(&rrtr));
Dlrr dlrr;
for (int i = 0; i < kMaxBlocks; ++i)
EXPECT_TRUE(xr.WithDlrr(&dlrr));
EXPECT_FALSE(xr.WithDlrr(&dlrr));
VoipMetric voip_metric;
for (int i = 0; i < kMaxBlocks; ++i)
EXPECT_TRUE(xr.WithVoipMetric(&voip_metric));
EXPECT_FALSE(xr.WithVoipMetric(&voip_metric));
bool operator==(const VoipMetric& metric1, const VoipMetric& metric2) {
return metric1.ssrc() == metric2.ssrc() &&
metric1.voip_metric() == metric2.voip_metric();
}
} // namespace rtcp
namespace {
const uint32_t kSenderSsrc = 0x12345678;
const uint8_t kEmptyPacket[8] = {0x80, 207, 0x00, 0x01,
0x12, 0x34, 0x56, 0x78};
bool Parse(const uint8_t* buffer,
size_t length,
ExtendedReports* packet) {
RtcpCommonHeader header;
EXPECT_TRUE(RtcpParseCommonHeader(buffer, length, &header));
EXPECT_EQ(length, header.BlockSize());
return packet->Parse(header, buffer + RtcpCommonHeader::kHeaderSizeBytes);
}
bool Parse(const RawPacket& buffer, ExtendedReports* packet) {
return Parse(buffer.Buffer(), buffer.Length(), packet);
}
} // namespace
class RtcpPacketExtendedReportsTest : public ::testing::Test {
public:
RtcpPacketExtendedReportsTest() : random_(0x123456789) {}
protected:
template <typename T>
T Rand() {
return random_.Rand<T>();
}
private:
Random random_;
};
template <>
ReceiveTimeInfo RtcpPacketExtendedReportsTest::Rand<ReceiveTimeInfo>() {
uint32_t ssrc = Rand<uint32_t>();
uint32_t last_rr = Rand<uint32_t>();
uint32_t delay_since_last_rr = Rand<uint32_t>();
return ReceiveTimeInfo(ssrc, last_rr, delay_since_last_rr);
}
template <>
NtpTime RtcpPacketExtendedReportsTest::Rand<NtpTime>() {
uint32_t secs = Rand<uint32_t>();
uint32_t frac = Rand<uint32_t>();
return NtpTime(secs, frac);
}
template <>
Rrtr RtcpPacketExtendedReportsTest::Rand<Rrtr>() {
Rrtr rrtr;
rrtr.WithNtp(Rand<NtpTime>());
return rrtr;
}
template <>
RTCPVoIPMetric RtcpPacketExtendedReportsTest::Rand<RTCPVoIPMetric>() {
RTCPVoIPMetric metric;
metric.lossRate = Rand<uint8_t>();
metric.discardRate = Rand<uint8_t>();
metric.burstDensity = Rand<uint8_t>();
metric.gapDensity = Rand<uint8_t>();
metric.burstDuration = Rand<uint16_t>();
metric.gapDuration = Rand<uint16_t>();
metric.roundTripDelay = Rand<uint16_t>();
metric.endSystemDelay = Rand<uint16_t>();
metric.signalLevel = Rand<uint8_t>();
metric.noiseLevel = Rand<uint8_t>();
metric.RERL = Rand<uint8_t>();
metric.Gmin = Rand<uint8_t>();
metric.Rfactor = Rand<uint8_t>();
metric.extRfactor = Rand<uint8_t>();
metric.MOSLQ = Rand<uint8_t>();
metric.MOSCQ = Rand<uint8_t>();
metric.RXconfig = Rand<uint8_t>();
metric.JBnominal = Rand<uint16_t>();
metric.JBmax = Rand<uint16_t>();
metric.JBabsMax = Rand<uint16_t>();
return metric;
}
template <>
VoipMetric RtcpPacketExtendedReportsTest::Rand<VoipMetric>() {
VoipMetric voip_metric;
voip_metric.To(Rand<uint32_t>());
voip_metric.WithVoipMetric(Rand<RTCPVoIPMetric>());
return voip_metric;
}
TEST_F(RtcpPacketExtendedReportsTest, CreateWithoutReportBlocks) {
ExtendedReports xr;
xr.From(kSenderSsrc);
rtc::scoped_ptr<RawPacket> packet = xr.Build();
EXPECT_THAT(make_tuple(packet->Buffer(), packet->Length()),
ElementsAreArray(kEmptyPacket));
}
TEST_F(RtcpPacketExtendedReportsTest, ParseWithoutReportBlocks) {
ExtendedReports parsed;
EXPECT_TRUE(Parse(kEmptyPacket, sizeof(kEmptyPacket), &parsed));
EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
EXPECT_THAT(parsed.rrtrs(), IsEmpty());
EXPECT_THAT(parsed.dlrrs(), IsEmpty());
EXPECT_THAT(parsed.voip_metrics(), IsEmpty());
}
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithOneRrtrBlock) {
Rrtr rrtr = Rand<Rrtr>();
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithRrtr(rrtr));
rtc::scoped_ptr<RawPacket> packet = xr.Build();
ExtendedReports mparsed;
EXPECT_TRUE(Parse(*packet, &mparsed));
const ExtendedReports& parsed = mparsed;
EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
EXPECT_THAT(parsed.rrtrs(), ElementsAre(rrtr));
}
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithTwoRrtrBlocks) {
Rrtr rrtr1 = Rand<Rrtr>();
Rrtr rrtr2 = Rand<Rrtr>();
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithRrtr(rrtr1));
EXPECT_TRUE(xr.WithRrtr(rrtr2));
rtc::scoped_ptr<RawPacket> packet = xr.Build();
ExtendedReports mparsed;
EXPECT_TRUE(Parse(*packet, &mparsed));
const ExtendedReports& parsed = mparsed;
EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
EXPECT_THAT(parsed.rrtrs(), ElementsAre(rrtr1, rrtr2));
}
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithDlrrWithOneSubBlock) {
Dlrr dlrr;
EXPECT_TRUE(dlrr.WithDlrrItem(Rand<ReceiveTimeInfo>()));
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithDlrr(dlrr));
rtc::scoped_ptr<RawPacket> packet = xr.Build();
ExtendedReports mparsed;
EXPECT_TRUE(Parse(*packet, &mparsed));
const ExtendedReports& parsed = mparsed;
EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
EXPECT_THAT(parsed.dlrrs(), ElementsAre(dlrr));
}
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithDlrrWithTwoSubBlocks) {
Dlrr dlrr;
EXPECT_TRUE(dlrr.WithDlrrItem(Rand<ReceiveTimeInfo>()));
EXPECT_TRUE(dlrr.WithDlrrItem(Rand<ReceiveTimeInfo>()));
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithDlrr(dlrr));
rtc::scoped_ptr<RawPacket> packet = xr.Build();
ExtendedReports mparsed;
EXPECT_TRUE(Parse(*packet, &mparsed));
const ExtendedReports& parsed = mparsed;
EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
EXPECT_THAT(parsed.dlrrs(), ElementsAre(dlrr));
}
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithTwoDlrrBlocks) {
Dlrr dlrr1;
EXPECT_TRUE(dlrr1.WithDlrrItem(Rand<ReceiveTimeInfo>()));
Dlrr dlrr2;
EXPECT_TRUE(dlrr2.WithDlrrItem(Rand<ReceiveTimeInfo>()));
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithDlrr(dlrr1));
EXPECT_TRUE(xr.WithDlrr(dlrr2));
rtc::scoped_ptr<RawPacket> packet = xr.Build();
ExtendedReports mparsed;
EXPECT_TRUE(Parse(*packet, &mparsed));
const ExtendedReports& parsed = mparsed;
EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
EXPECT_THAT(parsed.dlrrs(), ElementsAre(dlrr1, dlrr2));
}
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithVoipMetric) {
VoipMetric voip_metric = Rand<VoipMetric>();
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithVoipMetric(voip_metric));
rtc::scoped_ptr<RawPacket> packet = xr.Build();
ExtendedReports mparsed;
EXPECT_TRUE(Parse(*packet, &mparsed));
const ExtendedReports& parsed = mparsed;
EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
EXPECT_THAT(parsed.voip_metrics(), ElementsAre(voip_metric));
}
TEST_F(RtcpPacketExtendedReportsTest, CreateAndParseWithMultipleReportBlocks) {
Rrtr rrtr = Rand<Rrtr>();
Dlrr dlrr;
EXPECT_TRUE(dlrr.WithDlrrItem(Rand<ReceiveTimeInfo>()));
VoipMetric metric = Rand<VoipMetric>();
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithRrtr(rrtr));
EXPECT_TRUE(xr.WithDlrr(dlrr));
EXPECT_TRUE(xr.WithVoipMetric(metric));
rtc::scoped_ptr<RawPacket> packet = xr.Build();
ExtendedReports mparsed;
EXPECT_TRUE(Parse(*packet, &mparsed));
const ExtendedReports& parsed = mparsed;
EXPECT_EQ(kSenderSsrc, parsed.sender_ssrc());
EXPECT_THAT(parsed.rrtrs(), ElementsAre(rrtr));
EXPECT_THAT(parsed.dlrrs(), ElementsAre(dlrr));
EXPECT_THAT(parsed.voip_metrics(), ElementsAre(metric));
}
TEST_F(RtcpPacketExtendedReportsTest, DlrrWithoutItemNotIncludedInPacket) {
Rrtr rrtr = Rand<Rrtr>();
Dlrr dlrr;
VoipMetric metric = Rand<VoipMetric>();
ExtendedReports xr;
xr.From(kSenderSsrc);
EXPECT_TRUE(xr.WithRrtr(rrtr));
EXPECT_TRUE(xr.WithDlrr(dlrr));
EXPECT_TRUE(xr.WithVoipMetric(metric));
rtc::scoped_ptr<RawPacket> packet = xr.Build();
ExtendedReports mparsed;
EXPECT_TRUE(Parse(*packet, &mparsed));
const ExtendedReports& parsed = mparsed;
EXPECT_THAT(parsed.rrtrs(), ElementsAre(rrtr));
EXPECT_THAT(parsed.dlrrs(), IsEmpty());
EXPECT_THAT(parsed.voip_metrics(), ElementsAre(metric));
}
TEST_F(RtcpPacketExtendedReportsTest, WithTooManyBlocks) {
const size_t kMaxBlocks = 50;
ExtendedReports xr;
Rrtr rrtr = Rand<Rrtr>();
for (size_t i = 0; i < kMaxBlocks; ++i)
EXPECT_TRUE(xr.WithRrtr(rrtr));
EXPECT_FALSE(xr.WithRrtr(rrtr));
Dlrr dlrr;
for (size_t i = 0; i < kMaxBlocks; ++i)
EXPECT_TRUE(xr.WithDlrr(dlrr));
EXPECT_FALSE(xr.WithDlrr(dlrr));
VoipMetric voip_metric = Rand<VoipMetric>();
for (size_t i = 0; i < kMaxBlocks; ++i)
EXPECT_TRUE(xr.WithVoipMetric(voip_metric));
EXPECT_FALSE(xr.WithVoipMetric(voip_metric));
}
} // namespace webrtc

View File

@ -602,7 +602,7 @@ TEST_F(RtcpReceiverTest, InjectExtendedReportsVoipPacket) {
voip_metric.WithVoipMetric(metric);
rtcp::ExtendedReports xr;
xr.From(0x2345);
xr.WithVoipMetric(&voip_metric);
xr.WithVoipMetric(voip_metric);
rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build());
EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
ASSERT_TRUE(rtcp_packet_info_.VoIPMetric != nullptr);
@ -620,7 +620,7 @@ TEST_F(RtcpReceiverTest, ExtendedReportsVoipPacketNotToUsIgnored) {
voip_metric.To(kSourceSsrc + 1);
rtcp::ExtendedReports xr;
xr.From(0x2345);
xr.WithVoipMetric(&voip_metric);
xr.WithVoipMetric(voip_metric);
rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build());
EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags);
@ -631,7 +631,7 @@ TEST_F(RtcpReceiverTest, InjectExtendedReportsReceiverReferenceTimePacket) {
rrtr.WithNtp(NtpTime(0x10203, 0x40506));
rtcp::ExtendedReports xr;
xr.From(0x2345);
xr.WithRrtr(&rrtr);
xr.WithRrtr(rrtr);
rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build());
EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
@ -649,7 +649,7 @@ TEST_F(RtcpReceiverTest, ExtendedReportsDlrrPacketNotToUsIgnored) {
dlrr.WithDlrrItem(kSourceSsrc + 1, 0x12345, 0x67890);
rtcp::ExtendedReports xr;
xr.From(0x2345);
xr.WithDlrr(&dlrr);
xr.WithDlrr(dlrr);
rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build());
EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags);
@ -666,7 +666,7 @@ TEST_F(RtcpReceiverTest, InjectExtendedReportsDlrrPacketWithSubBlock) {
dlrr.WithDlrrItem(kSourceSsrc, 0x12345, 0x67890);
rtcp::ExtendedReports xr;
xr.From(0x2345);
xr.WithDlrr(&dlrr);
xr.WithDlrr(dlrr);
rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build());
EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
// The parser should note the DLRR report block item, but not flag the packet
@ -686,7 +686,7 @@ TEST_F(RtcpReceiverTest, InjectExtendedReportsDlrrPacketWithMultipleSubBlocks) {
dlrr.WithDlrrItem(kSourceSsrc, 0x12345, 0x67890);
rtcp::ExtendedReports xr;
xr.From(0x2345);
xr.WithDlrr(&dlrr);
xr.WithDlrr(dlrr);
rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build());
EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
// The parser should note the DLRR report block item, but not flag the packet
@ -707,9 +707,9 @@ TEST_F(RtcpReceiverTest, InjectExtendedReportsPacketWithMultipleReportBlocks) {
metric.To(kSourceSsrc);
rtcp::ExtendedReports xr;
xr.From(0x2345);
xr.WithRrtr(&rrtr);
xr.WithDlrr(&dlrr);
xr.WithVoipMetric(&metric);
xr.WithRrtr(rrtr);
xr.WithDlrr(dlrr);
xr.WithVoipMetric(metric);
rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build());
EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
EXPECT_EQ(static_cast<unsigned int>(kRtcpXrReceiverReferenceTime +
@ -735,9 +735,9 @@ TEST_F(RtcpReceiverTest, InjectExtendedReportsPacketWithUnknownReportBlock) {
metric.To(kSourceSsrc);
rtcp::ExtendedReports xr;
xr.From(0x2345);
xr.WithRrtr(&rrtr);
xr.WithDlrr(&dlrr);
xr.WithVoipMetric(&metric);
xr.WithRrtr(rrtr);
xr.WithDlrr(dlrr);
xr.WithVoipMetric(metric);
rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build());
// Modify the DLRR block to have an unsupported block type, from 5 to 6.
uint8_t* buffer = const_cast<uint8_t*>(packet->Buffer());
@ -771,7 +771,7 @@ TEST_F(RtcpReceiverTest, GetLastReceivedExtendedReportsReferenceTimeInfo) {
rrtr.WithNtp(kNtp);
rtcp::ExtendedReports xr;
xr.From(kSenderSsrc);
xr.WithRrtr(&rrtr);
xr.WithRrtr(rrtr);
rtc::scoped_ptr<rtcp::RawPacket> packet(xr.Build());
EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length()));
EXPECT_EQ(kRtcpXrReceiverReferenceTime,

View File

@ -762,7 +762,7 @@ rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildReceiverReferenceTime(
rtcp::Rrtr rrtr;
rrtr.WithNtp(NtpTime(ctx.ntp_sec_, ctx.ntp_frac_));
xr->WithRrtr(&rrtr);
xr->WithRrtr(rrtr);
// TODO(sprang): Merge XR report sending to contain all of RRTR, DLRR, VOIP?
@ -778,7 +778,7 @@ rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildDlrr(
const RtcpReceiveTimeInfo& info = ctx.feedback_state_.last_xr_rr;
dlrr.WithDlrrItem(info.sourceSSRC, info.lastRR, info.delaySinceLastRR);
xr->WithDlrr(&dlrr);
xr->WithDlrr(dlrr);
return rtc::scoped_ptr<rtcp::RtcpPacket>(xr);
}
@ -793,7 +793,7 @@ rtc::scoped_ptr<rtcp::RtcpPacket> RTCPSender::BuildVoIPMetric(
voip.To(remote_ssrc_);
voip.WithVoipMetric(xr_voip_metric_);
xr->WithVoipMetric(&voip);
xr->WithVoipMetric(voip);
return rtc::scoped_ptr<rtcp::RtcpPacket>(xr);
}