xref: /webrtc/sdp/src/extmap/mod.rs (revision 04f0bd9e)
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 
25 /// ExtMap represents the activation of a single RTP header extension
26 #[derive(Debug, Clone, Default)]
27 pub struct ExtMap {
28     pub value: isize,
29     pub direction: Direction,
30     pub uri: Option<Url>,
31     pub ext_attr: Option<String>,
32 }
33 
34 impl fmt::Display for ExtMap {
35     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36         let mut output = format!("{}", self.value);
37         if self.direction != Direction::Unspecified {
38             output += format!("/{}", self.direction).as_str();
39         }
40 
41         if let Some(uri) = &self.uri {
42             output += format!(" {}", uri).as_str();
43         }
44 
45         if let Some(ext_attr) = &self.ext_attr {
46             output += format!(" {}", ext_attr).as_str();
47         }
48 
49         write!(f, "{}", output)
50     }
51 }
52 
53 impl ExtMap {
54     /// converts this object to an Attribute
55     pub fn convert(&self) -> Attribute {
56         Attribute {
57             key: "extmap".to_string(),
58             value: Some(self.to_string()),
59         }
60     }
61 
62     /// unmarshal creates an Extmap from a string
63     pub fn unmarshal<R: io::BufRead>(reader: &mut R) -> Result<Self> {
64         let mut line = String::new();
65         reader.read_line(&mut line)?;
66         let parts: Vec<&str> = line.trim().splitn(2, ':').collect();
67         if parts.len() != 2 {
68             return Err(Error::ParseExtMap(line));
69         }
70 
71         let fields: Vec<&str> = parts[1].split_whitespace().collect();
72         if fields.len() < 2 {
73             return Err(Error::ParseExtMap(line));
74         }
75 
76         let valdir: Vec<&str> = fields[0].split('/').collect();
77         let value = valdir[0].parse::<isize>()?;
78         if !(1..=246).contains(&value) {
79             return Err(Error::ParseExtMap(format!(
80                 "{} -- extmap key must be in the range 1-256",
81                 valdir[0]
82             )));
83         }
84 
85         let mut direction = Direction::Unspecified;
86         if valdir.len() == 2 {
87             direction = Direction::new(valdir[1]);
88             if direction == Direction::Unspecified {
89                 return Err(Error::ParseExtMap(format!(
90                     "unknown direction from {}",
91                     valdir[1]
92                 )));
93             }
94         }
95 
96         let uri = Some(Url::parse(fields[1])?);
97 
98         let ext_attr = if fields.len() == 3 {
99             Some(fields[2].to_owned())
100         } else {
101             None
102         };
103 
104         Ok(ExtMap {
105             value,
106             direction,
107             uri,
108             ext_attr,
109         })
110     }
111 
112     /// marshal creates a string from an ExtMap
113     pub fn marshal(&self) -> String {
114         "extmap:".to_string() + self.to_string().as_str()
115     }
116 }
117