rtcp_types/
compound.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use crate::{
4    prelude::*,
5    utils::{parser::*, writer::*},
6    RtcpPacket, RtcpParseError, RtcpWriteError,
7};
8
9/// A (currently) unknown RTCP packet type.  Can also be used as a way to parse a custom RTCP packet
10/// type.
11#[derive(Debug, PartialEq, Eq)]
12pub struct Unknown<'a> {
13    data: &'a [u8],
14}
15
16impl RtcpPacket for Unknown<'_> {
17    const MIN_PACKET_LEN: usize = 4;
18    const PACKET_TYPE: u8 = 255; // Not used
19}
20
21impl<'a> RtcpPacketParser<'a> for Unknown<'a> {
22    fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
23        if data.len() < Self::MIN_PACKET_LEN {
24            return Err(RtcpParseError::Truncated {
25                expected: Self::MIN_PACKET_LEN,
26                actual: data.len(),
27            });
28        }
29
30        let version = parse_version(data);
31        if parse_version(data) != Self::VERSION {
32            return Err(RtcpParseError::UnsupportedVersion(version));
33        }
34
35        let length = parse_length(data);
36        if data.len() < length {
37            return Err(RtcpParseError::Truncated {
38                expected: length,
39                actual: data.len(),
40            });
41        }
42        if data.len() > length {
43            return Err(RtcpParseError::TooLarge {
44                expected: length,
45                actual: data.len(),
46            });
47        }
48
49        Ok(Self { data })
50    }
51
52    #[inline(always)]
53    fn header_data(&self) -> [u8; 4] {
54        self.data[..4].try_into().unwrap()
55    }
56}
57
58impl<'a> Unknown<'a> {
59    /// The data of this RTCP packet
60    pub fn data(&self) -> &[u8] {
61        self.data
62    }
63
64    /// Try to parse this unknown RTCP packet as a different RTCP packet.  Can be used with an
65    /// external implementation of [`RtcpPacket`] to parse a custom RTCP packet.
66    pub fn try_as<P>(&'a self) -> Result<P, RtcpParseError>
67    where
68        P: RtcpPacket,
69        P: TryFrom<&'a Self, Error = RtcpParseError>,
70    {
71        TryFrom::try_from(self)
72    }
73
74    /// The builder for an [`Unknown`] RTCP packet.  The data does not include the 4 byte RTCP
75    /// header.
76    pub fn builder(type_: u8, data: &'a [u8]) -> UnknownBuilder<'a> {
77        UnknownBuilder::new(type_, data)
78    }
79}
80
81/// Unknown RTCP packet builder
82#[derive(Debug)]
83#[must_use = "The builder must be built to be used"]
84pub struct UnknownBuilder<'a> {
85    padding: u8,
86    type_: u8,
87    count: u8,
88    data: &'a [u8],
89}
90
91impl<'a> UnknownBuilder<'a> {
92    /// Create a new builder for an [`Unknown`] RTCP packet.  The data does not include the 4 byte RTCP
93    /// header.
94    pub fn new(type_: u8, data: &'a [u8]) -> UnknownBuilder<'a> {
95        UnknownBuilder {
96            padding: 0,
97            type_,
98            count: 0,
99            data,
100        }
101    }
102
103    /// Sets the number of padding bytes to use for this Unknown packet
104    pub fn padding(mut self, padding: u8) -> Self {
105        self.padding = padding;
106        self
107    }
108
109    /// Set the count (or possibly type) field in the RTCP header.  The exact interpretation of
110    /// this value is RTCP packet specific.
111    pub fn count(mut self, count: u8) -> Self {
112        self.count = count;
113        self
114    }
115}
116
117impl RtcpPacketWriter for UnknownBuilder<'_> {
118    /// Calculates the size required to write this Unknown packet.
119    ///
120    /// Returns an error if:
121    ///
122    /// * The count is out of range.
123    /// * The padding is not a multiple of 4.
124    fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
125        if self.count > Unknown::MAX_COUNT {
126            return Err(RtcpWriteError::CountOutOfRange {
127                count: self.count,
128                max: Unknown::MAX_COUNT,
129            });
130        }
131
132        check_padding(self.padding)?;
133
134        Ok(Unknown::MIN_PACKET_LEN + self.data.len())
135    }
136
137    /// Write this Unknown packet data into `buf` without any validity checks.
138    ///
139    /// Returns the number of bytes written.
140    ///
141    /// # Panic
142    ///
143    /// Panics if the buf is not large enough.
144    #[inline]
145    fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
146        write_header_unchecked::<Unknown>(self.padding, self.count, buf);
147        buf[1] = self.type_;
148
149        let mut end = 4 + self.data.len();
150        buf[4..end].copy_from_slice(self.data);
151
152        end += write_padding_unchecked(self.padding, &mut buf[end..]);
153
154        end
155    }
156
157    fn get_padding(&self) -> Option<u8> {
158        if self.padding == 0 {
159            return None;
160        }
161
162        Some(self.padding)
163    }
164}
165
166/// A (closed) enum of all currently known RTCP packet types.  The Unknown variant can be used to
167/// parse a custom RTCP packet.
168#[derive(Debug)]
169pub enum Packet<'a> {
170    /// An [`App`](crate::App) packet.
171    App(crate::App<'a>),
172    /// A [`Bye`](crate::Bye) packet.
173    Bye(crate::Bye<'a>),
174    /// A [`ReceiverReport`](crate::ReceiverReport) packet.
175    Rr(crate::ReceiverReport<'a>),
176    /// A [`Sdes`](crate::Sdes) packet.
177    Sdes(crate::Sdes<'a>),
178    /// A [`SenderReport`](crate::SenderReport) packet.
179    Sr(crate::SenderReport<'a>),
180    /// A [`TransportFeedback`](crate::TransportFeedback) packet.
181    TransportFeedback(crate::TransportFeedback<'a>),
182    /// A [`PayloadFeedback`](crate::PayloadFeedback) packet.
183    PayloadFeedback(crate::PayloadFeedback<'a>),
184    /// An [`XR`](crate::Xr) packet.
185    Xr(crate::Xr<'a>),
186    /// An [`Unknown`](crate::Unknown) packet.
187    Unknown(Unknown<'a>),
188}
189
190impl Packet<'_> {
191    /// Whether the packet is of an unknown type.
192    pub fn is_unknown(&self) -> bool {
193        matches!(self, Packet::Unknown(_))
194    }
195}
196
197impl RtcpPacket for Packet<'_> {
198    const MIN_PACKET_LEN: usize = 4;
199    const PACKET_TYPE: u8 = 255; // Not used
200}
201
202impl<'a> RtcpPacketParser<'a> for Packet<'a> {
203    fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
204        if data.len() < Self::MIN_PACKET_LEN {
205            return Err(RtcpParseError::Truncated {
206                expected: Self::MIN_PACKET_LEN,
207                actual: data.len(),
208            });
209        }
210
211        match parse_packet_type(data) {
212            crate::App::PACKET_TYPE => crate::App::parse(data).map(Packet::App),
213            crate::Bye::PACKET_TYPE => crate::Bye::parse(data).map(Packet::Bye),
214            crate::ReceiverReport::PACKET_TYPE => {
215                crate::ReceiverReport::parse(data).map(Packet::Rr)
216            }
217            crate::Sdes::PACKET_TYPE => crate::Sdes::parse(data).map(Packet::Sdes),
218            crate::SenderReport::PACKET_TYPE => crate::SenderReport::parse(data).map(Packet::Sr),
219            crate::PayloadFeedback::PACKET_TYPE => {
220                crate::PayloadFeedback::parse(data).map(Packet::PayloadFeedback)
221            }
222            crate::TransportFeedback::PACKET_TYPE => {
223                crate::TransportFeedback::parse(data).map(Packet::TransportFeedback)
224            }
225            crate::Xr::PACKET_TYPE => crate::Xr::parse(data).map(Packet::Xr),
226            _ => Ok(Packet::Unknown(Unknown::parse(data)?)),
227        }
228    }
229
230    #[inline(always)]
231    fn header_data(&self) -> [u8; 4] {
232        use Packet::*;
233        match self {
234            App(this) => this.header_data(),
235            Bye(this) => this.header_data(),
236            Rr(this) => this.header_data(),
237            Sdes(this) => this.header_data(),
238            Sr(this) => this.header_data(),
239            TransportFeedback(this) => this.header_data(),
240            PayloadFeedback(this) => this.header_data(),
241            Xr(this) => this.header_data(),
242            Unknown(this) => this.header_data(),
243        }
244    }
245}
246
247impl<'a> Packet<'a> {
248    /// Try parsing this [`Packet`] as a particular [`RtcpPacket`] implementation.
249    pub fn try_as<P>(&'a self) -> Result<P, RtcpParseError>
250    where
251        P: RtcpPacket,
252        P: TryFrom<&'a Self, Error = RtcpParseError>,
253    {
254        TryFrom::try_from(self)
255    }
256}
257
258/// A compound RTCP packet consisting of multiple RTCP packets one after the other
259#[derive(Debug)]
260pub struct Compound<'a> {
261    data: &'a [u8],
262    offset: usize,
263    is_over: bool,
264}
265
266impl<'a> Compound<'a> {
267    /// Parse data into a [`Compound`] RTCP packet.
268    ///
269    /// This will validate that the length of each individual RTCP packet is valid upfront.
270    pub fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
271        let mut offset = 0;
272        let mut packet_length;
273
274        if data.is_empty() {
275            return Err(RtcpParseError::Truncated {
276                expected: 4,
277                actual: 0,
278            });
279        }
280
281        while offset < data.len() {
282            // This also checks that there is no undeclared padding at the end of the packet
283            if data.len() < offset + Unknown::MIN_PACKET_LEN {
284                return Err(RtcpParseError::Truncated {
285                    expected: offset + Unknown::MIN_PACKET_LEN,
286                    actual: data.len(),
287                });
288            }
289
290            let version = parse_version(data);
291            if parse_version(data) != 2 {
292                return Err(RtcpParseError::UnsupportedVersion(version));
293            }
294
295            let padding_bit = parse_padding_bit(&data[offset..]);
296
297            packet_length = parse_length(&data[offset..]);
298            if data.len() < offset + packet_length {
299                return Err(RtcpParseError::Truncated {
300                    expected: offset + packet_length,
301                    actual: data.len(),
302                });
303            }
304
305            offset += packet_length;
306
307            // Only the last RTCP packet in a compound packet is allowed to have padding
308            if offset < data.len() && padding_bit {
309                return Err(RtcpParseError::InvalidPadding);
310            }
311        }
312
313        Ok(Self {
314            data,
315            offset: 0,
316            is_over: false,
317        })
318    }
319
320    /// Create a new [`CompoundBuilder`]
321    pub fn builder() -> CompoundBuilder<'a> {
322        CompoundBuilder::default()
323    }
324}
325
326impl<'a> Iterator for Compound<'a> {
327    type Item = Result<Packet<'a>, RtcpParseError>;
328
329    fn next(&mut self) -> Option<Self::Item> {
330        if self.is_over {
331            return None;
332        }
333
334        // Length conformity checked in `Self::parse`
335
336        let packet_length = parse_length(&self.data[self.offset..]);
337        let res = Packet::parse(&self.data[self.offset..self.offset + packet_length]);
338
339        self.is_over = res.is_err();
340
341        self.offset += packet_length;
342        if self.offset >= self.data.len() {
343            self.is_over = true;
344        }
345
346        Some(res)
347    }
348}
349
350/// A builder for a RTCP packet
351#[derive(Debug)]
352#[must_use = "The builder must be built to be used"]
353pub enum PacketBuilder<'a> {
354    /// An [`App`](crate::AppBuilder) packet.
355    App(crate::app::AppBuilder<'a>),
356    /// A [`Bye`](crate::ByeBuilder) packet.
357    Bye(crate::bye::ByeBuilder<'a>),
358    /// A [`ReceiverReport`](crate::ReceiverReportBuilder) packet.
359    Rr(crate::receiver::ReceiverReportBuilder),
360    /// A [`Sdes`](crate::SdesBuilder) packet.
361    Sdes(crate::sdes::SdesBuilder<'a>),
362    /// A [`SenderReport`](crate::SenderReportBuilder) packet.
363    Sr(crate::sender::SenderReportBuilder),
364    /// A [`TransportFeedback`](crate::TransportFeedbackBuilder) packet.
365    TransportFeedback(crate::feedback::TransportFeedbackBuilder<'a>),
366    /// A [`PayloadFeedback`](crate::PayloadFeedbackBuilder) packet.
367    PayloadFeedback(crate::feedback::PayloadFeedbackBuilder<'a>),
368    /// An [`XR`](crate::XrBuilder) packet.
369    Xr(crate::xr::XrBuilder),
370    /// An [`Unknown`](crate::UnknownBuilder) packet.
371    Unknown(UnknownBuilder<'a>),
372}
373
374impl RtcpPacketWriter for PacketBuilder<'_> {
375    fn get_padding(&self) -> Option<u8> {
376        use PacketBuilder::*;
377        match self {
378            App(this) => this.get_padding(),
379            Bye(this) => this.get_padding(),
380            Rr(this) => this.get_padding(),
381            Sdes(this) => this.get_padding(),
382            Sr(this) => this.get_padding(),
383            TransportFeedback(this) => this.get_padding(),
384            PayloadFeedback(this) => this.get_padding(),
385            Xr(this) => this.get_padding(),
386            Unknown(this) => this.get_padding(),
387        }
388    }
389
390    fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
391        use PacketBuilder::*;
392        match self {
393            App(this) => this.calculate_size(),
394            Bye(this) => this.calculate_size(),
395            Rr(this) => this.calculate_size(),
396            Sdes(this) => this.calculate_size(),
397            Sr(this) => this.calculate_size(),
398            TransportFeedback(this) => this.calculate_size(),
399            PayloadFeedback(this) => this.calculate_size(),
400            Xr(this) => this.calculate_size(),
401            Unknown(this) => this.calculate_size(),
402        }
403    }
404
405    fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
406        use PacketBuilder::*;
407        match self {
408            App(this) => this.write_into_unchecked(buf),
409            Bye(this) => this.write_into_unchecked(buf),
410            Rr(this) => this.write_into_unchecked(buf),
411            Sdes(this) => this.write_into_unchecked(buf),
412            Sr(this) => this.write_into_unchecked(buf),
413            TransportFeedback(this) => this.write_into_unchecked(buf),
414            PayloadFeedback(this) => this.write_into_unchecked(buf),
415            Xr(this) => this.write_into_unchecked(buf),
416            Unknown(this) => this.write_into_unchecked(buf),
417        }
418    }
419}
420
421/// A builder for a [`Compound`] RTCP packet
422#[derive(Default, Debug)]
423#[must_use = "The builder must be built to be used"]
424pub struct CompoundBuilder<'a> {
425    packets: Vec<Box<dyn RtcpPacketWriter + 'a>>,
426}
427
428impl<'a> CompoundBuilder<'a> {
429    /// Add a packet to the compound rtcp packet
430    pub fn add_packet(mut self, packet: impl RtcpPacketWriter + 'a) -> Self {
431        self.packets.push(Box::new(packet));
432        self
433    }
434}
435
436impl RtcpPacketWriter for CompoundBuilder<'_> {
437    /// Calculates the size required to write this Receiver Report packet.
438    ///
439    /// Returns an error if:
440    ///
441    /// * A Packet is erroneous.
442    /// * A Packet defined a padding
443    ///   while it's not the last packet in the Compound.
444    fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
445        let mut size = 0;
446        let last = self.packets.len().saturating_sub(1);
447        for (idx, packet) in self.packets.iter().enumerate() {
448            size += packet.calculate_size()?;
449
450            if packet.get_padding().unwrap_or(0) > 0 && idx != last {
451                return Err(RtcpWriteError::NonLastCompoundPacketPadding);
452            }
453        }
454
455        Ok(size)
456    }
457
458    /// Writes this Compound packet into `buf` without prior length checks.
459    ///
460    /// Uses the length of the buffer for the length field.
461    ///
462    /// Returns the number of bytes written.
463    ///
464    /// # Panic
465    ///
466    /// Panics if the buf is not large enough or if a packet is invalid.
467    fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
468        let mut offset = 0;
469        for packet in self.packets.iter() {
470            let req_size = packet.calculate_size().unwrap();
471            offset += packet.write_into_unchecked(&mut buf[offset..offset + req_size]);
472        }
473
474        offset
475    }
476
477    fn get_padding(&self) -> Option<u8> {
478        self.packets.last()?.get_padding()
479    }
480}
481
482macro_rules! impl_try_from {
483    ($parser:ty, $builder:ty, $variant:ident) => {
484        impl<'a> TryFrom<Unknown<'a>> for $parser {
485            type Error = RtcpParseError;
486
487            fn try_from(p: Unknown<'a>) -> Result<Self, Self::Error> {
488                <$parser>::parse(p.data)
489            }
490        }
491
492        impl<'a> TryFrom<&'a Unknown<'a>> for $parser {
493            type Error = RtcpParseError;
494
495            fn try_from(p: &'a Unknown<'a>) -> Result<Self, Self::Error> {
496                <$parser>::parse(p.data)
497            }
498        }
499
500        impl<'a> TryFrom<Packet<'a>> for $parser {
501            type Error = RtcpParseError;
502
503            fn try_from(p: Packet<'a>) -> Result<Self, Self::Error> {
504                match p {
505                    Packet::$variant(this) => Ok(this),
506                    Packet::Unknown(p) => Self::try_from(p),
507                    _ => Err(RtcpParseError::PacketTypeMismatch {
508                        actual: p.type_(),
509                        requested: <$parser>::PACKET_TYPE,
510                    }),
511                }
512            }
513        }
514
515        impl<'a> TryFrom<&'a Packet<'a>> for $parser {
516            type Error = RtcpParseError;
517
518            fn try_from(p: &'a Packet<'a>) -> Result<Self, Self::Error> {
519                match p {
520                    Packet::$variant(this) => Ok(this.clone()),
521                    Packet::Unknown(p) => Self::try_from(p),
522                    _ => Err(RtcpParseError::PacketTypeMismatch {
523                        actual: p.type_(),
524                        requested: <$parser>::PACKET_TYPE,
525                    }),
526                }
527            }
528        }
529
530        impl<'a> From<$parser> for Packet<'a> {
531            fn from(p: $parser) -> Self {
532                Packet::$variant(p)
533            }
534        }
535
536        impl<'a> From<$builder> for PacketBuilder<'a> {
537            fn from(pb: $builder) -> Self {
538                Self::$variant(pb)
539            }
540        }
541    };
542}
543
544impl_try_from!(crate::app::App<'a>, crate::app::AppBuilder<'a>, App);
545impl_try_from!(crate::bye::Bye<'a>, crate::bye::ByeBuilder<'a>, Bye);
546impl_try_from!(crate::sdes::Sdes<'a>, crate::sdes::SdesBuilder<'a>, Sdes);
547impl_try_from!(
548    crate::receiver::ReceiverReport<'a>,
549    crate::receiver::ReceiverReportBuilder,
550    Rr
551);
552impl_try_from!(
553    crate::sender::SenderReport<'a>,
554    crate::sender::SenderReportBuilder,
555    Sr
556);
557impl_try_from!(
558    crate::feedback::TransportFeedback<'a>,
559    crate::feedback::TransportFeedbackBuilder<'a>,
560    TransportFeedback
561);
562impl_try_from!(
563    crate::feedback::PayloadFeedback<'a>,
564    crate::feedback::PayloadFeedbackBuilder<'a>,
565    PayloadFeedback
566);
567impl_try_from!(crate::xr::Xr<'a>, crate::xr::XrBuilder, Xr);
568
569impl<'a> From<Unknown<'a>> for Packet<'a> {
570    fn from(p: Unknown<'a>) -> Self {
571        Packet::Unknown(p)
572    }
573}
574
575impl<'a> From<UnknownBuilder<'a>> for PacketBuilder<'a> {
576    fn from(pb: UnknownBuilder<'a>) -> Self {
577        Self::Unknown(pb)
578    }
579}
580
581#[cfg(test)]
582mod tests {
583    use super::*;
584    use crate::{App, Bye, ReceiverReport, SenderReport};
585
586    #[test]
587    fn parse_rr_bye() {
588        let data = [
589            0x80, 0xc9, 0x00, 0x01, 0x91, 0x82, 0x73, 0x64, 0x80, 0xcb, 0x00, 0x00,
590        ];
591        let mut compound = Compound::parse(&data).unwrap();
592        let packet = compound.next().unwrap().unwrap();
593        matches!(packet, Packet::Rr(_));
594
595        let packet = compound.next().unwrap().unwrap();
596        matches!(packet, Packet::Bye(_));
597
598        assert!(compound.next().is_none());
599    }
600
601    #[test]
602    fn build_rr_bye() {
603        const REQ_LEN: usize = ReceiverReport::MIN_PACKET_LEN + Bye::MIN_PACKET_LEN;
604
605        let b = Compound::builder()
606            .add_packet(ReceiverReport::builder(0x1234567))
607            .add_packet(Bye::builder());
608
609        let mut data = [0; REQ_LEN];
610        let len = b.write_into(&mut data).unwrap();
611        assert_eq!(len, REQ_LEN);
612        assert_eq!(
613            data,
614            [0x80, 0xc9, 0x00, 0x01, 0x01, 0x23, 0x45, 0x67, 0x80, 0xcb, 0x00, 0x00]
615        );
616    }
617
618    #[test]
619    fn parse_sr_bye() {
620        let data = [
621            0x80, 0xc8, 0x00, 0x06, 0x91, 0x82, 0x73, 0x64, 0x89, 0xab, 0xcd, 0xef, 0x02, 0x24,
622            0x46, 0x68, 0x8a, 0xac, 0xce, 0xe0, 0xf1, 0xe2, 0xd3, 0xc4, 0xb5, 0xa6, 0x97, 0x88,
623            0x80, 0xcb, 0x00, 0x00,
624        ];
625        let mut compound = Compound::parse(&data).unwrap();
626        let packet = compound.next().unwrap().unwrap();
627        matches!(packet, Packet::Sr(_));
628
629        let packet = compound.next().unwrap().unwrap();
630        matches!(packet, Packet::Bye(_));
631
632        assert!(compound.next().is_none());
633    }
634
635    #[test]
636    fn build_sr_bye() {
637        const REQ_LEN: usize = SenderReport::MIN_PACKET_LEN + Bye::MIN_PACKET_LEN;
638
639        let b = Compound::builder()
640            .add_packet(SenderReport::builder(0x1234567))
641            .add_packet(Bye::builder());
642
643        let mut data = [0; REQ_LEN];
644        let len = b.write_into(&mut data).unwrap();
645        assert_eq!(len, REQ_LEN);
646        assert_eq!(
647            data,
648            [
649                0x80, 0xc8, 0x00, 0x06, 0x01, 0x23, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
650                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
651                0x80, 0xcb, 0x00, 0x00,
652            ]
653        );
654    }
655
656    #[test]
657    fn build_rr_bye_padding() {
658        const REQ_LEN: usize = ReceiverReport::MIN_PACKET_LEN + Bye::MIN_PACKET_LEN + 4;
659
660        let b = Compound::builder()
661            .add_packet(ReceiverReport::builder(0x1234567))
662            .add_packet(Bye::builder().padding(4));
663
664        let mut data = [0; REQ_LEN];
665        let len = b.write_into(&mut data).unwrap();
666        assert_eq!(len, REQ_LEN);
667        assert_eq!(
668            data,
669            [
670                0x80, 0xc9, 0x00, 0x01, 0x01, 0x23, 0x45, 0x67, 0xa0, 0xcb, 0x00, 0x01, 0x00, 0x00,
671                0x00, 0x04,
672            ]
673        );
674    }
675
676    #[test]
677    fn parse_unknown() {
678        let data = [
679            0x80, 0xf2, 0x00, 0x02, 0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x00, 0x00,
680        ];
681        let p = Packet::parse(&data).unwrap();
682        assert!(p.is_unknown());
683        assert_eq!(p.type_(), 242);
684    }
685
686    #[test]
687    fn build_app_padding_bye() {
688        let b = Compound::builder()
689            .add_packet(App::builder(0x91827364, "name").padding(4))
690            .add_packet(Bye::builder());
691
692        let err = b.calculate_size().unwrap_err();
693        assert_eq!(err, RtcpWriteError::NonLastCompoundPacketPadding);
694    }
695
696    #[test]
697    fn parse_rr_bye_wrong_first_len() {
698        let data = [
699            0x80, 0xc9, 0x00, 0x03, 0x91, 0x82, 0x73, 0x64, 0x80, 0xcb, 0x00, 0x00,
700        ];
701        let err = Compound::parse(&data).unwrap_err();
702        assert_eq!(
703            err,
704            RtcpParseError::Truncated {
705                expected: 16,
706                actual: 12
707            }
708        );
709    }
710
711    #[test]
712    fn parse_rr_truncated_bye() {
713        let data = [
714            0x80, 0xc9, 0x00, 0x01, 0x91, 0x82, 0x73, 0x64, 0x80, 0xcb, 0x00,
715        ];
716        let err = Compound::parse(&data).unwrap_err();
717        assert_eq!(
718            err,
719            RtcpParseError::Truncated {
720                expected: 12,
721                actual: 11
722            }
723        );
724    }
725
726    #[test]
727    fn parsing_failure_rr_bye() {
728        let data = [
729            0x81, 0xc9, 0x00, 0x01, 0x91, 0x82, 0x73, 0x64, 0x80, 0xcb, 0x00, 0x00,
730        ];
731        let mut compound = Compound::parse(&data).unwrap();
732
733        // RR count is 1 when the actual packet contains no reports.
734        let err = compound.next().unwrap().unwrap_err();
735        assert_eq!(
736            err,
737            RtcpParseError::Truncated {
738                expected: 32,
739                actual: 8
740            }
741        );
742
743        assert!(compound.next().is_none());
744    }
745
746    #[test]
747    fn parse_rr_bye_wrong_version() {
748        let data = [
749            0x40, 0xc9, 0x00, 0x01, 0x91, 0x82, 0x73, 0x64, 0x40, 0xcb, 0x00, 0x00,
750        ];
751        let err = Compound::parse(&data).unwrap_err();
752        assert_eq!(err, RtcpParseError::UnsupportedVersion(1));
753    }
754
755    #[test]
756    fn parse_rr_bye_undeclared_padding() {
757        let data = [
758            0x80, 0xc9, 0x00, 0x01, 0x91, 0x82, 0x73, 0x64, 0x80, 0xcb, 0x00, 0x00, 0x00, 0x00,
759        ];
760        let err = Compound::parse(&data).unwrap_err();
761        assert_eq!(
762            err,
763            RtcpParseError::Truncated {
764                expected: 16,
765                actual: 14
766            }
767        );
768    }
769
770    #[test]
771    fn parse_rr_bye_first_packet_padded() {
772        let data = [
773            0xa0, 0xc9, 0x00, 0x02, 0x91, 0x82, 0x73, 0x64, 0x00, 0x00, 0x00, 0x04, 0x80, 0xcb,
774            0x00, 0x00,
775        ];
776        let err = Compound::parse(&data).unwrap_err();
777        assert_eq!(err, RtcpParseError::InvalidPadding);
778    }
779
780    #[test]
781    fn parse_rr_bye_padded() {
782        let data = [
783            0x80, 0xc9, 0x00, 0x01, 0x91, 0x82, 0x73, 0x64, 0xa0, 0xcb, 0x00, 0x01, 0x00, 0x00,
784            0x00, 0x04,
785        ];
786
787        let mut compound = Compound::parse(&data).unwrap();
788        let packet = compound.next().unwrap().unwrap();
789        matches!(packet, Packet::Rr(_));
790
791        let packet = compound.next().unwrap().unwrap();
792        matches!(packet, Packet::Bye(_));
793
794        assert!(compound.next().is_none());
795    }
796
797    #[test]
798    fn parse_rr_one_packet_padded() {
799        let data = [
800            0xa0, 0xc9, 0x00, 0x02, 0x91, 0x82, 0x73, 0x64, 0x00, 0x00, 0x00, 0x04,
801        ];
802        let mut compound = Compound::parse(&data).unwrap();
803        let packet = compound.next().unwrap().unwrap();
804        matches!(packet, Packet::Rr(_));
805
806        assert!(compound.next().is_none());
807    }
808
809    #[test]
810    fn parse_packet_try_as_app() {
811        let data = [
812            0x80, 0xcc, 0x00, 0x02, 0x91, 0x82, 0x73, 0x64, 0x6e, 0x61, 0x6d, 0x65,
813        ];
814        let packet = Packet::parse(&data).unwrap();
815
816        let app = packet.try_as::<crate::App>().unwrap();
817        assert_eq!(app.name(), "name".as_bytes());
818
819        matches!(packet, Packet::App(_));
820    }
821
822    #[test]
823    fn parse_unknown_try_as_bye() {
824        let data = [0x81, 0xcb, 0x00, 0x01, 0x12, 0x34, 0x56, 0x78];
825        let unknown = Unknown::parse(&data).unwrap();
826
827        let bye = unknown.try_as::<crate::Bye>().unwrap();
828        let mut ssrcs = bye.ssrcs();
829        let ssrc = ssrcs.next().unwrap();
830        assert_eq!(ssrc, 0x12345678);
831    }
832}