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}