use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
use std::{fmt, io};
use url::Url;
use super::common_description::*;
use super::error::Error;
use super::media_description::*;
use super::util::*;
#[cfg(test)]
mod session_description_test;
pub const ATTR_KEY_CANDIDATE: &str = "candidate";
pub const ATTR_KEY_END_OF_CANDIDATES: &str = "end-of-candidates";
pub const ATTR_KEY_IDENTITY: &str = "identity";
pub const ATTR_KEY_GROUP: &str = "group";
pub const ATTR_KEY_SSRC: &str = "ssrc";
pub const ATTR_KEY_SSRCGROUP: &str = "ssrc-group";
pub const ATTR_KEY_MSID: &str = "msid";
pub const ATTR_KEY_MSID_SEMANTIC: &str = "msid-semantic";
pub const ATTR_KEY_CONNECTION_SETUP: &str = "setup";
pub const ATTR_KEY_MID: &str = "mid";
pub const ATTR_KEY_ICELITE: &str = "ice-lite";
pub const ATTR_KEY_RTCPMUX: &str = "rtcp-mux";
pub const ATTR_KEY_RTCPRSIZE: &str = "rtcp-rsize";
pub const ATTR_KEY_INACTIVE: &str = "inactive";
pub const ATTR_KEY_RECV_ONLY: &str = "recvonly";
pub const ATTR_KEY_SEND_ONLY: &str = "sendonly";
pub const ATTR_KEY_SEND_RECV: &str = "sendrecv";
pub const ATTR_KEY_EXT_MAP: &str = "extmap";
pub const SEMANTIC_TOKEN_LIP_SYNCHRONIZATION: &str = "LS";
pub const SEMANTIC_TOKEN_FLOW_IDENTIFICATION: &str = "FID";
pub const SEMANTIC_TOKEN_FORWARD_ERROR_CORRECTION: &str = "FEC";
pub const SEMANTIC_TOKEN_WEB_RTCMEDIA_STREAMS: &str = "WMS";
pub type Version = isize;
#[derive(Debug, Default)]
pub struct Origin {
pub username: String,
pub session_id: u64,
pub session_version: u64,
pub network_type: String,
pub address_type: String,
pub unicast_address: String,
}
impl fmt::Display for Origin {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} {} {} {} {} {}",
self.username,
self.session_id,
self.session_version,
self.network_type,
self.address_type,
self.unicast_address,
)
}
}
impl Origin {
pub fn new() -> Self {
Origin {
username: "".to_owned(),
session_id: 0,
session_version: 0,
network_type: "".to_owned(),
address_type: "".to_owned(),
unicast_address: "".to_owned(),
}
}
}
pub type SessionName = String;
pub type EmailAddress = String;
pub type PhoneNumber = String;
#[derive(Debug, Default)]
pub struct TimeZone {
pub adjustment_time: u64,
pub offset: i64,
}
impl fmt::Display for TimeZone {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.adjustment_time, self.offset)
}
}
#[derive(Debug, Default)]
pub struct TimeDescription {
pub timing: Timing,
pub repeat_times: Vec<RepeatTime>,
}
#[derive(Debug, Default)]
pub struct Timing {
pub start_time: u64,
pub stop_time: u64,
}
impl fmt::Display for Timing {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.start_time, self.stop_time)
}
}
#[derive(Debug, Default)]
pub struct RepeatTime {
pub interval: i64,
pub duration: i64,
pub offsets: Vec<i64>,
}
impl fmt::Display for RepeatTime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut fields = vec![format!("{}", self.interval), format!("{}", self.duration)];
for value in &self.offsets {
fields.push(format!("{}", value));
}
write!(f, "{}", fields.join(" "))
}
}
#[derive(Debug, Default)]
pub struct SessionDescription {
pub version: Version,
pub origin: Origin,
pub session_name: SessionName,
pub session_information: Option<Information>,
pub uri: Option<Url>,
pub email_address: Option<EmailAddress>,
pub phone_number: Option<PhoneNumber>,
pub connection_information: Option<ConnectionInformation>,
pub bandwidth: Vec<Bandwidth>,
pub time_descriptions: Vec<TimeDescription>,
pub time_zones: Vec<TimeZone>,
pub encryption_key: Option<EncryptionKey>,
pub attributes: Vec<Attribute>,
pub media_descriptions: Vec<MediaDescription>,
}
impl SessionDescription {
pub fn new_jsep_session_description(identity: bool) -> Self {
let d = SessionDescription {
version: 0,
origin: Origin {
username: "-".to_string(),
session_id: new_session_id(),
session_version: SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.subsec_nanos() as u64,
network_type: "IN".to_string(),
address_type: "IP4".to_string(),
unicast_address: "0.0.0.0".to_string(),
},
session_name: "-".to_string(),
session_information: None,
uri: None,
email_address: None,
phone_number: None,
connection_information: None,
bandwidth: vec![],
time_descriptions: vec![TimeDescription {
timing: Timing {
start_time: 0,
stop_time: 0,
},
repeat_times: vec![],
}],
time_zones: vec![],
encryption_key: None,
attributes: vec![],
media_descriptions: vec![],
};
if identity {
d.with_property_attribute(ATTR_KEY_IDENTITY.to_string())
} else {
d
}
}
pub fn with_property_attribute(mut self, key: String) -> Self {
self.attributes.push(Attribute::new(key, None));
self
}
pub fn with_value_attribute(mut self, key: String, value: String) -> Self {
self.attributes.push(Attribute::new(key, Some(value)));
self
}
pub fn with_fingerprint(self, algorithm: String, value: String) -> Self {
self.with_value_attribute("fingerprint".to_string(), algorithm + " " + value.as_str())
}
pub fn with_media(mut self, md: MediaDescription) -> Self {
self.media_descriptions.push(md);
self
}
fn build_codec_map(&self) -> HashMap<u8, Codec> {
let mut codecs: HashMap<u8, Codec> = HashMap::new();
for m in &self.media_descriptions {
for a in &m.attributes {
let attr = a.to_string();
if attr.starts_with("rtpmap:") {
if let Ok(codec) = parse_rtpmap(&attr) {
merge_codecs(codec, &mut codecs);
}
} else if attr.starts_with("fmtp:") {
if let Ok(codec) = parse_fmtp(&attr) {
merge_codecs(codec, &mut codecs);
}
} else if attr.starts_with("rtcp-fb:") {
if let Ok(codec) = parse_rtcp_fb(&attr) {
merge_codecs(codec, &mut codecs);
}
}
}
}
codecs
}
pub fn get_codec_for_payload_type(&self, payload_type: u8) -> Result<Codec, Error> {
let codecs = self.build_codec_map();
if let Some(codec) = codecs.get(&payload_type) {
Ok(codec.clone())
} else {
Err(Error::PayloadTypeNotFound)
}
}
pub fn get_payload_type_for_codec(&self, wanted: &Codec) -> Result<u8, Error> {
let codecs = self.build_codec_map();
for (payload_type, codec) in codecs.iter() {
if codecs_match(wanted, codec) {
return Ok(*payload_type);
}
}
Err(Error::CodecNotFound)
}
pub fn marshal(&self) -> String {
let mut result = String::new();
result += key_value_build("v=", Some(&self.version.to_string())).as_str();
result += key_value_build("o=", Some(&self.origin.to_string())).as_str();
result += key_value_build("s=", Some(&self.session_name)).as_str();
result += key_value_build("i=", self.session_information.as_ref()).as_str();
if let Some(uri) = &self.uri {
result += key_value_build("u=", Some(&format!("{}", uri))).as_str();
}
result += key_value_build("e=", self.email_address.as_ref()).as_str();
result += key_value_build("p=", self.phone_number.as_ref()).as_str();
if let Some(connection_information) = &self.connection_information {
result += key_value_build("c=", Some(&connection_information.to_string())).as_str();
}
for bandwidth in &self.bandwidth {
result += key_value_build("b=", Some(&bandwidth.to_string())).as_str();
}
for time_description in &self.time_descriptions {
result += key_value_build("t=", Some(&time_description.timing.to_string())).as_str();
for repeat_time in &time_description.repeat_times {
result += key_value_build("r=", Some(&repeat_time.to_string())).as_str();
}
}
if !self.time_zones.is_empty() {
let mut time_zones = vec![];
for time_zone in &self.time_zones {
time_zones.push(time_zone.to_string());
}
result += key_value_build("z=", Some(&time_zones.join(" "))).as_str();
}
result += key_value_build("k=", self.encryption_key.as_ref()).as_str();
for attribute in &self.attributes {
result += key_value_build("a=", Some(&attribute.to_string())).as_str();
}
for media_description in &self.media_descriptions {
result +=
key_value_build("m=", Some(&media_description.media_name.to_string())).as_str();
result += key_value_build("i=", media_description.media_title.as_ref()).as_str();
if let Some(connection_information) = &media_description.connection_information {
result += key_value_build("c=", Some(&connection_information.to_string())).as_str();
}
for bandwidth in &media_description.bandwidth {
result += key_value_build("b=", Some(&bandwidth.to_string())).as_str();
}
result += key_value_build("k=", media_description.encryption_key.as_ref()).as_str();
for attribute in &media_description.attributes {
result += key_value_build("a=", Some(&attribute.to_string())).as_str();
}
}
result
}
pub fn unmarshal<R: io::BufRead + io::Seek>(reader: &mut R) -> Result<Self, Error> {
let mut lexer = Lexer {
desc: SessionDescription {
version: 0,
origin: Origin::new(),
session_name: "".to_owned(),
session_information: None,
uri: None,
email_address: None,
phone_number: None,
connection_information: None,
bandwidth: vec![],
time_descriptions: vec![],
time_zones: vec![],
encryption_key: None,
attributes: vec![],
media_descriptions: vec![],
},
reader,
};
let mut state = Some(StateFn { f: s1 });
while let Some(s) = state {
state = (s.f)(&mut lexer)?;
}
Ok(lexer.desc)
}
}
fn s1<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, _) = read_type(lexer.reader)?;
if &key == "v=" {
return Ok(Some(StateFn {
f: unmarshal_protocol_version,
}));
}
Err(Error::SdpInvalidSyntax(key))
}
fn s2<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, _) = read_type(lexer.reader)?;
if &key == "o=" {
return Ok(Some(StateFn {
f: unmarshal_origin,
}));
}
Err(Error::SdpInvalidSyntax(key))
}
fn s3<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, _) = read_type(lexer.reader)?;
if &key == "s=" {
return Ok(Some(StateFn {
f: unmarshal_session_name,
}));
}
Err(Error::SdpInvalidSyntax(key))
}
fn s4<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, _) = read_type(lexer.reader)?;
match key.as_str() {
"i=" => Ok(Some(StateFn {
f: unmarshal_session_information,
})),
"u=" => Ok(Some(StateFn { f: unmarshal_uri })),
"e=" => Ok(Some(StateFn { f: unmarshal_email })),
"p=" => Ok(Some(StateFn { f: unmarshal_phone })),
"c=" => Ok(Some(StateFn {
f: unmarshal_session_connection_information,
})),
"b=" => Ok(Some(StateFn {
f: unmarshal_session_bandwidth,
})),
"t=" => Ok(Some(StateFn {
f: unmarshal_timing,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s5<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, _) = read_type(lexer.reader)?;
match key.as_str() {
"b=" => Ok(Some(StateFn {
f: unmarshal_session_bandwidth,
})),
"t=" => Ok(Some(StateFn {
f: unmarshal_timing,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s6<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, _) = read_type(lexer.reader)?;
match key.as_str() {
"p=" => Ok(Some(StateFn { f: unmarshal_phone })),
"c=" => Ok(Some(StateFn {
f: unmarshal_session_connection_information,
})),
"b=" => Ok(Some(StateFn {
f: unmarshal_session_bandwidth,
})),
"t=" => Ok(Some(StateFn {
f: unmarshal_timing,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s7<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, _) = read_type(lexer.reader)?;
match key.as_str() {
"u=" => Ok(Some(StateFn { f: unmarshal_uri })),
"e=" => Ok(Some(StateFn { f: unmarshal_email })),
"p=" => Ok(Some(StateFn { f: unmarshal_phone })),
"c=" => Ok(Some(StateFn {
f: unmarshal_session_connection_information,
})),
"b=" => Ok(Some(StateFn {
f: unmarshal_session_bandwidth,
})),
"t=" => Ok(Some(StateFn {
f: unmarshal_timing,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s8<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, _) = read_type(lexer.reader)?;
match key.as_str() {
"c=" => Ok(Some(StateFn {
f: unmarshal_session_connection_information,
})),
"b=" => Ok(Some(StateFn {
f: unmarshal_session_bandwidth,
})),
"t=" => Ok(Some(StateFn {
f: unmarshal_timing,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s9<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, num_bytes) = read_type(lexer.reader)?;
if key.is_empty() && num_bytes == 0 {
return Ok(None);
}
match key.as_str() {
"z=" => Ok(Some(StateFn {
f: unmarshal_time_zones,
})),
"k=" => Ok(Some(StateFn {
f: unmarshal_session_encryption_key,
})),
"a=" => Ok(Some(StateFn {
f: unmarshal_session_attribute,
})),
"r=" => Ok(Some(StateFn {
f: unmarshal_repeat_times,
})),
"t=" => Ok(Some(StateFn {
f: unmarshal_timing,
})),
"m=" => Ok(Some(StateFn {
f: unmarshal_media_description,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s10<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, _) = read_type(lexer.reader)?;
match key.as_str() {
"e=" => Ok(Some(StateFn { f: unmarshal_email })),
"p=" => Ok(Some(StateFn { f: unmarshal_phone })),
"c=" => Ok(Some(StateFn {
f: unmarshal_session_connection_information,
})),
"b=" => Ok(Some(StateFn {
f: unmarshal_session_bandwidth,
})),
"t=" => Ok(Some(StateFn {
f: unmarshal_timing,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s11<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, num_bytes) = read_type(lexer.reader)?;
if key.is_empty() && num_bytes == 0 {
return Ok(None);
}
match key.as_str() {
"a=" => Ok(Some(StateFn {
f: unmarshal_session_attribute,
})),
"m=" => Ok(Some(StateFn {
f: unmarshal_media_description,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s12<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, num_bytes) = read_type(lexer.reader)?;
if key.is_empty() && num_bytes == 0 {
return Ok(None);
}
match key.as_str() {
"a=" => Ok(Some(StateFn {
f: unmarshal_media_attribute,
})),
"k=" => Ok(Some(StateFn {
f: unmarshal_media_encryption_key,
})),
"b=" => Ok(Some(StateFn {
f: unmarshal_media_bandwidth,
})),
"c=" => Ok(Some(StateFn {
f: unmarshal_media_connection_information,
})),
"i=" => Ok(Some(StateFn {
f: unmarshal_media_title,
})),
"m=" => Ok(Some(StateFn {
f: unmarshal_media_description,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s13<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, num_bytes) = read_type(lexer.reader)?;
if key.is_empty() && num_bytes == 0 {
return Ok(None);
}
match key.as_str() {
"a=" => Ok(Some(StateFn {
f: unmarshal_session_attribute,
})),
"k=" => Ok(Some(StateFn {
f: unmarshal_session_encryption_key,
})),
"m=" => Ok(Some(StateFn {
f: unmarshal_media_description,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s14<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, num_bytes) = read_type(lexer.reader)?;
if key.is_empty() && num_bytes == 0 {
return Ok(None);
}
match key.as_str() {
"a=" => Ok(Some(StateFn {
f: unmarshal_media_attribute,
})),
"k=" => Ok(Some(StateFn {
f: unmarshal_media_encryption_key,
})),
"b=" => Ok(Some(StateFn {
f: unmarshal_media_bandwidth,
})),
"c=" => Ok(Some(StateFn {
f: unmarshal_media_connection_information,
})),
"i=" => Ok(Some(StateFn {
f: unmarshal_media_title,
})),
"m=" => Ok(Some(StateFn {
f: unmarshal_media_description,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s15<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, num_bytes) = read_type(lexer.reader)?;
if key.is_empty() && num_bytes == 0 {
return Ok(None);
}
match key.as_str() {
"a=" => Ok(Some(StateFn {
f: unmarshal_media_attribute,
})),
"k=" => Ok(Some(StateFn {
f: unmarshal_media_encryption_key,
})),
"b=" => Ok(Some(StateFn {
f: unmarshal_media_bandwidth,
})),
"c=" => Ok(Some(StateFn {
f: unmarshal_media_connection_information,
})),
"i=" => Ok(Some(StateFn {
f: unmarshal_media_title,
})),
"m=" => Ok(Some(StateFn {
f: unmarshal_media_description,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn s16<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (key, num_bytes) = read_type(lexer.reader)?;
if key.is_empty() && num_bytes == 0 {
return Ok(None);
}
match key.as_str() {
"a=" => Ok(Some(StateFn {
f: unmarshal_media_attribute,
})),
"k=" => Ok(Some(StateFn {
f: unmarshal_media_encryption_key,
})),
"c=" => Ok(Some(StateFn {
f: unmarshal_media_connection_information,
})),
"b=" => Ok(Some(StateFn {
f: unmarshal_media_bandwidth,
})),
"i=" => Ok(Some(StateFn {
f: unmarshal_media_title,
})),
"m=" => Ok(Some(StateFn {
f: unmarshal_media_description,
})),
_ => Err(Error::SdpInvalidSyntax(key)),
}
}
fn unmarshal_protocol_version<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
let version = value.parse::<u32>()?;
if version != 0 {
return Err(Error::SdpInvalidSyntax(value));
}
Ok(Some(StateFn { f: s2 }))
}
fn unmarshal_origin<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
let fields: Vec<&str> = value.split_whitespace().collect();
if fields.len() != 6 {
return Err(Error::SdpInvalidSyntax(format!("`o={}`", value)));
}
let session_id = fields[1].parse::<u64>()?;
let session_version = fields[2].parse::<u64>()?;
let i = index_of(fields[3], &["IN"]);
if i == -1 {
return Err(Error::SdpInvalidValue(fields[3].to_owned()));
}
let i = index_of(fields[4], &["IP4", "IP6"]);
if i == -1 {
return Err(Error::SdpInvalidValue(fields[4].to_owned()));
}
lexer.desc.origin = Origin {
username: fields[0].to_owned(),
session_id,
session_version,
network_type: fields[3].to_owned(),
address_type: fields[4].to_owned(),
unicast_address: fields[5].to_owned(),
};
Ok(Some(StateFn { f: s3 }))
}
fn unmarshal_session_name<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
lexer.desc.session_name = value;
Ok(Some(StateFn { f: s4 }))
}
fn unmarshal_session_information<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
lexer.desc.session_information = Some(value);
Ok(Some(StateFn { f: s7 }))
}
fn unmarshal_uri<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
lexer.desc.uri = Some(Url::parse(&value)?);
Ok(Some(StateFn { f: s10 }))
}
fn unmarshal_email<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
lexer.desc.email_address = Some(value);
Ok(Some(StateFn { f: s6 }))
}
fn unmarshal_phone<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
lexer.desc.phone_number = Some(value);
Ok(Some(StateFn { f: s8 }))
}
fn unmarshal_session_connection_information<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
lexer.desc.connection_information = unmarshal_connection_information(&value)?;
Ok(Some(StateFn { f: s5 }))
}
fn unmarshal_connection_information(value: &str) -> Result<Option<ConnectionInformation>, Error> {
let fields: Vec<&str> = value.split_whitespace().collect();
if fields.len() < 2 {
return Err(Error::SdpInvalidSyntax(format!("`c={}`", value)));
}
let i = index_of(fields[0], &["IN"]);
if i == -1 {
return Err(Error::SdpInvalidValue(fields[0].to_owned()));
}
let i = index_of(fields[1], &["IP4", "IP6"]);
if i == -1 {
return Err(Error::SdpInvalidValue(fields[1].to_owned()));
}
let address = if fields.len() > 2 {
Some(Address {
address: fields[2].to_owned(),
ttl: None,
range: None,
})
} else {
None
};
Ok(Some(ConnectionInformation {
network_type: fields[0].to_owned(),
address_type: fields[1].to_owned(),
address,
}))
}
fn unmarshal_session_bandwidth<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
lexer.desc.bandwidth.push(unmarshal_bandwidth(&value)?);
Ok(Some(StateFn { f: s5 }))
}
fn unmarshal_bandwidth(value: &str) -> Result<Bandwidth, Error> {
let mut parts: Vec<&str> = value.split(':').collect();
if parts.len() != 2 {
return Err(Error::SdpInvalidSyntax(format!("`b={}`", value)));
}
let experimental = parts[0].starts_with("X-");
if experimental {
parts[0] = parts[0].trim_start_matches("X-");
} else {
let i = index_of(parts[0], &["CT", "AS"]);
if i == -1 {
return Err(Error::SdpInvalidValue(parts[0].to_owned()));
}
}
let bandwidth = parts[1].parse::<u64>()?;
Ok(Bandwidth {
experimental,
bandwidth_type: parts[0].to_owned(),
bandwidth,
})
}
fn unmarshal_timing<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
let fields: Vec<&str> = value.split_whitespace().collect();
if fields.len() < 2 {
return Err(Error::SdpInvalidSyntax(format!("`t={}`", value)));
}
let start_time = fields[0].parse::<u64>()?;
let stop_time = fields[1].parse::<u64>()?;
lexer.desc.time_descriptions.push(TimeDescription {
timing: Timing {
start_time,
stop_time,
},
repeat_times: vec![],
});
Ok(Some(StateFn { f: s9 }))
}
fn unmarshal_repeat_times<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
let fields: Vec<&str> = value.split_whitespace().collect();
if fields.len() < 3 {
return Err(Error::SdpInvalidSyntax(format!("`r={}`", value)));
}
if let Some(latest_time_desc) = lexer.desc.time_descriptions.last_mut() {
let interval = parse_time_units(fields[0])?;
let duration = parse_time_units(fields[1])?;
let mut offsets = vec![];
for field in fields.iter().skip(2) {
let offset = parse_time_units(field)?;
offsets.push(offset);
}
latest_time_desc.repeat_times.push(RepeatTime {
interval,
duration,
offsets,
});
Ok(Some(StateFn { f: s9 }))
} else {
Err(Error::SdpEmptyTimeDescription)
}
}
fn unmarshal_time_zones<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
let fields: Vec<&str> = value.split_whitespace().collect();
if fields.len() % 2 != 0 {
return Err(Error::SdpInvalidSyntax(format!("`t={}`", value)));
}
for i in (0..fields.len()).step_by(2) {
let adjustment_time = fields[i].parse::<u64>()?;
let offset = parse_time_units(fields[i + 1])?;
lexer.desc.time_zones.push(TimeZone {
adjustment_time,
offset,
});
}
Ok(Some(StateFn { f: s13 }))
}
fn unmarshal_session_encryption_key<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
lexer.desc.encryption_key = Some(value);
Ok(Some(StateFn { f: s11 }))
}
fn unmarshal_session_attribute<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
let fields: Vec<&str> = value.splitn(2, ':').collect();
let attribute = if fields.len() == 2 {
Attribute {
key: fields[0].to_owned(),
value: Some(fields[1].to_owned()),
}
} else {
Attribute {
key: fields[0].to_owned(),
value: None,
}
};
lexer.desc.attributes.push(attribute);
Ok(Some(StateFn { f: s11 }))
}
fn unmarshal_media_description<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
let fields: Vec<&str> = value.split_whitespace().collect();
if fields.len() < 4 {
return Err(Error::SdpInvalidSyntax(format!("`m={}`", value)));
}
let i = index_of(
fields[0],
&["audio", "video", "text", "application", "message"],
);
if i == -1 {
return Err(Error::SdpInvalidValue(fields[0].to_owned()));
}
let parts: Vec<&str> = fields[1].split('/').collect();
let port_value = parts[0].parse::<u16>()? as isize;
let port_range = if parts.len() > 1 {
Some(parts[1].parse::<i32>()? as isize)
} else {
None
};
let mut protos = vec![];
for proto in fields[2].split('/').collect::<Vec<&str>>() {
let i = index_of(
proto,
&[
"UDP", "RTP", "AVP", "SAVP", "SAVPF", "TLS", "DTLS", "SCTP", "AVPF",
],
);
if i == -1 {
return Err(Error::SdpInvalidValue(fields[2].to_owned()));
}
protos.push(proto.to_owned());
}
let mut formats = vec![];
for field in fields.iter().skip(3) {
formats.push(field.to_string());
}
lexer.desc.media_descriptions.push(MediaDescription {
media_name: MediaName {
media: fields[0].to_owned(),
port: RangedPort {
value: port_value,
range: port_range,
},
protos,
formats,
},
media_title: None,
connection_information: None,
bandwidth: vec![],
encryption_key: None,
attributes: vec![],
});
Ok(Some(StateFn { f: s12 }))
}
fn unmarshal_media_title<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
if let Some(latest_media_desc) = lexer.desc.media_descriptions.last_mut() {
latest_media_desc.media_title = Some(value);
Ok(Some(StateFn { f: s16 }))
} else {
Err(Error::SdpEmptyTimeDescription)
}
}
fn unmarshal_media_connection_information<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
if let Some(latest_media_desc) = lexer.desc.media_descriptions.last_mut() {
latest_media_desc.connection_information = unmarshal_connection_information(&value)?;
Ok(Some(StateFn { f: s15 }))
} else {
Err(Error::SdpEmptyTimeDescription)
}
}
fn unmarshal_media_bandwidth<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
if let Some(latest_media_desc) = lexer.desc.media_descriptions.last_mut() {
let bandwidth = unmarshal_bandwidth(&value)?;
latest_media_desc.bandwidth.push(bandwidth);
Ok(Some(StateFn { f: s15 }))
} else {
Err(Error::SdpEmptyTimeDescription)
}
}
fn unmarshal_media_encryption_key<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
if let Some(latest_media_desc) = lexer.desc.media_descriptions.last_mut() {
latest_media_desc.encryption_key = Some(value);
Ok(Some(StateFn { f: s14 }))
} else {
Err(Error::SdpEmptyTimeDescription)
}
}
fn unmarshal_media_attribute<'a, R: io::BufRead + io::Seek>(
lexer: &mut Lexer<'a, R>,
) -> Result<Option<StateFn<'a, R>>, Error> {
let (value, _) = read_value(lexer.reader)?;
let fields: Vec<&str> = value.splitn(2, ':').collect();
let attribute = if fields.len() == 2 {
Attribute {
key: fields[0].to_owned(),
value: Some(fields[1].to_owned()),
}
} else {
Attribute {
key: fields[0].to_owned(),
value: None,
}
};
if let Some(latest_media_desc) = lexer.desc.media_descriptions.last_mut() {
latest_media_desc.attributes.push(attribute);
Ok(Some(StateFn { f: s14 }))
} else {
Err(Error::SdpEmptyTimeDescription)
}
}
fn parse_time_units(value: &str) -> Result<i64, Error> {
let val = value.as_bytes();
let len = val.len();
let num = match val[len - 1] {
b'd' => value.trim_end_matches('d').parse::<i64>()? * 86400,
b'h' => value.trim_end_matches('h').parse::<i64>()? * 3600,
b'm' => value.trim_end_matches('m').parse::<i64>()? * 60,
_ => value.trim_end_matches('m').parse::<i64>()?,
};
Ok(num)
}