rtc_sdp/extmap/
mod.rs

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