aboutsummaryrefslogtreecommitdiff
path: root/rtp/src/rtcp.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-11-19 15:28:29 +0100
committermetamuffin <metamuffin@disroot.org>2024-11-19 15:28:29 +0100
commit8d02c52f770e5626a67dfdc47214fc23b744ac47 (patch)
tree4dc77317e407e1a1e45552870e257745656a40c6 /rtp/src/rtcp.rs
parentd40f5bc6ece18c8fa09013d2e47e500a9e333dcd (diff)
downloadsip-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.rs152
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());
}
}