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}
This commit is contained in:
danilchap 2015-12-16 01:56:20 -08:00 committed by Commit bot
parent 29e2f9385b
commit 54999d411b
8 changed files with 280 additions and 105 deletions

View File

@ -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',

View File

@ -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",

View File

@ -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',

View File

@ -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]);

View File

@ -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.

View File

@ -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

View File

@ -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_

View File

@ -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