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