1const RTP_VERSION: u8 = 2;
35
36pub const RTP_HEADER_LEN: usize = 12;
38
39pub const PT_PCMU: u8 = 0;
41pub const PT_PCMA: u8 = 8;
43
44#[derive(Debug, Clone, PartialEq, Eq)]
50pub struct RtpPacket {
51 pub payload_type: u8,
53 pub seq: u16,
55 pub timestamp: u32,
57 pub ssrc: u32,
59 pub marker: bool,
61 pub payload: Vec<u8>,
63}
64
65#[derive(Debug, Clone, PartialEq, Eq)]
67pub enum RtpParseError {
68 TooShort,
70 BadVersion(u8),
72 Truncated,
74}
75
76impl std::fmt::Display for RtpParseError {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 match self {
79 RtpParseError::TooShort => write!(f, "RTP datagram shorter than 12-byte header"),
80 RtpParseError::BadVersion(v) => write!(f, "RTP version {v} != 2"),
81 RtpParseError::Truncated => write!(f, "RTP header claims more bytes than present"),
82 }
83 }
84}
85
86#[derive(Debug, Clone)]
92pub struct RtpSender {
93 ssrc: u32,
94 payload_type: u8,
95 seq: u16,
96 timestamp: u32,
97}
98
99impl RtpSender {
100 pub fn new(payload_type: u8) -> Self {
103 Self::with_seeds(
104 payload_type,
105 rand::random::<u32>(),
106 rand::random::<u16>(),
107 rand::random::<u32>(),
108 )
109 }
110
111 pub fn with_seeds(payload_type: u8, ssrc: u32, seq: u16, timestamp: u32) -> Self {
113 Self {
114 ssrc,
115 payload_type,
116 seq,
117 timestamp,
118 }
119 }
120
121 pub fn ssrc(&self) -> u32 {
123 self.ssrc
124 }
125
126 pub fn packetize(&mut self, payload: &[u8]) -> Vec<u8> {
131 let mut pkt = Vec::with_capacity(RTP_HEADER_LEN + payload.len());
132 pkt.push(RTP_VERSION << 6);
134 pkt.push(self.payload_type & 0x7f);
136 pkt.extend_from_slice(&self.seq.to_be_bytes());
138 pkt.extend_from_slice(&self.timestamp.to_be_bytes());
140 pkt.extend_from_slice(&self.ssrc.to_be_bytes());
142 pkt.extend_from_slice(payload);
143
144 self.seq = self.seq.wrapping_add(1);
147 self.timestamp = self.timestamp.wrapping_add(payload.len() as u32);
148 pkt
149 }
150}
151
152pub fn depacketize(buf: &[u8]) -> Result<RtpPacket, RtpParseError> {
155 if buf.len() < RTP_HEADER_LEN {
156 return Err(RtpParseError::TooShort);
157 }
158 let b0 = buf[0];
159 let version = b0 >> 6;
160 if version != RTP_VERSION {
161 return Err(RtpParseError::BadVersion(version));
162 }
163 let has_extension = (b0 & 0x10) != 0;
164 let csrc_count = (b0 & 0x0f) as usize;
165
166 let b1 = buf[1];
167 let marker = (b1 & 0x80) != 0;
168 let payload_type = b1 & 0x7f;
169 let seq = u16::from_be_bytes([buf[2], buf[3]]);
170 let timestamp = u32::from_be_bytes([buf[4], buf[5], buf[6], buf[7]]);
171 let ssrc = u32::from_be_bytes([buf[8], buf[9], buf[10], buf[11]]);
172
173 let mut offset = RTP_HEADER_LEN + csrc_count * 4;
175 if buf.len() < offset {
176 return Err(RtpParseError::Truncated);
177 }
178
179 if has_extension {
182 if buf.len() < offset + 4 {
183 return Err(RtpParseError::Truncated);
184 }
185 let ext_words = u16::from_be_bytes([buf[offset + 2], buf[offset + 3]]) as usize;
186 offset += 4 + ext_words * 4;
187 if buf.len() < offset {
188 return Err(RtpParseError::Truncated);
189 }
190 }
191
192 Ok(RtpPacket {
193 payload_type,
194 seq,
195 timestamp,
196 ssrc,
197 marker,
198 payload: buf[offset..].to_vec(),
199 })
200}
201
202pub const JITTER_DEPTH: usize = 2;
226
227#[derive(Debug)]
229pub struct JitterBuffer {
230 buf: Vec<RtpPacket>,
232 depth: usize,
234 last_released: Option<u16>,
237 primed: bool,
240}
241
242impl JitterBuffer {
243 pub fn new() -> Self {
245 Self::with_depth(JITTER_DEPTH)
246 }
247
248 pub fn with_depth(depth: usize) -> Self {
250 Self {
251 buf: Vec::with_capacity(depth + 1),
252 depth: depth.max(1),
253 last_released: None,
254 primed: false,
255 }
256 }
257
258 pub fn reset(&mut self) {
264 self.buf.clear();
265 self.last_released = None;
266 self.primed = false;
267 }
268
269 fn seq_lt(seq: u16, reference: u16) -> bool {
274 seq != reference && seq.wrapping_sub(reference) > 0x8000
276 }
277
278 pub fn push(&mut self, pkt: RtpPacket) -> Vec<RtpPacket> {
284 if self.primed {
286 let last = self.last_released.unwrap();
287 if pkt.seq == last || Self::seq_lt(pkt.seq, last) {
288 return Vec::new();
289 }
290 }
291 if self.buf.iter().any(|p| p.seq == pkt.seq) {
293 return Vec::new();
294 }
295
296 let pos = self
299 .buf
300 .iter()
301 .position(|p| Self::seq_lt(pkt.seq, p.seq))
302 .unwrap_or(self.buf.len());
303 self.buf.insert(pos, pkt);
304
305 let mut out = Vec::new();
307 while self.buf.len() > self.depth {
308 let p = self.buf.remove(0);
309 self.last_released = Some(p.seq);
310 self.primed = true;
311 out.push(p);
312 }
313 out
314 }
315
316 pub fn drain(&mut self) -> Vec<RtpPacket> {
318 let out: Vec<RtpPacket> = self.buf.drain(..).collect();
319 if let Some(last) = out.last() {
320 self.last_released = Some(last.seq);
321 self.primed = true;
322 }
323 out
324 }
325}
326
327impl Default for JitterBuffer {
328 fn default() -> Self {
329 Self::new()
330 }
331}
332
333#[cfg(test)]
334mod tests {
335 use super::*;
336
337 fn pkt(seq: u16, payload: &[u8]) -> RtpPacket {
338 RtpPacket {
339 payload_type: PT_PCMU,
340 seq,
341 timestamp: seq as u32 * 160,
342 ssrc: 0xDEAD_BEEF,
343 marker: false,
344 payload: payload.to_vec(),
345 }
346 }
347
348 #[test]
351 fn packetize_writes_a_well_formed_12_byte_header() {
352 let mut s = RtpSender::with_seeds(PT_PCMU, 0x1122_3344, 0x0010, 0x0000_0100);
353 let payload: Vec<u8> = (0..160u16).map(|i| i as u8).collect();
354 let dgram = s.packetize(&payload);
355
356 assert_eq!(dgram.len(), RTP_HEADER_LEN + 160);
357 assert_eq!(dgram[0], 0x80);
359 assert_eq!(dgram[1], 0x00);
361 assert_eq!(u16::from_be_bytes([dgram[2], dgram[3]]), 0x0010);
363 assert_eq!(
364 u32::from_be_bytes([dgram[4], dgram[5], dgram[6], dgram[7]]),
365 0x0000_0100
366 );
367 assert_eq!(
368 u32::from_be_bytes([dgram[8], dgram[9], dgram[10], dgram[11]]),
369 0x1122_3344
370 );
371 assert_eq!(&dgram[RTP_HEADER_LEN..], &payload[..]);
372 }
373
374 #[test]
375 fn packetize_advances_seq_by_one_and_ts_by_sample_count() {
376 let mut s = RtpSender::with_seeds(PT_PCMA, 7, 100, 1000);
377 let a = depacketize(&s.packetize(&[0u8; 160])).unwrap();
378 let b = depacketize(&s.packetize(&[0u8; 160])).unwrap();
379 let c = depacketize(&s.packetize(&[0u8; 80])).unwrap(); assert_eq!((a.seq, a.timestamp), (100, 1000));
381 assert_eq!((b.seq, b.timestamp), (101, 1160)); assert_eq!((c.seq, c.timestamp), (102, 1320)); assert_eq!(a.payload_type, PT_PCMA);
385 assert_eq!(a.ssrc, 7);
386 }
387
388 #[test]
389 fn packetize_then_depacketize_preserves_all_fields_and_payload() {
390 let mut s = RtpSender::with_seeds(PT_PCMU, 0xCAFE_BABE, 65530, 4_000_000_000);
391 let payload: Vec<u8> = (0..160u32).map(|i| (i * 7) as u8).collect();
392 let dgram = s.packetize(&payload);
393 let p = depacketize(&dgram).unwrap();
394 assert_eq!(p.payload_type, PT_PCMU);
395 assert_eq!(p.seq, 65530);
396 assert_eq!(p.timestamp, 4_000_000_000);
397 assert_eq!(p.ssrc, 0xCAFE_BABE);
398 assert!(!p.marker);
399 assert_eq!(p.payload, payload);
400 }
401
402 #[test]
403 fn seq_and_timestamp_wrap_around() {
404 let mut s = RtpSender::with_seeds(PT_PCMU, 1, u16::MAX, u32::MAX - 100);
406 let a = depacketize(&s.packetize(&[0u8; 160])).unwrap();
407 let b = depacketize(&s.packetize(&[0u8; 160])).unwrap();
408 assert_eq!(a.seq, u16::MAX);
409 assert_eq!(b.seq, 0); assert_eq!(a.timestamp, u32::MAX - 100);
411 assert_eq!(b.timestamp, 59);
413 }
414
415 #[test]
416 fn depacketize_rejects_short_and_bad_version() {
417 assert_eq!(depacketize(&[0u8; 11]), Err(RtpParseError::TooShort));
418 let mut bad = vec![0x40u8];
420 bad.extend_from_slice(&[0u8; 11]);
421 assert_eq!(depacketize(&bad), Err(RtpParseError::BadVersion(1)));
422 }
423
424 #[test]
425 fn depacketize_skips_csrc_list() {
426 let mut dgram = vec![0x82u8, PT_PCMU];
428 dgram.extend_from_slice(&5u16.to_be_bytes()); dgram.extend_from_slice(&0u32.to_be_bytes()); dgram.extend_from_slice(&0u32.to_be_bytes()); dgram.extend_from_slice(&[0u8; 8]); dgram.extend_from_slice(&[0xAA, 0xBB]); let p = depacketize(&dgram).unwrap();
434 assert_eq!(p.seq, 5);
435 assert_eq!(p.payload, vec![0xAA, 0xBB]);
436 }
437
438 #[test]
439 fn depacketize_skips_header_extension() {
440 let mut dgram = vec![0x90u8, PT_PCMU];
442 dgram.extend_from_slice(&9u16.to_be_bytes()); dgram.extend_from_slice(&0u32.to_be_bytes()); dgram.extend_from_slice(&0u32.to_be_bytes()); dgram.extend_from_slice(&0xBEEFu16.to_be_bytes()); dgram.extend_from_slice(&1u16.to_be_bytes()); dgram.extend_from_slice(&[1, 2, 3, 4]); dgram.extend_from_slice(&[0x77]); let p = depacketize(&dgram).unwrap();
450 assert_eq!(p.seq, 9);
451 assert_eq!(p.payload, vec![0x77]);
452 }
453
454 fn run(jb: &mut JitterBuffer, seqs: &[u16]) -> Vec<u16> {
458 let mut out = Vec::new();
459 for &s in seqs {
460 for p in jb.push(pkt(s, &[s as u8])) {
461 out.push(p.seq);
462 }
463 }
464 out
465 }
466
467 #[test]
469 fn depacketize_exactly_12_bytes_is_empty_payload_no_panic() {
470 let mut d = vec![0x80u8, PT_PCMU];
471 d.extend_from_slice(&7u16.to_be_bytes());
472 d.extend_from_slice(&0u32.to_be_bytes());
473 d.extend_from_slice(&0u32.to_be_bytes());
474 let p = depacketize(&d).unwrap();
475 assert_eq!(p.seq, 7);
476 assert!(p.payload.is_empty());
477 }
478
479 #[test]
480 fn depacketize_rejects_truncated_csrc_list() {
481 let mut d = vec![0x82u8, PT_PCMU];
483 d.extend_from_slice(&1u16.to_be_bytes());
484 d.extend_from_slice(&0u32.to_be_bytes());
485 d.extend_from_slice(&0u32.to_be_bytes());
486 assert_eq!(depacketize(&d), Err(RtpParseError::Truncated));
487 }
488
489 #[test]
490 fn depacketize_rejects_truncated_header_extension() {
491 let mut d = vec![0x90u8, PT_PCMU];
493 d.extend_from_slice(&2u16.to_be_bytes());
494 d.extend_from_slice(&0u32.to_be_bytes());
495 d.extend_from_slice(&0u32.to_be_bytes());
496 d.extend_from_slice(&0xBEEFu16.to_be_bytes());
497 d.extend_from_slice(&4u16.to_be_bytes());
498 assert_eq!(depacketize(&d), Err(RtpParseError::Truncated));
499 }
500
501 #[test]
502 fn depacketize_parses_marker_bit_set() {
503 let mut d = vec![0x80u8, 0x80 | PT_PCMU];
504 d.extend_from_slice(&3u16.to_be_bytes());
505 d.extend_from_slice(&0u32.to_be_bytes());
506 d.extend_from_slice(&0u32.to_be_bytes());
507 d.push(0xAA);
508 let p = depacketize(&d).unwrap();
509 assert!(p.marker, "marker bit should parse as true");
510 assert_eq!(p.payload_type, PT_PCMU);
511 assert_eq!(p.payload, vec![0xAA]);
512 }
513
514 #[test]
515 fn depacketize_does_not_panic_on_arbitrary_short_buffers() {
516 for n in 0..RTP_HEADER_LEN {
517 assert_eq!(depacketize(&vec![0xFFu8; n]), Err(RtpParseError::TooShort));
518 }
519 }
520
521 #[test]
523 fn sender_seq_and_ts_wrap_independently() {
524 let mut s = RtpSender::with_seeds(PT_PCMU, 1, u16::MAX - 1, 0);
525 let seqs: Vec<u16> = (0..4)
526 .map(|_| depacketize(&s.packetize(&[0u8; 160])).unwrap().seq)
527 .collect();
528 assert_eq!(seqs, vec![u16::MAX - 1, u16::MAX, 0, 1]);
529
530 let mut s2 = RtpSender::with_seeds(PT_PCMU, 1, 0, u32::MAX - 160);
531 assert_eq!(
532 depacketize(&s2.packetize(&[0u8; 160])).unwrap().timestamp,
533 u32::MAX - 160
534 );
535 assert_eq!(
536 depacketize(&s2.packetize(&[0u8; 160])).unwrap().timestamp,
537 u32::MAX
538 );
539 assert_eq!(
540 depacketize(&s2.packetize(&[0u8; 160])).unwrap().timestamp,
541 159
542 ); }
544
545 #[test]
547 fn jitter_depth_one_releases_immediately_in_order() {
548 let mut jb = JitterBuffer::with_depth(1);
549 assert_eq!(run(&mut jb, &[1, 2, 3, 4]), vec![1, 2, 3]);
550 let tail: Vec<u16> = jb.drain().into_iter().map(|p| p.seq).collect();
551 assert_eq!(tail, vec![4]);
552 }
553
554 #[test]
555 fn jitter_with_depth_zero_clamps_to_one() {
556 let mut jb = JitterBuffer::with_depth(0);
557 assert_eq!(run(&mut jb, &[5, 6]), vec![5]);
558 }
559
560 #[test]
561 fn jitter_lost_packet_does_not_stall_and_late_arrival_is_dropped() {
562 let mut jb = JitterBuffer::with_depth(2);
564 assert_eq!(run(&mut jb, &[1, 2, 4, 5, 6]), vec![1, 2, 4]);
565 assert_eq!(jb.push(pkt(3, &[3])), vec![], "late lost packet dropped");
566 }
567
568 #[test]
570 fn jitter_reset_clears_state_for_a_fresh_stream() {
571 let mut jb = JitterBuffer::with_depth(2);
572 let _ = run(&mut jb, &[40000, 40001, 40002, 40003]); jb.reset(); assert_eq!(run(&mut jb, &[100, 101, 102, 103]), vec![100, 101]);
578 }
579
580 #[test]
581 fn jitter_in_order_releases_in_order_after_priming() {
582 let mut jb = JitterBuffer::with_depth(4);
583 let released = run(&mut jb, &[1, 2, 3, 4, 5, 6, 7, 8]);
586 assert_eq!(released, vec![1, 2, 3, 4]);
587 let tail: Vec<u16> = jb.drain().into_iter().map(|p| p.seq).collect();
589 assert_eq!(tail, vec![5, 6, 7, 8]);
590 }
591
592 #[test]
593 fn jitter_reorders_within_window() {
594 let mut jb = JitterBuffer::with_depth(4);
595 let released = run(&mut jb, &[1, 2, 4, 3, 5, 6, 7]);
597 assert_eq!(released, vec![1, 2, 3]); let tail: Vec<u16> = jb.drain().into_iter().map(|p| p.seq).collect();
599 assert_eq!(tail, vec![4, 5, 6, 7]);
600 }
601
602 #[test]
603 fn jitter_drops_duplicates() {
604 let mut jb = JitterBuffer::with_depth(4);
605 let released = run(&mut jb, &[1, 2, 2, 3, 4, 5, 6]);
607 assert_eq!(released, vec![1, 2]);
608 let tail: Vec<u16> = jb.drain().into_iter().map(|p| p.seq).collect();
609 assert_eq!(tail, vec![3, 4, 5, 6]);
610 }
611
612 #[test]
613 fn jitter_drops_late_packet_below_release_point() {
614 let mut jb = JitterBuffer::with_depth(2);
615 let released = run(&mut jb, &[10, 11, 12, 13, 14]);
617 assert_eq!(released, vec![10, 11, 12]); assert_eq!(jb.push(pkt(11, &[0])), vec![]);
620 assert_eq!(jb.push(pkt(12, &[0])), vec![]);
622 }
623
624 #[test]
625 fn jitter_handles_seq_wraparound() {
626 let mut jb = JitterBuffer::with_depth(2);
627 let released = run(&mut jb, &[65534, 65535, 0, 1, 2]);
629 assert_eq!(released, vec![65534, 65535, 0]);
630 let tail: Vec<u16> = jb.drain().into_iter().map(|p| p.seq).collect();
631 assert_eq!(tail, vec![1, 2]);
632 }
633
634 #[test]
635 fn jitter_reordered_across_wrap_is_sorted() {
636 let mut jb = JitterBuffer::with_depth(3);
637 let released = run(&mut jb, &[65534, 0, 65535, 1, 2, 3]);
639 assert_eq!(released, vec![65534, 65535, 0]);
640 let tail: Vec<u16> = jb.drain().into_iter().map(|p| p.seq).collect();
641 assert_eq!(tail, vec![1, 2, 3]);
642 }
643}