rtp_parse/rtcp/
rtcp_packet.rs

1use anyhow::{anyhow, bail, Context};
2use parsely_rs::*;
3
4use crate::rtcp::rtcp_bye::RtcpByePacket;
5
6use super::{
7    rtcp_fb_fir::RtcpFbFirPacket,
8    rtcp_fb_header::RtcpFbHeader,
9    rtcp_fb_nack::RtcpFbNackPacket,
10    rtcp_fb_packet::{RtcpFbPsPacket, RtcpFbTlPacket},
11    rtcp_fb_tcc::RtcpFbTccPacket,
12    rtcp_header::RtcpHeader,
13    rtcp_rr::RtcpRrPacket,
14    rtcp_sdes::RtcpSdesPacket,
15    rtcp_sr::RtcpSrPacket,
16};
17
18#[derive(Debug)]
19pub enum SomeRtcpPacket {
20    CompoundRtcpPacket(Vec<SomeRtcpPacket>),
21    RtcpByePacket(RtcpByePacket),
22    RtcpSrPacket(RtcpSrPacket),
23    RtcpRrPacket(RtcpRrPacket),
24    RtcpSdesPacket(RtcpSdesPacket),
25    RtcpFbNackPacket(RtcpFbNackPacket),
26    RtcpFbFirPacket(RtcpFbFirPacket),
27    RtcpFbTccPacket(RtcpFbTccPacket),
28    // RtcpFbPliPacket(RtcpFbPliPacket),
29    UnknownRtcpPacket {
30        header: RtcpHeader,
31        payload: Vec<u8>,
32    },
33}
34
35impl<B: BitBuf> ParselyRead<B> for SomeRtcpPacket {
36    type Ctx = ();
37    fn read<T: ByteOrder>(buf: &mut B, _ctx: Self::Ctx) -> ParselyResult<Self> {
38        let mut packets: Vec<SomeRtcpPacket> = Vec::new();
39
40        let mut sub_packet_num = 1;
41        while buf.remaining_bytes() >= RtcpHeader::SIZE_BYTES {
42            let packet = read_single_rtcp_packet::<T, B>(buf)
43                .with_context(|| format!("sub packet {sub_packet_num}"))?;
44            packets.push(packet);
45            sub_packet_num += 1;
46        }
47
48        match packets.len() {
49            0 => Err(anyhow!("No valid packets found")),
50            1 => Ok(packets.remove(0)),
51            _ => Ok(SomeRtcpPacket::CompoundRtcpPacket(packets)),
52        }
53    }
54}
55
56pub fn read_single_rtcp_packet<T: ByteOrder, B: BitBuf>(
57    buf: &mut B,
58) -> ParselyResult<SomeRtcpPacket> {
59    let header = RtcpHeader::read::<T>(buf, ()).context("header")?;
60    let payload_length = header
61        .payload_length_bytes()
62        .context("header length field")? as usize;
63    if payload_length > buf.remaining_bytes() {
64        bail!("Invalid RTCP packet, length {payload_length} bytes but buf has only {} bytes remaining", buf.remaining_bytes());
65    }
66
67    let mut payload_buffer = buf.take_bytes(payload_length);
68    let result: ParselyResult<SomeRtcpPacket> = match header.packet_type {
69        RtcpByePacket::PT => Ok(SomeRtcpPacket::RtcpByePacket(
70            RtcpByePacket::read::<T>(&mut payload_buffer, (header,)).context("rtcp bye")?,
71        )),
72        RtcpSdesPacket::PT => Ok(SomeRtcpPacket::RtcpSdesPacket(
73            RtcpSdesPacket::read::<T>(&mut payload_buffer, (header,)).context("rtcp sdes")?,
74        )),
75        RtcpRrPacket::PT => Ok(SomeRtcpPacket::RtcpRrPacket(
76            RtcpRrPacket::read::<T>(&mut payload_buffer, (header,)).context("rtcp rr")?,
77        )),
78        RtcpSrPacket::PT => Ok(SomeRtcpPacket::RtcpSrPacket(
79            RtcpSrPacket::read::<T>(&mut payload_buffer, (header,)).context("rtcp sr")?,
80        )),
81        RtcpFbPsPacket::PT | RtcpFbTlPacket::PT => {
82            let fb_header =
83                RtcpFbHeader::read::<T>(&mut payload_buffer, ()).context("rtcp fb header")?;
84            match (header.packet_type, header.report_count) {
85                (RtcpFbPsPacket::PT, RtcpFbFirPacket::FMT) => Ok(SomeRtcpPacket::RtcpFbFirPacket(
86                    RtcpFbFirPacket::read::<T>(&mut payload_buffer, (header, fb_header))
87                        .context("rtcp fb fir")?,
88                )),
89                (RtcpFbTlPacket::PT, RtcpFbNackPacket::FMT) => {
90                    Ok(SomeRtcpPacket::RtcpFbNackPacket(
91                        RtcpFbNackPacket::read::<T>(&mut payload_buffer, (header, fb_header))
92                            .context("rtcp fb nack")?,
93                    ))
94                }
95                (RtcpFbTlPacket::PT, RtcpFbTccPacket::FMT) => Ok(SomeRtcpPacket::RtcpFbTccPacket(
96                    RtcpFbTccPacket::read::<T>(&mut payload_buffer, (header, fb_header))
97                        .context("rtcp fb tcc")?,
98                )),
99
100                (pt, fmt) => bail!("Unsuppsorted RTCP FB packet, pt {pt} fmt {fmt}"),
101            }
102        }
103        pt => bail!("Unsupported packet type {pt}"),
104    };
105    if payload_buffer.remaining_bytes() > 0 {
106        // TODO: ideally we'd get more context as to which type went wrong here
107        bail!("Did not consume entire buffer when reading rtcp packet");
108    }
109    // if result.is_ok() {
110    //     buf.advance(payload_length);
111    // }
112    result
113}
114
115// pub fn parse_single_rtcp_packet<B: BitBuf>(buf: &mut B) -> Result<SomeRtcpPacket> {
116//     // println!("Parsing single rtcp packet: {buf:x}");
117//     let header = read_rtcp_header(buf).context("rtcp header")?;
118//     let payload_length = header
119//         .payload_length_bytes()
120//         .context("header length field")? as usize;
121//     if payload_length > buf.remaining_bytes() {
122//         bail!("Invalid RTCP packet, length {payload_length} bytes but buf has only {} bytes
123// remaining", buf.remaining_bytes());     }
124//     let payload_length_bits = payload_length * 8;
125//     let mut payload_buffer = buf.sub_buffer(0..(payload_length * 8));
126//
127//     let result = match header.packet_type {
128//         RtcpByePacket::PT => Ok(SomeRtcpPacket::RtcpByePacket(
129//             read_rtcp_bye(&mut payload_buffer, header).context("rtcp bye")?,
130//         )),
131//         RtcpSrPacket::PT => Ok(SomeRtcpPacket::RtcpSrPacket(
132//             read_rtcp_sr(&mut payload_buffer, header).context("rtcp sr")?,
133//         )),
134//         RtcpRrPacket::PT => Ok(SomeRtcpPacket::RtcpRrPacket(
135//             read_rtcp_rr(&mut payload_buffer, header).context("rtcp sr")?,
136//         )),
137//         RtcpSdesPacket::PT => Ok(SomeRtcpPacket::RtcpSdesPacket(
138//             read_rtcp_sdes(&mut payload_buffer, header).context("rtcp sdes")?,
139//         )),
140//         RtcpFbPsPacket::PT | RtcpFbTlPacket::PT => {
141//             let fb_header = read_rtcp_fb_header(&mut payload_buffer).context("fb header")?;
142//             match (header.packet_type, header.report_count) {
143//                 (RtcpFbPsPacket::PT, RtcpFbFirPacket::FMT) => Ok(SomeRtcpPacket::RtcpFbFirPacket(
144//                     read_rtcp_fb_fir(&mut payload_buffer, header, fb_header)
145//                         .context("rtcp fb fir")?,
146//                 )),
147//                 (RtcpFbPsPacket::PT, RtcpFbPliPacket::FMT) => Ok(SomeRtcpPacket::RtcpFbPliPacket(
148//                     read_rtcp_fb_pli(&mut payload_buffer, header, fb_header)
149//                         .context("rtcp fb pli")?,
150//                 )),
151//                 (RtcpFbTlPacket::PT, RtcpFbTccPacket::FMT) => Ok(SomeRtcpPacket::RtcpFbTccPacket(
152//                     read_rtcp_fb_tcc(&mut payload_buffer, header, fb_header)
153//                         .context("rtcp fb tcc")?,
154//                 )),
155//                 (RtcpFbTlPacket::PT, RtcpFbNackPacket::FMT) => {
156//                     Ok(SomeRtcpPacket::RtcpFbNackPacket(
157//                         read_rtcp_fb_nack(&mut payload_buffer, header, fb_header)
158//                             .context("rtcp fb nack")?,
159//                     ))
160//                 }
161//                 (pt, fmt) => bail!("Unsuppsorted RTCP FB packet, pt {pt} fmt {fmt}"),
162//             }
163//         }
164//         pt => bail!("Unsupported packet type {pt}"),
165//     };
166//     drop(payload_buffer);
167//     if result.is_ok() {
168//         buf.seek(std::io::SeekFrom::Current(payload_length_bits as i64))?;
169//     }
170//     result
171// }
172
173#[cfg(test)]
174mod tests {
175    use super::*;
176
177    #[test]
178    fn test_read_rtcp() {
179        let mut rtcp_bye = RtcpByePacket::default()
180            .add_ssrc(42)
181            .add_ssrc(43)
182            .with_reason("ciao");
183        rtcp_bye.sync(()).expect("sync");
184
185        let packet_size = RtcpHeader::SIZE_BYTES + rtcp_bye.payload_length_bytes() as usize;
186        let mut buf_mut = BitsMut::new();
187        rtcp_bye
188            .write::<NetworkOrder>(&mut buf_mut, ())
189            .expect("successful write");
190
191        assert_eq!(packet_size, buf_mut.len_bytes());
192
193        let mut buf = buf_mut.freeze();
194
195        let result = SomeRtcpPacket::read::<NetworkOrder>(&mut buf, ()).expect("successful read");
196        dbg!(result);
197    }
198}