1use std::fmt;
4
5#[derive(Debug, thiserror::Error)]
7pub enum RtpParseError {
8 #[error("Unsupported RTP version {}", .0)]
10 UnsupportedVersion(u8),
11 #[error("Not enough data available to parse the packet: expected {}, actual {}", .expected, .actual)]
13 Truncated {
14 expected: usize,
16 actual: usize,
18 },
19 #[error("Padding contains invalid value {}", .0)]
21 PaddingInvalid(u8),
22}
23
24#[repr(transparent)]
26pub struct RtpPacket<'a> {
27 data: &'a [u8],
28}
29
30impl<'a> fmt::Debug for RtpPacket<'a> {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 struct DebugCsrc<'a>(&'a RtpPacket<'a>);
33
34 impl<'a> fmt::Debug for DebugCsrc<'a> {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 let mut list = f.debug_list();
37
38 for csrc in self.0.csrc() {
39 list.entry(&csrc);
40 }
41
42 list.finish()
43 }
44 }
45
46 f.debug_struct("RtpPacket")
47 .field("version", &self.version())
48 .field("marker_bit", &self.marker_bit())
49 .field("payload_type", &self.payload_type())
50 .field("sequence_number", &self.sequence_number())
51 .field("timestamp", &self.timestamp())
52 .field("ssrc", &self.ssrc())
53 .field("csrc", &DebugCsrc(self))
54 .field("extension", &self.extension())
55 .field("payload", &self.payload())
56 .field("padding", &self.padding())
57 .finish()
58 }
59}
60
61impl<'a> RtpPacket<'a> {
62 pub const MIN_RTP_PACKET_LEN: usize = 12;
64
65 pub const MAX_N_CSRCS: usize = 0xf;
67
68 pub fn parse(data: &'a [u8]) -> Result<RtpPacket<'a>, RtpParseError> {
72 if data.len() < Self::MIN_RTP_PACKET_LEN {
73 return Err(RtpParseError::Truncated {
74 expected: Self::MIN_RTP_PACKET_LEN,
75 actual: data.len(),
76 });
77 }
78
79 let ret = Self { data };
80 if ret.version() != 2 {
81 return Err(RtpParseError::UnsupportedVersion(ret.version()));
82 }
83
84 if ret.n_csrcs() > 0 {
85 let expected = ret.extension_offset();
87 if ret.data.len() < expected {
88 return Err(RtpParseError::Truncated {
89 expected,
90 actual: ret.data.len(),
91 });
92 }
93 }
94
95 if ret.extension_bit() {
96 let expected = ret.extension_offset() + 4;
98 if ret.data.len() < expected {
99 return Err(RtpParseError::Truncated {
100 expected,
101 actual: ret.data.len(),
102 });
103 }
104 let expected = expected + ret.extension_len();
105 if ret.data.len() < expected {
106 return Err(RtpParseError::Truncated {
107 expected,
108 actual: ret.data.len(),
109 });
110 }
111 }
112
113 if ret.padding_bit() {
114 let expected = ret.payload_offset() + 1;
116 if ret.data.len() < expected {
117 return Err(RtpParseError::Truncated {
118 expected,
119 actual: ret.data.len(),
120 });
121 }
122 let padding_len = ret.padding().unwrap();
123 if padding_len == 0 {
125 return Err(RtpParseError::PaddingInvalid(0));
126 }
127 let expected = ret.payload_offset() + padding_len as usize;
128 if ret.data.len() < expected {
129 return Err(RtpParseError::Truncated {
131 expected,
132 actual: ret.data.len(),
133 });
134 }
135 }
136 Ok(ret)
137 }
138
139 pub fn version(&self) -> u8 {
141 (self.data[0] & 0b1100_0000) >> 6
142 }
143
144 pub fn padding_bit(&self) -> bool {
146 self.data[0] & 0b0010_0000 != 0
147 }
148
149 pub fn padding(&self) -> Option<u8> {
151 if self.padding_bit() {
152 Some(self.data[self.data.len() - 1])
153 } else {
154 None
155 }
156 }
157
158 pub fn extension_bit(&self) -> bool {
160 (self.data[0] & 0b0001_0000) != 0
161 }
162
163 pub fn n_csrcs(&self) -> u8 {
166 self.data[0] & 0b0000_1111
167 }
168
169 #[deprecated = "Use `marker_bit()` instead"]
172 pub fn marker(&self) -> bool {
173 self.marker_bit()
174 }
175
176 pub fn marker_bit(&self) -> bool {
179 (self.data[1] & 0b1000_0000) != 0
180 }
181
182 pub fn payload_type(&self) -> u8 {
184 self.data[1] & 0b0111_1111
185 }
186
187 pub fn sequence_number(&self) -> u16 {
189 (self.data[2] as u16) << 8 | self.data[3] as u16
190 }
191
192 pub fn timestamp(&self) -> u32 {
194 (self.data[4] as u32) << 24
195 | (self.data[5] as u32) << 16
196 | (self.data[6] as u32) << 8
197 | (self.data[7] as u32)
198 }
199
200 pub fn ssrc(&self) -> u32 {
202 (self.data[8] as u32) << 24
203 | (self.data[9] as u32) << 16
204 | (self.data[10] as u32) << 8
205 | (self.data[11] as u32)
206 }
207
208 pub fn csrc(&self) -> impl Iterator<Item = u32> + '_ {
210 self.data[Self::MIN_RTP_PACKET_LEN..]
211 .chunks_exact(4)
212 .take(self.n_csrcs() as usize)
213 .map(|bytes| {
214 (bytes[0] as u32) << 24
215 | (bytes[1] as u32) << 16
216 | (bytes[2] as u32) << 8
217 | bytes[3] as u32
218 })
219 }
220
221 pub(crate) fn extension_offset(&self) -> usize {
222 Self::MIN_RTP_PACKET_LEN + (self.n_csrcs() as usize) * 4
223 }
224
225 pub fn extension_len(&self) -> usize {
227 if self.extension_bit() {
228 let offset = self.extension_offset();
229 4 * ((self.data[offset + 2] as usize) << 8 | self.data[offset + 3] as usize)
230 } else {
231 0
232 }
233 }
234
235 pub fn extension(&self) -> Option<(u16, &[u8])> {
238 if self.extension_bit() {
239 let offset = self.extension_offset();
240 let id = (self.data[offset] as u16) << 8 | self.data[offset + 1] as u16;
241 let offset = offset + 4;
242 Some((id, &self.data[offset..][..self.extension_len()]))
243 } else {
244 None
245 }
246 }
247
248 pub fn payload_offset(&self) -> usize {
250 self.extension_offset()
251 + if self.extension_bit() {
252 self.extension_len() + 4
253 } else {
254 0
255 }
256 }
257
258 pub fn payload_len(&self) -> usize {
260 let offset = self.payload_offset();
261 let pad = self.padding().unwrap_or_default() as usize;
262
263 self.data.len() - pad - offset
264 }
265
266 pub fn payload(&self) -> &[u8] {
268 let offset = self.payload_offset();
269 let pad = self.padding().unwrap_or_default() as usize;
270 &self.data[offset..self.data.len() - pad]
271 }
272
273 pub fn as_builder(&'a self) -> crate::RtpPacketBuilder<&'a [u8], &'a [u8]> {
276 let mut builder = crate::RtpPacketBuilder::new()
277 .marker_bit(self.marker_bit())
278 .payload_type(self.payload_type())
279 .sequence_number(self.sequence_number())
280 .timestamp(self.timestamp())
281 .ssrc(self.ssrc())
282 .payload(self.payload());
283 for csrc in self.csrc() {
284 builder = builder.add_csrc(csrc);
285 }
286 if let Some((ext_id, ext_data)) = self.extension() {
287 builder = builder.extension(ext_id, ext_data);
288 }
289 if let Some(padding) = self.padding() {
290 builder = builder.padding(padding);
291 }
292 builder
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299
300 #[test]
301 fn parse_rtp_no_payload_no_extension_no_csrc() {
302 let data: [u8; 12] = [
303 0x80, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
304 ];
305 let rtp = RtpPacket::parse(data.as_ref()).unwrap();
306 assert_eq!(rtp.version(), 2);
307 assert_eq!(rtp.padding(), None);
308 assert_eq!(rtp.n_csrcs(), 0);
309 assert!(!rtp.marker_bit());
310 assert_eq!(rtp.payload_type(), 96);
311 assert_eq!(rtp.sequence_number(), 0x0102);
312 assert_eq!(rtp.timestamp(), 0x03040506);
313 assert_eq!(rtp.ssrc(), 0x07080910);
314 assert_eq!(rtp.csrc().count(), 0);
315 assert_eq!(rtp.extension(), None);
316 assert_eq!(rtp.payload(), &[]);
317 let built = rtp.as_builder().write_vec().unwrap();
318 assert_eq!(built, data.as_ref());
319 }
320
321 #[test]
322 fn parse_truncated_rtp_packet() {
323 let data: [u8; 11] = [
324 0x80, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
325 ];
326 assert!(matches!(
327 RtpPacket::parse(data.as_ref()),
328 Err(RtpParseError::Truncated {
329 expected: 12,
330 actual: 11
331 })
332 ));
333 }
334
335 #[test]
336 fn parse_rtp_with_csrc() {
337 let data: [u8; 16] = [
338 0x81, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12,
339 0x13, 0x14,
340 ];
341 let rtp = RtpPacket::parse(data.as_ref()).unwrap();
342 assert_eq!(rtp.version(), 2);
343 assert_eq!(rtp.padding(), None);
344 assert_eq!(rtp.n_csrcs(), 1);
345 assert!(!rtp.marker_bit());
346 assert_eq!(rtp.payload_type(), 96);
347 assert_eq!(rtp.sequence_number(), 0x0102);
348 assert_eq!(rtp.timestamp(), 0x03040506);
349 assert_eq!(rtp.ssrc(), 0x07080910);
350 let mut csrc = rtp.csrc();
351 assert_eq!(csrc.next(), Some(0x11121314));
352 assert_eq!(csrc.next(), None);
353 assert_eq!(rtp.extension(), None);
354 assert_eq!(rtp.payload(), &[]);
355 let built = rtp.as_builder().write_vec().unwrap();
356 assert_eq!(built, data.as_ref());
357 }
358
359 #[test]
360 fn parse_rtp_with_short_csrc_data() {
361 let data: [u8; 15] = [
362 0x81, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12,
363 0x13,
364 ];
365 assert!(matches!(
366 RtpPacket::parse(data.as_ref()),
367 Err(RtpParseError::Truncated {
368 expected: 16,
369 actual: 15
370 })
371 ));
372 }
373
374 #[test]
375 fn parse_rtp_with_extension() {
376 let data: [u8; 20] = [
377 0x90, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
378 0x00, 0x1, 0x0d, 0x0e, 0x0f, 0x10,
379 ];
380 let rtp = RtpPacket::parse(data.as_ref()).unwrap();
381 assert_eq!(rtp.version(), 2);
382 assert_eq!(rtp.padding(), None);
383 assert_eq!(rtp.n_csrcs(), 0);
384 assert!(!rtp.marker_bit());
385 assert_eq!(rtp.payload_type(), 96);
386 assert_eq!(rtp.sequence_number(), 0x0102);
387 assert_eq!(rtp.timestamp(), 0x03040506);
388 assert_eq!(rtp.ssrc(), 0x0708090a);
389 assert_eq!(rtp.csrc().count(), 0);
390 assert_eq!(
391 rtp.extension(),
392 Some((0x0b0c, [0x0d, 0x0e, 0x0f, 0x10].as_ref()))
393 );
394 assert_eq!(rtp.payload(), &[]);
395 let built = rtp.as_builder().write_vec().unwrap();
396 assert_eq!(built, data.as_ref());
397 }
398
399 #[test]
400 fn parse_rtp_with_short_extension_header() {
401 let data: [u8; 15] = [
402 0x90, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
403 0x00,
404 ];
405 assert!(matches!(
406 RtpPacket::parse(data.as_ref()),
407 Err(RtpParseError::Truncated {
408 expected: 16,
409 actual: 15
410 })
411 ));
412 }
413
414 #[test]
415 fn parse_rtp_with_short_extension_data() {
416 let data: [u8; 19] = [
417 0x90, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
418 0x00, 0x01, 0x0d, 0x0e, 0x0f,
419 ];
420 assert!(matches!(
421 RtpPacket::parse(data.as_ref()),
422 Err(RtpParseError::Truncated {
423 expected: 20,
424 actual: 19
425 })
426 ));
427 }
428
429 #[test]
430 fn parse_rtp_with_payload() {
431 let data: [u8; 16] = [
432 0x80, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
433 0x0d, 0x0e,
434 ];
435 let rtp = RtpPacket::parse(data.as_ref()).unwrap();
436 assert_eq!(rtp.version(), 2);
437 assert_eq!(rtp.padding(), None);
438 assert_eq!(rtp.n_csrcs(), 0);
439 assert!(!rtp.marker_bit());
440 assert_eq!(rtp.payload_type(), 96);
441 assert_eq!(rtp.sequence_number(), 0x0102);
442 assert_eq!(rtp.timestamp(), 0x03040506);
443 assert_eq!(rtp.ssrc(), 0x0708090a);
444 assert_eq!(rtp.csrc().count(), 0);
445 assert_eq!(rtp.extension(), None);
446 assert_eq!(rtp.payload(), &[0x0b, 0x0c, 0x0d, 0x0e]);
447 let built = rtp.as_builder().write_vec().unwrap();
448 assert_eq!(built, data.as_ref());
449 }
450
451 #[test]
452 fn parse_rtp_with_padding() {
453 let data: [u8; 16] = [
454 0xa0, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
455 0x00, 0x02,
456 ];
457 let rtp = RtpPacket::parse(data.as_ref()).unwrap();
458 assert_eq!(rtp.version(), 2);
459 assert_eq!(rtp.padding(), Some(2));
460 assert_eq!(rtp.n_csrcs(), 0);
461 assert!(!rtp.marker_bit());
462 assert_eq!(rtp.payload_type(), 96);
463 assert_eq!(rtp.sequence_number(), 0x0102);
464 assert_eq!(rtp.timestamp(), 0x03040506);
465 assert_eq!(rtp.ssrc(), 0x0708090a);
466 assert_eq!(rtp.csrc().count(), 0);
467 assert_eq!(rtp.extension(), None);
468 assert_eq!(rtp.payload(), &[0x0b, 0x0c]);
469 let built = rtp.as_builder().write_vec().unwrap();
470 assert_eq!(built, data.as_ref());
471 }
472
473 #[test]
474 fn parse_rtp_with_too_large_padding() {
475 let data: [u8; 13] = [
476 0xa0, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x02,
477 ];
478 assert!(matches!(
479 RtpPacket::parse(data.as_ref()),
480 Err(RtpParseError::Truncated {
481 expected: 14,
482 actual: 13
483 })
484 ));
485 }
486
487 #[test]
488 fn parse_rtp_with_zero_padding_length() {
489 let data: [u8; 13] = [
490 0xa0, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x00,
491 ];
492 assert!(matches!(
493 RtpPacket::parse(data.as_ref()),
494 Err(RtpParseError::PaddingInvalid(0))
495 ));
496 }
497}