diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index eaedf6086c..419580f47c 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/extended_jitter_report_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', diff --git a/webrtc/modules/rtp_rtcp/BUILD.gn b/webrtc/modules/rtp_rtcp/BUILD.gn index fb6a1e8959..fd81586b85 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/extended_jitter_report.cc", + "source/rtcp_packet/extended_jitter_report.h", "source/rtcp_packet/report_block.cc", "source/rtcp_packet/report_block.h", "source/rtcp_packet/transport_feedback.cc", diff --git a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi index 025623d3c3..5eb3c5f79c 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/extended_jitter_report.cc', + 'source/rtcp_packet/extended_jitter_report.h', 'source/rtcp_packet/report_block.cc', 'source/rtcp_packet/report_block.h', 'source/rtcp_packet/transport_feedback.cc', diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc index 4af3292659..7c0650c488 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc @@ -163,28 +163,6 @@ void CreateReportBlocks(const std::vector& blocks, } } -// Transmission Time Offsets in RTP Streams (RFC 5450). -// -// 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 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// hdr |V=2|P| RC | PT=IJ=195 | length | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | inter-arrival jitter | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// . . -// . . -// . . -// | inter-arrival jitter | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - -void CreateIj(const std::vector& ij_items, - uint8_t* buffer, - size_t* pos) { - for (uint32_t item : ij_items) - AssignUWord32(buffer, pos, item); -} - // Source Description (SDES) (RFC 3550). // // 0 1 2 3 @@ -804,29 +782,6 @@ bool ReceiverReport::WithReportBlock(const ReportBlock& block) { return true; } -bool Ij::Create(uint8_t* packet, - size_t* index, - size_t max_length, - RtcpPacket::PacketReadyCallback* callback) const { - while (*index + BlockLength() > max_length) { - if (!OnBufferFull(packet, index, callback)) - return false; - } - size_t length = ij_items_.size(); - CreateHeader(length, PT_IJ, length, packet, index); - CreateIj(ij_items_, packet, index); - return true; -} - -bool Ij::WithJitterItem(uint32_t jitter) { - if (ij_items_.size() >= kMaxNumberOfIjItems) { - LOG(LS_WARNING) << "Max inter-arrival jitter items reached."; - return false; - } - ij_items_.push_back(jitter); - return true; -} - bool Sdes::Create(uint8_t* packet, size_t* index, size_t max_length, diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h index 85aa438b89..d27a9878ee 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h @@ -263,51 +263,6 @@ class ReceiverReport : public RtcpPacket { RTC_DISALLOW_COPY_AND_ASSIGN(ReceiverReport); }; -// Transmission Time Offsets in RTP Streams (RFC 5450). -// -// 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 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// hdr |V=2|P| RC | PT=IJ=195 | length | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | inter-arrival jitter | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// . . -// . . -// . . -// | inter-arrival jitter | -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// -// If present, this RTCP packet must be placed after a receiver report -// (inside a compound RTCP packet), and MUST have the same value for RC -// (reception report count) as the receiver report. - -class Ij : public RtcpPacket { - public: - Ij() : RtcpPacket() {} - - virtual ~Ij() {} - - bool WithJitterItem(uint32_t jitter); - - protected: - bool Create(uint8_t* packet, - size_t* index, - size_t max_length, - RtcpPacket::PacketReadyCallback* callback) const override; - - private: - static const int kMaxNumberOfIjItems = 0x1f; - - size_t BlockLength() const { - return kHeaderLength + 4 * ij_items_.size(); - } - - std::vector ij_items_; - - RTC_DISALLOW_COPY_AND_ASSIGN(Ij); -}; - // Source Description (SDES) (RFC 3550). // // 0 1 2 3 diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc new file mode 100644 index 0000000000..dfdf232102 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.cc @@ -0,0 +1,95 @@ +/* + * 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/extended_jitter_report.h" + +#include "webrtc/base/checks.h" +#include "webrtc/base/logging.h" +#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" +#include "webrtc/modules/rtp_rtcp/source/byte_io.h" + +using webrtc::RTCPUtility::RtcpCommonHeader; + +namespace webrtc { +namespace rtcp { + +// Transmission Time Offsets in RTP Streams (RFC 5450). +// +// 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 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// hdr |V=2|P| RC | PT=IJ=195 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | inter-arrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// . . +// . . +// . . +// | inter-arrival jitter | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// If present, this RTCP packet must be placed after a receiver report +// (inside a compound RTCP packet), and MUST have the same value for RC +// (reception report count) as the receiver report. + +bool ExtendedJitterReport::Parse(const RtcpCommonHeader& header, + const uint8_t* payload) { + RTC_DCHECK(header.packet_type == kPacketType); + + const uint8_t jitters_count = header.count_or_format; + const size_t kJitterSizeBytes = 4u; + + if (header.payload_size_bytes < jitters_count * kJitterSizeBytes) { + LOG(LS_WARNING) << "Packet is too small to contain all the jitter."; + return false; + } + + inter_arrival_jitters_.resize(jitters_count); + for (size_t index = 0; index < jitters_count; ++index) { + inter_arrival_jitters_[index] = + ByteReader::ReadBigEndian(&payload[index * kJitterSizeBytes]); + } + + return true; +} + +bool ExtendedJitterReport::WithJitter(uint32_t jitter) { + if (inter_arrival_jitters_.size() >= kMaxNumberOfJitters) { + LOG(LS_WARNING) << "Max inter-arrival jitter items reached."; + return false; + } + inter_arrival_jitters_.push_back(jitter); + return true; +} + +bool ExtendedJitterReport::Create( + uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + const size_t index_end = *index + BlockLength(); + size_t length = inter_arrival_jitters_.size(); + CreateHeader(length, kPacketType, length, packet, index); + + for (uint32_t jitter : inter_arrival_jitters_) { + ByteWriter::WriteBigEndian(packet + *index, jitter); + *index += sizeof(uint32_t); + } + // Sanity check. + RTC_DCHECK_EQ(index_end, *index); + return true; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h new file mode 100644 index 0000000000..49de7be1a8 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h @@ -0,0 +1,63 @@ +/* + * 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_EXTENDED_JITTER_REPORT_H_ +#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_JITTER_REPORT_H_ + +#include + +#include "webrtc/base/checks.h" +#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h" +#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" + +namespace webrtc { +namespace rtcp { + +class ExtendedJitterReport : public RtcpPacket { + public: + static const uint8_t kPacketType = 195; + + ExtendedJitterReport() : RtcpPacket() {} + + virtual ~ExtendedJitterReport() {} + + // 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. + + bool WithJitter(uint32_t jitter); + + size_t jitters_count() const { return inter_arrival_jitters_.size(); } + uint32_t jitter(size_t index) const { + RTC_DCHECK_LT(index, jitters_count()); + return inter_arrival_jitters_[index]; + } + + protected: + bool Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const override; + + private: + static const int kMaxNumberOfJitters = 0x1f; + + size_t BlockLength() const override { + return kHeaderLength + 4 * inter_arrival_jitters_.size(); + } + + std::vector inter_arrival_jitters_; + + RTC_DISALLOW_COPY_AND_ASSIGN(ExtendedJitterReport); +}; + +} // namespace rtcp +} // namespace webrtc +#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_EXTENDED_JITTER_REPORT_H_ diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc new file mode 100644 index 0000000000..673e1d89a4 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc @@ -0,0 +1,98 @@ +/* + * 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/extended_jitter_report.h" + +#include + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" + +using webrtc::rtcp::RawPacket; +using webrtc::rtcp::ExtendedJitterReport; +using webrtc::RTCPUtility::RtcpCommonHeader; +using webrtc::RTCPUtility::RtcpParseCommonHeader; + +namespace webrtc { +namespace { + +class RtcpPacketExtendedJitterReportTest : public ::testing::Test { + protected: + void BuildPacket() { packet = ij.Build().Pass(); } + void ParsePacket() { + RtcpCommonHeader header; + EXPECT_TRUE( + RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header)); + EXPECT_EQ(header.BlockSize(), packet->Length()); + EXPECT_TRUE(parsed_.Parse( + header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes)); + } + + ExtendedJitterReport ij; + rtc::scoped_ptr packet; + const ExtendedJitterReport& parsed() { return parsed_; } + + private: + ExtendedJitterReport parsed_; +}; + +TEST_F(RtcpPacketExtendedJitterReportTest, NoItem) { + // No initialization because packet is empty. + BuildPacket(); + ParsePacket(); + + EXPECT_EQ(0u, parsed().jitters_count()); +} + +TEST_F(RtcpPacketExtendedJitterReportTest, OneItem) { + EXPECT_TRUE(ij.WithJitter(0x11121314)); + + BuildPacket(); + ParsePacket(); + + EXPECT_EQ(1u, parsed().jitters_count()); + EXPECT_EQ(0x11121314U, parsed().jitter(0)); +} + +TEST_F(RtcpPacketExtendedJitterReportTest, TwoItems) { + EXPECT_TRUE(ij.WithJitter(0x11121418)); + EXPECT_TRUE(ij.WithJitter(0x22242628)); + + BuildPacket(); + ParsePacket(); + + EXPECT_EQ(2u, parsed().jitters_count()); + EXPECT_EQ(0x11121418U, parsed().jitter(0)); + EXPECT_EQ(0x22242628U, parsed().jitter(1)); +} + +TEST_F(RtcpPacketExtendedJitterReportTest, TooManyItems) { + const int kMaxIjItems = (1 << 5) - 1; + for (int i = 0; i < kMaxIjItems; ++i) { + EXPECT_TRUE(ij.WithJitter(i)); + } + EXPECT_FALSE(ij.WithJitter(kMaxIjItems)); +} + +TEST_F(RtcpPacketExtendedJitterReportTest, ParseFailWithTooManyItems) { + ij.WithJitter(0x11121418); + BuildPacket(); + RtcpCommonHeader header; + RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header); + header.count_or_format++; // Damage package. + + ExtendedJitterReport parsed; + + EXPECT_FALSE(parsed.Parse( + header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes)); +} + +} // namespace +} // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc index 77520b633b..ac84356c0f 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet_unittest.cc @@ -23,7 +23,6 @@ using webrtc::rtcp::Bye; using webrtc::rtcp::Dlrr; using webrtc::rtcp::Empty; using webrtc::rtcp::Fir; -using webrtc::rtcp::Ij; using webrtc::rtcp::Nack; using webrtc::rtcp::Pli; using webrtc::rtcp::Sdes; @@ -196,50 +195,6 @@ TEST(RtcpPacketTest, SrWithTooManyReportBlocks) { EXPECT_FALSE(sr.WithReportBlock(rb)); } -TEST(RtcpPacketTest, IjNoItem) { - Ij ij; - - rtc::scoped_ptr packet(ij.Build()); - RtcpPacketParser parser; - parser.Parse(packet->Buffer(), packet->Length()); - EXPECT_EQ(1, parser.ij()->num_packets()); - EXPECT_EQ(0, parser.ij_item()->num_packets()); -} - -TEST(RtcpPacketTest, IjOneItem) { - Ij ij; - EXPECT_TRUE(ij.WithJitterItem(0x11111111)); - - rtc::scoped_ptr packet(ij.Build()); - RtcpPacketParser parser; - parser.Parse(packet->Buffer(), packet->Length()); - EXPECT_EQ(1, parser.ij()->num_packets()); - EXPECT_EQ(1, parser.ij_item()->num_packets()); - EXPECT_EQ(0x11111111U, parser.ij_item()->Jitter()); -} - -TEST(RtcpPacketTest, IjTwoItems) { - Ij ij; - EXPECT_TRUE(ij.WithJitterItem(0x11111111)); - EXPECT_TRUE(ij.WithJitterItem(0x22222222)); - - rtc::scoped_ptr packet(ij.Build()); - RtcpPacketParser parser; - parser.Parse(packet->Buffer(), packet->Length()); - EXPECT_EQ(1, parser.ij()->num_packets()); - EXPECT_EQ(2, parser.ij_item()->num_packets()); - EXPECT_EQ(0x22222222U, parser.ij_item()->Jitter()); -} - -TEST(RtcpPacketTest, IjTooManyItems) { - Ij ij; - const int kMaxIjItems = (1 << 5) - 1; - for (int i = 0; i < kMaxIjItems; ++i) { - EXPECT_TRUE(ij.WithJitterItem(i)); - } - EXPECT_FALSE(ij.WithJitterItem(kMaxIjItems)); -} - TEST(RtcpPacketTest, AppWithNoData) { App app; app.WithSubType(30); diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc index 1581845476..45e803e372 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_receiver_unittest.cc @@ -25,6 +25,7 @@ #include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h" #include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h" #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" +#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" namespace webrtc { @@ -384,20 +385,20 @@ TEST_F(RtcpReceiverTest, GetRtt) { } TEST_F(RtcpReceiverTest, InjectIjWithNoItem) { - rtcp::Ij ij; + rtcp::ExtendedJitterReport ij; rtc::scoped_ptr packet(ij.Build()); EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); EXPECT_EQ(0U, rtcp_packet_info_.rtcpPacketTypeFlags); } TEST_F(RtcpReceiverTest, InjectIjWithOneItem) { - rtcp::Ij ij; - ij.WithJitterItem(0x11111111); + rtcp::ExtendedJitterReport ij; + ij.WithJitter(0x11213141); rtc::scoped_ptr packet(ij.Build()); EXPECT_EQ(0, InjectRtcpPacket(packet->Buffer(), packet->Length())); EXPECT_EQ(kRtcpTransmissionTimeOffset, rtcp_packet_info_.rtcpPacketTypeFlags); - EXPECT_EQ(0x11111111U, rtcp_packet_info_.interArrivalJitter); + EXPECT_EQ(0x11213141U, rtcp_packet_info_.interArrivalJitter); } TEST_F(RtcpReceiverTest, InjectAppWithNoData) {