From de13882d9471bf18709e52fa9a9eac1378b359be Mon Sep 17 00:00:00 2001 From: danilchap Date: Fri, 29 Jan 2016 11:26:14 -0800 Subject: [PATCH] rtcp::ExtenededReports packet class got Parse function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG=webrtc:5260 R=åsapersson Review URL: https://codereview.webrtc.org/1557593002 Cr-Commit-Position: refs/heads/master@{#11428} --- .../source/rtcp_packet/extended_reports.cc | 171 ++++-- .../source/rtcp_packet/extended_reports.h | 51 +- .../rtcp_packet/extended_reports_unittest.cc | 553 ++++++++++-------- .../rtp_rtcp/source/rtcp_receiver_unittest.cc | 26 +- webrtc/modules/rtp_rtcp/source/rtcp_sender.cc | 6 +- 5 files changed, 491 insertions(+), 316 deletions(-) diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc index a78ad464b7..243e4b743f 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.cc @@ -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::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::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::ReadBigEndian(current_block); + uint16_t block_length = + ByteReader::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::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 diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h index 6afac360e5..a85576db2d 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports.h @@ -25,21 +25,28 @@ namespace rtcp { // From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR). class ExtendedReports : public RtcpPacket { public: - typedef std::vector 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& rrtrs() const { return rrtr_blocks_; } + const std::vector& dlrrs() const { return dlrr_blocks_; } + const std::vector& 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_blocks_; std::vector dlrr_blocks_; std::vector voip_metric_blocks_; RTC_DISALLOW_COPY_AND_ASSIGN(ExtendedReports); }; - } // namespace rtcp } // namespace webrtc #endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_REPORTS_H_ diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc index e329213ba6..6716c01327 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_reports_unittest.cc @@ -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 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 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 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 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 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 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 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 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 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 + T Rand() { + return random_.Rand(); + } + + private: + Random random_; +}; + +template <> +ReceiveTimeInfo RtcpPacketExtendedReportsTest::Rand() { + uint32_t ssrc = Rand(); + uint32_t last_rr = Rand(); + uint32_t delay_since_last_rr = Rand(); + return ReceiveTimeInfo(ssrc, last_rr, delay_since_last_rr); +} + +template <> +NtpTime RtcpPacketExtendedReportsTest::Rand() { + uint32_t secs = Rand(); + uint32_t frac = Rand(); + return NtpTime(secs, frac); +} + +template <> +Rrtr RtcpPacketExtendedReportsTest::Rand() { + Rrtr rrtr; + rrtr.WithNtp(Rand()); + return rrtr; +} + +template <> +RTCPVoIPMetric RtcpPacketExtendedReportsTest::Rand() { + RTCPVoIPMetric metric; + metric.lossRate = Rand(); + metric.discardRate = Rand(); + metric.burstDensity = Rand(); + metric.gapDensity = Rand(); + metric.burstDuration = Rand(); + metric.gapDuration = Rand(); + metric.roundTripDelay = Rand(); + metric.endSystemDelay = Rand(); + metric.signalLevel = Rand(); + metric.noiseLevel = Rand(); + metric.RERL = Rand(); + metric.Gmin = Rand(); + metric.Rfactor = Rand(); + metric.extRfactor = Rand(); + metric.MOSLQ = Rand(); + metric.MOSCQ = Rand(); + metric.RXconfig = Rand(); + metric.JBnominal = Rand(); + metric.JBmax = Rand(); + metric.JBabsMax = Rand(); + return metric; +} + +template <> +VoipMetric RtcpPacketExtendedReportsTest::Rand() { + VoipMetric voip_metric; + voip_metric.To(Rand()); + voip_metric.WithVoipMetric(Rand()); + return voip_metric; +} + +TEST_F(RtcpPacketExtendedReportsTest, CreateWithoutReportBlocks) { + ExtendedReports xr; + xr.From(kSenderSsrc); + + rtc::scoped_ptr 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(); + ExtendedReports xr; + xr.From(kSenderSsrc); + EXPECT_TRUE(xr.WithRrtr(rrtr)); + rtc::scoped_ptr 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 rrtr2 = Rand(); + ExtendedReports xr; + xr.From(kSenderSsrc); + EXPECT_TRUE(xr.WithRrtr(rrtr1)); + EXPECT_TRUE(xr.WithRrtr(rrtr2)); + + rtc::scoped_ptr 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())); + ExtendedReports xr; + xr.From(kSenderSsrc); + EXPECT_TRUE(xr.WithDlrr(dlrr)); + + rtc::scoped_ptr 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())); + EXPECT_TRUE(dlrr.WithDlrrItem(Rand())); + ExtendedReports xr; + xr.From(kSenderSsrc); + EXPECT_TRUE(xr.WithDlrr(dlrr)); + + rtc::scoped_ptr 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())); + Dlrr dlrr2; + EXPECT_TRUE(dlrr2.WithDlrrItem(Rand())); + ExtendedReports xr; + xr.From(kSenderSsrc); + EXPECT_TRUE(xr.WithDlrr(dlrr1)); + EXPECT_TRUE(xr.WithDlrr(dlrr2)); + + rtc::scoped_ptr 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(); + + ExtendedReports xr; + xr.From(kSenderSsrc); + EXPECT_TRUE(xr.WithVoipMetric(voip_metric)); + + rtc::scoped_ptr 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(); + Dlrr dlrr; + EXPECT_TRUE(dlrr.WithDlrrItem(Rand())); + VoipMetric metric = Rand(); + ExtendedReports xr; + xr.From(kSenderSsrc); + EXPECT_TRUE(xr.WithRrtr(rrtr)); + EXPECT_TRUE(xr.WithDlrr(dlrr)); + EXPECT_TRUE(xr.WithVoipMetric(metric)); + + rtc::scoped_ptr 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(); + Dlrr dlrr; + VoipMetric metric = Rand(); + ExtendedReports xr; + xr.From(kSenderSsrc); + EXPECT_TRUE(xr.WithRrtr(rrtr)); + EXPECT_TRUE(xr.WithDlrr(dlrr)); + EXPECT_TRUE(xr.WithVoipMetric(metric)); + + rtc::scoped_ptr 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(); + 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(); + for (size_t i = 0; i < kMaxBlocks; ++i) + EXPECT_TRUE(xr.WithVoipMetric(voip_metric)); + EXPECT_FALSE(xr.WithVoipMetric(voip_metric)); +} } // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc index 7ec10bdb29..e0c70c2b5c 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc @@ -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 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 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 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 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 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 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 packet(xr.Build()); EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); EXPECT_EQ(static_cast(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 packet(xr.Build()); // Modify the DLRR block to have an unsupported block type, from 5 to 6. uint8_t* buffer = const_cast(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 packet(xr.Build()); EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); EXPECT_EQ(kRtcpXrReceiverReferenceTime, diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc index 37ea6922f7..b8ef58fd22 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc @@ -762,7 +762,7 @@ rtc::scoped_ptr 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 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(xr); } @@ -793,7 +793,7 @@ rtc::scoped_ptr RTCPSender::BuildVoIPMetric( voip.To(remote_ssrc_); voip.WithVoipMetric(xr_voip_metric_); - xr->WithVoipMetric(&voip); + xr->WithVoipMetric(voip); return rtc::scoped_ptr(xr); }