msf_sdp/
attribute.rs

1//! Session and media attributes.
2
3use std::{
4    borrow::Cow,
5    convert::Infallible,
6    fmt::{self, Display, Formatter},
7    ops::{Deref, DerefMut},
8    str::FromStr,
9};
10
11use str_reader::StringReader;
12
13use crate::ParseError;
14
15/// SDP attribute.
16#[derive(Debug, Clone)]
17pub struct Attribute {
18    name: String,
19    value: Option<String>,
20}
21
22impl Attribute {
23    /// Create a new flag-attribute (i.e. an attribute without a value).
24    #[inline]
25    pub fn new_flag<N>(name: N) -> Self
26    where
27        N: ToString,
28    {
29        Self {
30            name: name.to_string(),
31            value: None,
32        }
33    }
34
35    /// Create a new attribute.
36    #[inline]
37    pub fn new_attribute<N, V>(name: N, value: V) -> Self
38    where
39        N: ToString,
40        V: ToString,
41    {
42        Self {
43            name: name.to_string(),
44            value: Some(value.to_string()),
45        }
46    }
47
48    /// Get attribute name.
49    #[inline]
50    pub fn name(&self) -> &str {
51        &self.name
52    }
53
54    /// Get attribute value (if any).
55    #[inline]
56    pub fn value(&self) -> Option<&str> {
57        self.value.as_deref()
58    }
59}
60
61impl Display for Attribute {
62    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
63        f.write_str(&self.name)?;
64
65        if let Some(v) = self.value.as_ref() {
66            write!(f, ":{}", v)?;
67        }
68
69        Ok(())
70    }
71}
72
73impl FromStr for Attribute {
74    type Err = Infallible;
75
76    fn from_str(s: &str) -> Result<Self, Self::Err> {
77        let (name, value) = if let Some(colon) = s.find(':') {
78            let (name, rest) = s.split_at(colon);
79
80            let value = &rest[1..];
81
82            (name, Some(value))
83        } else {
84            (s, None)
85        };
86
87        let res = Self {
88            name: name.to_string(),
89            value: value.map(|v| v.to_string()),
90        };
91
92        Ok(res)
93    }
94}
95
96/// Collection of attributes.
97#[derive(Clone)]
98pub struct Attributes {
99    inner: Vec<Attribute>,
100}
101
102impl Attributes {
103    /// Create a new collection of attributes.
104    #[inline]
105    pub const fn new() -> Self {
106        Self { inner: Vec::new() }
107    }
108
109    /// Find the first attribute matching a given predicate.
110    #[inline]
111    pub fn find<F>(&self, predicate: F) -> Option<&Attribute>
112    where
113        F: FnMut(&Attribute) -> bool,
114    {
115        self.find_all(predicate).next()
116    }
117
118    /// Find all attributes matching a given predicate.
119    #[inline]
120    pub fn find_all<F>(&self, predicate: F) -> PredicateMatchingIter<'_, F>
121    where
122        F: FnMut(&Attribute) -> bool,
123    {
124        PredicateMatchingIter::new(self, predicate)
125    }
126
127    /// Get the first attribute matching a given name (case sensitive).
128    #[inline]
129    pub fn get(&self, name: &str) -> Option<&Attribute> {
130        self.find(|a| a.name() == name)
131    }
132
133    /// Get all attributes matching a given name (case sensitive).
134    #[inline]
135    pub fn get_all<'a>(&'a self, name: &'a str) -> NameMatchingIter<'a> {
136        NameMatchingIter::new(self, name)
137    }
138
139    /// Get value of the first attribute matching a given name (case
140    /// sensitive).
141    #[inline]
142    pub fn get_value(&self, name: &str) -> Option<&str> {
143        self.get(name).and_then(|a| a.value())
144    }
145
146    /// Check if there is an attribute matching a given name (case sensitive).
147    #[inline]
148    pub fn contains(&self, name: &str) -> bool {
149        self.get(name).is_some()
150    }
151}
152
153impl Default for Attributes {
154    #[inline]
155    fn default() -> Self {
156        Self::new()
157    }
158}
159
160impl Deref for Attributes {
161    type Target = Vec<Attribute>;
162
163    #[inline]
164    fn deref(&self) -> &Self::Target {
165        &self.inner
166    }
167}
168
169impl DerefMut for Attributes {
170    #[inline]
171    fn deref_mut(&mut self) -> &mut Self::Target {
172        &mut self.inner
173    }
174}
175
176/// Iterator over attributes matching a given predicate.
177pub struct PredicateMatchingIter<'a, F> {
178    predicate: F,
179    attributes: std::slice::Iter<'a, Attribute>,
180}
181
182impl<'a, F> PredicateMatchingIter<'a, F> {
183    /// Create a new iterator.
184    fn new(attributes: &'a [Attribute], predicate: F) -> Self {
185        Self {
186            predicate,
187            attributes: attributes.iter(),
188        }
189    }
190}
191
192impl<'a, F> Iterator for PredicateMatchingIter<'a, F>
193where
194    F: FnMut(&Attribute) -> bool,
195{
196    type Item = &'a Attribute;
197
198    #[inline]
199    fn next(&mut self) -> Option<Self::Item> {
200        loop {
201            if let Some(item) = self.attributes.next() {
202                if (self.predicate)(item) {
203                    return Some(item);
204                }
205            } else {
206                return None;
207            }
208        }
209    }
210}
211
212/// Iterator over attributes matching a given name.
213pub struct NameMatchingIter<'a> {
214    name: &'a str,
215    attributes: std::slice::Iter<'a, Attribute>,
216}
217
218impl<'a> NameMatchingIter<'a> {
219    /// Create a new iterator.
220    fn new(attributes: &'a [Attribute], name: &'a str) -> Self {
221        Self {
222            name,
223            attributes: attributes.iter(),
224        }
225    }
226}
227
228impl<'a> Iterator for NameMatchingIter<'a> {
229    type Item = &'a Attribute;
230
231    #[inline]
232    fn next(&mut self) -> Option<Self::Item> {
233        loop {
234            if let Some(item) = self.attributes.next() {
235                if item.name() == self.name {
236                    return Some(item);
237                }
238            } else {
239                return None;
240            }
241        }
242    }
243}
244
245/// Mapping from an RTP payload type to an actual encoding.
246#[derive(Clone)]
247pub struct RTPMap<'a> {
248    payload_type: u8,
249    encoding_name: &'a str,
250    clock_rate: u32,
251    encoding_parameters: Option<Cow<'a, str>>,
252}
253
254impl<'a> RTPMap<'a> {
255    /// Create a new rtpmap attribute value.
256    #[inline]
257    pub const fn new(payload_type: u8, encoding_name: &'a str, clock_rate: u32) -> Self {
258        Self {
259            payload_type,
260            encoding_name,
261            clock_rate,
262            encoding_parameters: None,
263        }
264    }
265
266    /// Set the encoding parameters.
267    #[inline]
268    pub fn with_encoding_parameters<T>(mut self, params: T) -> Self
269    where
270        T: ToString,
271    {
272        self.encoding_parameters = Some(Cow::Owned(params.to_string()));
273        self
274    }
275
276    /// Get the payload type.
277    #[inline]
278    pub fn payload_type(&self) -> u8 {
279        self.payload_type
280    }
281
282    /// Get name of the encoding.
283    #[inline]
284    pub fn encoding_name(&self) -> &str {
285        self.encoding_name
286    }
287
288    /// Get the clock rate.
289    #[inline]
290    pub fn clock_rate(&self) -> u32 {
291        self.clock_rate
292    }
293
294    /// Get the encoding parameters (if specified).
295    #[inline]
296    pub fn encoding_parameters(&self) -> Option<&str> {
297        self.encoding_parameters.as_deref()
298    }
299}
300
301impl<'a> Display for RTPMap<'a> {
302    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
303        write!(
304            f,
305            "{} {}/{}",
306            self.payload_type, self.encoding_name, self.clock_rate
307        )?;
308
309        if let Some(params) = self.encoding_parameters.as_ref() {
310            write!(f, "/{}", params)?;
311        }
312
313        Ok(())
314    }
315}
316
317impl<'a> TryFrom<&'a str> for RTPMap<'a> {
318    type Error = ParseError;
319
320    fn try_from(s: &'a str) -> Result<Self, Self::Error> {
321        let mut reader = StringReader::new(s);
322
323        let payload_type = reader.read_u8()?;
324
325        reader.skip_whitespace();
326
327        let encoding_name = reader.read_until(|c| c == '/');
328
329        reader.match_char('/')?;
330
331        let clock_rate = reader.read_until(|c| c == '/').parse()?;
332
333        let encoding_parameters = if reader.is_empty() {
334            None
335        } else {
336            Some(Cow::Borrowed(&reader.as_str()[1..]))
337        };
338
339        let res = Self {
340            payload_type,
341            encoding_name,
342            clock_rate,
343            encoding_parameters,
344        };
345
346        Ok(res)
347    }
348}
349
350/// Format-specific parameters.
351#[derive(Clone)]
352pub struct FormatParameters<'a> {
353    format: Cow<'a, str>,
354    params: Cow<'a, str>,
355}
356
357impl<'a> FormatParameters<'a> {
358    /// Create a new fmtp attribute value.
359    #[inline]
360    pub fn new<T, U>(format: T, parameters: U) -> Self
361    where
362        T: ToString,
363        U: ToString,
364    {
365        Self {
366            format: Cow::Owned(format.to_string()),
367            params: Cow::Owned(parameters.to_string()),
368        }
369    }
370
371    /// Get the format.
372    #[inline]
373    pub fn format(&self) -> &str {
374        &self.format
375    }
376
377    /// Get the format parameters.
378    #[inline]
379    pub fn parameters(&self) -> &str {
380        &self.params
381    }
382}
383
384impl<'a> Display for FormatParameters<'a> {
385    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
386        write!(f, "{} {}", self.format, self.params)
387    }
388}
389
390impl<'a> From<&'a str> for FormatParameters<'a> {
391    fn from(s: &'a str) -> Self {
392        let s = s.trim();
393
394        let (format, params) = if let Some(space) = s.find(' ') {
395            let (f, r) = s.split_at(space);
396
397            let p = &r[1..];
398
399            (f, p)
400        } else {
401            (s, "")
402        };
403
404        Self {
405            format: Cow::Borrowed(format),
406            params: Cow::Borrowed(params),
407        }
408    }
409}