RTCP Bye packet moved to own file

Bye class got support for Parsing
 Reason field implemented

Review URL: https://codereview.webrtc.org/1430013003

Cr-Commit-Position: refs/heads/master@{#10741}
This commit is contained in:
danilchap 2015-11-22 09:03:11 -08:00 committed by Commit bot
parent c9829138c0
commit 50c5136cb2
11 changed files with 377 additions and 134 deletions

View File

@ -305,6 +305,7 @@
'rtp_rtcp/source/rtcp_format_remb_unittest.cc',
'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/extended_jitter_report_unittest.cc',
'rtp_rtcp/source/rtcp_packet/report_block_unittest.cc',
'rtp_rtcp/source/rtcp_packet/transport_feedback_unittest.cc',

View File

@ -48,6 +48,8 @@ source_set("rtp_rtcp") {
"source/rtcp_packet.h",
"source/rtcp_packet/app.cc",
"source/rtcp_packet/app.h",
"source/rtcp_packet/bye.cc",
"source/rtcp_packet/bye.h",
"source/rtcp_packet/extended_jitter_report.cc",
"source/rtcp_packet/extended_jitter_report.h",
"source/rtcp_packet/report_block.cc",

View File

@ -43,6 +43,8 @@
'source/rtcp_packet.h',
'source/rtcp_packet/app.cc',
'source/rtcp_packet/app.h',
'source/rtcp_packet/bye.cc',
'source/rtcp_packet/bye.h',
'source/rtcp_packet/extended_jitter_report.cc',
'source/rtcp_packet/extended_jitter_report.h',
'source/rtcp_packet/report_block.cc',

View File

@ -19,7 +19,6 @@ using webrtc::RTCPUtility::kBtReceiverReferenceTime;
using webrtc::RTCPUtility::kBtVoipMetric;
using webrtc::RTCPUtility::PT_APP;
using webrtc::RTCPUtility::PT_BYE;
using webrtc::RTCPUtility::PT_IJ;
using webrtc::RTCPUtility::PT_PSFB;
using webrtc::RTCPUtility::PT_RR;
@ -29,7 +28,6 @@ using webrtc::RTCPUtility::PT_SR;
using webrtc::RTCPUtility::PT_XR;
using webrtc::RTCPUtility::RTCPPacketAPP;
using webrtc::RTCPUtility::RTCPPacketBYE;
using webrtc::RTCPUtility::RTCPPacketPSFBAPP;
using webrtc::RTCPUtility::RTCPPacketPSFBFIR;
using webrtc::RTCPUtility::RTCPPacketPSFBFIRItem;
@ -205,28 +203,6 @@ void CreateSdes(const std::vector<Sdes::Chunk>& chunks,
}
}
// Bye packet (BYE) (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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P| SC | PT=BYE=203 | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC/CSRC |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : ... :
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// (opt) | length | reason for leaving ...
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
void CreateBye(const RTCPPacketBYE& bye,
const std::vector<uint32_t>& csrcs,
uint8_t* buffer,
size_t* pos) {
AssignUWord32(buffer, pos, bye.SenderSSRC);
for (uint32_t csrc : csrcs)
AssignUWord32(buffer, pos, csrc);
}
// RFC 4585: Feedback format.
//
// Common packet format:
@ -801,29 +777,6 @@ size_t Sdes::BlockLength() const {
return length;
}
bool Bye::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 = HeaderLength();
CreateHeader(length, PT_BYE, length, packet, index);
CreateBye(bye_, csrcs_, packet, index);
return true;
}
bool Bye::WithCsrc(uint32_t csrc) {
if (csrcs_.size() >= kMaxNumberOfCsrcs) {
LOG(LS_WARNING) << "Max CSRC size reached.";
return false;
}
csrcs_.push_back(csrc);
return true;
}
bool Pli::Create(uint8_t* packet,
size_t* index,
size_t max_length,

View File

@ -319,56 +319,6 @@ class Sdes : public RtcpPacket {
RTC_DISALLOW_COPY_AND_ASSIGN(Sdes);
};
//
// Bye packet (BYE) (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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P| SC | PT=BYE=203 | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC/CSRC |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : ... :
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// (opt) | length | reason for leaving ...
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
class Bye : public RtcpPacket {
public:
Bye() : RtcpPacket() {
memset(&bye_, 0, sizeof(bye_));
}
virtual ~Bye() {}
void From(uint32_t ssrc) {
bye_.SenderSSRC = ssrc;
}
bool WithCsrc(uint32_t csrc);
// TODO(sprang): Add support for reason field?
protected:
bool Create(uint8_t* packet,
size_t* index,
size_t max_length,
RtcpPacket::PacketReadyCallback* callback) const override;
private:
static const int kMaxNumberOfCsrcs = 0x1f - 1; // First item is sender SSRC.
size_t BlockLength() const {
size_t source_count = 1 + csrcs_.size();
return kHeaderLength + 4 * source_count;
}
RTCPUtility::RTCPPacketBYE bye_;
std::vector<uint32_t> csrcs_;
RTC_DISALLOW_COPY_AND_ASSIGN(Bye);
};
// RFC 4585: Feedback format.
//
// Common packet format:

View File

@ -0,0 +1,133 @@
/*
* 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/bye.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/logging.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
using webrtc::RTCPUtility::RtcpCommonHeader;
namespace webrtc {
namespace rtcp {
// Bye packet (BYE) (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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |V=2|P| SC | PT=BYE=203 | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SSRC/CSRC |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// : ... :
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// (opt) | length | reason for leaving ...
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Bye::Bye() : sender_ssrc_(0) {}
bool Bye::Parse(const RtcpCommonHeader& header, const uint8_t* payload) {
RTC_DCHECK(header.packet_type == kPacketType);
const uint8_t src_count = header.count_or_format;
// Validate packet.
if (header.payload_size_bytes < 4u * src_count) {
LOG(LS_WARNING)
<< "Packet is too small to contain CSRCs it promise to have.";
return false;
}
bool has_reason = (header.payload_size_bytes > 4u * src_count);
uint8_t reason_length = 0;
if (has_reason) {
reason_length = payload[4u * src_count];
if (header.payload_size_bytes - 4u * src_count < 1u + reason_length) {
LOG(LS_WARNING) << "Invalid reason length: " << reason_length;
return false;
}
}
// Once sure packet is valid, copy values.
if (src_count == 0) { // A count value of zero is valid, but useless.
sender_ssrc_ = 0;
csrcs_.clear();
} else {
sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(payload);
csrcs_.resize(src_count - 1);
for (size_t i = 1; i < src_count; ++i)
csrcs_[i - 1] = ByteReader<uint32_t>::ReadBigEndian(&payload[4 * i]);
}
if (has_reason) {
reason_.assign(reinterpret_cast<const char*>(&payload[4u * src_count + 1]),
reason_length);
} else {
reason_.clear();
}
return true;
}
bool Bye::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();
CreateHeader(1 + csrcs_.size(), kPacketType, HeaderLength(), packet, index);
// Store srcs of the leaving clients.
ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], sender_ssrc_);
*index += sizeof(uint32_t);
for (uint32_t csrc : csrcs_) {
ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], csrc);
*index += sizeof(uint32_t);
}
// Store the reason to leave.
if (!reason_.empty()) {
uint8_t reason_length = reason_.size();
packet[(*index)++] = reason_length;
memcpy(&packet[*index], reason_.data(), reason_length);
*index += reason_length;
// Add padding bytes if needed.
size_t bytes_to_pad = index_end - *index;
RTC_DCHECK_LE(bytes_to_pad, 3u);
if (bytes_to_pad > 0) {
memset(&packet[*index], 0, bytes_to_pad);
*index += bytes_to_pad;
}
}
RTC_DCHECK_EQ(index_end, *index);
return true;
}
bool Bye::WithCsrc(uint32_t csrc) {
if (csrcs_.size() >= kMaxNumberOfCsrcs) {
LOG(LS_WARNING) << "Max CSRC size reached.";
return false;
}
csrcs_.push_back(csrc);
return true;
}
void Bye::WithReason(const std::string& reason) {
RTC_DCHECK_LE(reason.size(), 0xffu);
reason_ = reason;
}
size_t Bye::BlockLength() const {
size_t src_count = (1 + csrcs_.size());
size_t reason_size_in_32bits = reason_.empty() ? 0 : (reason_.size() / 4 + 1);
return kHeaderLength + 4 * (src_count + reason_size_in_32bits);
}
} // 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_BYE_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_BYE_H_
#include <string>
#include <vector>
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
namespace webrtc {
namespace rtcp {
class Bye : public RtcpPacket {
public:
static const uint8_t kPacketType = 203;
Bye();
virtual ~Bye() {}
// 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.
void From(uint32_t ssrc) { sender_ssrc_ = ssrc; }
bool WithCsrc(uint32_t csrc);
void WithReason(const std::string& reason);
uint32_t sender_ssrc() const { return sender_ssrc_; }
const std::vector<uint32_t>& csrcs() const { return csrcs_; }
const std::string& reason() const { return reason_; }
protected:
bool Create(uint8_t* packet,
size_t* index,
size_t max_length,
RtcpPacket::PacketReadyCallback* callback) const override;
private:
static const int kMaxNumberOfCsrcs = 0x1f - 1; // First item is sender SSRC.
size_t BlockLength() const override;
uint32_t sender_ssrc_;
std::vector<uint32_t> csrcs_;
std::string reason_;
RTC_DISALLOW_COPY_AND_ASSIGN(Bye);
};
} // namespace rtcp
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_BYE_H_

View File

@ -0,0 +1,173 @@
/*
* 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/bye.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
using ::testing::ElementsAre;
using webrtc::rtcp::Bye;
using webrtc::rtcp::RawPacket;
using webrtc::RTCPUtility::RtcpCommonHeader;
using webrtc::RTCPUtility::RtcpParseCommonHeader;
namespace webrtc {
namespace {
const uint32_t kSenderSsrc = 0x12345678;
const uint32_t kCsrc1 = 0x22232425;
const uint32_t kCsrc2 = 0x33343536;
class RtcpPacketByeTest : public ::testing::Test {
protected:
void BuildPacket() { packet = bye.Build().Pass(); }
void ParsePacket() {
RtcpCommonHeader header;
EXPECT_TRUE(
RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header));
// Check that there is exactly one RTCP packet in the buffer.
EXPECT_EQ(header.BlockSize(), packet->Length());
EXPECT_TRUE(parsed_bye.Parse(
header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
}
Bye bye;
rtc::scoped_ptr<RawPacket> packet;
Bye parsed_bye;
};
TEST_F(RtcpPacketByeTest, Bye) {
bye.From(kSenderSsrc);
BuildPacket();
ParsePacket();
EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
EXPECT_TRUE(parsed_bye.csrcs().empty());
EXPECT_TRUE(parsed_bye.reason().empty());
}
TEST_F(RtcpPacketByeTest, WithCsrcs) {
bye.From(kSenderSsrc);
EXPECT_TRUE(bye.WithCsrc(kCsrc1));
EXPECT_TRUE(bye.WithCsrc(kCsrc2));
EXPECT_TRUE(bye.reason().empty());
BuildPacket();
EXPECT_EQ(16u, packet->Length()); // Header: 4, 3xSRCs: 12, Reason: 0.
ParsePacket();
EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
EXPECT_THAT(parsed_bye.csrcs(), ElementsAre(kCsrc1, kCsrc2));
EXPECT_TRUE(parsed_bye.reason().empty());
}
TEST_F(RtcpPacketByeTest, WithCsrcsAndReason) {
const std::string kReason = "Some Reason";
bye.From(kSenderSsrc);
EXPECT_TRUE(bye.WithCsrc(kCsrc1));
EXPECT_TRUE(bye.WithCsrc(kCsrc2));
bye.WithReason(kReason);
BuildPacket();
EXPECT_EQ(28u, packet->Length()); // Header: 4, 3xSRCs: 12, Reason: 12.
ParsePacket();
EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
EXPECT_THAT(parsed_bye.csrcs(), ElementsAre(kCsrc1, kCsrc2));
EXPECT_EQ(kReason, parsed_bye.reason());
}
TEST_F(RtcpPacketByeTest, WithTooManyCsrcs) {
bye.From(kSenderSsrc);
const int kMaxCsrcs = (1 << 5) - 2; // 5 bit len, first item is sender SSRC.
for (int i = 0; i < kMaxCsrcs; ++i) {
EXPECT_TRUE(bye.WithCsrc(i));
}
EXPECT_FALSE(bye.WithCsrc(kMaxCsrcs));
}
TEST_F(RtcpPacketByeTest, WithAReason) {
const std::string kReason = "Some Random Reason";
bye.From(kSenderSsrc);
bye.WithReason(kReason);
BuildPacket();
ParsePacket();
EXPECT_EQ(kSenderSsrc, parsed_bye.sender_ssrc());
EXPECT_TRUE(parsed_bye.csrcs().empty());
EXPECT_EQ(kReason, parsed_bye.reason());
}
TEST_F(RtcpPacketByeTest, WithReasons) {
// Test that packet creation/parsing behave with reasons of different length
// both when it require padding and when it does not.
for (size_t reminder = 0; reminder < 4; ++reminder) {
const std::string kReason(4 + reminder, 'a' + reminder);
bye.From(kSenderSsrc);
bye.WithReason(kReason);
BuildPacket();
ParsePacket();
EXPECT_EQ(kReason, parsed_bye.reason());
}
}
TEST_F(RtcpPacketByeTest, ParseEmptyPacket) {
RtcpCommonHeader header;
header.packet_type = Bye::kPacketType;
header.count_or_format = 0;
header.payload_size_bytes = 0;
uint8_t empty_payload[1];
EXPECT_TRUE(parsed_bye.Parse(header, empty_payload + 1));
EXPECT_EQ(0u, parsed_bye.sender_ssrc());
EXPECT_TRUE(parsed_bye.csrcs().empty());
EXPECT_TRUE(parsed_bye.reason().empty());
}
TEST_F(RtcpPacketByeTest, ParseFailOnInvalidSrcCount) {
bye.From(kSenderSsrc);
BuildPacket();
RtcpCommonHeader header;
RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header);
header.count_or_format = 2; // Lie there are 2 ssrcs, not one.
EXPECT_FALSE(parsed_bye.Parse(
header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
}
TEST_F(RtcpPacketByeTest, ParseFailOnInvalidReasonLength) {
bye.From(kSenderSsrc);
bye.WithReason("18 characters long");
BuildPacket();
RtcpCommonHeader header;
RtcpParseCommonHeader(packet->Buffer(), packet->Length(), &header);
header.payload_size_bytes -= 4; // Payload is usually 32bit aligned.
EXPECT_FALSE(parsed_bye.Parse(
header, packet->Buffer() + RtcpCommonHeader::kHeaderSizeBytes));
}
} // namespace
} // namespace webrtc

View File

@ -15,6 +15,7 @@
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h"
#include "webrtc/test/rtcp_packet_parser.h"
using ::testing::ElementsAre;
@ -571,43 +572,6 @@ TEST(RtcpPacketTest, AppendPacketWithOwnAppendedPacket) {
EXPECT_EQ(1, parser.fir()->num_packets());
}
TEST(RtcpPacketTest, Bye) {
Bye bye;
bye.From(kSenderSsrc);
rtc::scoped_ptr<RawPacket> packet(bye.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.bye()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.bye()->Ssrc());
}
TEST(RtcpPacketTest, ByeWithCsrcs) {
Fir fir;
Bye bye;
bye.From(kSenderSsrc);
EXPECT_TRUE(bye.WithCsrc(0x22222222));
EXPECT_TRUE(bye.WithCsrc(0x33333333));
bye.Append(&fir);
rtc::scoped_ptr<RawPacket> packet(bye.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.bye()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.bye()->Ssrc());
EXPECT_EQ(1, parser.fir()->num_packets());
}
TEST(RtcpPacketTest, ByeWithTooManyCsrcs) {
Bye bye;
bye.From(kSenderSsrc);
const int kMaxCsrcs = (1 << 5) - 2; // 5 bit len, first item is sender SSRC.
for (int i = 0; i < kMaxCsrcs; ++i) {
EXPECT_TRUE(bye.WithCsrc(i));
}
EXPECT_FALSE(bye.WithCsrc(kMaxCsrcs));
}
TEST(RtcpPacketTest, BuildWithInputBuffer) {
Fir fir;
ReportBlock rb;

View File

@ -26,6 +26,7 @@
#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/app.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/extended_jitter_report.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"

View File

@ -23,6 +23,7 @@
#include "webrtc/common_types.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/app.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"