Skip to content
File

Blob: firmware/vendor/str0m/src/rtp/id.rs

rust375 lines
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#[cfg(feature = "drv")]
201crate::drv_identity_copy!(Mid, Rid, Ssrc, Pt, SessionId, SeqNo);
202 
203/// TWCC-specific sequence number.
204///
205/// Transport-Wide Congestion Control uses its own sequence number space,
206/// separate from RTP sequence numbers. This type ensures TWCC sequences
207/// cannot be confused with RTP SeqNo values.
208///
209/// TWCC sequences are also u64 internally (tracking rollovers), though the
210/// wire format uses u16.
211#[derive(
212 Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, Default,
213)]
214pub struct TwccSeq(u64);
215num_id!(TwccSeq, u64);
216 
217impl SeqNo {
218 pub(crate) const MAX: SeqNo = SeqNo(u64::MAX);
219 
220 /// Check if the `other` sequence number is directly following this.
221 #[inline(always)]
222 pub fn is_next(&self, other: SeqNo) -> bool {
223 if **self >= *other {
224 return false;
225 }
226 *other - **self == 1
227 }
228 
229 /// Increase (mutate) this sequence number and return the previous value.
230 #[inline(always)]
231 pub fn inc(&mut self) -> SeqNo {
232 let n = SeqNo(self.0);
233 self.0 += 1;
234 n
235 }
236 
237 #[inline(always)]
238 pub(crate) fn is_max(&self) -> bool {
239 self.0 == Self::MAX.0
240 }
241 
242 /// The RTP header value (discarding the ROC).
243 ///
244 /// This is the same as discarding the top 48 bits by casting to a u16.
245 ///
246 /// ```
247 /// # use str0m::rtp::SeqNo;
248 /// let seq_no: SeqNo = 65_537.into();
249 ///
250 /// // Use `as_u16()`.
251 /// let a = seq_no.as_u16();
252 ///
253 /// assert_eq!(a, 1);
254 /// ```
255 #[inline(always)]
256 pub fn as_u16(&self) -> u16 {
257 self.0 as u16
258 }
259 
260 /// Get the rollover counter (ROC) value.
261 ///
262 /// ```
263 /// # use str0m::rtp::SeqNo;
264 /// // More than 2^16, thus rolled over.
265 /// let seq_no: SeqNo = 95_000.into();
266 ///
267 /// assert_eq!(seq_no.roc(), 1);
268 ///
269 /// // Is the same as shifting 16 bits.
270 /// assert_eq!(seq_no.roc(), 95_000 >> 16);
271 /// ```
272 #[inline(always)]
273 pub fn roc(&self) -> u64 {
274 self.0 >> 16
275 }
276}
277 
278impl TwccSeq {
279 /// Check if the `other` sequence number is directly following this.
280 #[inline(always)]
281 pub fn is_next(&self, other: TwccSeq) -> bool {
282 if **self >= *other {
283 return false;
284 }
285 *other - **self == 1
286 }
287 
288 /// Increase (mutate) this sequence number and return the previous value.
289 #[inline(always)]
290 pub fn inc(&mut self) -> TwccSeq {
291 let n = TwccSeq(self.0);
292 self.0 += 1;
293 n
294 }
295 
296 /// The TWCC wire format value (discarding the ROC).
297 ///
298 /// This is the same as discarding the top 48 bits by casting to a u16.
299 #[inline(always)]
300 pub fn as_u16(&self) -> u16 {
301 self.0 as u16
302 }
303 
304 /// Get the rollover counter (ROC) value.
305 #[inline(always)]
306 pub fn roc(&self) -> u64 {
307 self.0 >> 16
308 }
309}
310 
311impl Default for SeqNo {
312 fn default() -> Self {
313 // https://www.rfc-editor.org/rfc/rfc3550#page-13
314 // The initial value of the sequence number SHOULD be random (unpredictable)
315 // to make known-plaintext attacks on encryption more difficult
316 // Upper half of range is avoided in order to prevent SRTP wraparound issues
317 // during startup.
318 // Sequence number 0 is avoided for historical reasons, presumably to avoid
319 // debugability or test usage conflicts.
320 // i.e the range is (1, 2^15-1)
321 Self((NonCryptographicRng::u16() % 32767 + 1) as u64)
322 }
323}
324 
325/// Probe cluster identifier for bandwidth estimation.
326///
327/// Used to tag TWCC packets as belonging to a specific probe cluster,
328/// enabling analysis of probe results when feedback arrives.
329///
330/// Uses u64 to avoid wrap-around in long-running connections.
331#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
332pub struct TwccClusterId(u64);
333num_id!(TwccClusterId, u64);
334 
335impl TwccClusterId {
336 /// Increase (mutate) this cluster ID and return the previous value.
337 #[inline(always)]
338 pub fn inc(&mut self) -> TwccClusterId {
339 let n = TwccClusterId(self.0);
340 self.0 = self.0.wrapping_add(1);
341 n
342 }
343}
344 
345impl Pt {
346 /// Create a PT with a specific value.
347 ///
348 /// PTs are 7 bit. Values with 8 bits are not valid in RTP headers.
349 pub const fn new_with_value(v: u8) -> Pt {
350 Pt(v)
351 }
352}
353 
354/// A combination of Mid/Rid
355///
356/// In many cases they go hand-in-hand.
357#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
358pub(crate) struct MidRid(pub Mid, pub Option<Rid>);
359 
360impl MidRid {
361 #[inline(always)]
362 pub fn mid(&self) -> Mid {
363 self.0
364 }
365 
366 #[inline(always)]
367 pub fn rid(&self) -> Option<Rid> {
368 self.1
369 }
370 
371 pub fn special_equals(&self, other: &MidRid) -> bool {
372 self.0 == other.0 && (self.1.is_none() || self.1 == other.1)
373 }
374}