blob: bac03e73d29e3ffd07cec24114712370ff0fe412 [file] [log] [blame]
/*
* Copyright (c) 2014 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 "modules/rtp_rtcp/source/rtcp_packet.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "rtc_base/checks.h"
namespace webrtc {
namespace rtcp {
constexpr size_t RtcpPacket::kHeaderLength;
rtc::Buffer RtcpPacket::Build() const {
rtc::Buffer packet(BlockLength());
size_t length = 0;
bool created = Create(packet.data(), &length, packet.capacity(), nullptr);
RTC_DCHECK(created) << "Invalid packet is not supported.";
RTC_DCHECK_EQ(length, packet.size())
<< "BlockLength mispredicted size used by Create";
return packet;
}
bool RtcpPacket::Build(size_t max_length, PacketReadyCallback callback) const {
RTC_CHECK_LE(max_length, IP_PACKET_SIZE);
uint8_t buffer[IP_PACKET_SIZE];
size_t index = 0;
if (!Create(buffer, &index, max_length, callback))
return false;
return OnBufferFull(buffer, &index, callback);
}
bool RtcpPacket::OnBufferFull(uint8_t* packet,
size_t* index,
PacketReadyCallback callback) const {
if (*index == 0)
return false;
RTC_DCHECK(callback) << "Fragmentation not supported.";
callback(rtc::ArrayView<const uint8_t>(packet, *index));
*index = 0;
return true;
}
size_t RtcpPacket::HeaderLength() const {
size_t length_in_bytes = BlockLength();
RTC_DCHECK_GT(length_in_bytes, 0);
RTC_DCHECK_EQ(length_in_bytes % 4, 0)
<< "Padding must be handled by each subclass.";
// Length in 32-bit words without common header.
return (length_in_bytes - kHeaderLength) / 4;
}
// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
//
// RTP header format.
// 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| RC/FMT | PT | length |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
void RtcpPacket::CreateHeader(
size_t count_or_format, // Depends on packet type.
uint8_t packet_type,
size_t length,
uint8_t* buffer,
size_t* pos) {
CreateHeader(count_or_format, packet_type, length, /*padding=*/false, buffer,
pos);
}
void RtcpPacket::CreateHeader(
size_t count_or_format, // Depends on packet type.
uint8_t packet_type,
size_t length,
bool padding,
uint8_t* buffer,
size_t* pos) {
RTC_DCHECK_LE(length, 0xffffU);
RTC_DCHECK_LE(count_or_format, 0x1f);
constexpr uint8_t kVersionBits = 2 << 6;
uint8_t padding_bit = padding ? 1 << 5 : 0;
buffer[*pos + 0] =
kVersionBits | padding_bit | static_cast<uint8_t>(count_or_format);
buffer[*pos + 1] = packet_type;
buffer[*pos + 2] = (length >> 8) & 0xff;
buffer[*pos + 3] = length & 0xff;
*pos += kHeaderLength;
}
} // namespace rtcp
} // namespace webrtc