mod bye;
mod channel;
mod context;
mod handler;
mod report;
mod sdes;
mod stats;
use std::ops::Deref;
use bytes::{Buf, Bytes, BytesMut};
use zerocopy::{
byteorder::network_endian::U16, FromBytes, Immutable, IntoBytes, KnownLayout, SizeError,
Unaligned,
};
use crate::InvalidInput;
pub use self::{
bye::ByePacket,
channel::RtcpChannel,
context::{RtcpContext, RtcpContextHandle},
handler::{MuxedRtcpHandler, RtcpHandler, RtcpHandlerOptions},
report::{ReceiverReport, ReportBlock, SenderReport},
sdes::{SourceDescription, SourceDescriptionPacket},
};
#[derive(Clone)]
pub struct CompoundRtcpPacket {
inner: Vec<RtcpPacket>,
}
impl CompoundRtcpPacket {
pub fn new<T>(packets: T) -> Self
where
T: Into<Vec<RtcpPacket>>,
{
Self {
inner: packets.into(),
}
}
pub fn decode(mut frame: Bytes) -> Result<Self, InvalidInput> {
let mut res = Vec::new();
while !frame.is_empty() {
res.push(RtcpPacket::decode(&mut frame)?);
}
Ok(res.into())
}
pub fn encode(&self, buf: &mut BytesMut) {
buf.reserve(self.raw_size());
for packet in &self.inner {
packet.encode(buf);
}
}
pub fn raw_size(&self) -> usize {
self.inner.iter().map(|packet| packet.length()).sum()
}
}
impl Deref for CompoundRtcpPacket {
type Target = [RtcpPacket];
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl From<RtcpPacket> for CompoundRtcpPacket {
#[inline]
fn from(packet: RtcpPacket) -> Self {
Self {
inner: vec![packet],
}
}
}
impl<T> From<T> for CompoundRtcpPacket
where
T: Into<Vec<RtcpPacket>>,
{
#[inline]
fn from(packets: T) -> Self {
Self::new(packets)
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum RtcpPacketType {
SR,
RR,
SDES,
BYE,
Other(u8),
}
impl RtcpPacketType {
#[inline]
pub fn raw_id(self) -> u8 {
match self {
RtcpPacketType::SR => 200,
RtcpPacketType::RR => 201,
RtcpPacketType::SDES => 202,
RtcpPacketType::BYE => 203,
RtcpPacketType::Other(id) => id,
}
}
}
impl From<u8> for RtcpPacketType {
#[inline]
fn from(id: u8) -> RtcpPacketType {
match id {
200 => RtcpPacketType::SR,
201 => RtcpPacketType::RR,
202 => RtcpPacketType::SDES,
203 => RtcpPacketType::BYE,
id => RtcpPacketType::Other(id),
}
}
}
#[derive(Copy, Clone, KnownLayout, Immutable, Unaligned, IntoBytes, FromBytes)]
#[repr(C)]
struct RawRtcpHeader {
options: u8,
packet_type: u8,
length: U16,
}
#[derive(Copy, Clone)]
pub struct RtcpHeader {
options: u8,
packet_type: RtcpPacketType,
length: u16,
}
impl RtcpHeader {
pub const RAW_SIZE: usize = std::mem::size_of::<RawRtcpHeader>();
#[inline]
pub const fn new(packet_type: RtcpPacketType) -> Self {
Self {
options: 2 << 6,
packet_type,
length: 0,
}
}
pub fn decode(data: &mut Bytes) -> Result<Self, InvalidInput> {
let (raw, _) = RawRtcpHeader::ref_from_prefix(data)
.map_err(SizeError::from)
.map_err(|_| InvalidInput::new())?;
if (raw.options >> 6) != 2 {
return Err(InvalidInput::new());
}
let res = Self {
options: raw.options,
packet_type: raw.packet_type.into(),
length: raw.length.get(),
};
data.advance(std::mem::size_of::<RawRtcpHeader>());
Ok(res)
}
pub fn encode(&self, buf: &mut BytesMut) {
let raw = RawRtcpHeader {
options: self.options,
packet_type: self.packet_type.raw_id(),
length: U16::new(self.length),
};
buf.extend_from_slice(raw.as_bytes());
}
#[inline]
pub fn padding(&self) -> bool {
(self.options & 0x20) != 0
}
#[inline]
pub fn with_padding(mut self, padding: bool) -> Self {
self.options &= !0x20;
self.options |= (padding as u8) << 5;
self
}
#[inline]
pub fn packet_length(&self) -> usize {
((self.length as usize) + 1) << 2
}
#[inline]
pub fn with_packet_length(mut self, length: usize) -> Self {
assert!((4..=262_144).contains(&length) && (length & 3) == 0);
self.length = ((length >> 2) - 1) as u16;
self
}
#[inline]
pub fn packet_type(&self) -> RtcpPacketType {
self.packet_type
}
#[inline]
pub fn with_packet_type(mut self, packet_type: RtcpPacketType) -> Self {
self.packet_type = packet_type;
self
}
#[inline]
pub fn item_count(&self) -> u8 {
self.options & 0x1f
}
#[inline]
pub fn with_item_count(mut self, count: u8) -> Self {
assert!(count < 32);
self.options &= !0x1f;
self.options |= count & 0x1f;
self
}
#[inline]
pub fn raw_size(&self) -> usize {
std::mem::size_of::<RawRtcpHeader>()
}
}
#[derive(Clone)]
pub struct RtcpPacket {
header: RtcpHeader,
payload: Bytes,
}
impl RtcpPacket {
#[inline]
pub const fn new(packet_type: RtcpPacketType) -> Self {
Self {
header: RtcpHeader::new(packet_type),
payload: Bytes::new(),
}
}
pub fn from_parts(header: RtcpHeader, payload: Bytes) -> Result<Self, InvalidInput> {
if header.padding() {
let padding_len = payload.last().copied().ok_or_else(InvalidInput::new)? as usize;
if padding_len == 0 || payload.len() < padding_len {
return Err(InvalidInput::new());
}
}
let packet_len = header.packet_length();
if packet_len != (payload.len() + 4) {
return Err(InvalidInput::new());
}
let res = Self { header, payload };
Ok(res)
}
#[inline]
pub fn deconstruct(self) -> (RtcpHeader, Bytes) {
(self.header, self.payload)
}
pub fn decode(data: &mut Bytes) -> Result<Self, InvalidInput> {
let mut buffer = data.clone();
let header = RtcpHeader::decode(&mut buffer)?;
let payload_len = header.packet_length() - 4;
if buffer.len() < payload_len {
return Err(InvalidInput::new());
}
let res = Self::from_parts(header, buffer.split_to(payload_len))?;
*data = buffer;
Ok(res)
}
pub fn encode(&self, buf: &mut BytesMut) {
buf.reserve(self.header.packet_length());
self.header.encode(buf);
buf.extend_from_slice(&self.payload);
}
#[inline]
pub fn header(&self) -> &RtcpHeader {
&self.header
}
#[inline]
pub fn packet_type(&self) -> RtcpPacketType {
self.header.packet_type()
}
#[inline]
pub fn with_packet_type(mut self, packet_type: RtcpPacketType) -> Self {
self.header = self.header.with_packet_type(packet_type);
self
}
#[inline]
pub fn item_count(&self) -> u8 {
self.header.item_count()
}
#[inline]
pub fn with_item_count(mut self, count: u8) -> Self {
self.header = self.header.with_item_count(count);
self
}
#[inline]
pub fn length(&self) -> usize {
self.header.packet_length()
}
#[inline]
pub fn padding(&self) -> u8 {
if self.header.padding() {
*self.payload.last().unwrap()
} else {
0
}
}
#[inline]
pub fn payload(&self) -> &Bytes {
&self.payload
}
#[inline]
pub fn stripped_payload(&self) -> Bytes {
let payload_len = self.payload.len();
let padding_len = self.padding() as usize;
let len = payload_len - padding_len;
self.payload.slice(..len)
}
pub fn with_payload(mut self, mut payload: Bytes, padding: u8) -> Self {
if padding > 0 {
let len = payload.len() + (padding as usize);
let mut buffer = BytesMut::with_capacity(len);
buffer.extend_from_slice(&payload);
buffer.resize(len, 0);
buffer[len - 1] = padding;
payload = buffer.freeze();
self.header = self
.header
.with_padding(true)
.with_packet_length(4 + payload.len());
} else {
self.header = self
.header
.with_padding(false)
.with_packet_length(4 + payload.len());
}
self.payload = payload;
self
}
pub fn with_padded_payload(mut self, payload: Bytes) -> Self {
let padding_len = payload.last().copied().expect("empty payload") as usize;
assert!(padding_len > 0 && payload.len() >= padding_len);
self.header = self
.header
.with_padding(true)
.with_packet_length(payload.len());
self.payload = payload;
self
}
#[inline]
pub fn raw_size(&self) -> usize {
self.length()
}
}