1#[track_caller]
4#[inline(always)]
5pub(crate) fn u16_from_be_bytes(bytes: &[u8]) -> u16 {
6 u16::from_be_bytes(bytes.try_into().expect("expecting 2 bytes"))
7}
8
9#[track_caller]
10#[inline(always)]
11pub(crate) fn u32_from_be_bytes(bytes: &[u8]) -> u32 {
12 u32::from_be_bytes(bytes.try_into().expect("expecting 4 bytes"))
13}
14
15#[track_caller]
16#[inline(always)]
17pub(crate) fn u64_from_be_bytes(bytes: &[u8]) -> u64 {
18 u64::from_be_bytes(bytes.try_into().expect("expecting 8 bytes"))
19}
20
21#[inline(always)]
22pub(crate) const fn pad_to_4bytes(num: usize) -> usize {
23 (num + 3) & !3
24}
25
26pub mod parser {
28 use crate::{RtcpPacket, RtcpParseError};
29
30 #[inline(always)]
34 pub fn check_packet<P: RtcpPacket>(packet: &[u8]) -> Result<(), RtcpParseError> {
35 if packet.len() < P::MIN_PACKET_LEN {
36 return Err(RtcpParseError::Truncated {
37 expected: P::MIN_PACKET_LEN,
38 actual: packet.len(),
39 });
40 }
41
42 let version = parse_version(packet);
43 if version != P::VERSION {
44 return Err(RtcpParseError::UnsupportedVersion(version));
45 }
46
47 if parse_packet_type(packet) != P::PACKET_TYPE {
48 return Err(RtcpParseError::PacketTypeMismatch {
49 actual: parse_packet_type(packet),
50 requested: P::PACKET_TYPE,
51 });
52 }
53
54 let length = parse_length(packet);
55 if packet.len() < length {
56 return Err(RtcpParseError::Truncated {
57 expected: length,
58 actual: packet.len(),
59 });
60 }
61
62 if packet.len() > length {
63 return Err(RtcpParseError::TooLarge {
64 expected: length,
65 actual: packet.len(),
66 });
67 }
68
69 if let Some(padding) = parse_padding(packet) {
70 if padding == 0 {
71 return Err(RtcpParseError::InvalidPadding);
72 }
73 }
74
75 Ok(())
76 }
77
78 #[inline(always)]
80 pub fn parse_version(packet: &[u8]) -> u8 {
81 packet[0] >> 6
82 }
83
84 #[inline(always)]
86 pub fn parse_padding_bit(packet: &[u8]) -> bool {
87 (packet[0] & 0x20) != 0
88 }
89
90 #[inline(always)]
95 pub fn parse_padding(packet: &[u8]) -> Option<u8> {
96 if parse_padding_bit(packet) {
97 let length = parse_length(packet);
98 Some(packet[length - 1])
99 } else {
100 None
101 }
102 }
103
104 #[inline(always)]
106 pub fn parse_count(packet: &[u8]) -> u8 {
107 packet[0] & 0x1f
108 }
109
110 #[inline(always)]
112 pub fn parse_packet_type(packet: &[u8]) -> u8 {
113 packet[1]
114 }
115
116 #[inline(always)]
118 pub fn parse_length(packet: &[u8]) -> usize {
119 4 * (super::u16_from_be_bytes(&packet[2..4]) as usize + 1)
120 }
121
122 #[inline(always)]
126 pub fn parse_ssrc(packet: &[u8]) -> u32 {
127 super::u32_from_be_bytes(&packet[4..8])
128 }
129}
130
131pub mod writer {
133 use crate::{RtcpPacket, RtcpWriteError};
134
135 #[inline(always)]
137 pub fn check_padding(padding: u8) -> Result<(), RtcpWriteError> {
138 if padding % 4 != 0 {
139 return Err(RtcpWriteError::InvalidPadding { padding });
140 }
141
142 Ok(())
143 }
144
145 #[inline(always)]
155 pub fn write_header_unchecked<P: RtcpPacket>(padding: u8, count: u8, buf: &mut [u8]) -> usize {
156 buf[0] = P::VERSION << 6;
157 if padding > 0 {
158 buf[0] |= 0x20;
159 }
160 buf[0] |= count;
161 buf[1] = P::PACKET_TYPE;
162 let len = buf.len();
163 buf[2..4].copy_from_slice(&((len / 4 - 1) as u16).to_be_bytes());
164
165 4
166 }
167
168 #[inline(always)]
176 pub fn write_padding_unchecked(padding: u8, buf: &mut [u8]) -> usize {
177 let mut end = 0;
178 if padding > 0 {
179 end += padding as usize;
180
181 buf[0..end - 1].fill(0);
182 buf[end - 1] = padding;
183 }
184
185 end
186 }
187}