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