xref: /webrtc/sdp/src/description/session.rs (revision 5d8fe953)
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