1use bytes::{BufMut, Bytes, BytesMut};
9
10pub const HEADER_LEN: usize = 12;
12
13#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
15#[non_exhaustive]
16pub enum RtpError {
17 #[error("packet is {0} bytes; an RTP header is {HEADER_LEN}")]
19 TooShort(usize),
20 #[error("RTP version {0}; only version 2 exists")]
22 BadVersion(u8),
23 #[error("header claims more bytes than the packet contains")]
25 Truncated,
26 #[error("padding of {0} bytes does not fit")]
28 BadPadding(usize),
29}
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct Packet {
34 pub marker: bool,
37 pub payload_type: u8,
39 pub sequence: u16,
41 pub timestamp: u32,
43 pub ssrc: u32,
45 pub csrc: Vec<u32>,
47 pub payload: Bytes,
49}
50
51impl Packet {
52 #[must_use]
54 pub fn new(payload_type: u8, sequence: u16, timestamp: u32, ssrc: u32, payload: Bytes) -> Self {
55 Self {
56 marker: false,
57 payload_type,
58 sequence,
59 timestamp,
60 ssrc,
61 csrc: Vec::new(),
62 payload,
63 }
64 }
65
66 #[must_use]
68 pub fn encode(&self) -> Bytes {
69 let csrc_count = self.csrc.len().min(15);
70 let mut out = BytesMut::with_capacity(HEADER_LEN + csrc_count * 4 + self.payload.len());
71
72 let first = 0b1000_0000 | u8::try_from(csrc_count).unwrap_or(0);
74 out.put_u8(first);
75 out.put_u8((u8::from(self.marker) << 7) | (self.payload_type & 0x7F));
76 out.put_u16(self.sequence);
77 out.put_u32(self.timestamp);
78 out.put_u32(self.ssrc);
79 for csrc in self.csrc.iter().take(csrc_count) {
80 out.put_u32(*csrc);
81 }
82 out.put_slice(&self.payload);
83 out.freeze()
84 }
85
86 pub fn decode(bytes: &Bytes) -> Result<Self, RtpError> {
91 if bytes.len() < HEADER_LEN {
92 return Err(RtpError::TooShort(bytes.len()));
93 }
94
95 let first = bytes.first().copied().unwrap_or(0);
96 let version = first >> 6;
97 if version != 2 {
98 return Err(RtpError::BadVersion(version));
99 }
100 let has_padding = first & 0b0010_0000 != 0;
101 let has_extension = first & 0b0001_0000 != 0;
102 let csrc_count = usize::from(first & 0x0F);
103
104 let second = bytes.get(1).copied().unwrap_or(0);
105 let marker = second & 0x80 != 0;
106 let payload_type = second & 0x7F;
107
108 let sequence = u16::from_be_bytes([
109 bytes.get(2).copied().unwrap_or(0),
110 bytes.get(3).copied().unwrap_or(0),
111 ]);
112 let timestamp = read_u32(bytes, 4)?;
113 let ssrc = read_u32(bytes, 8)?;
114
115 let mut offset = HEADER_LEN;
116 let mut csrc = Vec::with_capacity(csrc_count);
117 for _ in 0..csrc_count {
118 csrc.push(read_u32(bytes, offset)?);
119 offset += 4;
120 }
121
122 if has_extension {
123 let words = usize::from(u16::from_be_bytes([
127 bytes.get(offset + 2).copied().ok_or(RtpError::Truncated)?,
128 bytes.get(offset + 3).copied().ok_or(RtpError::Truncated)?,
129 ]));
130 offset = offset
131 .checked_add(4 + words * 4)
132 .ok_or(RtpError::Truncated)?;
133 }
134
135 if offset > bytes.len() {
136 return Err(RtpError::Truncated);
137 }
138 let mut end = bytes.len();
139
140 if has_padding {
141 let pad = usize::from(bytes.last().copied().unwrap_or(0));
143 if pad == 0 || pad > end - offset {
144 return Err(RtpError::BadPadding(pad));
145 }
146 end -= pad;
147 }
148
149 Ok(Self {
150 marker,
151 payload_type,
152 sequence,
153 timestamp,
154 ssrc,
155 csrc,
156 payload: bytes.slice(offset..end),
157 })
158 }
159}
160
161fn read_u32(bytes: &Bytes, at: usize) -> Result<u32, RtpError> {
162 Ok(u32::from_be_bytes([
163 bytes.get(at).copied().ok_or(RtpError::Truncated)?,
164 bytes.get(at + 1).copied().ok_or(RtpError::Truncated)?,
165 bytes.get(at + 2).copied().ok_or(RtpError::Truncated)?,
166 bytes.get(at + 3).copied().ok_or(RtpError::Truncated)?,
167 ]))
168}
169
170#[must_use]
176pub fn sequence_is_newer(candidate: u16, current: u16) -> bool {
177 candidate != current && candidate.wrapping_sub(current) < 0x8000
179}
180
181#[must_use]
183pub fn sequence_distance(from: u16, to: u16) -> u16 {
184 to.wrapping_sub(from)
185}
186
187#[cfg(test)]
188#[allow(
189 clippy::unwrap_used,
190 clippy::expect_used,
191 clippy::panic,
192 clippy::indexing_slicing
193)]
194mod tests {
195 use super::*;
196
197 fn sample_packet() -> Packet {
198 Packet::new(
199 0,
200 1000,
201 160_000,
202 0xDEAD_BEEF,
203 Bytes::from_static(&[0xFF; 160]),
204 )
205 }
206
207 #[test]
208 fn a_packet_round_trips_through_the_wire_format() {
209 let original = sample_packet();
210 let decoded = Packet::decode(&original.encode()).expect("decodes");
211 assert_eq!(decoded, original);
212 }
213
214 #[test]
215 fn the_header_is_twelve_bytes_before_the_payload() {
216 let encoded = sample_packet().encode();
217 assert_eq!(encoded.len(), HEADER_LEN + 160);
218 assert_eq!(encoded[0] >> 6, 2, "version 2");
219 assert_eq!(encoded[1] & 0x7F, 0, "payload type 0");
220 assert_eq!(u16::from_be_bytes([encoded[2], encoded[3]]), 1000);
221 }
222
223 #[test]
224 fn the_marker_bit_survives_a_round_trip() {
225 let mut packet = sample_packet();
226 packet.marker = true;
227 let decoded = Packet::decode(&packet.encode()).expect("decodes");
228 assert!(decoded.marker);
229 assert_eq!(
230 decoded.payload_type, 0,
231 "the marker must not bleed into the type"
232 );
233 }
234
235 #[test]
238 fn a_high_payload_type_does_not_collide_with_the_marker() {
239 let mut packet = sample_packet();
240 packet.payload_type = 127;
241 packet.marker = false;
242 let decoded = Packet::decode(&packet.encode()).expect("decodes");
243 assert_eq!(decoded.payload_type, 127);
244 assert!(!decoded.marker);
245 }
246
247 #[test]
248 fn contributing_sources_survive() {
249 let mut packet = sample_packet();
250 packet.csrc = vec![1, 2, 3];
251 let decoded = Packet::decode(&packet.encode()).expect("decodes");
252 assert_eq!(decoded.csrc, vec![1, 2, 3]);
253 assert_eq!(
254 decoded.payload, packet.payload,
255 "the payload starts after them"
256 );
257 }
258
259 #[test]
262 fn padding_is_stripped_from_the_payload() {
263 let mut raw = BytesMut::new();
264 raw.put_u8(0b1010_0000); raw.put_u8(0);
266 raw.put_u16(1);
267 raw.put_u32(0);
268 raw.put_u32(0);
269 raw.put_slice(&[1, 2, 3, 4]);
270 raw.put_slice(&[0, 0, 0, 4]); let decoded = Packet::decode(&raw.freeze()).expect("decodes");
273 assert_eq!(decoded.payload.as_ref(), &[1, 2, 3, 4]);
274 }
275
276 #[test]
277 fn impossible_padding_is_rejected() {
278 let mut raw = BytesMut::new();
279 raw.put_u8(0b1010_0000);
280 raw.put_u8(0);
281 raw.put_u16(1);
282 raw.put_u32(0);
283 raw.put_u32(0);
284 raw.put_slice(&[1, 2, 200]); assert!(matches!(
286 Packet::decode(&raw.freeze()),
287 Err(RtpError::BadPadding(200))
288 ));
289 }
290
291 #[test]
294 fn a_header_extension_is_skipped_not_played() {
295 let mut raw = BytesMut::new();
296 raw.put_u8(0b1001_0000); raw.put_u8(0);
298 raw.put_u16(7);
299 raw.put_u32(0);
300 raw.put_u32(0);
301 raw.put_u16(0xBEDE); raw.put_u16(2); raw.put_slice(&[9; 8]);
304 raw.put_slice(&[1, 2, 3]);
305
306 let decoded = Packet::decode(&raw.freeze()).expect("decodes");
307 assert_eq!(
308 decoded.payload.as_ref(),
309 &[1, 2, 3],
310 "the extension is not payload"
311 );
312 }
313
314 #[test]
315 fn a_short_packet_is_rejected() {
316 assert!(matches!(
317 Packet::decode(&Bytes::from_static(&[0x80, 0, 0])),
318 Err(RtpError::TooShort(3))
319 ));
320 }
321
322 #[test]
325 fn a_wrong_version_is_rejected() {
326 let mut raw = BytesMut::from(&[0u8; 12][..]);
327 raw[0] = 0b0100_0000; assert!(matches!(
329 Packet::decode(&raw.freeze()),
330 Err(RtpError::BadVersion(1))
331 ));
332 }
333
334 #[test]
335 fn a_truncated_csrc_list_is_rejected() {
336 let mut raw = BytesMut::from(&[0u8; 12][..]);
337 raw[0] = 0b1000_0011; assert!(matches!(
339 Packet::decode(&raw.freeze()),
340 Err(RtpError::Truncated)
341 ));
342 }
343
344 #[test]
348 fn sequence_wraparound_is_ordered_correctly() {
349 assert!(sequence_is_newer(1, 0));
350 assert!(!sequence_is_newer(0, 1));
351
352 assert!(sequence_is_newer(0, 65_535));
354 assert!(!sequence_is_newer(65_535, 0));
355 assert!(sequence_is_newer(5, 65_530));
356 assert!(!sequence_is_newer(65_530, 5));
357
358 assert!(!sequence_is_newer(42, 42));
360
361 assert!(!sequence_is_newer(0x8000, 0));
364 assert!(sequence_is_newer(0x7FFF, 0));
365 }
366
367 #[test]
368 fn sequence_distance_counts_forward_across_the_wrap() {
369 assert_eq!(sequence_distance(0, 1), 1);
370 assert_eq!(sequence_distance(65_535, 0), 1);
371 assert_eq!(sequence_distance(65_530, 5), 11);
372 assert_eq!(sequence_distance(10, 10), 0);
373 }
374}