1mod bandwidth;
2mod key;
3mod origin;
4mod parser;
5
6pub mod attribute;
7pub mod connection;
8pub mod media;
9pub mod time;
10
11#[cfg(feature = "h264")]
12pub mod h264;
13
14#[cfg(feature = "ice")]
15pub mod ice;
16
17use std::{
18 convert::Infallible,
19 error::Error,
20 fmt::{self, Display, Formatter},
21 str::FromStr,
22};
23
24use self::{
25 attribute::Attributes,
26 parser::{FromSessionDescriptionLines, SessionDescriptionLines},
27 time::{TimeZoneAdjustment, TimeZoneAdjustments},
28};
29
30pub use self::{
31 attribute::Attribute,
32 bandwidth::{Bandwidth, BandwidthType},
33 connection::{ConnectionAddress, ConnectionInfo},
34 key::EncryptionKey,
35 media::MediaDescription,
36 origin::Origin,
37 time::TimeDescription,
38};
39
40#[derive(Debug)]
42pub struct ParseError {
43 msg: String,
44 cause: Option<Box<dyn Error + Send + Sync>>,
45}
46
47impl ParseError {
48 pub fn plain() -> Self {
50 Self {
51 msg: String::new(),
52 cause: None,
53 }
54 }
55
56 pub fn with_msg<M>(msg: M) -> Self
58 where
59 M: ToString,
60 {
61 Self {
62 msg: msg.to_string(),
63 cause: None,
64 }
65 }
66
67 pub fn with_cause_and_msg<M, C>(msg: M, cause: C) -> Self
69 where
70 M: ToString,
71 C: Into<Box<dyn Error + Send + Sync>>,
72 {
73 Self {
74 msg: msg.to_string(),
75 cause: Some(cause.into()),
76 }
77 }
78
79 pub fn with_cause<C>(cause: C) -> Self
81 where
82 C: Into<Box<dyn Error + Send + Sync>>,
83 {
84 Self {
85 msg: String::new(),
86 cause: Some(cause.into()),
87 }
88 }
89}
90
91impl Display for ParseError {
92 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
93 if let Some(cause) = self.cause.as_ref() {
94 if self.msg.is_empty() {
95 Display::fmt(cause, f)
96 } else {
97 write!(f, "{}: {}", self.msg, cause)
98 }
99 } else if self.msg.is_empty() {
100 f.write_str("parse error")
101 } else {
102 f.write_str(&self.msg)
103 }
104 }
105}
106
107impl Error for ParseError {
108 fn source(&self) -> Option<&(dyn Error + 'static)> {
109 if let Some(cause) = self.cause.as_ref() {
110 Some(cause.as_ref())
111 } else {
112 None
113 }
114 }
115}
116
117impl From<std::convert::Infallible> for ParseError {
118 fn from(_: std::convert::Infallible) -> Self {
119 Self::plain()
120 }
121}
122
123impl From<str_reader::ParseError> for ParseError {
124 fn from(err: str_reader::ParseError) -> Self {
125 Self::with_cause(err)
126 }
127}
128
129impl From<std::net::AddrParseError> for ParseError {
130 fn from(err: std::net::AddrParseError) -> Self {
131 Self::with_cause(err)
132 }
133}
134
135impl From<std::num::ParseIntError> for ParseError {
136 fn from(err: std::num::ParseIntError) -> Self {
137 Self::with_cause(err)
138 }
139}
140
141#[derive(Clone)]
143pub struct SessionDescriptionBuilder {
144 inner: SessionDescription,
145}
146
147impl SessionDescriptionBuilder {
148 fn new() -> Self {
150 let inner = SessionDescription {
151 version: 0,
152 origin: Origin::default(),
153 session_name: String::new(),
154 session_information: None,
155 url: None,
156 emails: Vec::new(),
157 phones: Vec::new(),
158 connection: None,
159 bandwidth: Vec::new(),
160 time_descriptions: Vec::new(),
161 tz_adjustments: TimeZoneAdjustments::empty(),
162 key: None,
163 attributes: Attributes::new(),
164 media: Vec::new(),
165 };
166
167 Self { inner }
168 }
169
170 #[inline]
172 pub fn version(&mut self, version: u16) -> &mut Self {
173 self.inner.version = version;
174 self
175 }
176
177 #[inline]
179 pub fn origin(&mut self, origin: Origin) -> &mut Self {
180 self.inner.origin = origin;
181 self
182 }
183
184 #[inline]
186 pub fn session_name<T>(&mut self, name: T) -> &mut Self
187 where
188 T: ToString,
189 {
190 self.inner.session_name = name.to_string();
191 self
192 }
193
194 #[inline]
196 pub fn session_information<T>(&mut self, info: T) -> &mut Self
197 where
198 T: ToString,
199 {
200 self.inner.session_information = Some(info.to_string());
201 self
202 }
203
204 #[inline]
206 pub fn url<T>(&mut self, url: T) -> &mut Self
207 where
208 T: ToString,
209 {
210 self.inner.url = Some(url.to_string());
211 self
212 }
213
214 #[inline]
216 pub fn email<T>(&mut self, email: T) -> &mut Self
217 where
218 T: ToString,
219 {
220 self.inner.emails.push(email.to_string());
221 self
222 }
223
224 #[inline]
226 pub fn phone<T>(&mut self, phone: T) -> &mut Self
227 where
228 T: ToString,
229 {
230 self.inner.phones.push(phone.to_string());
231 self
232 }
233
234 #[inline]
236 pub fn connection(&mut self, connection: ConnectionInfo) -> &mut Self {
237 self.inner.connection = Some(connection);
238 self
239 }
240
241 #[inline]
243 pub fn bandwidth(&mut self, bandwidth: Bandwidth) -> &mut Self {
244 self.inner.bandwidth.push(bandwidth);
245 self
246 }
247
248 #[inline]
250 pub fn time_description(&mut self, td: TimeDescription) -> &mut Self {
251 self.inner.time_descriptions.push(td);
252 self
253 }
254
255 #[inline]
257 pub fn tz_adjustment(&mut self, tz_adjustment: TimeZoneAdjustment) -> &mut Self {
258 self.inner.tz_adjustments.push(tz_adjustment);
259 self
260 }
261
262 #[inline]
264 pub fn encryption_key(&mut self, key: EncryptionKey) -> &mut Self {
265 self.inner.key = Some(key);
266 self
267 }
268
269 #[inline]
271 pub fn flag<T>(&mut self, name: T) -> &mut Self
272 where
273 T: ToString,
274 {
275 self.inner.attributes.push(Attribute::new_flag(name));
276 self
277 }
278
279 #[inline]
281 pub fn attribute<T, U>(&mut self, name: T, value: U) -> &mut Self
282 where
283 T: ToString,
284 U: ToString,
285 {
286 self.inner
287 .attributes
288 .push(Attribute::new_attribute(name, value));
289 self
290 }
291
292 #[inline]
294 pub fn media_description(&mut self, desc: MediaDescription) -> &mut Self {
295 self.inner.media.push(desc);
296 self
297 }
298
299 pub fn build(mut self) -> SessionDescription {
301 if self.inner.session_name.is_empty() {
302 self.inner.session_name = String::from("-");
303 }
304
305 if self.inner.time_descriptions.is_empty() {
306 self.inner
307 .time_descriptions
308 .push(TimeDescription::default());
309 }
310
311 self.inner
312 }
313}
314
315#[derive(Clone)]
317pub struct SessionDescription {
318 version: u16,
319 origin: Origin,
320 session_name: String,
321 session_information: Option<String>,
322 url: Option<String>,
323 emails: Vec<String>,
324 phones: Vec<String>,
325 connection: Option<ConnectionInfo>,
326 bandwidth: Vec<Bandwidth>,
327 time_descriptions: Vec<TimeDescription>,
328 tz_adjustments: TimeZoneAdjustments,
329 key: Option<EncryptionKey>,
330 attributes: Attributes,
331 media: Vec<MediaDescription>,
332}
333
334impl SessionDescription {
335 fn empty() -> Self {
337 Self {
338 version: 0,
339 origin: Origin::default(),
340 session_name: String::new(),
341 session_information: None,
342 url: None,
343 emails: Vec::new(),
344 phones: Vec::new(),
345 connection: None,
346 bandwidth: Vec::new(),
347 time_descriptions: Vec::new(),
348 tz_adjustments: TimeZoneAdjustments::empty(),
349 key: None,
350 attributes: Attributes::new(),
351 media: Vec::new(),
352 }
353 }
354
355 #[inline]
357 pub fn builder() -> SessionDescriptionBuilder {
358 SessionDescriptionBuilder::new()
359 }
360
361 #[inline]
363 pub fn version(&self) -> u16 {
364 self.version
365 }
366
367 #[inline]
369 pub fn origin(&self) -> &Origin {
370 &self.origin
371 }
372
373 #[inline]
375 pub fn session_name(&self) -> &str {
376 &self.session_name
377 }
378
379 #[inline]
381 pub fn session_information(&self) -> Option<&str> {
382 self.session_information.as_deref()
383 }
384
385 #[inline]
387 pub fn url(&self) -> Option<&str> {
388 self.url.as_deref()
389 }
390
391 #[inline]
393 pub fn emails(&self) -> &[String] {
394 &self.emails
395 }
396
397 #[inline]
399 pub fn phones(&self) -> &[String] {
400 &self.phones
401 }
402
403 #[inline]
405 pub fn connection(&self) -> Option<&ConnectionInfo> {
406 self.connection.as_ref()
407 }
408
409 #[inline]
411 pub fn bandwidth(&self) -> &[Bandwidth] {
412 &self.bandwidth
413 }
414
415 #[inline]
417 pub fn time_descriptions(&self) -> &[TimeDescription] {
418 &self.time_descriptions
419 }
420
421 #[inline]
423 pub fn tz_adjustments(&self) -> &[TimeZoneAdjustment] {
424 &self.tz_adjustments
425 }
426
427 #[inline]
429 pub fn encryption_key(&self) -> Option<&EncryptionKey> {
430 self.key.as_ref()
431 }
432
433 #[inline]
435 pub fn attributes(&self) -> &Attributes {
436 &self.attributes
437 }
438
439 #[inline]
441 pub fn media_descriptions(&self) -> &[MediaDescription] {
442 &self.media
443 }
444}
445
446impl Display for SessionDescription {
447 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
448 write!(f, "v={}\r\n", self.version)?;
449 write!(f, "o={}\r\n", self.origin)?;
450 write!(f, "s={}\r\n", self.session_name)?;
451
452 if let Some(info) = self.session_information.as_ref() {
453 write!(f, "i={info}\r\n")?;
454 }
455
456 if let Some(url) = self.url.as_ref() {
457 write!(f, "u={url}\r\n")?;
458 }
459
460 for email in &self.emails {
461 write!(f, "e={email}\r\n")?;
462 }
463
464 for phone in &self.phones {
465 write!(f, "p={phone}\r\n")?;
466 }
467
468 if let Some(connection) = self.connection.as_ref() {
469 write!(f, "c={connection}\r\n")?;
470 }
471
472 for bw in &self.bandwidth {
473 write!(f, "b={bw}\r\n")?;
474 }
475
476 for td in &self.time_descriptions {
477 Display::fmt(td, f)?;
478 }
479
480 if !self.tz_adjustments.is_empty() {
481 write!(f, "z={}\r\n", self.tz_adjustments)?;
482 }
483
484 if let Some(k) = self.key.as_ref() {
485 write!(f, "k={k}\r\n")?;
486 }
487
488 for attr in self.attributes.iter() {
489 write!(f, "a={attr}\r\n")?;
490 }
491
492 for media in &self.media {
493 Display::fmt(media, f)?;
494 }
495
496 Ok(())
497 }
498}
499
500impl FromSessionDescriptionLines for SessionDescription {
501 fn from_sdp_lines(lines: &mut SessionDescriptionLines) -> Result<Self, ParseError> {
502 let mut sdp = SessionDescription::empty();
503
504 while let Some((t, _)) = lines.current() {
505 match t {
506 'v' => sdp.version = lines.parse()?,
507 'o' => sdp.origin = lines.parse()?,
508 's' => sdp.session_name = lines.parse()?,
509 'i' => sdp.session_information = Some(lines.parse()?),
510 'u' => sdp.url = Some(lines.parse()?),
511 'e' => sdp.emails.push(lines.parse()?),
512 'p' => sdp.phones.push(lines.parse()?),
513 'c' => sdp.connection = Some(lines.parse()?),
514 'b' => sdp.bandwidth.push(lines.parse()?),
515 't' => sdp.time_descriptions.push(lines.parse_multiple()?),
516 'z' => sdp.tz_adjustments = lines.parse()?,
517 'k' => sdp.key = Some(lines.parse()?),
518 'a' => sdp.attributes.push(lines.parse()?),
519 'm' => sdp.media.push(lines.parse_multiple()?),
520 _ => return Err(ParseError::with_msg(format!("unknown SDP field: {t}"))),
521 }
522 }
523
524 Ok(sdp)
525 }
526}
527
528impl FromStr for SessionDescription {
529 type Err = ParseError;
530
531 fn from_str(s: &str) -> Result<Self, Self::Err> {
532 let mut lines = SessionDescriptionLines::new(s)?;
533
534 SessionDescription::from_sdp_lines(&mut lines)
535 }
536}
537
538#[derive(Clone, Eq, PartialEq, Hash)]
540pub enum NetworkType {
541 Internet,
542 Other(String),
543}
544
545impl Display for NetworkType {
546 #[inline]
547 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
548 let s = match self {
549 Self::Internet => "IN",
550 Self::Other(o) => o,
551 };
552
553 f.write_str(s)
554 }
555}
556
557impl FromStr for NetworkType {
558 type Err = Infallible;
559
560 fn from_str(s: &str) -> Result<Self, Self::Err> {
561 let res = match s.trim() {
562 "IN" => Self::Internet,
563 o => Self::Other(o.to_string()),
564 };
565
566 Ok(res)
567 }
568}
569
570#[derive(Clone, Eq, PartialEq, Hash)]
572pub enum AddressType {
573 IPv4,
574 IPv6,
575 Other(String),
576}
577
578impl Display for AddressType {
579 #[inline]
580 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
581 let s = match self {
582 Self::IPv4 => "IP4",
583 Self::IPv6 => "IP6",
584 Self::Other(o) => o,
585 };
586
587 f.write_str(s)
588 }
589}
590
591impl FromStr for AddressType {
592 type Err = Infallible;
593
594 fn from_str(s: &str) -> Result<Self, Self::Err> {
595 let res = match s.trim() {
596 "IP4" => Self::IPv4,
597 "IP6" => Self::IPv6,
598 o => Self::Other(o.to_string()),
599 };
600
601 Ok(res)
602 }
603}