diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index 9db7cfdb7a..eaedf6086c 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -247,6 +247,7 @@ 'rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc', 'rtp_rtcp/source/rtcp_format_remb_unittest.cc', 'rtp_rtcp/source/rtcp_packet_unittest.cc', + 'rtp_rtcp/source/rtcp_packet/report_block_unittest.cc', 'rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc', 'rtp_rtcp/source/rtcp_receiver_unittest.cc', 'rtp_rtcp/source/rtcp_sender_unittest.cc', diff --git a/webrtc/modules/rtp_rtcp/BUILD.gn b/webrtc/modules/rtp_rtcp/BUILD.gn index 6239c0420d..fb6a1e8959 100644 --- a/webrtc/modules/rtp_rtcp/BUILD.gn +++ b/webrtc/modules/rtp_rtcp/BUILD.gn @@ -46,6 +46,8 @@ source_set("rtp_rtcp") { "source/remote_ntp_time_estimator.cc", "source/rtcp_packet.cc", "source/rtcp_packet.h", + "source/rtcp_packet/report_block.cc", + "source/rtcp_packet/report_block.h", "source/rtcp_packet/transport_feedback.cc", "source/rtcp_packet/transport_feedback.h", "source/rtcp_receiver.cc", diff --git a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi index 57bea0b2dc..025623d3c3 100644 --- a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi +++ b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi @@ -41,6 +41,8 @@ 'source/rtp_rtcp_impl.h', 'source/rtcp_packet.cc', 'source/rtcp_packet.h', + 'source/rtcp_packet/report_block.cc', + 'source/rtcp_packet/report_block.h', 'source/rtcp_packet/transport_feedback.cc', 'source/rtcp_packet/transport_feedback.h', 'source/rtcp_receiver.cc', diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc index 792caa7b8b..4af3292659 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc @@ -154,18 +154,12 @@ void CreateReceiverReport(const RTCPPacketRR& rr, // | delay since last SR (DLSR) | // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -void CreateReportBlocks(const std::vector& blocks, +void CreateReportBlocks(const std::vector& blocks, uint8_t* buffer, size_t* pos) { - for (std::vector::const_iterator - it = blocks.begin(); it != blocks.end(); ++it) { - AssignUWord32(buffer, pos, (*it).SSRC); - AssignUWord8(buffer, pos, (*it).FractionLost); - AssignUWord24(buffer, pos, (*it).CumulativeNumOfPacketsLost); - AssignUWord32(buffer, pos, (*it).ExtendedHighestSequenceNumber); - AssignUWord32(buffer, pos, (*it).Jitter); - AssignUWord32(buffer, pos, (*it).LastSR); - AssignUWord32(buffer, pos, (*it).DelayLastSR); + for (const ReportBlock& block : blocks) { + block.Create(buffer + *pos); + *pos += ReportBlock::kLength; } } @@ -781,7 +775,7 @@ bool SenderReport::WithReportBlock(const ReportBlock& block) { LOG(LS_WARNING) << "Max report blocks reached."; return false; } - report_blocks_.push_back(block.report_block_); + report_blocks_.push_back(block); sr_.NumberOfReportBlocks = report_blocks_.size(); return true; } @@ -805,7 +799,7 @@ bool ReceiverReport::WithReportBlock(const ReportBlock& block) { LOG(LS_WARNING) << "Max report blocks reached."; return false; } - report_blocks_.push_back(block.report_block_); + report_blocks_.push_back(block); rr_.NumberOfReportBlocks = report_blocks_.size(); return true; } diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h index 2956bc7bea..85aa438b89 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h @@ -17,6 +17,7 @@ #include #include "webrtc/base/scoped_ptr.h" +#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "webrtc/typedefs.h" @@ -145,63 +146,6 @@ class Empty : public RtcpPacket { RTC_DISALLOW_COPY_AND_ASSIGN(Empty); }; -// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications. -// -// RTCP report block (RFC 3550). -// -// 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 -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | SSRC_1 (SSRC of first source) | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | fraction lost | cumulative number of packets lost | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | extended highest sequence number received | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | interarrival jitter | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | last SR (LSR) | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | delay since last SR (DLSR) | -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ - -class ReportBlock { - public: - ReportBlock() { - // TODO(asapersson): Consider adding a constructor to struct. - memset(&report_block_, 0, sizeof(report_block_)); - } - - ~ReportBlock() {} - - void To(uint32_t ssrc) { - report_block_.SSRC = ssrc; - } - void WithFractionLost(uint8_t fraction_lost) { - report_block_.FractionLost = fraction_lost; - } - void WithCumulativeLost(uint32_t cumulative_lost) { - report_block_.CumulativeNumOfPacketsLost = cumulative_lost; - } - void WithExtHighestSeqNum(uint32_t ext_highest_seq_num) { - report_block_.ExtendedHighestSequenceNumber = ext_highest_seq_num; - } - void WithJitter(uint32_t jitter) { - report_block_.Jitter = jitter; - } - void WithLastSr(uint32_t last_sr) { - report_block_.LastSR = last_sr; - } - void WithDelayLastSr(uint32_t delay_last_sr) { - report_block_.DelayLastSR = delay_last_sr; - } - - private: - friend class SenderReport; - friend class ReceiverReport; - RTCPUtility::RTCPPacketReportBlockItem report_block_; -}; - // RTCP sender report (RFC 3550). // // 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 @@ -268,7 +212,7 @@ class SenderReport : public RtcpPacket { } RTCPUtility::RTCPPacketSR sr_; - std::vector report_blocks_; + std::vector report_blocks_; RTC_DISALLOW_COPY_AND_ASSIGN(SenderReport); }; @@ -314,7 +258,7 @@ class ReceiverReport : public RtcpPacket { } RTCPUtility::RTCPPacketRR rr_; - std::vector report_blocks_; + std::vector report_blocks_; RTC_DISALLOW_COPY_AND_ASSIGN(ReceiverReport); }; diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc new file mode 100644 index 0000000000..4911dbf5b7 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.cc @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h" + +#include "webrtc/base/checks.h" +#include "webrtc/base/logging.h" +#include "webrtc/modules/rtp_rtcp/source/byte_io.h" + +namespace webrtc { +namespace rtcp { + +// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications. +// +// RTCP report block (RFC 3550). +// +// 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 | SSRC_1 (SSRC of first source) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 4 | fraction lost | cumulative number of packets lost | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 8 | extended highest sequence number received | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 12 | interarrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 16 | last SR (LSR) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// 20 | delay since last SR (DLSR) | +// 24 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +ReportBlock::ReportBlock() + : source_ssrc_(0), + fraction_lost_(0), + cumulative_lost_(0), + extended_high_seq_num_(0), + jitter_(0), + last_sr_(0), + delay_since_last_sr_(0) {} + +bool ReportBlock::Parse(const uint8_t* buffer, size_t length) { + RTC_DCHECK(buffer != nullptr); + if (length < ReportBlock::kLength) { + LOG(LS_ERROR) << "Report Block should be 24 bytes long"; + return false; + } + + source_ssrc_ = ByteReader::ReadBigEndian(&buffer[0]); + fraction_lost_ = buffer[4]; + cumulative_lost_ = ByteReader::ReadBigEndian(&buffer[5]); + extended_high_seq_num_ = ByteReader::ReadBigEndian(&buffer[8]); + jitter_ = ByteReader::ReadBigEndian(&buffer[12]); + last_sr_ = ByteReader::ReadBigEndian(&buffer[16]); + delay_since_last_sr_ = ByteReader::ReadBigEndian(&buffer[20]); + + return true; +} + +void ReportBlock::Create(uint8_t* buffer) const { + // Runtime check should be done while setting cumulative_lost. + RTC_DCHECK_LT(cumulative_lost(), (1u << 24)); // Have only 3 bytes for it. + + ByteWriter::WriteBigEndian(&buffer[0], source_ssrc()); + ByteWriter::WriteBigEndian(&buffer[4], fraction_lost()); + ByteWriter::WriteBigEndian(&buffer[5], cumulative_lost()); + ByteWriter::WriteBigEndian(&buffer[8], extended_high_seq_num()); + ByteWriter::WriteBigEndian(&buffer[12], jitter()); + ByteWriter::WriteBigEndian(&buffer[16], last_sr()); + ByteWriter::WriteBigEndian(&buffer[20], delay_since_last_sr()); +} + +bool ReportBlock::WithCumulativeLost(uint32_t cumulative_lost) { + if (cumulative_lost >= (1u << 24)) { // Have only 3 bytes to store it. + LOG(LS_WARNING) << "Cumulative lost is too big to fit into Report Block"; + return false; + } + cumulative_lost_ = cumulative_lost; + return true; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h new file mode 100644 index 0000000000..ef99e17297 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + * + */ + +#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REPORT_BLOCK_H_ +#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REPORT_BLOCK_H_ + +#include "webrtc/base/basictypes.h" + +namespace webrtc { +namespace rtcp { + +class ReportBlock { + public: + static const size_t kLength = 24; + + ReportBlock(); + ~ReportBlock() {} + + bool Parse(const uint8_t* buffer, size_t length); + + // Fills buffer with the ReportBlock. + // Consumes ReportBlock::kLength bytes. + void Create(uint8_t* buffer) const; + + void To(uint32_t ssrc) { source_ssrc_ = ssrc; } + void WithFractionLost(uint8_t fraction_lost) { + fraction_lost_ = fraction_lost; + } + bool WithCumulativeLost(uint32_t cumulative_lost); + void WithExtHighestSeqNum(uint32_t ext_highest_seq_num) { + extended_high_seq_num_ = ext_highest_seq_num; + } + void WithJitter(uint32_t jitter) { jitter_ = jitter; } + void WithLastSr(uint32_t last_sr) { last_sr_ = last_sr; } + void WithDelayLastSr(uint32_t delay_last_sr) { + delay_since_last_sr_ = delay_last_sr; + } + + uint32_t source_ssrc() const { return source_ssrc_; } + uint8_t fraction_lost() const { return fraction_lost_; } + uint32_t cumulative_lost() const { return cumulative_lost_; } + uint32_t extended_high_seq_num() const { return extended_high_seq_num_; } + uint32_t jitter() const { return jitter_; } + uint32_t last_sr() const { return last_sr_; } + uint32_t delay_since_last_sr() const { return delay_since_last_sr_; } + + private: + uint32_t source_ssrc_; + uint8_t fraction_lost_; + uint32_t cumulative_lost_; + uint32_t extended_high_seq_num_; + uint32_t jitter_; + uint32_t last_sr_; + uint32_t delay_since_last_sr_; +}; + +} // namespace rtcp +} // namespace webrtc +#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_REPORT_BLOCK_H_ diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc new file mode 100644 index 0000000000..fcde0e4c17 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block_unittest.cc @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h" + +#include + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/test/random.h" + +using webrtc::rtcp::ReportBlock; + +namespace webrtc { +namespace { + +const uint32_t kRemoteSsrc = 0x23456789; +const uint8_t kFractionLost = 55; +// Use values that are streamed differently LE and BE. +const uint32_t kCumulativeLost = 0x111213; +const uint32_t kExtHighestSeqNum = 0x22232425; +const uint32_t kJitter = 0x33343536; +const uint32_t kLastSr = 0x44454647; +const uint32_t kDelayLastSr = 0x55565758; +const size_t kBufferLength = ReportBlock::kLength; + +TEST(RtcpPacketReportBlockTest, ParseChecksLength) { + uint8_t buffer[kBufferLength]; + memset(buffer, 0, sizeof(buffer)); + + ReportBlock rb; + EXPECT_FALSE(rb.Parse(buffer, kBufferLength - 1)); + EXPECT_TRUE(rb.Parse(buffer, kBufferLength)); +} + +TEST(RtcpPacketReportBlockTest, ParseAnyData) { + uint8_t buffer[kBufferLength]; + // Fill buffer with semi-random data. + test::Random generator(testing::FLAGS_gtest_random_seed); + for (size_t i = 0; i < kBufferLength; ++i) + buffer[i] = static_cast(generator.Rand(0, 0xff)); + + ReportBlock rb; + EXPECT_TRUE(rb.Parse(buffer, kBufferLength)); +} + +TEST(RtcpPacketReportBlockTest, ParseMatchCreate) { + ReportBlock rb; + rb.To(kRemoteSsrc); + rb.WithFractionLost(kFractionLost); + rb.WithCumulativeLost(kCumulativeLost); + rb.WithExtHighestSeqNum(kExtHighestSeqNum); + rb.WithJitter(kJitter); + rb.WithLastSr(kLastSr); + rb.WithDelayLastSr(kDelayLastSr); + + uint8_t buffer[kBufferLength]; + rb.Create(buffer); + + ReportBlock parsed; + EXPECT_TRUE(parsed.Parse(buffer, kBufferLength)); + + EXPECT_EQ(kRemoteSsrc, parsed.source_ssrc()); + EXPECT_EQ(kFractionLost, parsed.fraction_lost()); + EXPECT_EQ(kCumulativeLost, parsed.cumulative_lost()); + EXPECT_EQ(kExtHighestSeqNum, parsed.extended_high_seq_num()); + EXPECT_EQ(kJitter, parsed.jitter()); + EXPECT_EQ(kLastSr, parsed.last_sr()); + EXPECT_EQ(kDelayLastSr, parsed.delay_since_last_sr()); +} + +TEST(RtcpPacketReportBlockTest, ValidateCumulativeLost) { + const uint32_t kMaxCumulativeLost = 0xffffff; + ReportBlock rb; + EXPECT_FALSE(rb.WithCumulativeLost(kMaxCumulativeLost + 1)); + EXPECT_TRUE(rb.WithCumulativeLost(kMaxCumulativeLost)); +} + +} // namespace +} // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc index 22b9477e05..1b8c62faaf 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_sender.cc @@ -459,7 +459,10 @@ int32_t RTCPSender::AddReportBlock(const RTCPReportBlock& report_block) { rtcp::ReportBlock* block = &report_blocks_[report_block.remoteSSRC]; block->To(report_block.remoteSSRC); block->WithFractionLost(report_block.fractionLost); - block->WithCumulativeLost(report_block.cumulativeLost); + if (!block->WithCumulativeLost(report_block.cumulativeLost)) { + LOG(LS_WARNING) << "Cumulative lost is oversized."; + return -1; + } block->WithExtHighestSeqNum(report_block.extendedHighSeqNum); block->WithJitter(report_block.jitter); block->WithLastSr(report_block.lastSR); @@ -1024,6 +1027,8 @@ int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state, RTCPReportBlock report_block; if (PrepareReport(feedback_state, it->first, it->second, &report_block)) { + // TODO(danilchap) AddReportBlock may fail (for 2 different reasons). + // Probably it shouldn't be ignored. AddReportBlock(report_block); } }