115 lines
4.4 KiB
C++
115 lines
4.4 KiB
C++
|
|
/*
|
||
|
|
* 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
|