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 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result57 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 {
new() -> Self72 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 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result107 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 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result137 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 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result152 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.
new_jsep_session_description(identity: bool) -> Self244 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
with_property_attribute(mut self, key: String) -> Self286 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
with_value_attribute(mut self, key: String, value: String) -> Self292 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
with_fingerprint(self, algorithm: String, value: String) -> Self298 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
with_media(mut self, md: MediaDescription) -> Self303 pub fn with_media(mut self, md: MediaDescription) -> Self {
304 self.media_descriptions.push(md);
305 self
306 }
307
build_codec_map(&self) -> HashMap<u8, Codec>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
get_codec_for_payload_type(&self, payload_type: u8) -> Result<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
get_payload_type_for_codec(&self, wanted: &Codec) -> Result<u8>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
attribute(&self, key: &str) -> Option<&String>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)
marshal(&self) -> String401 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 /// ```
unmarshal<R: io::BufRead + io::Seek>(reader: &mut R) -> Result<Self>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 {
from(sdp: SessionDescription) -> String568 fn from(sdp: SessionDescription) -> String {
569 sdp.marshal()
570 }
571 }
572
573 impl TryFrom<String> for SessionDescription {
574 type Error = Error;
try_from(sdp_string: String) -> Result<Self>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
s1<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s2<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s3<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s4<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s5<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s6<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s7<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s8<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s9<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s10<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s11<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s12<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s13<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s14<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s15<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
s16<'a, R: io::BufRead + io::Seek>(lexer: &mut Lexer<'a, R>) -> Result<Option<StateFn<'a, R>>>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
unmarshal_protocol_version<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_origin<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_session_name<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_session_information<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_uri<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_email<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_phone<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_session_connection_information<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_connection_information(value: &str) -> Result<Option<ConnectionInformation>>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
unmarshal_session_bandwidth<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_bandwidth(value: &str) -> Result<Bandwidth>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
unmarshal_timing<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_repeat_times<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_time_zones<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_session_encryption_key<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_session_attribute<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_media_description<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_media_title<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_media_connection_information<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_media_bandwidth<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_media_encryption_key<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
unmarshal_media_attribute<'a, R: io::BufRead + io::Seek>( lexer: &mut Lexer<'a, R>, ) -> Result<Option<StateFn<'a, R>>>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
parse_time_units(value: &str) -> Result<i64>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