use crate::rtp::SSRC; #[derive(Debug, thiserror::Error)] pub enum Error { #[error("packet truncated")] Truncated, #[error("unsupported version")] Version, } pub struct RtcpPacket<'a> { pub parts: Vec>, } pub enum RtcpPart<'a> { SenderReport(SenderReport<'a>), ReceiverReport(ReceiverReport), SourceDescription(SourceDescription), Bye(Bye<'a>), Application(Application<'a>), } pub struct SenderReport<'a> { pub ssrc: SSRC, pub sender_info: SenderInfo, pub reports: Vec, pub extension: &'a [u8], } pub struct ReceiverReport { pub sender_ssrc: SSRC, pub reports: Vec, } pub struct SourceDescription { sources: Vec<(SSRC, Vec)>, } pub enum SourceDescriptionItem { CanonicalName(String), Name(String), Email(String), Phone(String), Location(String), Tool(String), Notice(String), PrivateExtension(String), } pub struct Bye<'a> { pub ssrcs: Vec, pub reason: &'a [u8], } pub struct Application<'a> { pub subtype: u8, pub name: [u8; 4], pub data: &'a [u8], } pub struct SenderInfo { pub ntp_ts: u64, pub rtp_ts: u32, pub packet_count: u32, pub octet_count: u32, } pub struct ReportBlock { pub ssrc: SSRC, pub fraction_lost: u8, pub cumulative_packets_lost: u32, pub ext_max_seq_num_recv: u32, pub interarrical_jitter: u32, pub lsr: u32, pub dlsr: u32, } impl<'a> RtcpPacket<'a> { pub fn parse(mut packet: &'a [u8]) -> Result, Error> { let mut parts = Vec::with_capacity(2); while packet.len() > 0 { if packet.len() < 4 { return Err(Error::Truncated); } let version = (packet[0] & 0b11000000) >> 6; if !matches!(version, 1 | 2) { return Err(Error::Version); } let padding = (packet[0] & 0b00100000) != 0; let num_reports = (packet[0] & 0b00011111) >> 0; let packet_type = packet[1]; let length = u16::from_be_bytes([packet[2], packet[3]]); match packet_type { 200 => { // sender seport if packet.len() < 28 + 24 * num_reports as usize { return Err(Error::Truncated); } let ssrc = SSRC(u32::from_be_bytes(packet[4..8].try_into().unwrap())); let sender_info = SenderInfo::parse(packet[8..28].try_into().unwrap()); let mut reports = Vec::with_capacity(num_reports as usize); for n in 0..num_reports as usize { reports.push(ReportBlock::parse( packet[28 + 24 * n..28 + 24 * (n + 1)].try_into().unwrap(), )); } let extension = &packet[28 + 24 * num_reports as usize..]; parts.push(RtcpPart::SenderReport(SenderReport { reports, sender_info, ssrc, extension, })) } 201 => { // receiver report } 202 => { // source description } 203 => { // bye } 204 => { // application defined } _ => {} } packet = &packet[length as usize..]; } Ok(Self { parts }) } pub fn write(&self, out: &mut Vec) { for part in &self.parts { let version = 2; let padding = false; match part { RtcpPart::SenderReport(sender_report) => { out.push( version << 6 | (padding as u8) << 5 | sender_report.reports.len() as u8, ); out.push(200); } RtcpPart::ReceiverReport(receiver_report) => todo!(), RtcpPart::SourceDescription(source_description) => todo!(), RtcpPart::Bye(bye) => todo!(), RtcpPart::Application(application) => todo!(), } } } } impl SenderInfo { pub const SIZE: usize = 5 * 4; pub fn parse(packet: [u8; 5 * 4]) -> SenderInfo { Self { ntp_ts: u64::from_be_bytes(packet[0..8].try_into().unwrap()), rtp_ts: u32::from_be_bytes(packet[8..12].try_into().unwrap()), packet_count: u32::from_be_bytes(packet[12..16].try_into().unwrap()), octet_count: u32::from_be_bytes(packet[16..20].try_into().unwrap()), } } pub fn write(&self, out: &mut Vec) { out.extend(self.ntp_ts.to_be_bytes()); out.extend(self.rtp_ts.to_be_bytes()); out.extend(self.packet_count.to_be_bytes()); out.extend(self.octet_count.to_be_bytes()); } } impl ReportBlock { pub fn parse(packet: [u8; 6 * 4]) -> ReportBlock { Self { ssrc: SSRC(u32::from_be_bytes(packet[0..4].try_into().unwrap())), fraction_lost: packet[4], cumulative_packets_lost: u32::from_be_bytes([0, packet[5], packet[6], packet[7]]), ext_max_seq_num_recv: u32::from_be_bytes(packet[8..12].try_into().unwrap()), interarrical_jitter: u32::from_be_bytes(packet[12..16].try_into().unwrap()), lsr: u32::from_be_bytes(packet[16..20].try_into().unwrap()), dlsr: u32::from_be_bytes(packet[20..24].try_into().unwrap()), } } pub fn write(&self, out: &mut Vec) { out.extend(self.ssrc.0.to_be_bytes()); out.push(self.fraction_lost); out.extend(&self.cumulative_packets_lost.to_be_bytes()[1..]); out.extend(self.ext_max_seq_num_recv.to_be_bytes()); out.extend(self.interarrical_jitter.to_be_bytes()); out.extend(self.lsr.to_be_bytes()); out.extend(self.dlsr.to_be_bytes()); } }