1use crate::{
4 prelude::*,
5 utils::{parser::*, writer::*},
6 RtcpPacket, RtcpParseError, RtcpWriteError,
7};
8
9#[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; }
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 pub fn data(&self) -> &[u8] {
61 self.data
62 }
63
64 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 pub fn builder(type_: u8, data: &'a [u8]) -> UnknownBuilder<'a> {
77 UnknownBuilder::new(type_, data)
78 }
79}
80
81#[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 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 pub fn padding(mut self, padding: u8) -> Self {
105 self.padding = padding;
106 self
107 }
108
109 pub fn count(mut self, count: u8) -> Self {
112 self.count = count;
113 self
114 }
115}
116
117impl RtcpPacketWriter for UnknownBuilder<'_> {
118 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 #[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#[derive(Debug)]
169pub enum Packet<'a> {
170 App(crate::App<'a>),
172 Bye(crate::Bye<'a>),
174 Rr(crate::ReceiverReport<'a>),
176 Sdes(crate::Sdes<'a>),
178 Sr(crate::SenderReport<'a>),
180 TransportFeedback(crate::TransportFeedback<'a>),
182 PayloadFeedback(crate::PayloadFeedback<'a>),
184 Xr(crate::Xr<'a>),
186 Unknown(Unknown<'a>),
188}
189
190impl Packet<'_> {
191 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; }
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 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#[derive(Debug)]
260pub struct Compound<'a> {
261 data: &'a [u8],
262 offset: usize,
263 is_over: bool,
264}
265
266impl<'a> Compound<'a> {
267 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 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 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 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 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#[derive(Debug)]
352#[must_use = "The builder must be built to be used"]
353pub enum PacketBuilder<'a> {
354 App(crate::app::AppBuilder<'a>),
356 Bye(crate::bye::ByeBuilder<'a>),
358 Rr(crate::receiver::ReceiverReportBuilder),
360 Sdes(crate::sdes::SdesBuilder<'a>),
362 Sr(crate::sender::SenderReportBuilder),
364 TransportFeedback(crate::feedback::TransportFeedbackBuilder<'a>),
366 PayloadFeedback(crate::feedback::PayloadFeedbackBuilder<'a>),
368 Xr(crate::xr::XrBuilder),
370 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#[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 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 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 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 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}