diff options
author | danilchap <danilchap@webrtc.org> | 2015-12-16 01:56:20 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-16 09:56:22 +0000 |
commit | 54999d411b97e3df54121e5f7bfb28846f3c8086 (patch) | |
tree | 95b31e98f7610d2c21485043207b7dd1043070b7 /webrtc/modules | |
parent | 29e2f9385b7e0dde4af7317af5cd0ce6adf1ee9d (diff) | |
download | webrtc-54999d411b97e3df54121e5f7bfb28846f3c8086.tar.gz |
rtcp::Dlrr block moved into own file and got Parse function
BUG=webrtc:5260
Review URL: https://codereview.webrtc.org/1453973005
Cr-Commit-Position: refs/heads/master@{#11044}
Diffstat (limited to 'webrtc/modules')
-rw-r--r-- | webrtc/modules/modules.gyp | 1 | ||||
-rw-r--r-- | webrtc/modules/rtp_rtcp/BUILD.gn | 2 | ||||
-rw-r--r-- | webrtc/modules/rtp_rtcp/rtp_rtcp.gypi | 2 | ||||
-rw-r--r-- | webrtc/modules/rtp_rtcp/source/rtcp_packet.cc | 77 | ||||
-rw-r--r-- | webrtc/modules/rtp_rtcp/source/rtcp_packet.h | 38 | ||||
-rw-r--r-- | webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc | 100 | ||||
-rw-r--r-- | webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.h | 63 | ||||
-rw-r--r-- | webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc | 102 |
8 files changed, 280 insertions, 105 deletions
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp index f58e0f4034..0dec33749d 100644 --- a/webrtc/modules/modules.gyp +++ b/webrtc/modules/modules.gyp @@ -306,6 +306,7 @@ 'rtp_rtcp/source/rtcp_packet_unittest.cc', 'rtp_rtcp/source/rtcp_packet/app_unittest.cc', 'rtp_rtcp/source/rtcp_packet/bye_unittest.cc', + 'rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc', 'rtp_rtcp/source/rtcp_packet/extended_jitter_report_unittest.cc', 'rtp_rtcp/source/rtcp_packet/pli_unittest.cc', 'rtp_rtcp/source/rtcp_packet/receiver_report_unittest.cc', diff --git a/webrtc/modules/rtp_rtcp/BUILD.gn b/webrtc/modules/rtp_rtcp/BUILD.gn index be6e2e4c7d..aa2e9c5800 100644 --- a/webrtc/modules/rtp_rtcp/BUILD.gn +++ b/webrtc/modules/rtp_rtcp/BUILD.gn @@ -50,6 +50,8 @@ source_set("rtp_rtcp") { "source/rtcp_packet/app.h", "source/rtcp_packet/bye.cc", "source/rtcp_packet/bye.h", + "source/rtcp_packet/dlrr.cc", + "source/rtcp_packet/dlrr.h", "source/rtcp_packet/extended_jitter_report.cc", "source/rtcp_packet/extended_jitter_report.h", "source/rtcp_packet/pli.cc", diff --git a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi index 1b88055695..98b2659c94 100644 --- a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi +++ b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi @@ -45,6 +45,8 @@ 'source/rtcp_packet/app.h', 'source/rtcp_packet/bye.cc', 'source/rtcp_packet/bye.h', + 'source/rtcp_packet/dlrr.cc', + 'source/rtcp_packet/dlrr.h', 'source/rtcp_packet/extended_jitter_report.cc', 'source/rtcp_packet/extended_jitter_report.h', 'source/rtcp_packet/pli.cc', diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc index 28cb20eca2..1508658f5d 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc @@ -407,50 +407,6 @@ void CreateXrHeader(const RTCPPacketXR& header, AssignUWord32(buffer, pos, header.OriginatorSSRC); } -void CreateXrBlockHeader(uint8_t block_type, - uint16_t block_length, - uint8_t* buffer, - size_t* pos) { - AssignUWord8(buffer, pos, block_type); - AssignUWord8(buffer, pos, 0); - AssignUWord16(buffer, pos, block_length); -} - -// DLRR Report Block (RFC 3611). -// -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | BT=5 | reserved | block length | -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | SSRC_1 (SSRC of first receiver) | sub- -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block -// | last RR (LRR) | 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | delay since last RR (DLRR) | -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | SSRC_2 (SSRC of second receiver) | sub- -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block -// : ... : 2 - -void CreateDlrr(const std::vector<Xr::DlrrBlock>& dlrrs, - uint8_t* buffer, - size_t* pos) { - for (std::vector<Xr::DlrrBlock>::const_iterator it = dlrrs.begin(); - it != dlrrs.end(); ++it) { - if ((*it).empty()) { - continue; - } - uint16_t block_length = 3 * (*it).size(); - CreateXrBlockHeader(kBtDlrr, block_length, buffer, pos); - for (Xr::DlrrBlock::const_iterator it_block = (*it).begin(); - it_block != (*it).end(); ++it_block) { - AssignUWord32(buffer, pos, (*it_block).SSRC); - AssignUWord32(buffer, pos, (*it_block).LastRR); - AssignUWord32(buffer, pos, (*it_block).DelayLastRR); - } - } -} } // namespace void RtcpPacket::Append(RtcpPacket* packet) { @@ -834,7 +790,10 @@ bool Xr::Create(uint8_t* packet, block.Create(packet + *index); *index += Rrtr::kLength; } - CreateDlrr(dlrr_blocks_, packet, index); + for (const Dlrr& block : dlrr_blocks_) { + block.Create(packet + *index); + *index += block.BlockLength(); + } for (const VoipMetric& block : voip_metric_blocks_) { block.Create(packet + *index); *index += VoipMetric::kLength; @@ -853,12 +812,12 @@ bool Xr::WithRrtr(Rrtr* rrtr) { } bool Xr::WithDlrr(Dlrr* dlrr) { - assert(dlrr); + RTC_DCHECK(dlrr); if (dlrr_blocks_.size() >= kMaxNumberOfDlrrBlocks) { LOG(LS_WARNING) << "Max DLRR blocks reached."; return false; } - dlrr_blocks_.push_back(dlrr->dlrr_block_); + dlrr_blocks_.push_back(*dlrr); return true; } @@ -873,33 +832,13 @@ bool Xr::WithVoipMetric(VoipMetric* voip_metric) { } size_t Xr::DlrrLength() const { - const size_t kBlockHeaderLen = 4; - const size_t kSubBlockLen = 12; size_t length = 0; - for (std::vector<DlrrBlock>::const_iterator it = dlrr_blocks_.begin(); - it != dlrr_blocks_.end(); ++it) { - if (!(*it).empty()) { - length += kBlockHeaderLen + kSubBlockLen * (*it).size(); - } + for (const Dlrr& block : dlrr_blocks_) { + length += block.BlockLength(); } return length; } -bool Dlrr::WithDlrrItem(uint32_t ssrc, - uint32_t last_rr, - uint32_t delay_last_rr) { - if (dlrr_block_.size() >= kMaxNumberOfDlrrItems) { - LOG(LS_WARNING) << "Max DLRR items reached."; - return false; - } - RTCPPacketXRDLRRReportBlockItem dlrr; - dlrr.SSRC = ssrc; - dlrr.LastRR = last_rr; - dlrr.DelayLastRR = delay_last_rr; - dlrr_block_.push_back(dlrr); - return true; -} - RawPacket::RawPacket(size_t buffer_length) : buffer_length_(buffer_length), length_(0) { buffer_.reset(new uint8_t[buffer_length]); diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h index dcbb1e72d3..3adcc9a759 100644 --- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h @@ -18,6 +18,7 @@ #include "webrtc/base/scoped_ptr.h" #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" +#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/report_block.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/rrtr.h" #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/voip_metric.h" @@ -30,7 +31,6 @@ namespace rtcp { static const int kCommonFbFmtLength = 12; static const int kReportBlockLength = 24; -class Dlrr; class RawPacket; // Class for building RTCP packets. @@ -679,46 +679,12 @@ class Xr : public RtcpPacket { RTCPUtility::RTCPPacketXR xr_header_; std::vector<Rrtr> rrtr_blocks_; - std::vector<DlrrBlock> dlrr_blocks_; + std::vector<Dlrr> dlrr_blocks_; std::vector<VoipMetric> voip_metric_blocks_; RTC_DISALLOW_COPY_AND_ASSIGN(Xr); }; -// DLRR Report Block (RFC 3611). -// -// 0 1 2 3 -// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | BT=5 | reserved | block length | -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | SSRC_1 (SSRC of first receiver) | sub- -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block -// | last RR (LRR) | 1 -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -// | delay since last RR (DLRR) | -// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ -// | SSRC_2 (SSRC of second receiver) | sub- -// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block -// : ... : 2 - -class Dlrr { - public: - Dlrr() {} - ~Dlrr() {} - - // Max 100 DLRR Items can be added per DLRR report block. - bool WithDlrrItem(uint32_t ssrc, uint32_t last_rr, uint32_t delay_last_rr); - - private: - friend class Xr; - static const int kMaxNumberOfDlrrItems = 100; - - std::vector<RTCPUtility::RTCPPacketXRDLRRReportBlockItem> dlrr_block_; - - RTC_DISALLOW_COPY_AND_ASSIGN(Dlrr); -}; - // Class holding a RTCP packet. // // Takes a built rtcp packet. diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc new file mode 100644 index 0000000000..6d6c48fada --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.cc @@ -0,0 +1,100 @@ +/* + * 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/dlrr.h" + +#include "webrtc/base/checks.h" +#include "webrtc/base/logging.h" +#include "webrtc/modules/rtp_rtcp/source/byte_io.h" + +namespace webrtc { +namespace rtcp { +// DLRR Report Block (RFC 3611). +// +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | BT=5 | reserved | block length | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | SSRC_1 (SSRC of first receiver) | sub- +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block +// | last RR (LRR) | 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | delay since last RR (DLRR) | +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// | SSRC_2 (SSRC of second receiver) | sub- +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block +// : ... : 2 +bool Dlrr::Parse(const uint8_t* buffer, uint16_t block_length_32bits) { + RTC_DCHECK(buffer[0] == kBlockType); + // kReserved = buffer[1]; + RTC_DCHECK_EQ(block_length_32bits, + ByteReader<uint16_t>::ReadBigEndian(&buffer[2])); + if (block_length_32bits % 3 != 0) { + LOG(LS_WARNING) << "Invalid size for dlrr block."; + return false; + } + + size_t blocks_count = block_length_32bits / 3; + const uint8_t* read_at = buffer + kBlockHeaderLength; + sub_blocks_.resize(blocks_count); + for (SubBlock& sub_block : sub_blocks_) { + sub_block.ssrc = ByteReader<uint32_t>::ReadBigEndian(&read_at[0]); + sub_block.last_rr = ByteReader<uint32_t>::ReadBigEndian(&read_at[4]); + sub_block.delay_since_last_rr = + ByteReader<uint32_t>::ReadBigEndian(&read_at[8]); + read_at += kSubBlockLength; + } + return true; +} + +size_t Dlrr::BlockLength() const { + if (sub_blocks_.empty()) + return 0; + return kBlockHeaderLength + kSubBlockLength * sub_blocks_.size(); +} + +void Dlrr::Create(uint8_t* buffer) const { + if (sub_blocks_.empty()) // No subblocks, no need to write header either. + return; + // Create block header. + const uint8_t kReserved = 0; + buffer[0] = kBlockType; + buffer[1] = kReserved; + ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], 3 * sub_blocks_.size()); + // Create sub blocks. + uint8_t* write_at = buffer + kBlockHeaderLength; + for (const SubBlock& sub_block : sub_blocks_) { + ByteWriter<uint32_t>::WriteBigEndian(&write_at[0], sub_block.ssrc); + ByteWriter<uint32_t>::WriteBigEndian(&write_at[4], sub_block.last_rr); + ByteWriter<uint32_t>::WriteBigEndian(&write_at[8], + sub_block.delay_since_last_rr); + write_at += kSubBlockLength; + } + RTC_DCHECK_EQ(buffer + BlockLength(), write_at); +} + +bool Dlrr::WithDlrrItem(uint32_t ssrc, + uint32_t last_rr, + uint32_t delay_last_rr) { + if (sub_blocks_.size() >= kMaxNumberOfDlrrItems) { + LOG(LS_WARNING) << "Max DLRR items reached."; + return false; + } + SubBlock block; + block.ssrc = ssrc; + block.last_rr = last_rr; + block.delay_since_last_rr = delay_last_rr; + sub_blocks_.push_back(block); + return true; +} + +} // namespace rtcp +} // namespace webrtc diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.h new file mode 100644 index 0000000000..9af2dedf3f --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr.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_DLRR_H_ +#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_DLRR_H_ + +#include <vector> + +#include "webrtc/base/basictypes.h" + +namespace webrtc { +namespace rtcp { + +// DLRR Report Block: Delay since the Last Receiver Report (RFC 3611). +class Dlrr { + public: + struct SubBlock { + // RFC 3611 4.5 + uint32_t ssrc; + uint32_t last_rr; + uint32_t delay_since_last_rr; + }; + + static const uint8_t kBlockType = 5; + static const size_t kMaxNumberOfDlrrItems = 100; + + Dlrr() {} + Dlrr(const Dlrr& other) = default; + ~Dlrr() {} + + Dlrr& operator=(const Dlrr& other) = default; + + // Second parameter is value read from block header, + // i.e. size of block in 32bits excluding block header itself. + bool Parse(const uint8_t* buffer, uint16_t block_length_32bits); + + size_t BlockLength() const; + // Fills buffer with the Dlrr. + // Consumes BlockLength() bytes. + void Create(uint8_t* buffer) const; + + // Max 100 DLRR Items can be added per DLRR report block. + bool WithDlrrItem(uint32_t ssrc, uint32_t last_rr, uint32_t delay_last_rr); + + const std::vector<SubBlock>& sub_blocks() const { return sub_blocks_; } + + private: + static const size_t kBlockHeaderLength = 4; + static const size_t kSubBlockLength = 12; + + std::vector<SubBlock> sub_blocks_; +}; +} // namespace rtcp +} // namespace webrtc +#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_DLRR_H_ diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc new file mode 100644 index 0000000000..c7c139c560 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/dlrr_unittest.cc @@ -0,0 +1,102 @@ +/* + * 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/dlrr.h" + +#include "testing/gtest/include/gtest/gtest.h" + +#include "webrtc/modules/rtp_rtcp/source/byte_io.h" + +using webrtc::rtcp::Dlrr; + +namespace webrtc { +namespace { + +const uint32_t kSsrc = 0x12345678; +const uint32_t kLastRR = 0x23344556; +const uint32_t kDelay = 0x33343536; +const uint8_t kBlock[] = {0x05, 0x00, 0x00, 0x03, 0x12, 0x34, 0x56, 0x78, + 0x23, 0x34, 0x45, 0x56, 0x33, 0x34, 0x35, 0x36}; +const size_t kBlockSizeBytes = sizeof(kBlock); + +TEST(RtcpPacketDlrrTest, Empty) { + Dlrr dlrr; + + EXPECT_EQ(0u, dlrr.BlockLength()); +} + +TEST(RtcpPacketDlrrTest, Create) { + Dlrr dlrr; + EXPECT_TRUE(dlrr.WithDlrrItem(kSsrc, kLastRR, kDelay)); + + ASSERT_EQ(kBlockSizeBytes, dlrr.BlockLength()); + uint8_t buffer[kBlockSizeBytes]; + + dlrr.Create(buffer); + EXPECT_EQ(0, memcmp(buffer, kBlock, kBlockSizeBytes)); +} + +TEST(RtcpPacketDlrrTest, Parse) { + Dlrr dlrr; + uint16_t block_length = ByteReader<uint16_t>::ReadBigEndian(&kBlock[2]); + EXPECT_TRUE(dlrr.Parse(kBlock, block_length)); + + EXPECT_EQ(1u, dlrr.sub_blocks().size()); + const Dlrr::SubBlock& block = dlrr.sub_blocks().front(); + EXPECT_EQ(kSsrc, block.ssrc); + EXPECT_EQ(kLastRR, block.last_rr); + EXPECT_EQ(kDelay, block.delay_since_last_rr); +} + +TEST(RtcpPacketDlrrTest, ParseFailsOnBadSize) { + const size_t kBigBufferSize = 0x100; // More than enough. + uint8_t buffer[kBigBufferSize]; + buffer[0] = Dlrr::kBlockType; + buffer[1] = 0; // Reserved. + buffer[2] = 0; // Most significant size byte. + for (uint8_t size = 3; size < 6; ++size) { + buffer[3] = size; + Dlrr dlrr; + // Parse should be successful only when size is multiple of 3. + EXPECT_EQ(size % 3 == 0, dlrr.Parse(buffer, static_cast<uint16_t>(size))); + } +} + +TEST(RtcpPacketDlrrTest, FailsOnTooManySubBlocks) { + Dlrr dlrr; + for (size_t i = 1; i <= Dlrr::kMaxNumberOfDlrrItems; ++i) { + EXPECT_TRUE(dlrr.WithDlrrItem(kSsrc + i, kLastRR + i, kDelay + i)); + } + EXPECT_FALSE(dlrr.WithDlrrItem(kSsrc, kLastRR, kDelay)); +} + +TEST(RtcpPacketDlrrTest, CreateAndParseMaxSubBlocks) { + const size_t kBufferSize = 0x1000; // More than enough. + uint8_t buffer[kBufferSize]; + + // Create. + Dlrr dlrr; + for (size_t i = 1; i <= Dlrr::kMaxNumberOfDlrrItems; ++i) { + EXPECT_TRUE(dlrr.WithDlrrItem(kSsrc + i, kLastRR + i, kDelay + i)); + } + size_t used_buffer_size = dlrr.BlockLength(); + ASSERT_LE(used_buffer_size, kBufferSize); + dlrr.Create(buffer); + + // Parse. + Dlrr parsed; + uint16_t block_length = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]); + EXPECT_EQ(used_buffer_size, (block_length + 1) * 4u); + EXPECT_TRUE(parsed.Parse(buffer, block_length)); + EXPECT_TRUE(parsed.sub_blocks().size() == Dlrr::kMaxNumberOfDlrrItems); +} + +} // namespace +} // namespace webrtc |