Skip to main content

str0m/rtp/
id.rs

1use std::fmt;
2use std::ops::Deref;
3use std::str::from_utf8;
4
5use serde::{Deserialize, Serialize};
6
7use str0m_proto::Id;
8use str0m_proto::NonCryptographicRng;
9
10macro_rules! str_id {
11    ($id:ident, $name:literal, $num:tt, $new_len:tt) => {
12        impl $id {
13            /// Creates a new random id.
14            pub fn new() -> $id {
15                let mut arr = Id::<$num>::random().into_array();
16                for i in $new_len..$num {
17                    arr[i] = b' ';
18                }
19                $id(arr)
20            }
21
22            /// Converts an array of bytes to an id.
23            pub const fn from_array(a: [u8; $num]) -> $id {
24                $id(a)
25            }
26        }
27
28        impl fmt::Display for $id {
29            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30                let s: &str = self;
31                write!(f, "{}", s)
32            }
33        }
34
35        impl fmt::Debug for $id {
36            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37                let s: &str = self;
38                write!(f, "{}({})", $name, s)
39            }
40        }
41
42        impl Deref for $id {
43            type Target = str;
44
45            fn deref(&self) -> &Self::Target {
46                from_utf8(&self.0).expect("ascii id").trim()
47            }
48        }
49
50        impl<'a> From<&'a str> for $id {
51            fn from(v: &'a str) -> Self {
52                let v = v
53                    .chars()
54                    .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
55                    .collect::<String>();
56
57                let bytes = v.as_bytes();
58                let bytes = &bytes[0..$num.min(bytes.len())];
59
60                // pad with space.
61                let mut array = [b' '; $num];
62
63                let max = bytes.len().min(array.len());
64                (&mut array[0..max]).copy_from_slice(bytes);
65
66                $id(array)
67            }
68        }
69
70        impl Default for $id {
71            fn default() -> Self {
72                $id::new()
73            }
74        }
75    };
76}
77
78macro_rules! num_id {
79    ($id:ident, $t:tt) => {
80        impl $id {
81            /// Creates a new random id.
82            pub fn new() -> Self {
83                loop {
84                    let v = NonCryptographicRng::$t();
85                    // At least Ssrc assigns special meaning to 0,
86                    // but it's fine to avoid for the other numeric
87                    // ids as well.
88                    if v != 0 {
89                        return $id(v);
90                    }
91                }
92            }
93        }
94
95        impl Deref for $id {
96            type Target = $t;
97
98            fn deref(&self) -> &Self::Target {
99                &self.0
100            }
101        }
102
103        impl From<$t> for $id {
104            fn from(v: $t) -> Self {
105                $id(v)
106            }
107        }
108
109        impl fmt::Display for $id {
110            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111                write!(f, "{}", self.0)
112            }
113        }
114    };
115}
116
117/// Media identifier.
118///
119/// In SDP this is found per m-line with the attribute `a=mid:<mid>`.
120///
121/// When using Direct API we still need `Mid`, since they group individual
122/// encoded streams. For example a simulcast of 3 layers would have
123/// 3 incoming StreamRx, but since they belong to the same media,
124/// the have the same `Mid`.
125#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
126pub struct Mid([u8; 16]);
127str_id!(Mid, "Mid", 16, 3);
128
129/// Identifier of a simulcast layer for an encoded stream.
130///
131/// The abbreviation means "RTP Stream Id", which is a very confusing name, because
132/// everything in RTP is a stream. People tend to just call it "rid".
133///
134/// In SDP this is an optional value that will be seen in [`MediaData`][crate::media::MediaData]
135/// if the remote peer is configured for simulcast.
136#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
137pub struct Rid([u8; 8]);
138str_id!(Rid, "Rid", 8, 3);
139
140/// Synchronization source.
141///
142/// Uniquely identifies a sending source of data. Each video/audio stream would be associated
143/// with at least one synchronization source. Multiple sources for the same stream happens
144/// for RTX (resend) and simulcast.
145#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
146pub struct Ssrc(u32);
147num_id!(Ssrc, u32);
148
149impl Ssrc {
150    /// Returns true if this is the probe SSRC (0).
151    ///
152    /// libwebrtc uses SSRC 0 for bandwidth estimation probes sent before
153    /// video media starts. These probes require special handling.
154    pub fn is_probe(&self) -> bool {
155        self.0 == 0
156    }
157}
158
159/// Payload type.
160///
161/// The payload type identifies which codec and format parameters a stream is sent with.
162/// The mappings of Pt-Codec + parameters is negotiated in SDP OFFER/ANSWER.
163///
164/// PTs in RTP headers are 7 bits. Values >=128 are not valid.
165#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
166pub struct Pt(u8);
167num_id!(Pt, u8);
168
169/// Identifier of an SDP session.
170///
171/// This value is rarely interesting, but is part of the SDP OFFER and ANSWER.
172#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
173pub struct SessionId(u64);
174num_id!(SessionId, u64);
175
176/// Sequence number of an RTP packet.
177///
178/// An RTP packet is identified by: SSRC + SeqNo. However in the RTP header the sequence number
179/// is a `u16`, meaning the value quite quickly "rolls over". To uniquely identify a packet,
180/// str0m keeps track of the roll overs and converts the `u16` to `u64` in this `SeqNo`.
181///
182/// To get the RTP u16 value from a `SeqNo`, use `as_u16()` or cast it to u16.
183///
184/// ```
185/// # use str0m::rtp::SeqNo;
186/// let seq_no: SeqNo = 65_537.into();
187///
188/// // Use `as_u16()`.
189/// let a = seq_no.as_u16();
190/// // Discard upper 48 bits to get RTP u16.
191/// let b = *seq_no as u16;
192///
193/// assert_eq!(a, 1);
194/// assert_eq!(b, 1);
195/// ```
196#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
197pub struct SeqNo(u64);
198num_id!(SeqNo, u64);
199
200/// TWCC-specific sequence number.
201///
202/// Transport-Wide Congestion Control uses its own sequence number space,
203/// separate from RTP sequence numbers. This type ensures TWCC sequences
204/// cannot be confused with RTP SeqNo values.
205///
206/// TWCC sequences are also u64 internally (tracking rollovers), though the
207/// wire format uses u16.
208#[derive(
209    Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, Default,
210)]
211pub struct TwccSeq(u64);
212num_id!(TwccSeq, u64);
213
214impl SeqNo {
215    pub(crate) const MAX: SeqNo = SeqNo(u64::MAX);
216
217    /// Check if the `other` sequence number is directly following this.
218    #[inline(always)]
219    pub fn is_next(&self, other: SeqNo) -> bool {
220        if **self >= *other {
221            return false;
222        }
223        *other - **self == 1
224    }
225
226    /// Increase (mutate) this sequence number and return the previous value.
227    #[inline(always)]
228    pub fn inc(&mut self) -> SeqNo {
229        let n = SeqNo(self.0);
230        self.0 += 1;
231        n
232    }
233
234    #[inline(always)]
235    pub(crate) fn is_max(&self) -> bool {
236        self.0 == Self::MAX.0
237    }
238
239    /// The RTP header value (discarding the ROC).
240    ///
241    /// This is the same as discarding the top 48 bits by casting to a u16.
242    ///
243    /// ```
244    /// # use str0m::rtp::SeqNo;
245    /// let seq_no: SeqNo = 65_537.into();
246    ///
247    /// // Use `as_u16()`.
248    /// let a = seq_no.as_u16();
249    ///
250    /// assert_eq!(a, 1);
251    /// ```
252    #[inline(always)]
253    pub fn as_u16(&self) -> u16 {
254        self.0 as u16
255    }
256
257    /// Get the rollover counter (ROC) value.
258    ///
259    /// ```
260    /// # use str0m::rtp::SeqNo;
261    /// // More than 2^16, thus rolled over.
262    /// let seq_no: SeqNo = 95_000.into();
263    ///
264    /// assert_eq!(seq_no.roc(), 1);
265    ///
266    /// // Is the same as shifting 16 bits.
267    /// assert_eq!(seq_no.roc(), 95_000 >> 16);
268    /// ```
269    #[inline(always)]
270    pub fn roc(&self) -> u64 {
271        self.0 >> 16
272    }
273}
274
275impl TwccSeq {
276    /// Check if the `other` sequence number is directly following this.
277    #[inline(always)]
278    pub fn is_next(&self, other: TwccSeq) -> bool {
279        if **self >= *other {
280            return false;
281        }
282        *other - **self == 1
283    }
284
285    /// Increase (mutate) this sequence number and return the previous value.
286    #[inline(always)]
287    pub fn inc(&mut self) -> TwccSeq {
288        let n = TwccSeq(self.0);
289        self.0 += 1;
290        n
291    }
292
293    /// The TWCC wire format value (discarding the ROC).
294    ///
295    /// This is the same as discarding the top 48 bits by casting to a u16.
296    #[inline(always)]
297    pub fn as_u16(&self) -> u16 {
298        self.0 as u16
299    }
300
301    /// Get the rollover counter (ROC) value.
302    #[inline(always)]
303    pub fn roc(&self) -> u64 {
304        self.0 >> 16
305    }
306}
307
308impl Default for SeqNo {
309    fn default() -> Self {
310        // https://www.rfc-editor.org/rfc/rfc3550#page-13
311        // The initial value of the sequence number SHOULD be random (unpredictable)
312        // to make known-plaintext attacks on encryption more difficult
313        // Upper half of range is avoided in order to prevent SRTP wraparound issues
314        // during startup.
315        // Sequence number 0 is avoided for historical reasons, presumably to avoid
316        // debugability or test usage conflicts.
317        // i.e the range is (1, 2^15-1)
318        Self((NonCryptographicRng::u16() % 32767 + 1) as u64)
319    }
320}
321
322/// Probe cluster identifier for bandwidth estimation.
323///
324/// Used to tag TWCC packets as belonging to a specific probe cluster,
325/// enabling analysis of probe results when feedback arrives.
326///
327/// Uses u64 to avoid wrap-around in long-running connections.
328#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
329pub struct TwccClusterId(u64);
330num_id!(TwccClusterId, u64);
331
332impl TwccClusterId {
333    /// Increase (mutate) this cluster ID and return the previous value.
334    #[inline(always)]
335    pub fn inc(&mut self) -> TwccClusterId {
336        let n = TwccClusterId(self.0);
337        self.0 = self.0.wrapping_add(1);
338        n
339    }
340}
341
342impl Pt {
343    /// Create a PT with a specific value.
344    ///
345    /// PTs are 7 bit. Values with 8 bits are not valid in RTP headers.
346    pub const fn new_with_value(v: u8) -> Pt {
347        Pt(v)
348    }
349}
350
351/// A combination of Mid/Rid
352///
353/// In many cases they go hand-in-hand.
354#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
355pub(crate) struct MidRid(pub Mid, pub Option<Rid>);
356
357impl MidRid {
358    #[inline(always)]
359    pub fn mid(&self) -> Mid {
360        self.0
361    }
362
363    #[inline(always)]
364    pub fn rid(&self) -> Option<Rid> {
365        self.1
366    }
367
368    pub fn special_equals(&self, other: &MidRid) -> bool {
369        self.0 == other.0 && (self.1.is_none() || self.1 == other.1)
370    }
371}