1 use std::collections::HashMap; 2 use std::convert::TryFrom; 3 use std::time::{Duration, SystemTime, UNIX_EPOCH}; 4 use std::{fmt, io}; 5 use url::Url; 6 7 use crate::error::{Error, Result}; 8 use crate::lexer::*; 9 use crate::util::*; 10 11 use super::common::*; 12 use super::media::*; 13 14 /// Constants for SDP attributes used in JSEP 15 pub const ATTR_KEY_CANDIDATE: &str = "candidate"; 16 pub const ATTR_KEY_END_OF_CANDIDATES: &str = "end-of-candidates"; 17 pub const ATTR_KEY_IDENTITY: &str = "identity"; 18 pub const ATTR_KEY_GROUP: &str = "group"; 19 pub const ATTR_KEY_SSRC: &str = "ssrc"; 20 pub const ATTR_KEY_SSRCGROUP: &str = "ssrc-group"; 21 pub const ATTR_KEY_MSID: &str = "msid"; 22 pub const ATTR_KEY_MSID_SEMANTIC: &str = "msid-semantic"; 23 pub const ATTR_KEY_CONNECTION_SETUP: &str = "setup"; 24 pub const ATTR_KEY_MID: &str = "mid"; 25 pub const ATTR_KEY_ICELITE: &str = "ice-lite"; 26 pub const ATTR_KEY_RTCPMUX: &str = "rtcp-mux"; 27 pub const ATTR_KEY_RTCPRSIZE: &str = "rtcp-rsize"; 28 pub const ATTR_KEY_INACTIVE: &str = "inactive"; 29 pub const ATTR_KEY_RECV_ONLY: &str = "recvonly"; 30 pub const ATTR_KEY_SEND_ONLY: &str = "sendonly"; 31 pub const ATTR_KEY_SEND_RECV: &str = "sendrecv"; 32 pub const ATTR_KEY_EXT_MAP: &str = "extmap"; 33 34 /// Constants for semantic tokens used in JSEP 35 pub const SEMANTIC_TOKEN_LIP_SYNCHRONIZATION: &str = "LS"; 36 pub const SEMANTIC_TOKEN_FLOW_IDENTIFICATION: &str = "FID"; 37 pub const SEMANTIC_TOKEN_FORWARD_ERROR_CORRECTION: &str = "FEC"; 38 pub const SEMANTIC_TOKEN_WEBRTC_MEDIA_STREAMS: &str = "WMS"; 39 40 /// Version describes the value provided by the "v=" field which gives 41 /// the version of the Session Description Protocol. 42 pub type Version = isize; 43 44 /// Origin defines the structure for the "o=" field which provides the 45 /// originator of the session plus a session identifier and version number. 46 #[derive(Debug, Default, Clone)] 47 pub struct Origin { 48 pub username: String, 49 pub session_id: u64, 50 pub session_version: u64, 51 pub network_type: String, 52 pub address_type: String, 53 pub unicast_address: String, 54 } 55 56 impl fmt::Display for Origin { 57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 58 write!( 59 f, 60 "{} {} {} {} {} {}", 61 self.username, 62 self.session_id, 63 self.session_version, 64 self.network_type, 65 self.address_type, 66 self.unicast_address, 67 ) 68 } 69 } 70 71 impl Origin { 72 pub fn new() -> Self { 73 Origin { 74 username: "".to_owned(), 75 session_id: 0, 76 session_version: 0, 77 network_type: "".to_owned(), 78 address_type: "".to_owned(), 79 unicast_address: "".to_owned(), 80 } 81 } 82 } 83 84 /// SessionName describes a structured representations for the "s=" field 85 /// and is the textual session name. 86 pub type SessionName = String; 87 88 /// EmailAddress describes a structured representations for the "e=" line 89 /// which specifies email contact information for the person responsible for 90 /// the conference. 91 pub type EmailAddress = String; 92 93 /// PhoneNumber describes a structured representations for the "p=" line 94 /// specify phone contact information for the person responsible for the 95 /// conference. 96 pub type PhoneNumber = String; 97 98 /// TimeZone defines the structured object for "z=" line which describes 99 /// repeated sessions scheduling. 100 #[derive(Debug, Default, Clone)] 101 pub struct TimeZone { 102 pub adjustment_time: u64, 103 pub offset: i64, 104 } 105 106 impl fmt::Display for TimeZone { 107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 108 write!(f, "{} {}", self.adjustment_time, self.offset) 109 } 110 } 111 112 /// TimeDescription describes "t=", "r=" fields of the session description 113 /// which are used to specify the start and stop times for a session as well as 114 /// repeat intervals and durations for the scheduled session. 115 #[derive(Debug, Default, Clone)] 116 pub struct TimeDescription { 117 /// `t=<start-time> <stop-time>` 118 /// 119 /// <https://tools.ietf.org/html/rfc4566#section-5.9> 120 pub timing: Timing, 121 122 /// `r=<repeat interval> <active duration> <offsets from start-time>` 123 /// 124 /// <https://tools.ietf.org/html/rfc4566#section-5.10> 125 pub repeat_times: Vec<RepeatTime>, 126 } 127 128 /// Timing defines the "t=" field's structured representation for the start and 129 /// stop times. 130 #[derive(Debug, Default, Clone)] 131 pub struct Timing { 132 pub start_time: u64, 133 pub stop_time: u64, 134 } 135 136 impl fmt::Display for Timing { 137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 138 write!(f, "{} {}", self.start_time, self.stop_time) 139 } 140 } 141 142 /// RepeatTime describes the "r=" fields of the session description which 143 /// represents the intervals and durations for repeated scheduled sessions. 144 #[derive(Debug, Default, Clone)] 145 pub struct RepeatTime { 146 pub interval: i64, 147 pub duration: i64, 148 pub offsets: Vec<i64>, 149 } 150 151 impl fmt::Display for RepeatTime { 152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 153 let mut fields = vec![format!("{}", self.interval), format!("{}", self.duration)]; 154 for value in &self.offsets { 155 fields.push(format!("{}", value)); 156 } 157 write!(f, "{}", fields.join(" ")) 158 } 159 } 160 161 /// SessionDescription is a a well-defined format for conveying sufficient 162 /// information to discover and participate in a multimedia session. 163 #[derive(Debug, Default, Clone)] 164 pub struct SessionDescription { 165 /// `v=0` 166 /// 167 /// <https://tools.ietf.org/html/rfc4566#section-5.1> 168 pub version: Version, 169 170 /// `o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>` 171 /// 172 /// <https://tools.ietf.org/html/rfc4566#section-5.2> 173 pub origin: Origin, 174 175 /// `s=<session name>` 176 /// 177 /// <https://tools.ietf.org/html/rfc4566#section-5.3> 178 pub session_name: SessionName, 179 180 /// `i=<session description>` 181 /// 182 /// <https://tools.ietf.org/html/rfc4566#section-5.4> 183 pub session_information: Option<Information>, 184 185 /// `u=<uri>` 186 /// 187 /// <https://tools.ietf.org/html/rfc4566#section-5.5> 188 pub uri: Option<Url>, 189 190 /// `e=<email-address>` 191 /// 192 /// <https://tools.ietf.org/html/rfc4566#section-5.6> 193 pub email_address: Option<EmailAddress>, 194 195 /// `p=<phone-number>` 196 /// 197 /// <https://tools.ietf.org/html/rfc4566#section-5.6> 198 pub phone_number: Option<PhoneNumber>, 199 200 /// `c=<nettype> <addrtype> <connection-address>` 201 /// 202 /// <https://tools.ietf.org/html/rfc4566#section-5.7> 203 pub connection_information: Option<ConnectionInformation>, 204 205 /// `b=<bwtype>:<bandwidth>` 206 /// 207 /// <https://tools.ietf.org/html/rfc4566#section-5.8> 208 pub bandwidth: Vec<Bandwidth>, 209 210 /// <https://tools.ietf.org/html/rfc4566#section-5.9> 211 /// <https://tools.ietf.org/html/rfc4566#section-5.10> 212 pub time_descriptions: Vec<TimeDescription>, 213 214 /// `z=<adjustment time> <offset> <adjustment time> <offset> ...` 215 /// 216 /// <https://tools.ietf.org/html/rfc4566#section-5.11> 217 pub time_zones: Vec<TimeZone>, 218 219 /// `k=<method>` 220 /// 221 /// `k=<method>:<encryption key>` 222 /// 223 /// <https://tools.ietf.org/html/rfc4566#section-5.12> 224 pub encryption_key: Option<EncryptionKey>, 225 226 /// `a=<attribute>` 227 /// 228 /// `a=<attribute>:<value>` 229 /// 230 /// <https://tools.ietf.org/html/rfc4566#section-5.13> 231 pub attributes: Vec<Attribute>, 232 233 /// <https://tools.ietf.org/html/rfc4566#section-5.14> 234 pub media_descriptions: Vec<MediaDescription>, 235 } 236 237 /// Reset cleans the SessionDescription, and sets all fields back to their default values 238 impl SessionDescription { 239 /// API to match draft-ietf-rtcweb-jsep 240 /// Move to webrtc or its own package? 241 242 /// NewJSEPSessionDescription creates a new SessionDescription with 243 /// some settings that are required by the JSEP spec. 244 pub fn new_jsep_session_description(identity: bool) -> Self { 245 let d = SessionDescription { 246 version: 0, 247 origin: Origin { 248 username: "-".to_string(), 249 session_id: new_session_id(), 250 session_version: SystemTime::now() 251 .duration_since(UNIX_EPOCH) 252 .unwrap_or_else(|_| Duration::from_secs(0)) 253 .subsec_nanos() as u64, 254 network_type: "IN".to_string(), 255 address_type: "IP4".to_string(), 256 unicast_address: "0.0.0.0".to_string(), 257 }, 258 session_name: "-".to_string(), 259 session_information: None, 260 uri: None, 261 email_address: None, 262 phone_number: None, 263 connection_information: None, 264 bandwidth: vec![], 265 time_descriptions: vec![TimeDescription { 266 timing: Timing { 267 start_time: 0, 268 stop_time: 0, 269 }, 270 repeat_times: vec![], 271 }], 272 time_zones: vec![], 273 encryption_key: None, 274 attributes: vec![], // TODO: implement trickle ICE 275 media_descriptions: vec![], 276 }; 277 278 if identity { 279 d.with_property_attribute(ATTR_KEY_IDENTITY.to_string()) 280 } else { 281 d 282 } 283 } 284 285 /// WithPropertyAttribute adds a property attribute 'a=key' to the session description 286 pub fn with_property_attribute(mut self, key: String) -> Self { 287 self.attributes.push(Attribute::new(key, None)); 288 self 289 } 290 291 /// WithValueAttribute adds a value attribute 'a=key:value' to the session description 292 pub fn with_value_attribute(mut self, key: String, value: String) -> Self { 293 self.attributes.push(Attribute::new(key, Some(value))); 294 self 295 } 296 297 /// WithFingerprint adds a fingerprint to the session description 298 pub fn with_fingerprint(self, algorithm: String, value: String) -> Self { 299 self.with_value_attribute("fingerprint".to_string(), algorithm + " " + value.as_str()) 300 } 301 302 /// WithMedia adds a media description to the session description 303 pub fn with_media(mut self, md: MediaDescription) -> Self { 304 self.media_descriptions.push(md); 305 self 306 } 307 308 fn build_codec_map(&self) -> HashMap<u8, Codec> { 309 let mut codecs: HashMap<u8, Codec> = HashMap::new(); 310 311 for m in &self.media_descriptions { 312 for a in &m.attributes { 313 let attr = a.to_string(); 314 if attr.starts_with("rtpmap:") { 315 if let Ok(codec) = parse_rtpmap(&attr) { 316 merge_codecs(codec, &mut codecs); 317 } 318 } else if attr.starts_with("fmtp:") { 319 if let Ok(codec) = parse_fmtp(&attr) { 320 merge_codecs(codec, &mut codecs); 321 } 322 } else if attr.starts_with("rtcp-fb:") { 323 if let Ok(codec) = parse_rtcp_fb(&attr) { 324 merge_codecs(codec, &mut codecs); 325 } 326 } 327 } 328 } 329 330 codecs 331 } 332 333 /// get_codec_for_payload_type scans the SessionDescription for the given payload type and returns the codec 334 pub fn get_codec_for_payload_type(&self, payload_type: u8) -> Result<Codec> { 335 let codecs = self.build_codec_map(); 336 337 if let Some(codec) = codecs.get(&payload_type) { 338 Ok(codec.clone()) 339 } else { 340 Err(Error::PayloadTypeNotFound) 341 } 342 } 343 344 /// get_payload_type_for_codec scans the SessionDescription for a codec that matches the provided codec 345 /// as closely as possible and returns its payload type 346 pub fn get_payload_type_for_codec(&self, wanted: &Codec) -> Result<u8> { 347 let codecs = self.build_codec_map(); 348 349 for (payload_type, codec) in codecs.iter() { 350 if codecs_match(wanted, codec) { 351 return Ok(*payload_type); 352 } 353 } 354 355 Err(Error::CodecNotFound) 356 } 357 358 /// Attribute returns the value of an attribute and if it exists 359 pub fn attribute(&self, key: &str) -> Option<&String> { 360 for a in &self.attributes { 361 if a.key == key { 362 return a.value.as_ref(); 363 } 364 } 365 None 366 } 367 368 /// Marshal takes a SDP struct to text 369 /// 370 /// <https://tools.ietf.org/html/rfc4566#section-5> 371 /// 372 /// Session description 373 /// v= (protocol version) 374 /// o= (originator and session identifier) 375 /// s= (session name) 376 /// i=* (session information) 377 /// u=* (URI of description) 378 /// e=* (email address) 379 /// p=* (phone number) 380 /// c=* (connection information -- not required if included in 381 /// all media) 382 /// b=* (zero or more bandwidth information lines) 383 /// One or more time descriptions ("t=" and "r=" lines; see below) 384 /// z=* (time zone adjustments) 385 /// k=* (encryption key) 386 /// a=* (zero or more session attribute lines) 387 /// Zero or more media descriptions 388 /// 389 /// Time description 390 /// t= (time the session is active) 391 /// r=* (zero or more repeat times) 392 /// 393 /// Media description, if present 394 /// m= (media name and transport address) 395 /// i=* (media title) 396 /// c=* (connection information -- optional if included at 397 /// session level) 398 /// b=* (zero or more bandwidth information lines) 399 /// k=* (encryption key) 400 /// a=* (zero or more media attribute lines) 401 pub fn marshal(&self) -> String { 402 let mut result = String::new(); 403 404 result += key_value_build("v=", Some(&self.version.to_string())).as_str(); 405 result += key_value_build("o=", Some(&self.origin.to_string())).as_str(); 406 result += key_value_build("s=", Some(&self.session_name)).as_str(); 407 408 result += key_value_build("i=", self.session_information.as_ref()).as_str(); 409 410 if let Some(uri) = &self.uri { 411 result += key_value_build("u=", Some(&format!("{}", uri))).as_str(); 412 } 413 result += key_value_build("e=", self.email_address.as_ref()).as_str(); 414 result += key_value_build("p=", self.phone_number.as_ref()).as_str(); 415 if let Some(connection_information) = &self.connection_information { 416 result += key_value_build("c=", Some(&connection_information.to_string())).as_str(); 417 } 418 419 for bandwidth in &self.bandwidth { 420 result += key_value_build("b=", Some(&bandwidth.to_string())).as_str(); 421 } 422 for time_description in &self.time_descriptions { 423 result += key_value_build("t=", Some(&time_description.timing.to_string())).as_str(); 424 for repeat_time in &time_description.repeat_times { 425 result += key_value_build("r=", Some(&repeat_time.to_string())).as_str(); 426 } 427 } 428 if !self.time_zones.is_empty() { 429 let mut time_zones = vec![]; 430 for time_zone in &self.time_zones { 431 time_zones.push(time_zone.to_string()); 432 } 433 result += key_value_build("z=", Some(&time_zones.join(" "))).as_str(); 434 } 435 result += key_value_build("k=", self.encryption_key.as_ref()).as_str(); 436 for attribute in &self.attributes { 437 result += key_value_build("a=", Some(&attribute.to_string())).as_str(); 438 } 439 440 for media_description in &self.media_descriptions { 441 result += 442 key_value_build("m=", Some(&media_description.media_name.to_string())).as_str(); 443 result += key_value_build("i=", media_description.media_title.as_ref()).as_str(); 444 if let Some(connection_information) = &media_description.connection_information { 445 result += key_value_build("c=", Some(&connection_information.to_string())).as_str(); 446 } 447 for bandwidth in &media_description.bandwidth { 448 result += key_value_build("b=", Some(&bandwidth.to_string())).as_str(); 449 } 450 result += key_value_build("k=", media_description.encryption_key.as_ref()).as_str(); 451 for attribute in &media_description.attributes { 452 result += key_value_build("a=", Some(&attribute.to_string())).as_str(); 453 } 454 } 455 456 result 457 } 458 459 /// Unmarshal is the primary function that deserializes the session description 460 /// message and stores it inside of a structured SessionDescription object. 461 /// 462 /// The States Transition Table describes the computation flow between functions 463 /// (namely s1, s2, s3, ...) for a parsing procedure that complies with the 464 /// specifications laid out by the rfc4566#section-5 as well as by JavaScript 465 /// Session Establishment Protocol draft. Links: 466 /// <https://tools.ietf.org/html/rfc4566#section-5> 467 /// <https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24> 468 /// 469 /// <https://tools.ietf.org/html/rfc4566#section-5> 470 /// 471 /// Session description 472 /// v= (protocol version) 473 /// o= (originator and session identifier) 474 /// s= (session name) 475 /// i=* (session information) 476 /// u=* (URI of description) 477 /// e=* (email address) 478 /// p=* (phone number) 479 /// c=* (connection information -- not required if included in 480 /// all media) 481 /// b=* (zero or more bandwidth information lines) 482 /// One or more time descriptions ("t=" and "r=" lines; see below) 483 /// z=* (time zone adjustments) 484 /// k=* (encryption key) 485 /// a=* (zero or more session attribute lines) 486 /// Zero or more media descriptions 487 /// 488 /// Time description 489 /// t= (time the session is active) 490 /// r=* (zero or more repeat times) 491 /// 492 /// Media description, if present 493 /// m= (media name and transport address) 494 /// i=* (media title) 495 /// c=* (connection information -- optional if included at 496 /// session level) 497 /// b=* (zero or more bandwidth information lines) 498 /// k=* (encryption key) 499 /// a=* (zero or more media attribute lines) 500 /// 501 /// In order to generate the following state table and draw subsequent 502 /// deterministic finite-state automota ("DFA") the following regex was used to 503 /// derive the DFA: 504 /// vosi?u?e?p?c?b*(tr*)+z?k?a*(mi?c?b*k?a*)* 505 /// possible place and state to exit: 506 /// ** * * * ** * * * * 507 /// 99 1 1 1 11 1 1 1 1 508 /// 3 1 1 26 5 5 4 4 509 /// 510 /// Please pay close attention to the `k`, and `a` parsing states. In the table 511 /// below in order to distinguish between the states belonging to the media 512 /// description as opposed to the session description, the states are marked 513 /// with an asterisk ("a*", "k*"). 514 /// 515 /// ```ignore 516 /// +--------+----+-------+----+-----+----+-----+---+----+----+---+---+-----+---+---+----+---+----+ 517 /// | STATES | a* | a*,k* | a | a,k | b | b,c | e | i | m | o | p | r,t | s | t | u | v | z | 518 /// +--------+----+-------+----+-----+----+-----+---+----+----+---+---+-----+---+---+----+---+----+ 519 /// | s1 | | | | | | | | | | | | | | | | 2 | | 520 /// | s2 | | | | | | | | | | 3 | | | | | | | | 521 /// | s3 | | | | | | | | | | | | | 4 | | | | | 522 /// | s4 | | | | | | 5 | 6 | 7 | | | 8 | | | 9 | 10 | | | 523 /// | s5 | | | | | 5 | | | | | | | | | 9 | | | | 524 /// | s6 | | | | | | 5 | | | | | 8 | | | 9 | | | | 525 /// | s7 | | | | | | 5 | 6 | | | | 8 | | | 9 | 10 | | | 526 /// | s8 | | | | | | 5 | | | | | | | | 9 | | | | 527 /// | s9 | | | | 11 | | | | | 12 | | | 9 | | | | | 13 | 528 /// | s10 | | | | | | 5 | 6 | | | | 8 | | | 9 | | | | 529 /// | s11 | | | 11 | | | | | | 12 | | | | | | | | | 530 /// | s12 | | 14 | | | | 15 | | 16 | 12 | | | | | | | | | 531 /// | s13 | | | | 11 | | | | | 12 | | | | | | | | | 532 /// | s14 | 14 | | | | | | | | 12 | | | | | | | | | 533 /// | s15 | | 14 | | | 15 | | | | 12 | | | | | | | | | 534 /// | s16 | | 14 | | | | 15 | | | 12 | | | | | | | | | 535 /// +--------+----+-------+----+-----+----+-----+---+----+----+---+---+-----+---+---+----+---+----+ 536 /// ``` 537 pub fn unmarshal<R: io::BufRead + io::Seek>(reader: &mut R) -> Result<Self> { 538 let mut lexer = Lexer { 539 desc: SessionDescription { 540 version: 0, 541 origin: Origin::new(), 542 session_name: "".to_owned(), 543 session_information: None, 544 uri: None, 545 email_address: None, 546 phone_number: None, 547 connection_information: None, 548 bandwidth: vec![], 549 time_descriptions: vec![], 550 time_zones: vec![], 551 encryption_key: None, 552 attributes: vec![], 553 media_descriptions: vec![], 554 }, 555 reader, 556 }; 557 558 let mut state = Some(StateFn { f: s1 }); 559 while let Some(s) = state { 560 state = (s.f)(&mut lexer)?; 561 } 562 563 Ok(lexer.desc) 564 } 565 } 566 567 impl From<SessionDescription> for String { 568 fn from(sdp: SessionDescription) -> String { 569 sdp.marshal() 570 } 571 } 572 573 impl TryFrom<String> for SessionDescription { 574 type Error = Error; 575 fn try_from(sdp_string: String) -> Result<Self> { 576 let mut reader = io::Cursor::new(sdp_string.as_bytes()); 577 let session_description = SessionDescription::unmarshal(&mut reader)?; 578 Ok(session_description) 579 } 580 } 581 582 fn s1<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 583 let (key, _) = read_type(lexer.reader)?; 584 if &key == b"v=" { 585 return Ok(Some(StateFn { 586 f: unmarshal_protocol_version, 587 })); 588 } 589 590 Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)) 591 } 592 593 fn s2<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 594 let (key, _) = read_type(lexer.reader)?; 595 if &key == b"o=" { 596 return Ok(Some(StateFn { 597 f: unmarshal_origin, 598 })); 599 } 600 601 Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)) 602 } 603 604 fn s3<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 605 let (key, _) = read_type(lexer.reader)?; 606 if &key == b"s=" { 607 return Ok(Some(StateFn { 608 f: unmarshal_session_name, 609 })); 610 } 611 612 Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)) 613 } 614 615 fn s4<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 616 let (key, _) = read_type(lexer.reader)?; 617 match key.as_slice() { 618 b"i=" => Ok(Some(StateFn { 619 f: unmarshal_session_information, 620 })), 621 b"u=" => Ok(Some(StateFn { f: unmarshal_uri })), 622 b"e=" => Ok(Some(StateFn { f: unmarshal_email })), 623 b"p=" => Ok(Some(StateFn { f: unmarshal_phone })), 624 b"c=" => Ok(Some(StateFn { 625 f: unmarshal_session_connection_information, 626 })), 627 b"b=" => Ok(Some(StateFn { 628 f: unmarshal_session_bandwidth, 629 })), 630 b"t=" => Ok(Some(StateFn { 631 f: unmarshal_timing, 632 })), 633 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 634 } 635 } 636 637 fn s5<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 638 let (key, _) = read_type(lexer.reader)?; 639 match key.as_slice() { 640 b"b=" => Ok(Some(StateFn { 641 f: unmarshal_session_bandwidth, 642 })), 643 b"t=" => Ok(Some(StateFn { 644 f: unmarshal_timing, 645 })), 646 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 647 } 648 } 649 650 fn s6<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 651 let (key, _) = read_type(lexer.reader)?; 652 match key.as_slice() { 653 b"p=" => Ok(Some(StateFn { f: unmarshal_phone })), 654 b"c=" => Ok(Some(StateFn { 655 f: unmarshal_session_connection_information, 656 })), 657 b"b=" => Ok(Some(StateFn { 658 f: unmarshal_session_bandwidth, 659 })), 660 b"t=" => Ok(Some(StateFn { 661 f: unmarshal_timing, 662 })), 663 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 664 } 665 } 666 667 fn s7<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 668 let (key, _) = read_type(lexer.reader)?; 669 match key.as_slice() { 670 b"u=" => Ok(Some(StateFn { f: unmarshal_uri })), 671 b"e=" => Ok(Some(StateFn { f: unmarshal_email })), 672 b"p=" => Ok(Some(StateFn { f: unmarshal_phone })), 673 b"c=" => Ok(Some(StateFn { 674 f: unmarshal_session_connection_information, 675 })), 676 b"b=" => Ok(Some(StateFn { 677 f: unmarshal_session_bandwidth, 678 })), 679 b"t=" => Ok(Some(StateFn { 680 f: unmarshal_timing, 681 })), 682 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 683 } 684 } 685 686 fn s8<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 687 let (key, _) = read_type(lexer.reader)?; 688 match key.as_slice() { 689 b"c=" => Ok(Some(StateFn { 690 f: unmarshal_session_connection_information, 691 })), 692 b"b=" => Ok(Some(StateFn { 693 f: unmarshal_session_bandwidth, 694 })), 695 b"t=" => Ok(Some(StateFn { 696 f: unmarshal_timing, 697 })), 698 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 699 } 700 } 701 702 fn s9<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 703 let (key, num_bytes) = read_type(lexer.reader)?; 704 if key.is_empty() && num_bytes == 0 { 705 return Ok(None); 706 } 707 708 match key.as_slice() { 709 b"z=" => Ok(Some(StateFn { 710 f: unmarshal_time_zones, 711 })), 712 b"k=" => Ok(Some(StateFn { 713 f: unmarshal_session_encryption_key, 714 })), 715 b"a=" => Ok(Some(StateFn { 716 f: unmarshal_session_attribute, 717 })), 718 b"r=" => Ok(Some(StateFn { 719 f: unmarshal_repeat_times, 720 })), 721 b"t=" => Ok(Some(StateFn { 722 f: unmarshal_timing, 723 })), 724 b"m=" => Ok(Some(StateFn { 725 f: unmarshal_media_description, 726 })), 727 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 728 } 729 } 730 731 fn s10<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 732 let (key, _) = read_type(lexer.reader)?; 733 match key.as_slice() { 734 b"e=" => Ok(Some(StateFn { f: unmarshal_email })), 735 b"p=" => Ok(Some(StateFn { f: unmarshal_phone })), 736 b"c=" => Ok(Some(StateFn { 737 f: unmarshal_session_connection_information, 738 })), 739 b"b=" => Ok(Some(StateFn { 740 f: unmarshal_session_bandwidth, 741 })), 742 b"t=" => Ok(Some(StateFn { 743 f: unmarshal_timing, 744 })), 745 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 746 } 747 } 748 749 fn s11<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 750 let (key, num_bytes) = read_type(lexer.reader)?; 751 if key.is_empty() && num_bytes == 0 { 752 return Ok(None); 753 } 754 755 match key.as_slice() { 756 b"a=" => Ok(Some(StateFn { 757 f: unmarshal_session_attribute, 758 })), 759 b"m=" => Ok(Some(StateFn { 760 f: unmarshal_media_description, 761 })), 762 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 763 } 764 } 765 766 fn s12<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 767 let (key, num_bytes) = read_type(lexer.reader)?; 768 if key.is_empty() && num_bytes == 0 { 769 return Ok(None); 770 } 771 772 match key.as_slice() { 773 b"a=" => Ok(Some(StateFn { 774 f: unmarshal_media_attribute, 775 })), 776 b"k=" => Ok(Some(StateFn { 777 f: unmarshal_media_encryption_key, 778 })), 779 b"b=" => Ok(Some(StateFn { 780 f: unmarshal_media_bandwidth, 781 })), 782 b"c=" => Ok(Some(StateFn { 783 f: unmarshal_media_connection_information, 784 })), 785 b"i=" => Ok(Some(StateFn { 786 f: unmarshal_media_title, 787 })), 788 b"m=" => Ok(Some(StateFn { 789 f: unmarshal_media_description, 790 })), 791 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 792 } 793 } 794 795 fn s13<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 796 let (key, num_bytes) = read_type(lexer.reader)?; 797 if key.is_empty() && num_bytes == 0 { 798 return Ok(None); 799 } 800 801 match key.as_slice() { 802 b"a=" => Ok(Some(StateFn { 803 f: unmarshal_session_attribute, 804 })), 805 b"k=" => Ok(Some(StateFn { 806 f: unmarshal_session_encryption_key, 807 })), 808 b"m=" => Ok(Some(StateFn { 809 f: unmarshal_media_description, 810 })), 811 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 812 } 813 } 814 815 fn s14<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 816 let (key, num_bytes) = read_type(lexer.reader)?; 817 if key.is_empty() && num_bytes == 0 { 818 return Ok(None); 819 } 820 821 match key.as_slice() { 822 b"a=" => Ok(Some(StateFn { 823 f: unmarshal_media_attribute, 824 })), 825 // Non-spec ordering 826 b"k=" => Ok(Some(StateFn { 827 f: unmarshal_media_encryption_key, 828 })), 829 // Non-spec ordering 830 b"b=" => Ok(Some(StateFn { 831 f: unmarshal_media_bandwidth, 832 })), 833 // Non-spec ordering 834 b"c=" => Ok(Some(StateFn { 835 f: unmarshal_media_connection_information, 836 })), 837 // Non-spec ordering 838 b"i=" => Ok(Some(StateFn { 839 f: unmarshal_media_title, 840 })), 841 b"m=" => Ok(Some(StateFn { 842 f: unmarshal_media_description, 843 })), 844 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 845 } 846 } 847 848 fn s15<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 849 let (key, num_bytes) = read_type(lexer.reader)?; 850 if key.is_empty() && num_bytes == 0 { 851 return Ok(None); 852 } 853 854 match key.as_slice() { 855 b"a=" => Ok(Some(StateFn { 856 f: unmarshal_media_attribute, 857 })), 858 b"k=" => Ok(Some(StateFn { 859 f: unmarshal_media_encryption_key, 860 })), 861 b"b=" => Ok(Some(StateFn { 862 f: unmarshal_media_bandwidth, 863 })), 864 b"c=" => Ok(Some(StateFn { 865 f: unmarshal_media_connection_information, 866 })), 867 // Non-spec ordering 868 b"i=" => Ok(Some(StateFn { 869 f: unmarshal_media_title, 870 })), 871 b"m=" => Ok(Some(StateFn { 872 f: unmarshal_media_description, 873 })), 874 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 875 } 876 } 877 878 fn s16<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>> { 879 let (key, num_bytes) = read_type(lexer.reader)?; 880 if key.is_empty() && num_bytes == 0 { 881 return Ok(None); 882 } 883 884 match key.as_slice() { 885 b"a=" => Ok(Some(StateFn { 886 f: unmarshal_media_attribute, 887 })), 888 b"k=" => Ok(Some(StateFn { 889 f: unmarshal_media_encryption_key, 890 })), 891 b"c=" => Ok(Some(StateFn { 892 f: unmarshal_media_connection_information, 893 })), 894 b"b=" => Ok(Some(StateFn { 895 f: unmarshal_media_bandwidth, 896 })), 897 // Non-spec ordering 898 b"i=" => Ok(Some(StateFn { 899 f: unmarshal_media_title, 900 })), 901 b"m=" => Ok(Some(StateFn { 902 f: unmarshal_media_description, 903 })), 904 _ => Err(Error::SdpInvalidSyntax(String::from_utf8(key)?)), 905 } 906 } 907 908 fn unmarshal_protocol_version<'a, R: io::BufRead + io::Seek>( 909 lexer: &mut Lexer<'a, R>, 910 ) -> Result<Option<StateFn<'a, R>>> { 911 let (value, _) = read_value(lexer.reader)?; 912 913 let version = value.parse::<u32>()?; 914 915 // As off the latest draft of the rfc this value is required to be 0. 916 // https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-24#section-5.8.1 917 if version != 0 { 918 return Err(Error::SdpInvalidSyntax(value)); 919 } 920 921 Ok(Some(StateFn { f: s2 })) 922 } 923 924 fn unmarshal_origin<'a, R: io::BufRead + io::Seek>( 925 lexer: &mut Lexer<'a, R>, 926 ) -> Result<Option<StateFn<'a, R>>> { 927 let (value, _) = read_value(lexer.reader)?; 928 929 let fields: Vec<&str> = value.split_whitespace().collect(); 930 if fields.len() != 6 { 931 return Err(Error::SdpInvalidSyntax(format!("`o={}`", value))); 932 } 933 934 let session_id = fields[1].parse::<u64>()?; 935 let session_version = fields[2].parse::<u64>()?; 936 937 // Set according to currently registered with IANA 938 // https://tools.ietf.org/html/rfc4566#section-8.2.6 939 let i = index_of(fields[3], &["IN"]); 940 if i == -1 { 941 return Err(Error::SdpInvalidValue(fields[3].to_owned())); 942 } 943 944 // Set according to currently registered with IANA 945 // https://tools.ietf.org/html/rfc4566#section-8.2.7 946 let i = index_of(fields[4], &["IP4", "IP6"]); 947 if i == -1 { 948 return Err(Error::SdpInvalidValue(fields[4].to_owned())); 949 } 950 951 // TODO validated UnicastAddress 952 953 lexer.desc.origin = Origin { 954 username: fields[0].to_owned(), 955 session_id, 956 session_version, 957 network_type: fields[3].to_owned(), 958 address_type: fields[4].to_owned(), 959 unicast_address: fields[5].to_owned(), 960 }; 961 962 Ok(Some(StateFn { f: s3 })) 963 } 964 965 fn unmarshal_session_name<'a, R: io::BufRead + io::Seek>( 966 lexer: &mut Lexer<'a, R>, 967 ) -> Result<Option<StateFn<'a, R>>> { 968 let (value, _) = read_value(lexer.reader)?; 969 lexer.desc.session_name = value; 970 Ok(Some(StateFn { f: s4 })) 971 } 972 973 fn unmarshal_session_information<'a, R: io::BufRead + io::Seek>( 974 lexer: &mut Lexer<'a, R>, 975 ) -> Result<Option<StateFn<'a, R>>> { 976 let (value, _) = read_value(lexer.reader)?; 977 lexer.desc.session_information = Some(value); 978 Ok(Some(StateFn { f: s7 })) 979 } 980 981 fn unmarshal_uri<'a, R: io::BufRead + io::Seek>( 982 lexer: &mut Lexer<'a, R>, 983 ) -> Result<Option<StateFn<'a, R>>> { 984 let (value, _) = read_value(lexer.reader)?; 985 lexer.desc.uri = Some(Url::parse(&value)?); 986 Ok(Some(StateFn { f: s10 })) 987 } 988 989 fn unmarshal_email<'a, R: io::BufRead + io::Seek>( 990 lexer: &mut Lexer<'a, R>, 991 ) -> Result<Option<StateFn<'a, R>>> { 992 let (value, _) = read_value(lexer.reader)?; 993 lexer.desc.email_address = Some(value); 994 Ok(Some(StateFn { f: s6 })) 995 } 996 997 fn unmarshal_phone<'a, R: io::BufRead + io::Seek>( 998 lexer: &mut Lexer<'a, R>, 999 ) -> Result<Option<StateFn<'a, R>>> { 1000 let (value, _) = read_value(lexer.reader)?; 1001 lexer.desc.phone_number = Some(value); 1002 Ok(Some(StateFn { f: s8 })) 1003 } 1004 1005 fn unmarshal_session_connection_information<'a, R: io::BufRead + io::Seek>( 1006 lexer: &mut Lexer<'a, R>, 1007 ) -> Result<Option<StateFn<'a, R>>> { 1008 let (value, _) = read_value(lexer.reader)?; 1009 lexer.desc.connection_information = unmarshal_connection_information(&value)?; 1010 Ok(Some(StateFn { f: s5 })) 1011 } 1012 1013 fn unmarshal_connection_information(value: &str) -> Result<Option<ConnectionInformation>> { 1014 let fields: Vec<&str> = value.split_whitespace().collect(); 1015 if fields.len() < 2 { 1016 return Err(Error::SdpInvalidSyntax(format!("`c={}`", value))); 1017 } 1018 1019 // Set according to currently registered with IANA 1020 // https://tools.ietf.org/html/rfc4566#section-8.2.6 1021 let i = index_of(fields[0], &["IN"]); 1022 if i == -1 { 1023 return Err(Error::SdpInvalidValue(fields[0].to_owned())); 1024 } 1025 1026 // Set according to currently registered with IANA 1027 // https://tools.ietf.org/html/rfc4566#section-8.2.7 1028 let i = index_of(fields[1], &["IP4", "IP6"]); 1029 if i == -1 { 1030 return Err(Error::SdpInvalidValue(fields[1].to_owned())); 1031 } 1032 1033 let address = if fields.len() > 2 { 1034 Some(Address { 1035 address: fields[2].to_owned(), 1036 ttl: None, 1037 range: None, 1038 }) 1039 } else { 1040 None 1041 }; 1042 1043 Ok(Some(ConnectionInformation { 1044 network_type: fields[0].to_owned(), 1045 address_type: fields[1].to_owned(), 1046 address, 1047 })) 1048 } 1049 1050 fn unmarshal_session_bandwidth<'a, R: io::BufRead + io::Seek>( 1051 lexer: &mut Lexer<'a, R>, 1052 ) -> Result<Option<StateFn<'a, R>>> { 1053 let (value, _) = read_value(lexer.reader)?; 1054 lexer.desc.bandwidth.push(unmarshal_bandwidth(&value)?); 1055 Ok(Some(StateFn { f: s5 })) 1056 } 1057 1058 fn unmarshal_bandwidth(value: &str) -> Result<Bandwidth> { 1059 let mut parts: Vec<&str> = value.split(':').collect(); 1060 if parts.len() != 2 { 1061 return Err(Error::SdpInvalidSyntax(format!("`b={}`", value))); 1062 } 1063 1064 let experimental = parts[0].starts_with("X-"); 1065 if experimental { 1066 parts[0] = parts[0].trim_start_matches("X-"); 1067 } else { 1068 // Set according to currently registered with IANA 1069 // https://tools.ietf.org/html/rfc4566#section-5.8 1070 let i = index_of(parts[0], &["CT", "AS"]); 1071 if i == -1 { 1072 return Err(Error::SdpInvalidValue(parts[0].to_owned())); 1073 } 1074 } 1075 1076 let bandwidth = parts[1].parse::<u64>()?; 1077 1078 Ok(Bandwidth { 1079 experimental, 1080 bandwidth_type: parts[0].to_owned(), 1081 bandwidth, 1082 }) 1083 } 1084 1085 fn unmarshal_timing<'a, R: io::BufRead + io::Seek>( 1086 lexer: &mut Lexer<'a, R>, 1087 ) -> Result<Option<StateFn<'a, R>>> { 1088 let (value, _) = read_value(lexer.reader)?; 1089 1090 let fields: Vec<&str> = value.split_whitespace().collect(); 1091 if fields.len() < 2 { 1092 return Err(Error::SdpInvalidSyntax(format!("`t={}`", value))); 1093 } 1094 1095 let start_time = fields[0].parse::<u64>()?; 1096 let stop_time = fields[1].parse::<u64>()?; 1097 1098 lexer.desc.time_descriptions.push(TimeDescription { 1099 timing: Timing { 1100 start_time, 1101 stop_time, 1102 }, 1103 repeat_times: vec![], 1104 }); 1105 1106 Ok(Some(StateFn { f: s9 })) 1107 } 1108 1109 fn unmarshal_repeat_times<'a, R: io::BufRead + io::Seek>( 1110 lexer: &mut Lexer<'a, R>, 1111 ) -> Result<Option<StateFn<'a, R>>> { 1112 let (value, _) = read_value(lexer.reader)?; 1113 1114 let fields: Vec<&str> = value.split_whitespace().collect(); 1115 if fields.len() < 3 { 1116 return Err(Error::SdpInvalidSyntax(format!("`r={}`", value))); 1117 } 1118 1119 if let Some(latest_time_desc) = lexer.desc.time_descriptions.last_mut() { 1120 let interval = parse_time_units(fields[0])?; 1121 let duration = parse_time_units(fields[1])?; 1122 let mut offsets = vec![]; 1123 for field in fields.iter().skip(2) { 1124 let offset = parse_time_units(field)?; 1125 offsets.push(offset); 1126 } 1127 latest_time_desc.repeat_times.push(RepeatTime { 1128 interval, 1129 duration, 1130 offsets, 1131 }); 1132 1133 Ok(Some(StateFn { f: s9 })) 1134 } else { 1135 Err(Error::SdpEmptyTimeDescription) 1136 } 1137 } 1138 1139 fn unmarshal_time_zones<'a, R: io::BufRead + io::Seek>( 1140 lexer: &mut Lexer<'a, R>, 1141 ) -> Result<Option<StateFn<'a, R>>> { 1142 let (value, _) = read_value(lexer.reader)?; 1143 1144 // These fields are transimitted in pairs 1145 // z=<adjustment time> <offset> <adjustment time> <offset> .... 1146 // so we are making sure that there are actually multiple of 2 total. 1147 let fields: Vec<&str> = value.split_whitespace().collect(); 1148 if fields.len() % 2 != 0 { 1149 return Err(Error::SdpInvalidSyntax(format!("`t={}`", value))); 1150 } 1151 1152 for i in (0..fields.len()).step_by(2) { 1153 let adjustment_time = fields[i].parse::<u64>()?; 1154 let offset = parse_time_units(fields[i + 1])?; 1155 1156 lexer.desc.time_zones.push(TimeZone { 1157 adjustment_time, 1158 offset, 1159 }); 1160 } 1161 1162 Ok(Some(StateFn { f: s13 })) 1163 } 1164 1165 fn unmarshal_session_encryption_key<'a, R: io::BufRead + io::Seek>( 1166 lexer: &mut Lexer<'a, R>, 1167 ) -> Result<Option<StateFn<'a, R>>> { 1168 let (value, _) = read_value(lexer.reader)?; 1169 lexer.desc.encryption_key = Some(value); 1170 Ok(Some(StateFn { f: s11 })) 1171 } 1172 1173 fn unmarshal_session_attribute<'a, R: io::BufRead + io::Seek>( 1174 lexer: &mut Lexer<'a, R>, 1175 ) -> Result<Option<StateFn<'a, R>>> { 1176 let (value, _) = read_value(lexer.reader)?; 1177 1178 let fields: Vec<&str> = value.splitn(2, ':').collect(); 1179 let attribute = if fields.len() == 2 { 1180 Attribute { 1181 key: fields[0].to_owned(), 1182 value: Some(fields[1].to_owned()), 1183 } 1184 } else { 1185 Attribute { 1186 key: fields[0].to_owned(), 1187 value: None, 1188 } 1189 }; 1190 lexer.desc.attributes.push(attribute); 1191 1192 Ok(Some(StateFn { f: s11 })) 1193 } 1194 1195 fn unmarshal_media_description<'a, R: io::BufRead + io::Seek>( 1196 lexer: &mut Lexer<'a, R>, 1197 ) -> Result<Option<StateFn<'a, R>>> { 1198 let (value, _) = read_value(lexer.reader)?; 1199 1200 let fields: Vec<&str> = value.split_whitespace().collect(); 1201 if fields.len() < 4 { 1202 return Err(Error::SdpInvalidSyntax(format!("`m={}`", value))); 1203 } 1204 1205 // <media> 1206 // Set according to currently registered with IANA 1207 // https://tools.ietf.org/html/rfc4566#section-5.14 1208 let i = index_of( 1209 fields[0], 1210 &["audio", "video", "text", "application", "message"], 1211 ); 1212 if i == -1 { 1213 return Err(Error::SdpInvalidValue(fields[0].to_owned())); 1214 } 1215 1216 // <port> 1217 let parts: Vec<&str> = fields[1].split('/').collect(); 1218 let port_value = parts[0].parse::<u16>()? as isize; 1219 let port_range = if parts.len() > 1 { 1220 Some(parts[1].parse::<i32>()? as isize) 1221 } else { 1222 None 1223 }; 1224 1225 // <proto> 1226 // Set according to currently registered with IANA 1227 // https://tools.ietf.org/html/rfc4566#section-5.14 1228 let mut protos = vec![]; 1229 for proto in fields[2].split('/').collect::<Vec<&str>>() { 1230 let i = index_of( 1231 proto, 1232 &[ 1233 "UDP", "RTP", "AVP", "SAVP", "SAVPF", "TLS", "DTLS", "SCTP", "AVPF", 1234 ], 1235 ); 1236 if i == -1 { 1237 return Err(Error::SdpInvalidValue(fields[2].to_owned())); 1238 } 1239 protos.push(proto.to_owned()); 1240 } 1241 1242 // <fmt>... 1243 let mut formats = vec![]; 1244 for field in fields.iter().skip(3) { 1245 formats.push(field.to_string()); 1246 } 1247 1248 lexer.desc.media_descriptions.push(MediaDescription { 1249 media_name: MediaName { 1250 media: fields[0].to_owned(), 1251 port: RangedPort { 1252 value: port_value, 1253 range: port_range, 1254 }, 1255 protos, 1256 formats, 1257 }, 1258 media_title: None, 1259 connection_information: None, 1260 bandwidth: vec![], 1261 encryption_key: None, 1262 attributes: vec![], 1263 }); 1264 1265 Ok(Some(StateFn { f: s12 })) 1266 } 1267 1268 fn unmarshal_media_title<'a, R: io::BufRead + io::Seek>( 1269 lexer: &mut Lexer<'a, R>, 1270 ) -> Result<Option<StateFn<'a, R>>> { 1271 let (value, _) = read_value(lexer.reader)?; 1272 1273 if let Some(latest_media_desc) = lexer.desc.media_descriptions.last_mut() { 1274 latest_media_desc.media_title = Some(value); 1275 Ok(Some(StateFn { f: s16 })) 1276 } else { 1277 Err(Error::SdpEmptyTimeDescription) 1278 } 1279 } 1280 1281 fn unmarshal_media_connection_information<'a, R: io::BufRead + io::Seek>( 1282 lexer: &mut Lexer<'a, R>, 1283 ) -> Result<Option<StateFn<'a, R>>> { 1284 let (value, _) = read_value(lexer.reader)?; 1285 1286 if let Some(latest_media_desc) = lexer.desc.media_descriptions.last_mut() { 1287 latest_media_desc.connection_information = unmarshal_connection_information(&value)?; 1288 Ok(Some(StateFn { f: s15 })) 1289 } else { 1290 Err(Error::SdpEmptyTimeDescription) 1291 } 1292 } 1293 1294 fn unmarshal_media_bandwidth<'a, R: io::BufRead + io::Seek>( 1295 lexer: &mut Lexer<'a, R>, 1296 ) -> Result<Option<StateFn<'a, R>>> { 1297 let (value, _) = read_value(lexer.reader)?; 1298 1299 if let Some(latest_media_desc) = lexer.desc.media_descriptions.last_mut() { 1300 let bandwidth = unmarshal_bandwidth(&value)?; 1301 latest_media_desc.bandwidth.push(bandwidth); 1302 Ok(Some(StateFn { f: s15 })) 1303 } else { 1304 Err(Error::SdpEmptyTimeDescription) 1305 } 1306 } 1307 1308 fn unmarshal_media_encryption_key<'a, R: io::BufRead + io::Seek>( 1309 lexer: &mut Lexer<'a, R>, 1310 ) -> Result<Option<StateFn<'a, R>>> { 1311 let (value, _) = read_value(lexer.reader)?; 1312 1313 if let Some(latest_media_desc) = lexer.desc.media_descriptions.last_mut() { 1314 latest_media_desc.encryption_key = Some(value); 1315 Ok(Some(StateFn { f: s14 })) 1316 } else { 1317 Err(Error::SdpEmptyTimeDescription) 1318 } 1319 } 1320 1321 fn unmarshal_media_attribute<'a, R: io::BufRead + io::Seek>( 1322 lexer: &mut Lexer<'a, R>, 1323 ) -> Result<Option<StateFn<'a, R>>> { 1324 let (value, _) = read_value(lexer.reader)?; 1325 1326 let fields: Vec<&str> = value.splitn(2, ':').collect(); 1327 let attribute = if fields.len() == 2 { 1328 Attribute { 1329 key: fields[0].to_owned(), 1330 value: Some(fields[1].to_owned()), 1331 } 1332 } else { 1333 Attribute { 1334 key: fields[0].to_owned(), 1335 value: None, 1336 } 1337 }; 1338 1339 if let Some(latest_media_desc) = lexer.desc.media_descriptions.last_mut() { 1340 latest_media_desc.attributes.push(attribute); 1341 Ok(Some(StateFn { f: s14 })) 1342 } else { 1343 Err(Error::SdpEmptyTimeDescription) 1344 } 1345 } 1346 1347 fn parse_time_units(value: &str) -> Result<i64> { 1348 // Some time offsets in the protocol can be provided with a shorthand 1349 // notation. This code ensures to convert it to NTP timestamp format. 1350 let val = value.as_bytes(); 1351 let len = val.len(); 1352 let (num, factor) = match val.last() { 1353 Some(b'd') => (&value[..len - 1], 86400), // days 1354 Some(b'h') => (&value[..len - 1], 3600), // hours 1355 Some(b'm') => (&value[..len - 1], 60), // minutes 1356 Some(b's') => (&value[..len - 1], 1), // seconds (allowed for completeness) 1357 _ => (value, 1), 1358 }; 1359 num.parse::<i64>()? 1360 .checked_mul(factor) 1361 .ok_or_else(|| Error::SdpInvalidValue(value.to_owned())) 1362 } 1363