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