rtp_parse/rtcp/
rtcp_packet.rs

1use std::fmt::LowerHex;
2
3use anyhow::{anyhow, bail, Context, Result};
4
5use crate::{
6    rtcp::{
7        rtcp_bye::read_rtcp_bye,
8        rtcp_fb_nack::read_rtcp_fb_nack,
9        rtcp_fb_tcc::{read_rtcp_fb_tcc, RtcpFbTccPacket},
10        rtcp_header::read_rtcp_header,
11    },
12    PacketBuffer,
13};
14
15use super::{
16    rtcp_bye::RtcpByePacket,
17    rtcp_fb_fir::{read_rtcp_fb_fir, RtcpFbFirPacket},
18    rtcp_fb_header::read_rtcp_fb_header,
19    rtcp_fb_nack::RtcpFbNackPacket,
20    rtcp_fb_packet::{RtcpFbPsPacket, RtcpFbTlPacket},
21    rtcp_fb_pli::{read_rtcp_fb_pli, RtcpFbPliPacket},
22    rtcp_header::RtcpHeader,
23    rtcp_rr::{read_rtcp_rr, RtcpRrPacket},
24    rtcp_sdes::{read_rtcp_sdes, RtcpSdesPacket},
25    rtcp_sr::{read_rtcp_sr, RtcpSrPacket},
26};
27
28#[derive(Debug)]
29pub enum SomeRtcpPacket {
30    CompoundRtcpPacket(Vec<SomeRtcpPacket>),
31    RtcpByePacket(RtcpByePacket),
32    RtcpSrPacket(RtcpSrPacket),
33    RtcpRrPacket(RtcpRrPacket),
34    RtcpSdesPacket(RtcpSdesPacket),
35    RtcpFbNackPacket(RtcpFbNackPacket),
36    RtcpFbFirPacket(RtcpFbFirPacket),
37    RtcpFbTccPacket(RtcpFbTccPacket),
38    RtcpFbPliPacket(RtcpFbPliPacket),
39    UnknownRtcpPacket {
40        header: RtcpHeader,
41        payload: Vec<u8>,
42    },
43}
44
45pub fn parse_rtcp_packet<B: PacketBuffer + LowerHex>(buf: &mut B) -> Result<SomeRtcpPacket> {
46    let mut packets: Vec<SomeRtcpPacket> = Vec::new();
47
48    let mut sub_packet_num = 1;
49    // println!("parsing packet, buf: {buf:x}");
50    while buf.bytes_remaining() >= RtcpHeader::SIZE_BYTES {
51        let packet = parse_single_rtcp_packet(buf)
52            .with_context(|| format!("sub packet {sub_packet_num}"))?;
53        packets.push(packet);
54        sub_packet_num += 1;
55    }
56
57    match packets.len() {
58        0 => Err(anyhow!("No valid packets found")),
59        1 => Ok(packets.remove(0)),
60        _ => Ok(SomeRtcpPacket::CompoundRtcpPacket(packets)),
61    }
62}
63
64pub fn parse_single_rtcp_packet<B: PacketBuffer>(buf: &mut B) -> Result<SomeRtcpPacket> {
65    // println!("Parsing single rtcp packet: {buf:x}");
66    let header = read_rtcp_header(buf).context("rtcp header")?;
67    let payload_length = header
68        .payload_length_bytes()
69        .context("header length field")? as usize;
70    if payload_length > buf.bytes_remaining() {
71        bail!("Invalid RTCP packet, length {payload_length} bytes but buf has only {} bytes remaining", buf.bytes_remaining());
72    }
73    let payload_length_bits = payload_length * 8;
74    let mut payload_buffer = buf.sub_buffer(0..(payload_length * 8));
75
76    let result = match header.packet_type {
77        RtcpByePacket::PT => Ok(SomeRtcpPacket::RtcpByePacket(
78            read_rtcp_bye(&mut payload_buffer, header).context("rtcp bye")?,
79        )),
80        RtcpSrPacket::PT => Ok(SomeRtcpPacket::RtcpSrPacket(
81            read_rtcp_sr(&mut payload_buffer, header).context("rtcp sr")?,
82        )),
83        RtcpRrPacket::PT => Ok(SomeRtcpPacket::RtcpRrPacket(
84            read_rtcp_rr(&mut payload_buffer, header).context("rtcp sr")?,
85        )),
86        RtcpSdesPacket::PT => Ok(SomeRtcpPacket::RtcpSdesPacket(
87            read_rtcp_sdes(&mut payload_buffer, header).context("rtcp sdes")?,
88        )),
89        RtcpFbPsPacket::PT | RtcpFbTlPacket::PT => {
90            let fb_header = read_rtcp_fb_header(&mut payload_buffer).context("fb header")?;
91            match (header.packet_type, header.report_count) {
92                (RtcpFbPsPacket::PT, RtcpFbFirPacket::FMT) => Ok(SomeRtcpPacket::RtcpFbFirPacket(
93                    read_rtcp_fb_fir(&mut payload_buffer, header, fb_header)
94                        .context("rtcp fb fir")?,
95                )),
96                (RtcpFbPsPacket::PT, RtcpFbPliPacket::FMT) => Ok(SomeRtcpPacket::RtcpFbPliPacket(
97                    read_rtcp_fb_pli(&mut payload_buffer, header, fb_header)
98                        .context("rtcp fb pli")?,
99                )),
100                (RtcpFbTlPacket::PT, RtcpFbTccPacket::FMT) => Ok(SomeRtcpPacket::RtcpFbTccPacket(
101                    read_rtcp_fb_tcc(&mut payload_buffer, header, fb_header)
102                        .context("rtcp fb tcc")?,
103                )),
104                (RtcpFbTlPacket::PT, RtcpFbNackPacket::FMT) => {
105                    Ok(SomeRtcpPacket::RtcpFbNackPacket(
106                        read_rtcp_fb_nack(&mut payload_buffer, header, fb_header)
107                            .context("rtcp fb nack")?,
108                    ))
109                }
110                (pt, fmt) => bail!("Unsuppsorted RTCP FB packet, pt {pt} fmt {fmt}"),
111            }
112        }
113        pt => bail!("Unsupported packet type {pt}"),
114    };
115    drop(payload_buffer);
116    if result.is_ok() {
117        buf.seek(std::io::SeekFrom::Current(payload_length_bits as i64))?;
118    }
119    result
120}