[rtp_rtcp] rtcp::Sdes moved into own file

Cleaning/Parsing will be done in the https://codereview.webrtc.org/1439553003/

BUG=webrtc:5260
R=asapersson@webrtc.org, åsapersson

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

Cr-Commit-Position: refs/heads/master@{#11274}
This commit is contained in:
Danil Chapovalov
2016-01-15 17:34:27 +01:00
parent 79a5a83e10
commit 1567d0bd98
11 changed files with 258 additions and 201 deletions

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2016 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/sdes.h"
#include "webrtc/base/logging.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
using webrtc::RTCPUtility::PT_SDES;
namespace webrtc {
namespace rtcp {
namespace {
void AssignUWord8(uint8_t* buffer, size_t* offset, uint8_t value) {
buffer[(*offset)++] = value;
}
void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
ByteWriter<uint32_t>::WriteBigEndian(buffer + *offset, value);
*offset += 4;
}
// Source Description (SDES) (RFC 3550).
//
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// header |V=2|P| SC | PT=SDES=202 | length |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// chunk | SSRC/CSRC_1 |
// 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SDES items |
// | ... |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
// chunk | SSRC/CSRC_2 |
// 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | SDES items |
// | ... |
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// Canonical End-Point Identifier SDES Item (CNAME)
//
// 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
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | CNAME=1 | length | user and domain name ...
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
void CreateSdes(const std::vector<Sdes::Chunk>& chunks,
uint8_t* buffer,
size_t* pos) {
const uint8_t kSdesItemType = 1;
for (std::vector<Sdes::Chunk>::const_iterator it = chunks.begin();
it != chunks.end(); ++it) {
AssignUWord32(buffer, pos, (*it).ssrc);
AssignUWord8(buffer, pos, kSdesItemType);
AssignUWord8(buffer, pos, (*it).name.length());
memcpy(buffer + *pos, (*it).name.data(), (*it).name.length());
*pos += (*it).name.length();
memset(buffer + *pos, 0, (*it).null_octets);
*pos += (*it).null_octets;
}
}
} // namespace
bool Sdes::Create(uint8_t* packet,
size_t* index,
size_t max_length,
RtcpPacket::PacketReadyCallback* callback) const {
assert(!chunks_.empty());
while (*index + BlockLength() > max_length) {
if (!OnBufferFull(packet, index, callback))
return false;
}
CreateHeader(chunks_.size(), PT_SDES, HeaderLength(), packet, index);
CreateSdes(chunks_, packet, index);
return true;
}
bool Sdes::WithCName(uint32_t ssrc, const std::string& cname) {
assert(cname.length() <= 0xff);
if (chunks_.size() >= kMaxNumberOfChunks) {
LOG(LS_WARNING) << "Max SDES chunks reached.";
return false;
}
// In each chunk, the list of items must be terminated by one or more null
// octets. The next chunk must start on a 32-bit boundary.
// CNAME (1 byte) | length (1 byte) | name | padding.
int null_octets = 4 - ((2 + cname.length()) % 4);
Chunk chunk;
chunk.ssrc = ssrc;
chunk.name = cname;
chunk.null_octets = null_octets;
chunks_.push_back(chunk);
return true;
}
size_t Sdes::BlockLength() const {
// Header (4 bytes).
// Chunk:
// SSRC/CSRC (4 bytes) | CNAME (1 byte) | length (1 byte) | name | padding.
size_t length = kHeaderLength;
for (const Chunk& chunk : chunks_)
length += 6 + chunk.name.length() + chunk.null_octets;
assert(length % 4 == 0);
return length;
}
} // namespace rtcp
} // namespace webrtc

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2016 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_SDES_H_
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SDES_H_
#include <string>
#include <vector>
#include "webrtc/base/basictypes.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
namespace webrtc {
namespace rtcp {
// Source Description (SDES) (RFC 3550).
class Sdes : public RtcpPacket {
public:
Sdes() : RtcpPacket() {}
virtual ~Sdes() {}
bool WithCName(uint32_t ssrc, const std::string& cname);
struct Chunk {
uint32_t ssrc;
std::string name;
int null_octets;
};
protected:
bool Create(uint8_t* packet,
size_t* index,
size_t max_length,
RtcpPacket::PacketReadyCallback* callback) const override;
private:
static const int kMaxNumberOfChunks = 0x1f;
size_t BlockLength() const;
std::vector<Chunk> chunks_;
RTC_DISALLOW_COPY_AND_ASSIGN(Sdes);
};
} // namespace rtcp
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_RTCP_PACKET_SDES_H_

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2016 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/sdes.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/test/rtcp_packet_parser.h"
using webrtc::rtcp::RawPacket;
using webrtc::rtcp::Sdes;
using webrtc::test::RtcpPacketParser;
namespace webrtc {
const uint32_t kSenderSsrc = 0x12345678;
TEST(RtcpPacketSdesTest, WithOneChunk) {
Sdes sdes;
EXPECT_TRUE(sdes.WithCName(kSenderSsrc, "alice@host"));
rtc::scoped_ptr<RawPacket> packet(sdes.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.sdes()->num_packets());
EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
EXPECT_EQ("alice@host", parser.sdes_chunk()->Cname());
}
TEST(RtcpPacketSdesTest, WithMultipleChunks) {
Sdes sdes;
EXPECT_TRUE(sdes.WithCName(kSenderSsrc, "a"));
EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 1, "ab"));
EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 2, "abc"));
EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 3, "abcd"));
EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 4, "abcde"));
EXPECT_TRUE(sdes.WithCName(kSenderSsrc + 5, "abcdef"));
rtc::scoped_ptr<RawPacket> packet(sdes.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.sdes()->num_packets());
EXPECT_EQ(6, parser.sdes_chunk()->num_packets());
EXPECT_EQ(kSenderSsrc + 5, parser.sdes_chunk()->Ssrc());
EXPECT_EQ("abcdef", parser.sdes_chunk()->Cname());
}
TEST(RtcpPacketSdesTest, WithTooManyChunks) {
Sdes sdes;
const int kMaxChunks = (1 << 5) - 1;
for (int i = 0; i < kMaxChunks; ++i) {
uint32_t ssrc = kSenderSsrc + i;
std::ostringstream oss;
oss << "cname" << i;
EXPECT_TRUE(sdes.WithCName(ssrc, oss.str()));
}
EXPECT_FALSE(sdes.WithCName(kSenderSsrc + kMaxChunks, "foo"));
}
TEST(RtcpPacketSdesTest, CnameItemWithEmptyString) {
Sdes sdes;
EXPECT_TRUE(sdes.WithCName(kSenderSsrc, ""));
rtc::scoped_ptr<RawPacket> packet(sdes.Build());
RtcpPacketParser parser;
parser.Parse(packet->Buffer(), packet->Length());
EXPECT_EQ(1, parser.sdes()->num_packets());
EXPECT_EQ(1, parser.sdes_chunk()->num_packets());
EXPECT_EQ(kSenderSsrc, parser.sdes_chunk()->Ssrc());
EXPECT_EQ("", parser.sdes_chunk()->Cname());
}
} // namespace webrtc