xref: /webrtc/sdp/src/extmap/mod.rs (revision 5d8fe953)
1 #[cfg(test)]
2 mod extmap_test;
3 
4 use super::direction::*;
5 use super::error::{Error, Result};
6 use crate::description::common::*;
7 
8 use std::fmt;
9 use std::io;
10 use url::Url;
11 
12 /// Default ext values
13 pub const DEF_EXT_MAP_VALUE_ABS_SEND_TIME: usize = 1;
14 pub const DEF_EXT_MAP_VALUE_TRANSPORT_CC: usize = 2;
15 pub const DEF_EXT_MAP_VALUE_SDES_MID: usize = 3;
16 pub const DEF_EXT_MAP_VALUE_SDES_RTP_STREAM_ID: usize = 4;
17 
18 pub const ABS_SEND_TIME_URI: &str = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time";
19 pub const TRANSPORT_CC_URI: &str =
20     "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01";
21 pub const SDES_MID_URI: &str = "urn:ietf:params:rtp-hdrext:sdes:mid";
22 pub const SDES_RTP_STREAM_ID_URI: &str = "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id";
23 pub const AUDIO_LEVEL_URI: &str = "urn:ietf:params:rtp-hdrext:ssrc-audio-level";
24 pub const VIDEO_ORIENTATION_URI: &str = "urn:3gpp:video-orientation";
25 
26 /// ExtMap represents the activation of a single RTP header extension
27 #[derive(Debug, Clone, Default)]
28 pub struct ExtMap {
29     pub value: isize,
30     pub direction: Direction,
31     pub uri: Option<Url>,
32     pub ext_attr: Option<String>,
33 }
34 
35 impl fmt::Display for ExtMap {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result36     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37         let mut output = format!("{}", self.value);
38         if self.direction != Direction::Unspecified {
39             output += format!("/{}", self.direction).as_str();
40         }
41 
42         if let Some(uri) = &self.uri {
43             output += format!(" {uri}").as_str();
44         }
45 
46         if let Some(ext_attr) = &self.ext_attr {
47             output += format!(" {ext_attr}").as_str();
48         }
49 
50         write!(f, "{output}")
51     }
52 }
53 
54 impl ExtMap {
55     /// converts this object to an Attribute
convert(&self) -> Attribute56     pub fn convert(&self) -> Attribute {
57         Attribute {
58             key: "extmap".to_string(),
59             value: Some(self.to_string()),
60         }
61     }
62 
63     /// unmarshal creates an Extmap from a string
unmarshal<R: io::BufRead>(reader: &mut R) -> Result<Self>64     pub fn unmarshal<R: io::BufRead>(reader: &mut R) -> Result<Self> {
65         let mut line = String::new();
66         reader.read_line(&mut line)?;
67         let parts: Vec<&str> = line.trim().splitn(2, ':').collect();
68         if parts.len() != 2 {
69             return Err(Error::ParseExtMap(line));
70         }
71 
72         let fields: Vec<&str> = parts[1].split_whitespace().collect();
73         if fields.len() < 2 {
74             return Err(Error::ParseExtMap(line));
75         }
76 
77         let valdir: Vec<&str> = fields[0].split('/').collect();
78         let value = valdir[0].parse::<isize>()?;
79         if !(1..=246).contains(&value) {
80             return Err(Error::ParseExtMap(format!(
81                 "{} -- extmap key must be in the range 1-256",
82                 valdir[0]
83             )));
84         }
85 
86         let mut direction = Direction::Unspecified;
87         if valdir.len() == 2 {
88             direction = Direction::new(valdir[1]);
89             if direction == Direction::Unspecified {
90                 return Err(Error::ParseExtMap(format!(
91                     "unknown direction from {}",
92                     valdir[1]
93                 )));
94             }
95         }
96 
97         let uri = Some(Url::parse(fields[1])?);
98 
99         let ext_attr = if fields.len() == 3 {
100             Some(fields[2].to_owned())
101         } else {
102             None
103         };
104 
105         Ok(ExtMap {
106             value,
107             direction,
108             uri,
109             ext_attr,
110         })
111     }
112 
113     /// marshal creates a string from an ExtMap
marshal(&self) -> String114     pub fn marshal(&self) -> String {
115         "extmap:".to_string() + self.to_string().as_str()
116     }
117 }
118