Add a ParseHeader method to RtcpPacket, for parsing common RTCP header.
Also refactor TransportFeedback to use this.
BUG=
Review URL: https://codereview.webrtc.org/1307663004
Cr-Commit-Position: refs/heads/master@{#9935}
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
index 8cb6fb0..e5ea37e 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.cc
@@ -743,7 +743,7 @@
uint8_t packet_type,
size_t length,
uint8_t* buffer,
- size_t* pos) const {
+ size_t* pos) {
assert(length <= 0xffff);
const uint8_t kVersion = 2;
AssignUWord8(buffer, pos, (kVersion << 6) + count_or_format);
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
index c5432de..cfbe8ce 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet.h
@@ -99,11 +99,11 @@
size_t max_length,
PacketReadyCallback* callback) const = 0;
- void CreateHeader(uint8_t count_or_format,
- uint8_t packet_type,
- size_t length,
- uint8_t* buffer,
- size_t* pos) const;
+ static void CreateHeader(uint8_t count_or_format,
+ uint8_t packet_type,
+ size_t block_length, // Size in 32bit words - 1.
+ uint8_t* buffer,
+ size_t* pos);
bool OnBufferFull(uint8_t* packet,
size_t* index,
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
index 975d3f3..9cd5ac3 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
@@ -13,6 +13,7 @@
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
namespace webrtc {
namespace rtcp {
@@ -662,54 +663,23 @@
return nullptr;
}
- size_t packet_size_words =
- ByteReader<uint16_t>::ReadBigEndian(&buffer[2]) + 1;
- if (length < packet_size_words * 4) {
- LOG(LS_WARNING) << "Buffer too small (" << length
- << " bytes) to fit a FeedbackPacket of "
- << packet_size_words << " 32bit words.";
+ RTCPUtility::RtcpCommonHeader header;
+ if (!RtcpParseCommonHeader(buffer, length, &header))
return nullptr;
- }
- // TODO(sprang): Break this out and generalize when implementing parsing of
- // other RtcpPacket subclasses.
-
- const uint8_t kRtcpVersion = 2;
- uint8_t version = buffer[0] >> 6;
- if (version != kRtcpVersion) {
- LOG(LS_WARNING) << "Invalid RTCP header: Version must be " << kRtcpVersion
- << " but was " << version;
- return nullptr;
- }
-
- bool has_padding = (buffer[0] & 0x20) != 0;
-
- uint8_t format = buffer[0] & 0x1F;
- if (format != kFeedbackMessageType) {
+ if (header.count_or_format != kFeedbackMessageType) {
LOG(LS_WARNING) << "Invalid RTCP header: FMT must be "
- << kFeedbackMessageType << " but was " << format;
+ << kFeedbackMessageType << " but was "
+ << header.count_or_format;
return nullptr;
}
- uint8_t payload_type = buffer[1];
- if (payload_type != kPayloadType) {
+ if (header.packet_type != kPayloadType) {
LOG(LS_WARNING) << "Invalid RTCP header: PT must be " << kPayloadType
- << " but was " << payload_type;
+ << " but was " << header.packet_type;
return nullptr;
}
- size_t payload_size = packet_size_words * 4;
- if (has_padding) {
- uint8_t padding_bytes = buffer[payload_size - 1];
- if (payload_size < kMinSizeBytes + padding_bytes) {
- LOG(LS_WARNING) << "Invalid RTCP header: Too many padding bytes ("
- << padding_bytes << ") for a packet size of "
- << payload_size << "bytes.";
- return nullptr;
- }
- payload_size -= padding_bytes;
- }
-
packet->packet_sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
packet->media_source_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
packet->base_seq_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[12]);
@@ -717,6 +687,7 @@
packet->base_time_ = ByteReader<int32_t, 3>::ReadBigEndian(&buffer[16]);
packet->feedback_seq_ = buffer[19];
size_t index = 20;
+ const size_t end_index = kHeaderLength + header.payload_size_bytes;
if (num_packets == 0) {
LOG(LS_WARNING) << "Empty feedback messages not allowed.";
@@ -726,7 +697,7 @@
size_t packets_read = 0;
while (packets_read < num_packets) {
- if (index + 2 > payload_size) {
+ if (index + 2 > end_index) {
LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
return nullptr;
}
@@ -748,7 +719,7 @@
for (StatusSymbol symbol : symbols) {
switch (symbol) {
case StatusSymbol::kReceivedSmallDelta:
- if (index + 1 > payload_size) {
+ if (index + 1 > end_index) {
LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
return nullptr;
}
@@ -756,7 +727,7 @@
++index;
break;
case StatusSymbol::kReceivedLargeDelta:
- if (index + 2 > payload_size) {
+ if (index + 2 > end_index) {
LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
return nullptr;
}
@@ -769,8 +740,8 @@
}
}
- DCHECK_GE(index, payload_size - 3);
- DCHECK_LE(index, payload_size);
+ DCHECK_GE(index, end_index - 3);
+ DCHECK_LE(index, end_index);
return packet;
}
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc b/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
index 4e37cf3..47a6331 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility.cc
@@ -14,6 +14,10 @@
#include <math.h> // ceil
#include <string.h> // memcpy
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
+
namespace webrtc {
namespace RTCPUtility {
@@ -155,43 +159,40 @@
{
for (;;)
{
- RTCPCommonHeader header;
+ RtcpCommonHeader header;
+ if (_ptrRTCPDataEnd <= _ptrRTCPData)
+ return;
- const bool success = RTCPParseCommonHeader(_ptrRTCPData,
- _ptrRTCPDataEnd,
- header);
-
- if (!success)
- {
+ if (!RtcpParseCommonHeader(_ptrRTCPData, _ptrRTCPDataEnd - _ptrRTCPData,
+ &header)) {
return;
}
- _ptrRTCPBlockEnd = _ptrRTCPData + header.LengthInOctets;
+ _ptrRTCPBlockEnd = _ptrRTCPData + header.BlockSize();
if (_ptrRTCPBlockEnd > _ptrRTCPDataEnd)
{
// Bad block!
return;
}
- switch (header.PT)
- {
+ switch (header.packet_type) {
case PT_SR:
{
// number of Report blocks
- _numberOfBlocks = header.IC;
+ _numberOfBlocks = header.count_or_format;
ParseSR();
return;
}
case PT_RR:
{
// number of Report blocks
- _numberOfBlocks = header.IC;
+ _numberOfBlocks = header.count_or_format;
ParseRR();
return;
}
case PT_SDES:
{
// number of SDES blocks
- _numberOfBlocks = header.IC;
+ _numberOfBlocks = header.count_or_format;
const bool ok = ParseSDES();
if (!ok)
{
@@ -202,7 +203,7 @@
}
case PT_BYE:
{
- _numberOfBlocks = header.IC;
+ _numberOfBlocks = header.count_or_format;
const bool ok = ParseBYE();
if (!ok)
{
@@ -214,7 +215,7 @@
case PT_IJ:
{
// number of Report blocks
- _numberOfBlocks = header.IC;
+ _numberOfBlocks = header.count_or_format;
ParseIJ();
return;
}
@@ -410,20 +411,16 @@
void
RTCPUtility::RTCPParserV2::Validate()
{
- if (_ptrRTCPData == NULL)
- {
- return; // NOT VALID
- }
+ if (_ptrRTCPData == nullptr)
+ return; // NOT VALID
- RTCPCommonHeader header;
- const bool success = RTCPParseCommonHeader(_ptrRTCPDataBegin,
- _ptrRTCPDataEnd,
- header);
+ RtcpCommonHeader header;
+ if (_ptrRTCPDataEnd <= _ptrRTCPDataBegin)
+ return; // NOT VALID
- if (!success)
- {
- return; // NOT VALID!
- }
+ if (!RtcpParseCommonHeader(_ptrRTCPDataBegin,
+ _ptrRTCPDataEnd - _ptrRTCPDataBegin, &header))
+ return; // NOT VALID!
// * if (!reducedSize) : first packet must be RR or SR.
//
@@ -437,8 +434,7 @@
if (!_RTCPReducedSizeEnable)
{
- if ((header.PT != PT_SR) && (header.PT != PT_RR))
- {
+ if ((header.packet_type != PT_SR) && (header.packet_type != PT_RR)) {
return; // NOT VALID
}
}
@@ -458,48 +454,74 @@
_ptrRTCPData = _ptrRTCPBlockEnd;
}
-bool
-RTCPUtility::RTCPParseCommonHeader( const uint8_t* ptrDataBegin,
- const uint8_t* ptrDataEnd,
- RTCPCommonHeader& parsedHeader)
-{
- if (!ptrDataBegin || !ptrDataEnd)
- {
- return false;
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |V=2|P| IC | PT | length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// Common header for all RTCP packets, 4 octets.
+
+bool RTCPUtility::RtcpParseCommonHeader(const uint8_t* packet,
+ size_t size_bytes,
+ RtcpCommonHeader* parsed_header) {
+ DCHECK(parsed_header != nullptr);
+ if (size_bytes < RtcpCommonHeader::kHeaderSizeBytes) {
+ LOG(LS_WARNING) << "Too little data (" << size_bytes << " byte"
+ << (size_bytes != 1 ? "s" : "")
+ << ") remaining in buffer to parse RTCP header (4 bytes).";
+ return false;
+ }
+
+ const uint8_t kRtcpVersion = 2;
+ uint8_t version = packet[0] >> 6;
+ if (version != kRtcpVersion) {
+ LOG(LS_WARNING) << "Invalid RTCP header: Version must be "
+ << static_cast<int>(kRtcpVersion) << " but was "
+ << static_cast<int>(version);
+ return false;
+ }
+
+ bool has_padding = (packet[0] & 0x20) != 0;
+ uint8_t format = packet[0] & 0x1F;
+ uint8_t packet_type = packet[1];
+ size_t packet_size_words =
+ ByteReader<uint16_t>::ReadBigEndian(&packet[2]) + 1;
+
+ if (size_bytes < packet_size_words * 4) {
+ LOG(LS_WARNING) << "Buffer too small (" << size_bytes
+ << " bytes) to fit an RtcpPacket of " << packet_size_words
+ << " 32bit words.";
+ return false;
+ }
+
+ size_t payload_size = packet_size_words * 4;
+ size_t padding_bytes = 0;
+ if (has_padding) {
+ if (payload_size <= RtcpCommonHeader::kHeaderSizeBytes) {
+ LOG(LS_WARNING) << "Invalid RTCP header: Padding bit set but 0 payload "
+ "size specified.";
+ return false;
}
- // 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
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // |V=2|P| IC | PT | length |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- //
- // Common header for all RTCP packets, 4 octets.
-
- if ((ptrDataEnd - ptrDataBegin) < 4)
- {
- return false;
+ padding_bytes = packet[payload_size - 1];
+ if (RtcpCommonHeader::kHeaderSizeBytes + padding_bytes > payload_size) {
+ LOG(LS_WARNING) << "Invalid RTCP header: Too many padding bytes ("
+ << padding_bytes << ") for a packet size of "
+ << payload_size << "bytes.";
+ return false;
}
+ payload_size -= padding_bytes;
+ }
+ payload_size -= RtcpCommonHeader::kHeaderSizeBytes;
- parsedHeader.V = ptrDataBegin[0] >> 6;
- parsedHeader.P = ((ptrDataBegin[0] & 0x20) == 0) ? false : true;
- parsedHeader.IC = ptrDataBegin[0] & 0x1f;
- parsedHeader.PT = ptrDataBegin[1];
+ parsed_header->version = kRtcpVersion;
+ parsed_header->count_or_format = format;
+ parsed_header->packet_type = packet_type;
+ parsed_header->payload_size_bytes = payload_size;
+ parsed_header->padding_bytes = padding_bytes;
- parsedHeader.LengthInOctets = (ptrDataBegin[2] << 8) + ptrDataBegin[3] + 1;
- parsedHeader.LengthInOctets *= 4;
-
- if(parsedHeader.LengthInOctets == 0)
- {
- return false;
- }
- // Check if RTP version field == 2
- if (parsedHeader.V != 2)
- {
- return false;
- }
-
- return true;
+ return true;
}
bool
@@ -1137,10 +1159,9 @@
return false;
}
-bool
-RTCPUtility::RTCPParserV2::ParseFBCommon(const RTCPCommonHeader& header)
-{
- assert((header.PT == PT_RTPFB) || (header.PT == PT_PSFB)); // Parser logic check
+bool RTCPUtility::RTCPParserV2::ParseFBCommon(const RtcpCommonHeader& header) {
+ assert((header.packet_type == PT_RTPFB) ||
+ (header.packet_type == PT_PSFB)); // Parser logic check
const ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
@@ -1162,12 +1183,10 @@
mediaSSRC += *_ptrRTCPData++ << 8;
mediaSSRC += *_ptrRTCPData++;
- if (header.PT == PT_RTPFB)
- {
+ if (header.packet_type == PT_RTPFB) {
// Transport layer feedback
- switch (header.IC)
- {
+ switch (header.count_or_format) {
case 1:
{
// NACK
@@ -1222,12 +1241,9 @@
}
EndCurrentBlock();
return false;
- }
- else if (header.PT == PT_PSFB)
- {
+ } else if (header.packet_type == PT_PSFB) {
// Payload specific feedback
- switch (header.IC)
- {
+ switch (header.count_or_format) {
case 1:
// PLI
_packetType = RTCPPacketTypes::kPsfbPli;
@@ -1579,9 +1595,7 @@
return true;
}
-bool
-RTCPUtility::RTCPParserV2::ParseAPP( const RTCPCommonHeader& header)
-{
+bool RTCPUtility::RTCPParserV2::ParseAPP(const RtcpCommonHeader& header) {
ptrdiff_t length = _ptrRTCPBlockEnd - _ptrRTCPData;
if (length < 12) // 4 * 3, RFC 3550 6.7 APP: Application-Defined RTCP Packet
@@ -1606,7 +1620,7 @@
_packetType = RTCPPacketTypes::kApp;
- _packet.APP.SubType = header.IC;
+ _packet.APP.SubType = header.count_or_format;
_packet.APP.Name = name;
_state = ParseState::State_AppItem;
@@ -1651,37 +1665,31 @@
RTCPUtility::RTCPPacketIterator::~RTCPPacketIterator() {
}
-const RTCPUtility::RTCPCommonHeader*
-RTCPUtility::RTCPPacketIterator::Begin()
-{
+const RTCPUtility::RtcpCommonHeader* RTCPUtility::RTCPPacketIterator::Begin() {
_ptrBlock = _ptrBegin;
return Iterate();
}
-const RTCPUtility::RTCPCommonHeader*
-RTCPUtility::RTCPPacketIterator::Iterate()
-{
- const bool success = RTCPParseCommonHeader(_ptrBlock, _ptrEnd, _header);
- if (!success)
- {
- _ptrBlock = NULL;
- return NULL;
- }
- _ptrBlock += _header.LengthInOctets;
+const RTCPUtility::RtcpCommonHeader*
+RTCPUtility::RTCPPacketIterator::Iterate() {
+ if ((_ptrEnd <= _ptrBlock) ||
+ !RtcpParseCommonHeader(_ptrBlock, _ptrEnd - _ptrBlock, &_header)) {
+ _ptrBlock = nullptr;
+ return nullptr;
+ }
+ _ptrBlock += _header.BlockSize();
- if (_ptrBlock > _ptrEnd)
- {
- _ptrBlock = NULL;
- return NULL;
- }
+ if (_ptrBlock > _ptrEnd) {
+ _ptrBlock = nullptr;
+ return nullptr;
+ }
- return &_header;
+ return &_header;
}
-const RTCPUtility::RTCPCommonHeader*
-RTCPUtility::RTCPPacketIterator::Current()
-{
+const RTCPUtility::RtcpCommonHeader*
+RTCPUtility::RTCPPacketIterator::Current() {
if (!_ptrBlock)
{
return NULL;
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility.h b/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
index fcafe59..73658a0 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility.h
@@ -306,12 +306,24 @@
uint8_t* _ptrPacketEnd;
};
-struct RTCPCommonHeader {
- uint8_t V; // Version
- bool P; // Padding
- uint8_t IC; // Item count/subtype
- uint8_t PT; // Packet Type
- uint16_t LengthInOctets;
+struct RtcpCommonHeader {
+ static const uint8_t kHeaderSizeBytes = 4;
+ RtcpCommonHeader()
+ : version(2),
+ count_or_format(0),
+ packet_type(0),
+ payload_size_bytes(0),
+ padding_bytes(0) {}
+
+ uint32_t BlockSize() const {
+ return kHeaderSizeBytes + payload_size_bytes + padding_bytes;
+ }
+
+ uint8_t version;
+ uint8_t count_or_format;
+ uint8_t packet_type;
+ uint32_t payload_size_bytes;
+ uint8_t padding_bytes;
};
enum RTCPPT : uint8_t {
@@ -333,9 +345,9 @@
kBtVoipMetric = 7
};
-bool RTCPParseCommonHeader(const uint8_t* ptrDataBegin,
- const uint8_t* ptrDataEnd,
- RTCPCommonHeader& parsedHeader);
+bool RtcpParseCommonHeader(const uint8_t* buffer,
+ size_t size_bytes,
+ RtcpCommonHeader* parsed_header);
class RTCPParserV2 {
public:
@@ -418,7 +430,7 @@
bool ParseXrVoipMetricItem(int block_length_4bytes);
bool ParseXrUnsupportedBlockType(int block_length_4bytes);
- bool ParseFBCommon(const RTCPCommonHeader& header);
+ bool ParseFBCommon(const RtcpCommonHeader& header);
bool ParseNACKItem();
bool ParseTMMBRItem();
bool ParseTMMBNItem();
@@ -428,7 +440,7 @@
bool ParsePsfbAppItem();
bool ParsePsfbREMBItem();
- bool ParseAPP(const RTCPCommonHeader& header);
+ bool ParseAPP(const RtcpCommonHeader& header);
bool ParseAPPItem();
private:
@@ -452,9 +464,9 @@
RTCPPacketIterator(uint8_t* rtcpData, size_t rtcpDataLength);
~RTCPPacketIterator();
- const RTCPCommonHeader* Begin();
- const RTCPCommonHeader* Iterate();
- const RTCPCommonHeader* Current();
+ const RtcpCommonHeader* Begin();
+ const RtcpCommonHeader* Iterate();
+ const RtcpCommonHeader* Current();
private:
uint8_t* const _ptrBegin;
@@ -462,7 +474,7 @@
uint8_t* _ptrBlock;
- RTCPCommonHeader _header;
+ RtcpCommonHeader _header;
};
} // RTCPUtility
} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_utility_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtcp_utility_unittest.cc
index 275b007..1a13812 100644
--- a/webrtc/modules/rtp_rtcp/source/rtcp_utility_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtcp_utility_unittest.cc
@@ -10,10 +10,16 @@
#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/checks.h"
+#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
namespace webrtc {
+using RTCPUtility::RtcpCommonHeader;
+
+namespace rtcp {
+
TEST(RtcpUtilityTest, MidNtp) {
const uint32_t kNtpSec = 0x12345678;
const uint32_t kNtpFrac = 0x23456789;
@@ -68,5 +74,88 @@
EXPECT_EQ(8U, stats.requests());
}
+class RtcpParseCommonHeaderTest : public ::testing::Test {
+ public:
+ RtcpParseCommonHeaderTest() { memset(buffer, 0, kBufferCapacityBytes); }
+ virtual ~RtcpParseCommonHeaderTest() {}
+
+ protected:
+ static const size_t kBufferCapacityBytes = 40;
+ uint8_t buffer[kBufferCapacityBytes];
+ RtcpCommonHeader header;
+};
+
+TEST_F(RtcpParseCommonHeaderTest, TooSmallBuffer) {
+ // Buffer needs to be able to hold the header.
+ for (size_t i = 0; i < RtcpCommonHeader::kHeaderSizeBytes; ++i)
+ EXPECT_FALSE(RtcpParseCommonHeader(buffer, i, &header));
+}
+
+TEST_F(RtcpParseCommonHeaderTest, Version) {
+ // Version 2 is the only allowed for now.
+ for (int v = 0; v < 4; ++v) {
+ buffer[0] = v << 6;
+ EXPECT_EQ(v == 2, RtcpParseCommonHeader(
+ buffer, RtcpCommonHeader::kHeaderSizeBytes, &header));
+ }
+}
+
+TEST_F(RtcpParseCommonHeaderTest, PacketSize) {
+ // Set v = 2, leave p, fmt, pt as 0.
+ buffer[0] = 2 << 6;
+
+ const size_t kBlockSize = 3;
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], kBlockSize);
+ const size_t kSizeInBytes = (kBlockSize + 1) * 4;
+
+ EXPECT_FALSE(RtcpParseCommonHeader(buffer, kSizeInBytes - 1, &header));
+ EXPECT_TRUE(RtcpParseCommonHeader(buffer, kSizeInBytes, &header));
+}
+
+TEST_F(RtcpParseCommonHeaderTest, PayloadSize) {
+ // Set v = 2, p = 1, but leave fmt, pt as 0.
+ buffer[0] = (2 << 6) | (1 << 5);
+
+ // Padding bit set, but no byte for padding (can't specify padding length).
+ EXPECT_FALSE(RtcpParseCommonHeader(buffer, 4, &header));
+
+ const size_t kBlockSize = 3;
+ ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], kBlockSize);
+ const size_t kSizeInBytes = (kBlockSize + 1) * 4;
+ const size_t kPayloadSizeBytes =
+ kSizeInBytes - RtcpCommonHeader::kHeaderSizeBytes;
+
+ // Padding one byte larger than possible.
+ buffer[kSizeInBytes - 1] = kPayloadSizeBytes + 1;
+ EXPECT_FALSE(RtcpParseCommonHeader(buffer, kSizeInBytes, &header));
+
+ // Pure padding packet?
+ buffer[kSizeInBytes - 1] = kPayloadSizeBytes;
+ EXPECT_TRUE(RtcpParseCommonHeader(buffer, kSizeInBytes, &header));
+ EXPECT_EQ(kPayloadSizeBytes, header.padding_bytes);
+ EXPECT_EQ(0u, header.payload_size_bytes);
+
+ // Single byte of actual data.
+ buffer[kSizeInBytes - 1] = kPayloadSizeBytes - 1;
+ EXPECT_TRUE(RtcpParseCommonHeader(buffer, kSizeInBytes, &header));
+ EXPECT_EQ(kPayloadSizeBytes - 1, header.padding_bytes);
+ EXPECT_EQ(1u, header.payload_size_bytes);
+}
+
+TEST_F(RtcpParseCommonHeaderTest, FormatAndPayloadType) {
+ // Format/count and packet type both set to max values.
+ const uint8_t kCountOrFormat = 0x1F;
+ const uint8_t kPacketType = 0xFF;
+ buffer[0] = 2 << 6; // V = 2.
+ buffer[0] |= kCountOrFormat;
+ buffer[1] = kPacketType;
+
+ EXPECT_TRUE(RtcpParseCommonHeader(buffer, RtcpCommonHeader::kHeaderSizeBytes,
+ &header));
+ EXPECT_EQ(kCountOrFormat, header.count_or_format);
+ EXPECT_EQ(kPacketType, header.packet_type);
+}
+
+} // namespace rtcp
} // namespace webrtc