Skip to main content

rtc_rtcp/
packet.rs

1use crate::{
2    goodbye::*, header::*, payload_feedbacks::full_intra_request::*,
3    payload_feedbacks::picture_loss_indication::*,
4    payload_feedbacks::receiver_estimated_maximum_bitrate::*,
5    payload_feedbacks::slice_loss_indication::*, raw_packet::*, receiver_report::*,
6    sender_report::*, source_description::*,
7    transport_feedbacks::rapid_resynchronization_request::*,
8    transport_feedbacks::transport_layer_cc::*, transport_feedbacks::transport_layer_nack::*,
9};
10use shared::{
11    error::{Error, Result},
12    marshal::{Marshal, Unmarshal},
13};
14
15use crate::extended_report::ExtendedReport;
16use bytes::{Buf, BytesMut};
17use std::any::Any;
18use std::fmt;
19
20/// Packet represents an RTCP packet, a protocol used for out-of-band statistics and
21/// control information for an RTP session
22pub trait Packet: Send + Sync + Marshal + Unmarshal + fmt::Display + fmt::Debug {
23    /// This packet's RTCP header.
24    fn header(&self) -> Header;
25    /// The SSRCs this packet is about.
26    ///
27    /// Used to route feedback: a report's destination SSRCs identify the streams it concerns,
28    /// which is how an SFU decides where to forward it.
29    fn destination_ssrc(&self) -> Vec<u32>;
30    /// The encoded size in bytes, header and padding included.
31    fn raw_size(&self) -> usize;
32    /// Downcasting hook, so a caller holding `Box<dyn Packet>` can recover the concrete type.
33    fn as_any(&self) -> &dyn Any;
34    /// Compares against another packet, since `PartialEq` is not object safe.
35    fn equal(&self, other: &dyn Packet) -> bool;
36    /// Clones this packet behind a trait object, since `Clone` is not object safe.
37    fn cloned(&self) -> Box<dyn Packet>;
38}
39
40impl PartialEq for dyn Packet {
41    fn eq(&self, other: &Self) -> bool {
42        self.equal(other)
43    }
44}
45
46impl Clone for Box<dyn Packet> {
47    fn clone(&self) -> Box<dyn Packet> {
48        self.cloned()
49    }
50}
51
52/// marshal takes an array of Packets and serializes them to a single buffer
53pub fn marshal(packets: &[Box<dyn Packet>]) -> Result<BytesMut> {
54    // Size the compound packet up front and marshal each sub-packet straight
55    // into it, instead of allocating a fresh BytesMut per sub-packet
56    // (p.marshal()) and copying it in.
57    let total: usize = packets.iter().map(|p| p.marshal_size()).sum();
58    let mut out = BytesMut::new();
59    out.resize(total, 0);
60    let mut offset = 0;
61    for p in packets {
62        offset += p.marshal_to(&mut out[offset..])?;
63    }
64    Ok(out)
65}
66
67/// Unmarshal takes an entire udp datagram (which may consist of multiple RTCP packets) and
68/// returns the unmarshaled packets it contains.
69///
70/// If this is a reduced-size RTCP packet a feedback packet (Goodbye, SliceLossIndication, etc)
71/// will be returned. Otherwise, the underlying type of the returned packet will be
72/// CompoundPacket.
73pub fn unmarshal<B>(raw_data: &mut B) -> Result<Vec<Box<dyn Packet>>>
74where
75    B: Buf,
76{
77    let mut packets = vec![];
78
79    while raw_data.has_remaining() {
80        let p = unmarshaller(raw_data)?;
81        packets.push(p);
82    }
83
84    match packets.len() {
85        // Empty Packet
86        0 => Err(Error::InvalidHeader),
87
88        // Multiple Packet
89        _ => Ok(packets),
90    }
91}
92
93/// unmarshaller is a factory which pulls the first RTCP packet from a bytestream,
94/// and returns it's parsed representation, and the amount of data that was processed.
95pub(crate) fn unmarshaller<B>(raw_data: &mut B) -> Result<Box<dyn Packet>>
96where
97    B: Buf,
98{
99    let h = Header::unmarshal(raw_data)?;
100
101    let length = (h.length as usize) * 4;
102    if length > raw_data.remaining() {
103        return Err(Error::PacketTooShort);
104    }
105
106    // Re-serialize the just-parsed header into a stack buffer rather than a fresh
107    // heap `BytesMut` (`h.marshal()`), then chain it with the body so the
108    // sub-packet unmarshaller re-reads the same bytes -- one fewer heap
109    // allocation per RTCP sub-packet on the receive path.
110    let mut header_buf = [0u8; HEADER_LENGTH];
111    h.marshal_to(&mut header_buf[..])?;
112    let mut in_packet = header_buf.as_slice().chain(raw_data.take(length));
113
114    let p: Box<dyn Packet> = match h.packet_type {
115        PacketType::SenderReport => Box::new(SenderReport::unmarshal(&mut in_packet)?),
116        PacketType::ReceiverReport => Box::new(ReceiverReport::unmarshal(&mut in_packet)?),
117        PacketType::SourceDescription => Box::new(SourceDescription::unmarshal(&mut in_packet)?),
118        PacketType::Goodbye => Box::new(Goodbye::unmarshal(&mut in_packet)?),
119
120        PacketType::TransportSpecificFeedback => match h.count {
121            FORMAT_TLN => Box::new(TransportLayerNack::unmarshal(&mut in_packet)?),
122            FORMAT_RRR => Box::new(RapidResynchronizationRequest::unmarshal(&mut in_packet)?),
123            FORMAT_TCC => Box::new(TransportLayerCc::unmarshal(&mut in_packet)?),
124            _ => Box::new(RawPacket::unmarshal(&mut in_packet)?),
125        },
126        PacketType::PayloadSpecificFeedback => match h.count {
127            FORMAT_PLI => Box::new(PictureLossIndication::unmarshal(&mut in_packet)?),
128            FORMAT_SLI => Box::new(SliceLossIndication::unmarshal(&mut in_packet)?),
129            FORMAT_REMB => Box::new(ReceiverEstimatedMaximumBitrate::unmarshal(&mut in_packet)?),
130            FORMAT_FIR => Box::new(FullIntraRequest::unmarshal(&mut in_packet)?),
131            _ => Box::new(RawPacket::unmarshal(&mut in_packet)?),
132        },
133        PacketType::ExtendedReport => Box::new(ExtendedReport::unmarshal(&mut in_packet)?),
134        _ => Box::new(RawPacket::unmarshal(&mut in_packet)?),
135    };
136
137    Ok(p)
138}
139
140#[cfg(test)]
141mod test {
142    use super::*;
143    use crate::reception_report::*;
144    use bytes::Bytes;
145
146    #[test]
147    fn test_packet_unmarshal() {
148        let mut data = Bytes::from_static(&[
149            // Receiver Report (offset=0)
150            0x81, 0xc9, 0x0, 0x7, // v=2, p=0, count=1, RR, len=7
151            0x90, 0x2f, 0x9e, 0x2e, // ssrc=0x902f9e2e
152            0xbc, 0x5e, 0x9a, 0x40, // ssrc=0xbc5e9a40
153            0x0, 0x0, 0x0, 0x0, // fracLost=0, totalLost=0
154            0x0, 0x0, 0x46, 0xe1, // lastSeq=0x46e1
155            0x0, 0x0, 0x1, 0x11, // jitter=273
156            0x9, 0xf3, 0x64, 0x32, // lsr=0x9f36432
157            0x0, 0x2, 0x4a, 0x79, // delay=150137
158            // Source Description (offset=32)
159            0x81, 0xca, 0x0, 0xc, // v=2, p=0, count=1, SDES, len=12
160            0x90, 0x2f, 0x9e, 0x2e, // ssrc=0x902f9e2e
161            0x1, 0x26, // CNAME, len=38
162            0x7b, 0x39, 0x63, 0x30, 0x30, 0x65, 0x62, 0x39, 0x32, 0x2d, 0x31, 0x61, 0x66, 0x62,
163            0x2d, 0x39, 0x64, 0x34, 0x39, 0x2d, 0x61, 0x34, 0x37, 0x64, 0x2d, 0x39, 0x31, 0x66,
164            0x36, 0x34, 0x65, 0x65, 0x65, 0x36, 0x39, 0x66, 0x35,
165            0x7d, // text="{9c00eb92-1afb-9d49-a47d-91f64eee69f5}"
166            0x0, 0x0, 0x0, 0x0, // END + padding
167            // Goodbye (offset=84)
168            0x81, 0xcb, 0x0, 0x1, // v=2, p=0, count=1, BYE, len=1
169            0x90, 0x2f, 0x9e, 0x2e, // source=0x902f9e2e
170            0x81, 0xce, 0x0, 0x2, // Picture Loss Indication (offset=92)
171            0x90, 0x2f, 0x9e, 0x2e, // sender=0x902f9e2e
172            0x90, 0x2f, 0x9e, 0x2e, // media=0x902f9e2e
173            0x85, 0xcd, 0x0, 0x2, // RapidResynchronizationRequest (offset=104)
174            0x90, 0x2f, 0x9e, 0x2e, // sender=0x902f9e2e
175            0x90, 0x2f, 0x9e, 0x2e, // media=0x902f9e2e
176        ]);
177
178        let packet = unmarshal(&mut data).expect("Error unmarshalling packets");
179
180        let a = ReceiverReport {
181            ssrc: 0x902f9e2e,
182            reports: vec![ReceptionReport {
183                ssrc: 0xbc5e9a40,
184                fraction_lost: 0,
185                total_lost: 0,
186                last_sequence_number: 0x46e1,
187                jitter: 273,
188                last_sender_report: 0x9f36432,
189                delay: 150137,
190            }],
191            ..Default::default()
192        };
193
194        let b = SourceDescription {
195            chunks: vec![SourceDescriptionChunk {
196                source: 0x902f9e2e,
197                items: vec![SourceDescriptionItem {
198                    sdes_type: SdesType::SdesCname,
199                    text: Bytes::from_static(b"{9c00eb92-1afb-9d49-a47d-91f64eee69f5}"),
200                }],
201            }],
202        };
203
204        let c = Goodbye {
205            sources: vec![0x902f9e2e],
206            ..Default::default()
207        };
208
209        let d = PictureLossIndication {
210            sender_ssrc: 0x902f9e2e,
211            media_ssrc: 0x902f9e2e,
212        };
213
214        let e = RapidResynchronizationRequest {
215            sender_ssrc: 0x902f9e2e,
216            media_ssrc: 0x902f9e2e,
217        };
218
219        let expected: Vec<Box<dyn Packet>> = vec![
220            Box::new(a),
221            Box::new(b),
222            Box::new(c),
223            Box::new(d),
224            Box::new(e),
225        ];
226
227        assert!(packet == expected, "Invalid packets");
228    }
229
230    #[test]
231    fn test_packet_unmarshal_empty() -> Result<()> {
232        let result = unmarshal(&mut Bytes::new());
233        if let Err(got) = result {
234            let want = Error::InvalidHeader;
235            assert_eq!(got, want, "Unmarshal(nil) err = {got}, want {want}");
236        } else {
237            panic!("want error");
238        }
239
240        Ok(())
241    }
242
243    #[test]
244    fn test_packet_invalid_header_length() -> Result<()> {
245        let mut data = Bytes::from_static(&[
246            // Goodbye (offset=84)
247            // v=2, p=0, count=1, BYE, len=100
248            0x81, 0xcb, 0x0, 0x64,
249        ]);
250
251        let result = unmarshal(&mut data);
252        if let Err(got) = result {
253            let want = Error::PacketTooShort;
254            assert_eq!(
255                got, want,
256                "Unmarshal(invalid_header_length) err = {got}, want {want}"
257            );
258        } else {
259            panic!("want error");
260        }
261
262        Ok(())
263    }
264    #[test]
265    fn test_packet_unmarshal_firefox() -> Result<()> {
266        // issue report from https://github.com/webrtc-rs/srtp/issues/7
267        let tests = vec![
268            Bytes::from_static(&[
269                143, 205, 0, 6, 65, 227, 184, 49, 118, 243, 78, 96, 42, 63, 0, 5, 12, 162, 166, 0,
270                32, 5, 200, 4, 0, 4, 0, 0,
271            ]),
272            Bytes::from_static(&[
273                143, 205, 0, 9, 65, 227, 184, 49, 118, 243, 78, 96, 42, 68, 0, 17, 12, 162, 167, 1,
274                32, 17, 88, 0, 4, 0, 4, 8, 108, 0, 4, 0, 4, 12, 0, 4, 0, 4, 4, 0,
275            ]),
276            Bytes::from_static(&[
277                143, 205, 0, 8, 65, 227, 184, 49, 118, 243, 78, 96, 42, 91, 0, 12, 12, 162, 168, 3,
278                32, 12, 220, 4, 0, 4, 0, 8, 128, 4, 0, 4, 0, 8, 0, 0,
279            ]),
280            Bytes::from_static(&[
281                143, 205, 0, 7, 65, 227, 184, 49, 118, 243, 78, 96, 42, 103, 0, 8, 12, 162, 169, 4,
282                32, 8, 232, 4, 0, 4, 0, 4, 4, 0, 0, 0,
283            ]),
284        ];
285
286        for mut test in tests {
287            unmarshal(&mut test)?;
288        }
289
290        Ok(())
291    }
292
293    // Round-trips a compound through packet::marshal -> packet::unmarshal ->
294    // packet::marshal and asserts byte-stability, covering the in-place compound
295    // marshal and the sub-packet unmarshaller.
296    #[test]
297    fn test_marshal_compound_roundtrip() -> Result<()> {
298        use crate::reception_report::ReceptionReport;
299
300        let rr = ReceiverReport {
301            ssrc: 0x902f9e2e,
302            reports: vec![ReceptionReport {
303                ssrc: 0xbc5e9a40,
304                fraction_lost: 0,
305                total_lost: 0,
306                last_sequence_number: 0x46e1,
307                jitter: 273,
308                last_sender_report: 0x9f36432,
309                delay: 150137,
310            }],
311            ..Default::default()
312        };
313        let pli = PictureLossIndication {
314            sender_ssrc: 0x902f9e2e,
315            media_ssrc: 0x902f9e2e,
316        };
317        let packets: Vec<Box<dyn Packet>> = vec![Box::new(rr), Box::new(pli)];
318
319        let raw1 = marshal(&packets)?;
320        let out = unmarshal(&mut raw1.clone().freeze())?;
321        assert_eq!(out.len(), 2, "expected two sub-packets");
322        let raw2 = marshal(&out)?;
323        assert_eq!(raw1, raw2, "compound marshal/unmarshal round-trip mismatch");
324
325        Ok(())
326    }
327}