diff options
author | metamuffin <metamuffin@disroot.org> | 2024-11-19 15:28:29 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-11-19 15:28:29 +0100 |
commit | 8d02c52f770e5626a67dfdc47214fc23b744ac47 (patch) | |
tree | 4dc77317e407e1a1e45552870e257745656a40c6 /rtp/src/rtcp.rs | |
parent | d40f5bc6ece18c8fa09013d2e47e500a9e333dcd (diff) | |
download | sip-rs-8d02c52f770e5626a67dfdc47214fc23b744ac47.tar sip-rs-8d02c52f770e5626a67dfdc47214fc23b744ac47.tar.bz2 sip-rs-8d02c52f770e5626a67dfdc47214fc23b744ac47.tar.zst |
more rtcp
Diffstat (limited to 'rtp/src/rtcp.rs')
-rw-r--r-- | rtp/src/rtcp.rs | 152 |
1 files changed, 142 insertions, 10 deletions
diff --git a/rtp/src/rtcp.rs b/rtp/src/rtcp.rs index 0ae8ea7..da0a683 100644 --- a/rtp/src/rtcp.rs +++ b/rtp/src/rtcp.rs @@ -1,26 +1,158 @@ +use crate::rtp::SSRC; + #[derive(Debug, thiserror::Error)] pub enum Error { #[error("packet truncated")] Truncated, + #[error("unsupported version")] + Version, } pub struct RtcpPacket<'a> { - a: &'a [u8], + parts: Vec<RtcpPart<'a>>, +} + +pub enum RtcpPart<'a> { + SenderReport(SenderReport<'a>), + ReceiverReport(ReceiverReport), + SourceDescription(SourceDescription), + Bye(Bye), + Application(Application<'a>), } -pub enum RtcpPart { - SenderReport {}, - ReceiverReport {}, - SourceDescription {}, - Bye {}, - Application {}, +struct SenderReport<'a> { + ssrc: SSRC, + sender_info: SenderInfo, + reports: Vec<ReportBlock>, + extension: &'a [u8], +} +struct ReceiverReport { + sender_ssrc: SSRC, + reports: Vec<ReportBlock>, +} +struct SourceDescription {} +struct Bye {} +struct Application<'a> { + data: &'a [u8], +} +struct SenderInfo { + ntp_ts: u64, + rtp_ts: u32, + packet_count: u32, + octet_count: u32, +} +struct ReportBlock { + ssrc: SSRC, + fraction_lost: u8, + cumulative_packets_lost: u32, + ext_max_seq_num_recv: u32, + interarrical_jitter: u32, + lsr: u32, + dlsr: u32, } impl<'a> RtcpPacket<'a> { - pub fn parse(packet: &'a [u8]) -> Result<RtcpPacket<'a>, Error> { - Ok(Self { a: packet }) + pub fn parse(mut packet: &'a [u8]) -> Result<RtcpPacket<'a>, 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 Report + 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 + } + _ => {} + } + packet = &packet[length as usize..]; + } + Ok(Self { parts }) + } + pub fn write(&self, out: &mut Vec<u8>) { + 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<u8>) { + 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<u8>) { - out.extend(self.a); + 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()); } } |