rtp_rs/
lib.rs

1//! Parser and builder for packets formatted per [RFC 3550](https://tools.ietf.org/html/rfc3550), _A Transport
2//! Protocol for Real-Time Applications_.
3//!
4//! Parse a packet
5//! ```
6//! use rtp_rs::*;
7//! // let data = ...acquire UDP packet from the network etc...
8//! # let data = &[
9//! # 0x80u8, 0xe0u8, 0x27u8, 0x38u8, 0x64u8, 0xe4u8,
10//! # 0x05u8, 0xa7u8, 0xa2u8, 0x42u8, 0xafu8, 0x01u8
11//! # ];
12//! if let Ok(rtp) = RtpReader::new(data) {
13//!     println!("Sequence number {:?}", rtp.sequence_number());
14//!     println!("Payload length {:?}", rtp.payload().len());
15//! }
16//! ```
17//!
18//! Build a packet
19//! ```
20//! use rtp_rs::*;
21//!
22//! let payload = vec![0u8, 2, 5, 4, 6];
23//! let result = RtpPacketBuilder::new()
24//!     .payload_type(111)
25//!     .ssrc(1337)
26//!     .sequence(Seq::from(1234))
27//!     .timestamp(666657)
28//!     .padded(Pad::round_to(4))
29//!     .marked(true)
30//!     .payload(&payload)
31//!     .build();
32//! if let Ok(packet) = result {
33//!     println!("Packet: {:?}", packet);
34//! }
35//! ```
36
37#![forbid(unsafe_code)]
38#![deny(rust_2018_idioms, future_incompatible, missing_docs)]
39
40/// 16 bit RTP sequence number value, as obtained from the `sequence_number()` method of RtpReader.
41///
42/// ```
43/// use rtp_rs::*;
44/// let seq = Seq::from(123);
45/// ```
46///
47/// This type's behavior attempts to honour the expected wrap-around of sequence number values
48/// from `0xffff` back to `0x0000`.
49///
50/// You can perform logic over sequences of RTP packets using this type and other helpers from this
51/// crate,
52/// ```
53/// # use rtp_rs::*;
54/// let start = Seq::from(0xfffe);
55/// let end = Seq::from(0x0002);
56/// // produces the Seq values 0xfffe, 0xffff, 0x0000, 0x0001:
57/// for seq in (start..end).seq_iter() {
58///     // ...inspect some RTP packet you've stored against this sequence number...
59/// }
60/// ```
61///
62/// ## Unsoundness
63/// **Note** this type has implementations of `Ord` and `PartialOrd`, but those implementations
64/// violate the requirement for transitivity which both traits document.
65///
66/// ```should_panic
67/// # use rtp_rs::*;
68/// let a = Seq::from(0);
69/// let b = a + 0x7fff;
70/// let c = b + 0x7fff;
71/// assert!(a < b);
72/// assert!(b < c);
73/// assert!(a < c);  // Assertion fails, in violation of Ord/PartialOrd requirements
74/// ```
75/// A future release will potentially deprecate `Ord` / `PartialOrd` implementations for `Seq`, and
76/// hopefully provide a mechanism for sequence number processing which is sound.
77#[derive(PartialEq, Eq, Debug, Clone, Copy)]
78pub struct Seq(u16);
79impl Seq {
80    /// Produce the sequence value which follows this one.
81    ///
82    /// Sequence numbers wrap back to `0x0000` after reaching the value `0xffff`
83    pub fn next(self) -> Seq {
84        Seq(self.0.wrapping_add(1))
85    }
86
87    /// Returns `true` if this sequence number value is immediately before the given one
88    pub fn precedes(self, other: Seq) -> bool {
89        self.next() == other
90    }
91}
92impl From<Seq> for u16 {
93    fn from(v: Seq) -> Self {
94        v.0
95    }
96}
97impl From<u16> for Seq {
98    fn from(v: u16) -> Self {
99        Seq(v)
100    }
101}
102
103/// Implements wrapped subtraction such that for instance `Seq(0x0000) - Seq(0xffff)` results in
104/// `1` (rather than `-65535`).
105///
106/// This is for symmetry with addition, where for example `Seq(0xffff) + 1` gives `Seq(0x0000)`
107impl std::ops::Sub for Seq {
108    type Output = i32;
109
110    fn sub(self, rhs: Seq) -> Self::Output {
111        let delta = i32::from(self.0) - i32::from(rhs.0);
112        if delta < std::i16::MIN as i32 {
113            std::u16::MAX as i32 + 1 + delta
114        } else if delta > std::i16::MAX as i32 {
115            delta - std::u16::MAX as i32 - 1
116        } else {
117            delta
118        }
119    }
120}
121impl PartialOrd for Seq {
122    fn partial_cmp(&self, other: &Seq) -> Option<std::cmp::Ordering> {
123        (*self - *other).partial_cmp(&0)
124    }
125}
126impl Ord for Seq {
127    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
128        (*self - *other).cmp(&0)
129    }
130}
131
132impl std::ops::Add<u16> for Seq {
133    type Output = Seq;
134
135    fn add(self, rhs: u16) -> Self::Output {
136        Seq(self.0.wrapping_add(rhs))
137    }
138}
139
140/// Trait for types that can produce a `SeqIter`, with an implementation provided for `Range<Seq>`.
141pub trait IntoSeqIterator {
142    /// Produce an `Iterator` over sequence number values
143    fn seq_iter(self) -> SeqIter;
144}
145impl IntoSeqIterator for std::ops::Range<Seq> {
146    fn seq_iter(self) -> SeqIter {
147        SeqIter(self.start, self.end)
148    }
149}
150
151/// An `Iterator` which can produce values from the given start value to the given end value, inclusive.
152///
153/// Rather than using this directly, it is convenient to use a range like so,
154/// ```
155/// use rtp_rs::*;
156/// use rtp_rs::IntoSeqIterator;
157/// let here = 12.into();
158/// let there = 22.into();
159/// for seq in (here..there).seq_iter() {
160///     println!("{:?}", seq);
161/// }
162/// ```
163pub struct SeqIter(Seq, Seq);
164impl Iterator for SeqIter {
165    type Item = Seq;
166
167    fn next(&mut self) -> Option<Self::Item> {
168        if self.0 >= self.1 {
169            None
170        } else {
171            let res = self.0;
172            self.0 = self.0.next();
173            Some(res)
174        }
175    }
176}
177
178mod reader;
179pub use reader::*;
180
181mod builder;
182pub use builder::*;