webrtc_sdp/
attribute_type.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5extern crate url;
6use std::convert::TryFrom;
7use std::fmt;
8use std::fmt::Write;
9use std::iter;
10use std::str::FromStr;
11
12use error::SdpParserInternalError;
13use network::{parse_network_type, parse_unicast_address};
14use SdpType;
15
16use address::{Address, AddressType, ExplicitlyTypedAddress};
17use anonymizer::{AnonymizingClone, StatefulSdpAnonymizer};
18
19// Serialization helper marcos and functions
20#[macro_export]
21macro_rules! option_to_string {
22    ($fmt_str:expr, $opt:expr) => {
23        match $opt {
24            Some(ref x) => format!($fmt_str, x),
25            None => "".to_string(),
26        }
27    };
28}
29
30#[macro_export]
31macro_rules! write_option_string {
32    ($f:expr, $fmt_str:expr, $opt:expr) => {
33        match $opt {
34            Some(ref x) => write!($f, $fmt_str, x),
35            None => Ok(()),
36        }
37    };
38}
39
40#[macro_export]
41macro_rules! maybe_vector_to_string {
42    ($fmt_str:expr, $vec:expr, $sep:expr) => {
43        match $vec.len() {
44            0 => "".to_string(),
45            _ => format!(
46                $fmt_str,
47                $vec.iter()
48                    .map(ToString::to_string)
49                    .collect::<Vec<String>>()
50                    .join($sep)
51            ),
52        }
53    };
54}
55
56#[macro_export]
57macro_rules! non_empty_string_vec {
58    ( $( $x:expr ),* ) => {
59        {
60            let mut temp_vec = Vec::new();
61            $(
62                if !$x.is_empty() {
63                    temp_vec.push($x);
64                }
65            )*
66            temp_vec
67        }
68    };
69}
70
71pub fn maybe_print_param<T>(name: &str, param: T, default_value: T) -> String
72where
73    T: PartialEq + ToString,
74{
75    if param != default_value {
76        name.to_owned() + &param.to_string()
77    } else {
78        "".to_string()
79    }
80}
81
82pub fn maybe_print_bool_param(name: &str, param: bool, default_value: bool) -> String {
83    if param != default_value {
84        name.to_owned() + "=" + &(param as i32).to_string()
85    } else {
86        "".to_string()
87    }
88}
89
90#[derive(Debug, Clone, PartialEq)]
91#[cfg_attr(feature = "serialize", derive(Serialize))]
92pub enum SdpSingleDirection {
93    // This is explicitly 1 and 2 to match the defines in the C++ glue code.
94    Send = 1,
95    Recv = 2,
96}
97
98impl fmt::Display for SdpSingleDirection {
99    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100        match *self {
101            SdpSingleDirection::Send => "send",
102            SdpSingleDirection::Recv => "recv",
103        }
104        .fmt(f)
105    }
106}
107
108#[derive(Debug, PartialEq, Clone)]
109#[cfg_attr(feature = "serialize", derive(Serialize))]
110pub enum SdpAttributePayloadType {
111    PayloadType(u8),
112    Wildcard, // Wildcard means "*",
113}
114
115impl fmt::Display for SdpAttributePayloadType {
116    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117        match *self {
118            SdpAttributePayloadType::PayloadType(pt) => pt.fmt(f),
119            SdpAttributePayloadType::Wildcard => "*".fmt(f),
120        }
121    }
122}
123
124#[derive(Debug, Clone, PartialEq)]
125#[cfg_attr(feature = "serialize", derive(Serialize))]
126pub enum SdpAttributeCandidateTransport {
127    Udp,
128    Tcp,
129}
130
131impl fmt::Display for SdpAttributeCandidateTransport {
132    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133        match *self {
134            SdpAttributeCandidateTransport::Udp => "UDP",
135            SdpAttributeCandidateTransport::Tcp => "TCP",
136        }
137        .fmt(f)
138    }
139}
140
141#[derive(Debug, Clone, PartialEq)]
142#[cfg_attr(feature = "serialize", derive(Serialize))]
143pub enum SdpAttributeCandidateType {
144    Host,
145    Srflx,
146    Prflx,
147    Relay,
148}
149
150impl fmt::Display for SdpAttributeCandidateType {
151    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
152        match *self {
153            SdpAttributeCandidateType::Host => "host",
154            SdpAttributeCandidateType::Srflx => "srflx",
155            SdpAttributeCandidateType::Prflx => "prflx",
156            SdpAttributeCandidateType::Relay => "relay",
157        }
158        .fmt(f)
159    }
160}
161
162#[derive(Debug, Clone, PartialEq)]
163#[cfg_attr(feature = "serialize", derive(Serialize))]
164pub enum SdpAttributeCandidateTcpType {
165    Active,
166    Passive,
167    Simultaneous,
168}
169
170impl fmt::Display for SdpAttributeCandidateTcpType {
171    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
172        match *self {
173            SdpAttributeCandidateTcpType::Active => "active",
174            SdpAttributeCandidateTcpType::Passive => "passive",
175            SdpAttributeCandidateTcpType::Simultaneous => "so",
176        }
177        .fmt(f)
178    }
179}
180
181#[derive(Clone)]
182#[cfg_attr(feature = "serialize", derive(Serialize))]
183#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
184pub struct SdpAttributeCandidate {
185    pub foundation: String,
186    pub component: u32,
187    pub transport: SdpAttributeCandidateTransport,
188    pub priority: u64,
189    pub address: Address,
190    pub port: u32,
191    pub c_type: SdpAttributeCandidateType,
192    pub raddr: Option<Address>,
193    pub rport: Option<u32>,
194    pub tcp_type: Option<SdpAttributeCandidateTcpType>,
195    pub generation: Option<u32>,
196    pub ufrag: Option<String>,
197    pub networkcost: Option<u32>,
198    pub unknown_extensions: Vec<(String, String)>,
199}
200
201impl fmt::Display for SdpAttributeCandidate {
202    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203        write!(
204            f,
205            "{foundation} {component} {transport} {priority} \
206             {address} {port} typ {ctype}\
207             {raddr}{rport}{tcp_type}{generation}{ufrag}{cost}\
208             {unknown}",
209            foundation = self.foundation,
210            component = self.component,
211            transport = self.transport,
212            priority = self.priority,
213            address = self.address,
214            port = self.port,
215            ctype = self.c_type,
216            raddr = option_to_string!(" raddr {}", self.raddr),
217            rport = option_to_string!(" rport {}", self.rport),
218            tcp_type = option_to_string!(" tcptype {}", self.tcp_type),
219            generation = option_to_string!(" generation {}", self.generation),
220            ufrag = option_to_string!(" ufrag {}", self.ufrag),
221            cost = option_to_string!(" network-cost {}", self.networkcost),
222            unknown =
223                self.unknown_extensions
224                    .iter()
225                    .fold(String::new(), |mut output, (name, value)| {
226                        let _ = write!(output, " {name} {value}");
227                        output
228                    })
229        )
230    }
231}
232
233impl SdpAttributeCandidate {
234    pub fn new(
235        foundation: String,
236        component: u32,
237        transport: SdpAttributeCandidateTransport,
238        priority: u64,
239        address: Address,
240        port: u32,
241        c_type: SdpAttributeCandidateType,
242    ) -> SdpAttributeCandidate {
243        SdpAttributeCandidate {
244            foundation,
245            component,
246            transport,
247            priority,
248            address,
249            port,
250            c_type,
251            raddr: None,
252            rport: None,
253            tcp_type: None,
254            generation: None,
255            ufrag: None,
256            networkcost: None,
257            unknown_extensions: Vec::new(),
258        }
259    }
260
261    fn set_remote_address(&mut self, addr: Address) {
262        self.raddr = Some(addr)
263    }
264
265    fn set_remote_port(&mut self, p: u32) {
266        self.rport = Some(p)
267    }
268
269    fn set_tcp_type(&mut self, t: SdpAttributeCandidateTcpType) {
270        self.tcp_type = Some(t)
271    }
272
273    fn set_generation(&mut self, g: u32) {
274        self.generation = Some(g)
275    }
276
277    fn set_ufrag(&mut self, u: String) {
278        self.ufrag = Some(u)
279    }
280
281    fn set_network_cost(&mut self, n: u32) {
282        self.networkcost = Some(n)
283    }
284
285    fn add_unknown_extension(&mut self, name: String, value: String) {
286        self.unknown_extensions.push((name, value));
287    }
288}
289
290impl AnonymizingClone for SdpAttributeCandidate {
291    fn masked_clone(&self, anonymizer: &mut StatefulSdpAnonymizer) -> Self {
292        let mut masked = self.clone();
293        masked.address = anonymizer.mask_address(&self.address);
294        masked.port = anonymizer.mask_port(self.port);
295        masked.raddr = self
296            .raddr
297            .clone()
298            .map(|addr| anonymizer.mask_address(&addr));
299        masked.rport = self.rport.map(|port| anonymizer.mask_port(port));
300        masked
301    }
302}
303
304#[derive(Clone)]
305#[cfg_attr(feature = "serialize", derive(Serialize))]
306#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
307pub enum SdpAttributeDtlsMessage {
308    Client(String),
309    Server(String),
310}
311
312impl fmt::Display for SdpAttributeDtlsMessage {
313    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
314        match self {
315            SdpAttributeDtlsMessage::Client(msg) => format!("client {msg}"),
316            SdpAttributeDtlsMessage::Server(msg) => format!("server {msg}"),
317        }
318        .fmt(f)
319    }
320}
321
322#[derive(Clone)]
323#[cfg_attr(feature = "serialize", derive(Serialize))]
324#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
325pub struct SdpAttributeRemoteCandidate {
326    pub component: u32,
327    pub address: Address,
328    pub port: u32,
329}
330
331impl fmt::Display for SdpAttributeRemoteCandidate {
332    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
333        write!(
334            f,
335            "{component} {addr} {port}",
336            component = self.component,
337            addr = self.address,
338            port = self.port
339        )
340    }
341}
342
343impl AnonymizingClone for SdpAttributeRemoteCandidate {
344    fn masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self {
345        SdpAttributeRemoteCandidate {
346            address: anon.mask_address(&self.address),
347            port: anon.mask_port(self.port),
348            component: self.component,
349        }
350    }
351}
352
353#[derive(Clone)]
354#[cfg_attr(feature = "serialize", derive(Serialize))]
355#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
356pub struct SdpAttributeSimulcastId {
357    pub id: String,
358    pub paused: bool,
359}
360
361impl SdpAttributeSimulcastId {
362    pub fn new(idstr: &str) -> SdpAttributeSimulcastId {
363        if let Some(idstr) = idstr.strip_prefix('~') {
364            SdpAttributeSimulcastId {
365                id: idstr.to_string(),
366                paused: true,
367            }
368        } else {
369            SdpAttributeSimulcastId {
370                id: idstr.to_string(),
371                paused: false,
372            }
373        }
374    }
375}
376
377impl fmt::Display for SdpAttributeSimulcastId {
378    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
379        if self.paused {
380            write!(f, "~")?;
381        }
382        self.id.fmt(f)
383    }
384}
385
386#[repr(C)]
387#[derive(Clone)]
388#[cfg_attr(feature = "serialize", derive(Serialize))]
389#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
390pub struct SdpAttributeSimulcastVersion {
391    pub ids: Vec<SdpAttributeSimulcastId>,
392}
393
394impl SdpAttributeSimulcastVersion {
395    pub fn new(idlist: &str) -> SdpAttributeSimulcastVersion {
396        SdpAttributeSimulcastVersion {
397            ids: idlist
398                .split(',')
399                .map(SdpAttributeSimulcastId::new)
400                .collect(),
401        }
402    }
403}
404
405impl fmt::Display for SdpAttributeSimulcastVersion {
406    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
407        self.ids
408            .iter()
409            .map(ToString::to_string)
410            .collect::<Vec<String>>()
411            .join(",")
412            .fmt(f)
413    }
414}
415
416#[derive(Clone)]
417#[cfg_attr(feature = "serialize", derive(Serialize))]
418#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
419pub struct SdpAttributeSimulcast {
420    pub send: Vec<SdpAttributeSimulcastVersion>,
421    pub receive: Vec<SdpAttributeSimulcastVersion>,
422}
423
424impl fmt::Display for SdpAttributeSimulcast {
425    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
426        non_empty_string_vec![
427            maybe_vector_to_string!("send {}", self.send, ";"),
428            maybe_vector_to_string!("recv {}", self.receive, ";")
429        ]
430        .join(" ")
431        .fmt(f)
432    }
433}
434
435#[derive(Clone)]
436#[cfg_attr(feature = "serialize", derive(Serialize))]
437#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
438pub struct SdpAttributeRtcp {
439    pub port: u16,
440    pub unicast_addr: Option<ExplicitlyTypedAddress>,
441}
442
443impl SdpAttributeRtcp {
444    pub fn new(port: u16) -> SdpAttributeRtcp {
445        SdpAttributeRtcp {
446            port,
447            unicast_addr: None,
448        }
449    }
450
451    fn set_addr(&mut self, addr: ExplicitlyTypedAddress) {
452        self.unicast_addr = Some(addr)
453    }
454}
455
456impl fmt::Display for SdpAttributeRtcp {
457    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
458        match self.unicast_addr {
459            Some(ref addr) => write!(f, "{} {}", self.port, addr),
460            None => self.port.fmt(f),
461        }
462    }
463}
464
465#[derive(Clone)]
466#[cfg_attr(feature = "serialize", derive(Serialize))]
467#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
468pub enum SdpAttributeRtcpFbType {
469    Ack = 0,
470    Ccm = 2, // This is explicitly 2 to make the conversion to the
471    // enum used in the glue-code possible. The glue code has "app"
472    // in the place of 1
473    Nack,
474    TrrInt,
475    Remb,
476    TransCc,
477}
478
479impl fmt::Display for SdpAttributeRtcpFbType {
480    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
481        match *self {
482            SdpAttributeRtcpFbType::Ack => "ack",
483            SdpAttributeRtcpFbType::Ccm => "ccm",
484            SdpAttributeRtcpFbType::Nack => "nack",
485            SdpAttributeRtcpFbType::TrrInt => "trr-int",
486            SdpAttributeRtcpFbType::Remb => "goog-remb",
487            SdpAttributeRtcpFbType::TransCc => "transport-cc",
488        }
489        .fmt(f)
490    }
491}
492
493#[derive(Clone)]
494#[cfg_attr(feature = "serialize", derive(Serialize))]
495#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
496pub struct SdpAttributeRtcpFb {
497    pub payload_type: SdpAttributePayloadType,
498    pub feedback_type: SdpAttributeRtcpFbType,
499    pub parameter: String,
500    pub extra: String,
501}
502
503impl fmt::Display for SdpAttributeRtcpFb {
504    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
505        write!(f, "{} {}", self.payload_type, self.feedback_type,)?;
506        if !self.parameter.is_empty() {
507            write!(
508                f,
509                " {}{}",
510                self.parameter,
511                maybe_print_param(" ", self.extra.clone(), "".to_string()),
512            )?;
513        }
514        Ok(())
515    }
516}
517
518#[derive(Clone)]
519#[cfg_attr(feature = "serialize", derive(Serialize))]
520#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
521pub enum SdpAttributeDirection {
522    Recvonly,
523    Sendonly,
524    Sendrecv,
525}
526
527impl fmt::Display for SdpAttributeDirection {
528    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
529        match *self {
530            SdpAttributeDirection::Recvonly => "recvonly",
531            SdpAttributeDirection::Sendonly => "sendonly",
532            SdpAttributeDirection::Sendrecv => "sendrecv",
533        }
534        .fmt(f)
535    }
536}
537
538#[derive(Clone)]
539#[cfg_attr(feature = "serialize", derive(Serialize))]
540#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
541pub struct SdpAttributeExtmap {
542    pub id: u16,
543    pub direction: Option<SdpAttributeDirection>,
544    pub url: String,
545    pub extension_attributes: Option<String>,
546}
547
548impl fmt::Display for SdpAttributeExtmap {
549    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
550        write!(
551            f,
552            "{id}{direction} {url}{ext}",
553            id = self.id,
554            direction = option_to_string!("/{}", self.direction),
555            url = self.url,
556            ext = option_to_string!(" {}", self.extension_attributes)
557        )
558    }
559}
560
561#[derive(Clone, Copy)]
562#[cfg_attr(feature = "serialize", derive(Serialize))]
563#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
564pub struct RtxFmtpParameters {
565    pub apt: u8,
566    pub rtx_time: Option<u32>,
567}
568
569impl fmt::Display for RtxFmtpParameters {
570    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
571        if let Some(rtx_time) = self.rtx_time {
572            write!(f, "apt={};rtx-time={}", self.apt, rtx_time)
573        } else {
574            write!(f, "apt={}", self.apt)
575        }
576    }
577}
578
579#[derive(Clone)]
580#[cfg_attr(feature = "serialize", derive(Serialize))]
581#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
582pub struct SdpAttributeFmtpParameters {
583    // H264
584    // TODO(bug 1466859): Support sprop-parameter-sets
585    // pub static const max_sprop_len: u32 = 128,
586    // pub sprop_parameter_sets: [u8, max_sprop_len],
587    pub packetization_mode: u32,
588    pub level_asymmetry_allowed: bool,
589    pub profile_level_id: u32,
590    pub max_fs: u32,
591    pub max_cpb: u32,
592    pub max_dpb: u32,
593    pub max_br: u32,
594    pub max_mbps: u32,
595
596    // VP8 and VP9
597    // max_fs, already defined in H264
598    pub max_fr: u32,
599
600    // AV1
601    // Defined in https://aomediacodec.github.io/av1-rtp-spec/#72-sdp-parameters
602    // f(3) a 3 bit value that specifies the profile of the AV1 codec which is
603    // equivalent to the seq_profile field in the AV1 General Sequence Header
604    // OBU
605    // Defaults to 0 when not present
606    // Value must not be greater than 2 as values 3 to 7 are reserved
607    pub profile: Option<u8>,
608    // f(5) a 5 bit value that specifies the level maps to a table in A.3. of
609    // https://aomediacodec.github.io/av1-spec/av1-spec.pdf
610    // Defaults to 5 when not present
611    pub level_idx: Option<u8>,
612    // f(1) a 1 that specifies the tier 5.5.1 of
613    // https://aomediacodec.github.io/av1-spec/av1-spec.pdf
614    // Defaults to 0 when not present
615    pub tier: Option<u8>,
616
617    // Opus https://tools.ietf.org/html/rfc7587
618    pub maxplaybackrate: u32,
619    pub maxaveragebitrate: u32,
620    pub usedtx: bool,
621    pub stereo: bool,
622    pub useinbandfec: bool,
623    pub cbr: bool,
624    pub ptime: u32,
625    pub minptime: u32,
626    pub maxptime: u32,
627
628    // Red
629    pub encodings: Vec<u8>,
630
631    // telephone-event
632    pub dtmf_tones: String,
633
634    // RTX
635    pub rtx: Option<RtxFmtpParameters>,
636
637    // Unknown
638    pub unknown_tokens: Vec<String>,
639}
640
641impl fmt::Display for SdpAttributeFmtpParameters {
642    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
643        if let Some(ref rtx) = self.rtx {
644            // rtx
645            return write!(f, "{rtx}");
646        }
647        if !self.dtmf_tones.is_empty() {
648            // telephone-event
649            return write!(f, "{}", self.dtmf_tones);
650        } else if !self.encodings.is_empty() {
651            // red encodings
652            return self
653                .encodings
654                .iter()
655                .map(ToString::to_string)
656                .collect::<Vec<String>>()
657                .join("/")
658                .fmt(f);
659        };
660        write!(
661            f,
662            "{}",
663            non_empty_string_vec![
664                maybe_print_param(
665                    "profile-level-id=",
666                    format!("{:06x}", self.profile_level_id),
667                    "420010".to_string()
668                ),
669                maybe_print_bool_param(
670                    "level-asymmetry-allowed",
671                    self.level_asymmetry_allowed,
672                    false
673                ),
674                maybe_print_param("packetization-mode=", self.packetization_mode, 0),
675                maybe_print_param("max-fs=", self.max_fs, 0),
676                maybe_print_param("max-cpb=", self.max_cpb, 0),
677                maybe_print_param("max-dpb=", self.max_dpb, 0),
678                maybe_print_param("max-br=", self.max_br, 0),
679                maybe_print_param("max-mbps=", self.max_mbps, 0),
680                maybe_print_param("max-fr=", self.max_fr, 0),
681                match self.profile {
682                    Some(profile) => format!("profile={}", profile),
683                    None => "".to_string(),
684                },
685                match self.level_idx {
686                    Some(level_idx) => format!("level-idx={}", level_idx),
687                    None => "".to_string(),
688                },
689                match self.tier {
690                    Some(tier) => format!("tier={}", tier),
691                    None => "".to_string(),
692                },
693                maybe_print_param("maxplaybackrate=", self.maxplaybackrate, 48000),
694                maybe_print_param("maxaveragebitrate=", self.maxaveragebitrate, 0),
695                maybe_print_param("ptime=", self.ptime, 0),
696                maybe_print_param("minptime=", self.minptime, 0),
697                maybe_print_param("maxptime=", self.maxptime, 0),
698                maybe_print_bool_param("usedtx", self.usedtx, false),
699                maybe_print_bool_param("stereo", self.stereo, false),
700                maybe_print_bool_param("useinbandfec", self.useinbandfec, false),
701                maybe_print_bool_param("cbr", self.cbr, false),
702                maybe_vector_to_string!("{}", self.unknown_tokens, ",")
703            ]
704            .join(";")
705        )
706    }
707}
708
709#[derive(Clone)]
710#[cfg_attr(feature = "serialize", derive(Serialize))]
711#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
712pub struct SdpAttributeFmtp {
713    pub payload_type: u8,
714    pub parameters: SdpAttributeFmtpParameters,
715}
716
717impl fmt::Display for SdpAttributeFmtp {
718    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
719        write!(
720            f,
721            "{pt} {parameter}",
722            pt = self.payload_type,
723            parameter = self.parameters
724        )
725    }
726}
727
728#[derive(Clone, Copy, PartialEq, Eq)]
729#[cfg_attr(feature = "serialize", derive(Serialize))]
730#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
731pub enum SdpAttributeFingerprintHashType {
732    Sha1,
733    Sha224,
734    Sha256,
735    Sha384,
736    Sha512,
737}
738
739impl SdpAttributeFingerprintHashType {
740    pub fn try_from_name(name: &str) -> Result<Self, SdpParserInternalError> {
741        match name {
742            "sha-1" => Ok(Self::Sha1),
743            "sha-224" => Ok(Self::Sha224),
744            "sha-256" => Ok(Self::Sha256),
745            "sha-384" => Ok(Self::Sha384),
746            "sha-512" => Ok(Self::Sha512),
747            unknown => Err(SdpParserInternalError::Unsupported(format!(
748                "fingerprint contains an unsupported hash algorithm '{unknown}'"
749            ))),
750        }
751    }
752    pub fn octet_count(&self) -> usize {
753        match self {
754            Self::Sha1 => 20,
755            Self::Sha224 => 28,
756            Self::Sha256 => 32,
757            Self::Sha384 => 48,
758            Self::Sha512 => 64,
759        }
760    }
761
762    pub fn parse_octets(&self, octets_string: &str) -> Result<Vec<u8>, SdpParserInternalError> {
763        let bytes = octets_string
764            .split(':')
765            .map(|byte_token| {
766                if byte_token.len() != 2 {
767                    return Err(SdpParserInternalError::Generic(
768                        "fingerpint's byte tokens must have 2 hexdigits".to_string(),
769                    ));
770                }
771                Ok(u8::from_str_radix(byte_token, 16)?)
772            })
773            .collect::<Result<Vec<u8>, _>>()?;
774
775        if bytes.len() != self.octet_count() {
776            return Err(SdpParserInternalError::Generic(format!(
777                "fingerprint has {} bytes but should have {} bytes",
778                bytes.len(),
779                self.octet_count(),
780            )));
781        }
782
783        Ok(bytes)
784    }
785}
786
787impl fmt::Display for SdpAttributeFingerprintHashType {
788    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
789        match *self {
790            SdpAttributeFingerprintHashType::Sha1 => "sha-1",
791            SdpAttributeFingerprintHashType::Sha224 => "sha-224",
792            SdpAttributeFingerprintHashType::Sha256 => "sha-256",
793            SdpAttributeFingerprintHashType::Sha384 => "sha-384",
794            SdpAttributeFingerprintHashType::Sha512 => "sha-512",
795        }
796        .fmt(f)
797    }
798}
799
800#[derive(Clone, PartialEq, Eq)]
801#[cfg_attr(feature = "serialize", derive(Serialize))]
802#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
803pub struct SdpAttributeFingerprint {
804    pub hash_algorithm: SdpAttributeFingerprintHashType,
805    pub fingerprint: Vec<u8>,
806}
807
808impl TryFrom<(SdpAttributeFingerprintHashType, Vec<u8>)> for SdpAttributeFingerprint {
809    type Error = SdpParserInternalError;
810    fn try_from(
811        parts: (SdpAttributeFingerprintHashType, Vec<u8>),
812    ) -> Result<Self, SdpParserInternalError> {
813        let (hash_algorithm, fingerprint) = parts;
814        match (hash_algorithm.octet_count(), fingerprint.len()) {
815            (a, b) if a == b => Ok(Self {
816                hash_algorithm,
817                fingerprint,
818            }),
819            (a, b) => Err(SdpParserInternalError::Generic(format!(
820                "Hash algoritm expects {a} fingerprint bytes not {b}",
821            ))),
822        }
823    }
824}
825
826impl fmt::Display for SdpAttributeFingerprint {
827    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
828        write!(
829            f,
830            "{hash} {fp}",
831            hash = self.hash_algorithm,
832            fp = self
833                .fingerprint
834                .iter()
835                .map(|byte| format!("{byte:02X}"))
836                .collect::<Vec<String>>()
837                .join(":")
838        )
839    }
840}
841
842impl AnonymizingClone for SdpAttributeFingerprint {
843    fn masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self {
844        SdpAttributeFingerprint {
845            hash_algorithm: self.hash_algorithm,
846            fingerprint: anon.mask_cert_finger_print(&self.fingerprint),
847        }
848    }
849}
850
851fn imageattr_discrete_value_list_to_string<T>(values: &[T]) -> String
852where
853    T: ToString,
854{
855    match values.len() {
856        1 => values[0].to_string(),
857        _ => format!(
858            "[{}]",
859            values
860                .iter()
861                .map(ToString::to_string)
862                .collect::<Vec<String>>()
863                .join(",")
864        ),
865    }
866}
867
868#[derive(Debug, PartialEq, Clone)]
869#[cfg_attr(feature = "serialize", derive(Serialize))]
870pub enum SdpAttributeImageAttrXyRange {
871    Range(u32, u32, Option<u32>), // min, max, step
872    DiscreteValues(Vec<u32>),
873}
874
875impl fmt::Display for SdpAttributeImageAttrXyRange {
876    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
877        match *self {
878            SdpAttributeImageAttrXyRange::Range(ref min, ref max, ref step_opt) => {
879                write!(f, "[{min}:")?;
880                if step_opt.is_some() {
881                    write!(f, "{}:", step_opt.unwrap())?;
882                }
883                write!(f, "{max}]")
884            }
885            SdpAttributeImageAttrXyRange::DiscreteValues(ref values) => {
886                write!(f, "{}", imageattr_discrete_value_list_to_string(values))
887            }
888        }
889    }
890}
891
892#[derive(Debug, PartialEq, Clone)]
893#[cfg_attr(feature = "serialize", derive(Serialize))]
894pub enum SdpAttributeImageAttrSRange {
895    Range(f32, f32), // min, max
896    DiscreteValues(Vec<f32>),
897}
898
899impl fmt::Display for SdpAttributeImageAttrSRange {
900    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
901        match self {
902            SdpAttributeImageAttrSRange::Range(min, max) => write!(f, "[{min}-{max}]"),
903            SdpAttributeImageAttrSRange::DiscreteValues(values) => {
904                write!(f, "{}", imageattr_discrete_value_list_to_string(values))
905            }
906        }
907    }
908}
909
910#[derive(Debug, PartialEq, Clone)]
911#[cfg_attr(feature = "serialize", derive(Serialize))]
912pub struct SdpAttributeImageAttrPRange {
913    pub min: f32,
914    pub max: f32,
915}
916
917impl fmt::Display for SdpAttributeImageAttrPRange {
918    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
919        write!(f, "[{}-{}]", self.min, self.max)
920    }
921}
922
923#[derive(Debug, PartialEq, Clone)]
924#[cfg_attr(feature = "serialize", derive(Serialize))]
925pub struct SdpAttributeImageAttrSet {
926    pub x: SdpAttributeImageAttrXyRange,
927    pub y: SdpAttributeImageAttrXyRange,
928    pub sar: Option<SdpAttributeImageAttrSRange>,
929    pub par: Option<SdpAttributeImageAttrPRange>,
930    pub q: Option<f32>,
931}
932
933impl fmt::Display for SdpAttributeImageAttrSet {
934    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
935        write!(f, "[x={x},y={y}", x = self.x, y = self.y)?;
936        write_option_string!(f, ",sar={}", self.sar)?;
937        write_option_string!(f, ",par={}", self.par)?;
938        write_option_string!(f, ",q={}", self.q)?;
939        write!(f, "]")
940    }
941}
942
943#[derive(Debug, PartialEq, Clone)]
944#[cfg_attr(feature = "serialize", derive(Serialize))]
945pub enum SdpAttributeImageAttrSetList {
946    Sets(Vec<SdpAttributeImageAttrSet>),
947    Wildcard,
948}
949
950impl fmt::Display for SdpAttributeImageAttrSetList {
951    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
952        match *self {
953            SdpAttributeImageAttrSetList::Sets(ref sets) => sets
954                .iter()
955                .map(ToString::to_string)
956                .collect::<Vec<String>>()
957                .join(" ")
958                .fmt(f),
959            SdpAttributeImageAttrSetList::Wildcard => "*".fmt(f),
960        }
961    }
962}
963
964#[derive(Clone)]
965#[cfg_attr(feature = "serialize", derive(Serialize))]
966#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
967pub struct SdpAttributeImageAttr {
968    pub pt: SdpAttributePayloadType,
969    pub send: SdpAttributeImageAttrSetList,
970    pub recv: SdpAttributeImageAttrSetList,
971}
972
973impl fmt::Display for SdpAttributeImageAttr {
974    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
975        let maybe_sets_to_string = |set_list| match set_list {
976            SdpAttributeImageAttrSetList::Sets(sets) => match sets.len() {
977                0 => None,
978                _ => Some(SdpAttributeImageAttrSetList::Sets(sets)),
979            },
980            x => Some(x),
981        };
982        self.pt.fmt(f)?;
983        write_option_string!(f, " send {}", maybe_sets_to_string(self.send.clone()))?;
984        write_option_string!(f, " recv {}", maybe_sets_to_string(self.recv.clone()))
985    }
986}
987
988#[derive(Clone)]
989#[cfg_attr(feature = "serialize", derive(Serialize))]
990#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
991pub struct SdpAttributeSctpmap {
992    pub port: u16,
993    pub channels: u32,
994}
995
996impl fmt::Display for SdpAttributeSctpmap {
997    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
998        write!(
999            f,
1000            "{port} webrtc-datachannel {channels}",
1001            port = self.port,
1002            channels = self.channels
1003        )
1004    }
1005}
1006
1007#[derive(Clone)]
1008#[cfg_attr(feature = "serialize", derive(Serialize))]
1009#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
1010pub enum SdpAttributeGroupSemantic {
1011    LipSynchronization,          // RFC5888
1012    FlowIdentification,          // RFC5888
1013    SingleReservationFlow,       // RFC3524
1014    AlternateNetworkAddressType, // RFC4091
1015    ForwardErrorCorrection,      // RFC5956
1016    DecodingDependency,          // RFC5583
1017    Bundle,                      // draft-ietc-mmusic-bundle
1018}
1019
1020impl fmt::Display for SdpAttributeGroupSemantic {
1021    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1022        match *self {
1023            SdpAttributeGroupSemantic::LipSynchronization => "LS",
1024            SdpAttributeGroupSemantic::FlowIdentification => "FID",
1025            SdpAttributeGroupSemantic::SingleReservationFlow => "SRF",
1026            SdpAttributeGroupSemantic::AlternateNetworkAddressType => "ANAT",
1027            SdpAttributeGroupSemantic::ForwardErrorCorrection => "FEC",
1028            SdpAttributeGroupSemantic::DecodingDependency => "DDP",
1029            SdpAttributeGroupSemantic::Bundle => "BUNDLE",
1030        }
1031        .fmt(f)
1032    }
1033}
1034
1035#[derive(Clone)]
1036#[cfg_attr(feature = "serialize", derive(Serialize))]
1037#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
1038pub struct SdpAttributeGroup {
1039    pub semantics: SdpAttributeGroupSemantic,
1040    pub tags: Vec<String>,
1041}
1042
1043impl fmt::Display for SdpAttributeGroup {
1044    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1045        write!(
1046            f,
1047            "{}{}",
1048            self.semantics,
1049            maybe_vector_to_string!(" {}", self.tags, " ")
1050        )
1051    }
1052}
1053
1054#[derive(Clone)]
1055#[cfg_attr(feature = "serialize", derive(Serialize))]
1056#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
1057pub struct SdpAttributeMsid {
1058    pub id: String,
1059    pub appdata: Option<String>,
1060}
1061
1062impl fmt::Display for SdpAttributeMsid {
1063    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1064        self.id.fmt(f)?;
1065        write_option_string!(f, " {}", self.appdata)
1066    }
1067}
1068
1069#[derive(Clone, Debug)]
1070#[cfg_attr(feature = "serialize", derive(Serialize))]
1071pub struct SdpAttributeMsidSemantic {
1072    pub semantic: String,
1073    pub msids: Vec<String>,
1074}
1075
1076impl fmt::Display for SdpAttributeMsidSemantic {
1077    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1078        write!(f, "{} ", self.semantic)?;
1079        match self.msids.len() {
1080            0 => "*".fmt(f),
1081            _ => self.msids.join(" ").fmt(f),
1082        }
1083    }
1084}
1085
1086#[derive(Clone)]
1087#[cfg_attr(feature = "serialize", derive(Serialize))]
1088#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
1089pub struct SdpAttributeRidParameters {
1090    pub max_width: u32,
1091    pub max_height: u32,
1092    pub max_fps: u32,
1093    pub max_fs: u32,
1094    pub max_br: u32,
1095    pub max_pps: u32,
1096
1097    pub unknown: Vec<String>,
1098}
1099
1100impl fmt::Display for SdpAttributeRidParameters {
1101    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1102        non_empty_string_vec![
1103            maybe_print_param("max-width=", self.max_width, 0),
1104            maybe_print_param("max-height=", self.max_height, 0),
1105            maybe_print_param("max-fps=", self.max_fps, 0),
1106            maybe_print_param("max-fs=", self.max_fs, 0),
1107            maybe_print_param("max-br=", self.max_br, 0),
1108            maybe_print_param("max-pps=", self.max_pps, 0),
1109            maybe_vector_to_string!("{}", self.unknown, ";")
1110        ]
1111        .join(";")
1112        .fmt(f)
1113    }
1114}
1115
1116#[derive(Clone)]
1117#[cfg_attr(feature = "serialize", derive(Serialize))]
1118#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
1119pub struct SdpAttributeRid {
1120    pub id: String,
1121    pub direction: SdpSingleDirection,
1122    pub formats: Vec<u16>,
1123    pub params: SdpAttributeRidParameters,
1124    pub depends: Vec<String>,
1125}
1126
1127impl fmt::Display for SdpAttributeRid {
1128    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1129        write!(
1130            f,
1131            "{id} {direction}{format}",
1132            id = self.id,
1133            direction = self.direction,
1134            format = match non_empty_string_vec![
1135                maybe_vector_to_string!("pt={}", self.formats, ","),
1136                self.params.to_string(),
1137                maybe_vector_to_string!("depends={}", self.depends, ",")
1138            ]
1139            .join(";")
1140            .as_str()
1141            {
1142                "" => "".to_string(),
1143                x => format!(" {x}"),
1144            }
1145        )
1146    }
1147}
1148
1149#[derive(Clone)]
1150#[cfg_attr(feature = "serialize", derive(Serialize))]
1151#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
1152pub struct SdpAttributeRtpmap {
1153    pub payload_type: u8,
1154    pub codec_name: String,
1155    pub frequency: u32,
1156    pub channels: Option<u32>,
1157}
1158
1159impl SdpAttributeRtpmap {
1160    pub fn new(payload_type: u8, codec_name: String, frequency: u32) -> SdpAttributeRtpmap {
1161        SdpAttributeRtpmap {
1162            payload_type,
1163            codec_name,
1164            frequency,
1165            channels: None,
1166        }
1167    }
1168
1169    fn set_channels(&mut self, c: u32) {
1170        self.channels = Some(c)
1171    }
1172}
1173
1174impl fmt::Display for SdpAttributeRtpmap {
1175    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1176        write!(
1177            f,
1178            "{pt} {name}/{freq}",
1179            pt = self.payload_type,
1180            name = self.codec_name,
1181            freq = self.frequency
1182        )?;
1183        write_option_string!(f, "/{}", self.channels)
1184    }
1185}
1186
1187#[derive(Clone)]
1188#[cfg_attr(feature = "serialize", derive(Serialize))]
1189#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
1190pub enum SdpAttributeSetup {
1191    Active,
1192    Actpass,
1193    Holdconn,
1194    Passive,
1195}
1196
1197impl fmt::Display for SdpAttributeSetup {
1198    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1199        match *self {
1200            SdpAttributeSetup::Active => "active",
1201            SdpAttributeSetup::Actpass => "actpass",
1202            SdpAttributeSetup::Holdconn => "holdconn",
1203            SdpAttributeSetup::Passive => "passive",
1204        }
1205        .fmt(f)
1206    }
1207}
1208
1209#[derive(Clone)]
1210#[cfg_attr(feature = "serialize", derive(Serialize))]
1211#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
1212pub struct SdpAttributeSsrc {
1213    pub id: u32,
1214    pub attribute: Option<String>,
1215    pub value: Option<String>,
1216}
1217
1218impl SdpAttributeSsrc {
1219    pub fn new(id: u32) -> SdpAttributeSsrc {
1220        SdpAttributeSsrc {
1221            id,
1222            attribute: None,
1223            value: None,
1224        }
1225    }
1226
1227    fn set_attribute(&mut self, a: &str) {
1228        if a.find(':').is_none() {
1229            self.attribute = Some(a.to_string());
1230        } else {
1231            let v: Vec<&str> = a.splitn(2, ':').collect();
1232            self.attribute = Some(v[0].to_string());
1233            self.value = Some(v[1].to_string());
1234        }
1235    }
1236}
1237
1238impl fmt::Display for SdpAttributeSsrc {
1239    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1240        self.id.fmt(f)?;
1241        write_option_string!(f, " {}", self.attribute)?;
1242        write_option_string!(f, ":{}", self.value)
1243    }
1244}
1245
1246impl AnonymizingClone for SdpAttributeSsrc {
1247    fn masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self {
1248        Self {
1249            id: self.id,
1250            attribute: self.attribute.clone(),
1251            value: self.attribute.as_ref().and_then(|attribute| {
1252                match (attribute.to_lowercase().as_str(), &self.value) {
1253                    ("cname", Some(ref cname)) => Some(anon.mask_cname(cname.as_str())),
1254                    (_, Some(_)) => self.value.clone(),
1255                    (_, None) => None,
1256                }
1257            }),
1258        }
1259    }
1260}
1261
1262#[derive(Clone)]
1263#[cfg_attr(feature = "serialize", derive(Serialize))]
1264#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
1265pub enum SdpSsrcGroupSemantic {
1266    Duplication,              // RFC7104
1267    FlowIdentification,       // RFC5576
1268    ForwardErrorCorrection,   // RFC5576
1269    ForwardErrorCorrectionFr, // RFC5956
1270    Sim,                      // not registered with IANA, but used in hangouts
1271}
1272
1273impl fmt::Display for SdpSsrcGroupSemantic {
1274    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1275        match *self {
1276            SdpSsrcGroupSemantic::Duplication => "DUP",
1277            SdpSsrcGroupSemantic::FlowIdentification => "FID",
1278            SdpSsrcGroupSemantic::ForwardErrorCorrection => "FEC",
1279            SdpSsrcGroupSemantic::ForwardErrorCorrectionFr => "FEC-FR",
1280            SdpSsrcGroupSemantic::Sim => "SIM",
1281        }
1282        .fmt(f)
1283    }
1284}
1285
1286#[derive(Clone)]
1287#[cfg_attr(feature = "serialize", derive(Serialize))]
1288#[cfg_attr(feature = "enhanced_debug", derive(Debug))]
1289pub enum SdpAttribute {
1290    BundleOnly,
1291    Candidate(SdpAttributeCandidate),
1292    DtlsMessage(SdpAttributeDtlsMessage),
1293    EndOfCandidates,
1294    Extmap(SdpAttributeExtmap),
1295    ExtmapAllowMixed,
1296    Fingerprint(SdpAttributeFingerprint),
1297    Fmtp(SdpAttributeFmtp),
1298    FrameRate(f64),
1299    Group(SdpAttributeGroup),
1300    IceLite,
1301    IceMismatch,
1302    IceOptions(Vec<String>),
1303    IcePacing(u64),
1304    IcePwd(String),
1305    IceUfrag(String),
1306    Identity(String),
1307    ImageAttr(SdpAttributeImageAttr),
1308    Inactive,
1309    Label(String),
1310    MaxMessageSize(u64),
1311    MaxPtime(u64),
1312    Mid(String),
1313    Msid(SdpAttributeMsid),
1314    MsidSemantic(SdpAttributeMsidSemantic),
1315    Ptime(u64),
1316    Rid(SdpAttributeRid),
1317    Recvonly,
1318    RemoteCandidate(SdpAttributeRemoteCandidate),
1319    Rtpmap(SdpAttributeRtpmap),
1320    Rtcp(SdpAttributeRtcp),
1321    Rtcpfb(SdpAttributeRtcpFb),
1322    RtcpMux,
1323    RtcpMuxOnly, // RFC8858
1324    RtcpRsize,
1325    Sctpmap(SdpAttributeSctpmap),
1326    SctpPort(u64),
1327    Sendonly,
1328    Sendrecv,
1329    Setup(SdpAttributeSetup),
1330    Simulcast(SdpAttributeSimulcast),
1331    Ssrc(SdpAttributeSsrc),
1332    SsrcGroup(SdpSsrcGroupSemantic, Vec<SdpAttributeSsrc>),
1333}
1334
1335impl SdpAttribute {
1336    pub fn allowed_at_session_level(&self) -> bool {
1337        match *self {
1338            SdpAttribute::BundleOnly
1339            | SdpAttribute::Candidate(..)
1340            | SdpAttribute::Fmtp(..)
1341            | SdpAttribute::FrameRate(..)
1342            | SdpAttribute::IceMismatch
1343            | SdpAttribute::ImageAttr(..)
1344            | SdpAttribute::Label(..)
1345            | SdpAttribute::MaxMessageSize(..)
1346            | SdpAttribute::MaxPtime(..)
1347            | SdpAttribute::Mid(..)
1348            | SdpAttribute::Msid(..)
1349            | SdpAttribute::Ptime(..)
1350            | SdpAttribute::Rid(..)
1351            | SdpAttribute::RemoteCandidate(..)
1352            | SdpAttribute::Rtpmap(..)
1353            | SdpAttribute::Rtcp(..)
1354            | SdpAttribute::Rtcpfb(..)
1355            | SdpAttribute::RtcpMux
1356            | SdpAttribute::RtcpMuxOnly
1357            | SdpAttribute::RtcpRsize
1358            | SdpAttribute::Sctpmap(..)
1359            | SdpAttribute::SctpPort(..)
1360            | SdpAttribute::Simulcast(..)
1361            | SdpAttribute::Ssrc(..)
1362            | SdpAttribute::SsrcGroup(..) => false,
1363
1364            SdpAttribute::DtlsMessage { .. }
1365            | SdpAttribute::EndOfCandidates
1366            | SdpAttribute::Extmap(..)
1367            | SdpAttribute::ExtmapAllowMixed
1368            | SdpAttribute::Fingerprint(..)
1369            | SdpAttribute::Group(..)
1370            | SdpAttribute::IceLite
1371            | SdpAttribute::IceOptions(..)
1372            | SdpAttribute::IcePacing(..)
1373            | SdpAttribute::IcePwd(..)
1374            | SdpAttribute::IceUfrag(..)
1375            | SdpAttribute::Identity(..)
1376            | SdpAttribute::Inactive
1377            | SdpAttribute::MsidSemantic(..)
1378            | SdpAttribute::Recvonly
1379            | SdpAttribute::Sendonly
1380            | SdpAttribute::Sendrecv
1381            | SdpAttribute::Setup(..) => true,
1382        }
1383    }
1384
1385    pub fn allowed_at_media_level(&self) -> bool {
1386        match *self {
1387            SdpAttribute::DtlsMessage { .. }
1388            | SdpAttribute::Group(..)
1389            | SdpAttribute::IceLite
1390            | SdpAttribute::IcePacing(..)
1391            | SdpAttribute::Identity(..)
1392            | SdpAttribute::MsidSemantic(..) => false,
1393
1394            SdpAttribute::BundleOnly
1395            | SdpAttribute::Candidate(..)
1396            | SdpAttribute::EndOfCandidates
1397            | SdpAttribute::Extmap(..)
1398            | SdpAttribute::ExtmapAllowMixed
1399            | SdpAttribute::Fingerprint(..)
1400            | SdpAttribute::Fmtp(..)
1401            | SdpAttribute::FrameRate(..)
1402            | SdpAttribute::IceMismatch
1403            | SdpAttribute::IceOptions(..)
1404            | SdpAttribute::IcePwd(..)
1405            | SdpAttribute::IceUfrag(..)
1406            | SdpAttribute::ImageAttr(..)
1407            | SdpAttribute::Inactive
1408            | SdpAttribute::Label(..)
1409            | SdpAttribute::MaxMessageSize(..)
1410            | SdpAttribute::MaxPtime(..)
1411            | SdpAttribute::Mid(..)
1412            | SdpAttribute::Msid(..)
1413            | SdpAttribute::Ptime(..)
1414            | SdpAttribute::Rid(..)
1415            | SdpAttribute::Recvonly
1416            | SdpAttribute::RemoteCandidate(..)
1417            | SdpAttribute::Rtpmap(..)
1418            | SdpAttribute::Rtcp(..)
1419            | SdpAttribute::Rtcpfb(..)
1420            | SdpAttribute::RtcpMux
1421            | SdpAttribute::RtcpMuxOnly
1422            | SdpAttribute::RtcpRsize
1423            | SdpAttribute::Sctpmap(..)
1424            | SdpAttribute::SctpPort(..)
1425            | SdpAttribute::Sendonly
1426            | SdpAttribute::Sendrecv
1427            | SdpAttribute::Setup(..)
1428            | SdpAttribute::Simulcast(..)
1429            | SdpAttribute::Ssrc(..)
1430            | SdpAttribute::SsrcGroup(..) => true,
1431        }
1432    }
1433}
1434
1435impl FromStr for SdpAttribute {
1436    type Err = SdpParserInternalError;
1437
1438    fn from_str(line: &str) -> Result<Self, Self::Err> {
1439        let tokens: Vec<_> = line.splitn(2, ':').collect();
1440        let name = tokens[0].to_lowercase();
1441        let val = match tokens.get(1) {
1442            Some(x) => x.trim(),
1443            None => "",
1444        };
1445        if tokens.len() > 1 {
1446            match name.as_str() {
1447                "bundle-only" | "end-of-candidates" | "extmap-allow-mixed" | "ice-lite"
1448                | "ice-mismatch" | "inactive" | "recvonly" | "rtcp-mux" | "rtcp-mux-only"
1449                | "rtcp-rsize" | "sendonly" | "sendrecv" => {
1450                    return Err(SdpParserInternalError::Generic(format!(
1451                        "{name} attribute is not allowed to have a value",
1452                    )));
1453                }
1454                _ => (),
1455            }
1456        }
1457        match name.as_str() {
1458            "bundle-only" => Ok(SdpAttribute::BundleOnly),
1459            "dtls-message" => parse_dtls_message(val),
1460            "end-of-candidates" => Ok(SdpAttribute::EndOfCandidates),
1461            "ice-lite" => Ok(SdpAttribute::IceLite),
1462            "ice-mismatch" => Ok(SdpAttribute::IceMismatch),
1463            "extmap-allow-mixed" => Ok(SdpAttribute::ExtmapAllowMixed),
1464            "ice-pwd" => Ok(SdpAttribute::IcePwd(string_or_empty(val)?)),
1465            "ice-ufrag" => Ok(SdpAttribute::IceUfrag(string_or_empty(val)?)),
1466            "identity" => Ok(SdpAttribute::Identity(string_or_empty(val)?)),
1467            "imageattr" => parse_image_attr(val),
1468            "inactive" => Ok(SdpAttribute::Inactive),
1469            "label" => Ok(SdpAttribute::Label(string_or_empty(val)?)),
1470            "max-message-size" => Ok(SdpAttribute::MaxMessageSize(val.parse()?)),
1471            "maxptime" => Ok(SdpAttribute::MaxPtime(val.parse()?)),
1472            "mid" => Ok(SdpAttribute::Mid(string_or_empty(val)?)),
1473            "msid-semantic" => parse_msid_semantic(val),
1474            "ptime" => Ok(SdpAttribute::Ptime(val.parse()?)),
1475            "ice-pacing" => parse_ice_pacing(val),
1476            "rid" => parse_rid(val),
1477            "recvonly" => Ok(SdpAttribute::Recvonly),
1478            "rtcp-mux" => Ok(SdpAttribute::RtcpMux),
1479            "rtcp-mux-only" => Ok(SdpAttribute::RtcpMuxOnly),
1480            "rtcp-rsize" => Ok(SdpAttribute::RtcpRsize),
1481            "sendonly" => Ok(SdpAttribute::Sendonly),
1482            "sendrecv" => Ok(SdpAttribute::Sendrecv),
1483            "ssrc-group" => parse_ssrc_group(val),
1484            "sctp-port" => parse_sctp_port(val),
1485            "candidate" => parse_candidate(val),
1486            "extmap" => parse_extmap(val),
1487            "fingerprint" => parse_fingerprint(val),
1488            "fmtp" => parse_fmtp(val),
1489            "framerate" => parse_framerate(val),
1490            "group" => parse_group(val),
1491            "ice-options" => parse_ice_options(val),
1492            "msid" => parse_msid(val),
1493            "remote-candidates" => parse_remote_candidates(val),
1494            "rtpmap" => parse_rtpmap(val),
1495            "rtcp" => parse_rtcp(val),
1496            "rtcp-fb" => parse_rtcp_fb(val),
1497            "sctpmap" => parse_sctpmap(val),
1498            "setup" => parse_setup(val),
1499            "simulcast" => parse_simulcast(val),
1500            "ssrc" => parse_ssrc(val),
1501            _ => Err(SdpParserInternalError::Unsupported(format!(
1502                "Unknown attribute type {name}",
1503            ))),
1504        }
1505    }
1506}
1507
1508impl fmt::Display for SdpAttribute {
1509    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1510        let attr_type_name = SdpAttributeType::from(self).to_string();
1511        let attr_to_string = |attr_str: String| attr_type_name + ":" + &attr_str;
1512        match *self {
1513            SdpAttribute::BundleOnly => SdpAttributeType::BundleOnly.to_string(),
1514            SdpAttribute::Candidate(ref a) => attr_to_string(a.to_string()),
1515            SdpAttribute::DtlsMessage(ref a) => attr_to_string(a.to_string()),
1516            SdpAttribute::EndOfCandidates => SdpAttributeType::EndOfCandidates.to_string(),
1517            SdpAttribute::Extmap(ref a) => attr_to_string(a.to_string()),
1518            SdpAttribute::ExtmapAllowMixed => SdpAttributeType::ExtmapAllowMixed.to_string(),
1519            SdpAttribute::Fingerprint(ref a) => attr_to_string(a.to_string()),
1520            SdpAttribute::Fmtp(ref a) => attr_to_string(a.to_string()),
1521            SdpAttribute::FrameRate(ref a) => attr_to_string(a.to_string()),
1522            SdpAttribute::Group(ref a) => attr_to_string(a.to_string()),
1523            SdpAttribute::IceLite => SdpAttributeType::IceLite.to_string(),
1524            SdpAttribute::IceMismatch => SdpAttributeType::IceMismatch.to_string(),
1525            SdpAttribute::IceOptions(ref a) => attr_to_string(a.join(" ")),
1526            SdpAttribute::IcePacing(ref a) => attr_to_string(a.to_string()),
1527            SdpAttribute::IcePwd(ref a) => attr_to_string(a.to_string()),
1528            SdpAttribute::IceUfrag(ref a) => attr_to_string(a.to_string()),
1529            SdpAttribute::Identity(ref a) => attr_to_string(a.to_string()),
1530            SdpAttribute::ImageAttr(ref a) => attr_to_string(a.to_string()),
1531            SdpAttribute::Inactive => SdpAttributeType::Inactive.to_string(),
1532            SdpAttribute::Label(ref a) => attr_to_string(a.to_string()),
1533            SdpAttribute::MaxMessageSize(ref a) => attr_to_string(a.to_string()),
1534            SdpAttribute::MaxPtime(ref a) => attr_to_string(a.to_string()),
1535            SdpAttribute::Mid(ref a) => attr_to_string(a.to_string()),
1536            SdpAttribute::Msid(ref a) => attr_to_string(a.to_string()),
1537            SdpAttribute::MsidSemantic(ref a) => attr_to_string(a.to_string()),
1538            SdpAttribute::Ptime(ref a) => attr_to_string(a.to_string()),
1539            SdpAttribute::Rid(ref a) => attr_to_string(a.to_string()),
1540            SdpAttribute::Recvonly => SdpAttributeType::Recvonly.to_string(),
1541            SdpAttribute::RemoteCandidate(ref a) => attr_to_string(a.to_string()),
1542            SdpAttribute::Rtpmap(ref a) => attr_to_string(a.to_string()),
1543            SdpAttribute::Rtcp(ref a) => attr_to_string(a.to_string()),
1544            SdpAttribute::Rtcpfb(ref a) => attr_to_string(a.to_string()),
1545            SdpAttribute::RtcpMux => SdpAttributeType::RtcpMux.to_string(),
1546            SdpAttribute::RtcpMuxOnly => SdpAttributeType::RtcpMuxOnly.to_string(),
1547            SdpAttribute::RtcpRsize => SdpAttributeType::RtcpRsize.to_string(),
1548            SdpAttribute::Sctpmap(ref a) => attr_to_string(a.to_string()),
1549            SdpAttribute::SctpPort(ref a) => attr_to_string(a.to_string()),
1550            SdpAttribute::Sendonly => SdpAttributeType::Sendonly.to_string(),
1551            SdpAttribute::Sendrecv => SdpAttributeType::Sendrecv.to_string(),
1552            SdpAttribute::Setup(ref a) => attr_to_string(a.to_string()),
1553            SdpAttribute::Simulcast(ref a) => attr_to_string(a.to_string()),
1554            SdpAttribute::Ssrc(ref a) => attr_to_string(a.to_string()),
1555            SdpAttribute::SsrcGroup(ref a, ref ssrcs) => {
1556                let stringified_ssrcs: Vec<String> =
1557                    ssrcs.iter().map(|ssrc| ssrc.to_string()).collect();
1558                attr_to_string(a.to_string()) + " " + &stringified_ssrcs.join(" ")
1559            }
1560        }
1561        .fmt(f)
1562    }
1563}
1564
1565impl AnonymizingClone for SdpAttribute {
1566    fn masked_clone(&self, anon: &mut StatefulSdpAnonymizer) -> Self {
1567        match self {
1568            SdpAttribute::Candidate(i) => SdpAttribute::Candidate(i.masked_clone(anon)),
1569            SdpAttribute::Fingerprint(i) => SdpAttribute::Fingerprint(i.masked_clone(anon)),
1570            SdpAttribute::IcePwd(i) => SdpAttribute::IcePwd(anon.mask_ice_password(i)),
1571            SdpAttribute::IceUfrag(i) => SdpAttribute::IceUfrag(anon.mask_ice_user(i)),
1572            SdpAttribute::RemoteCandidate(i) => SdpAttribute::RemoteCandidate(i.masked_clone(anon)),
1573            SdpAttribute::Ssrc(i) => SdpAttribute::Ssrc(i.masked_clone(anon)),
1574            _ => self.clone(),
1575        }
1576    }
1577}
1578
1579#[derive(Clone, PartialEq)]
1580pub enum SdpAttributeType {
1581    BundleOnly,
1582    Candidate,
1583    DtlsMessage,
1584    EndOfCandidates,
1585    Extmap,
1586    ExtmapAllowMixed,
1587    Fingerprint,
1588    Fmtp,
1589    FrameRate,
1590    Group,
1591    IceLite,
1592    IceMismatch,
1593    IceOptions,
1594    IcePacing,
1595    IcePwd,
1596    IceUfrag,
1597    Identity,
1598    ImageAttr,
1599    Inactive,
1600    Label,
1601    MaxMessageSize,
1602    MaxPtime,
1603    Mid,
1604    Msid,
1605    MsidSemantic,
1606    Ptime,
1607    Rid,
1608    Recvonly,
1609    RemoteCandidate,
1610    Rtpmap,
1611    Rtcp,
1612    Rtcpfb,
1613    RtcpMux,
1614    RtcpMuxOnly,
1615    RtcpRsize,
1616    Sctpmap,
1617    SctpPort,
1618    Sendonly,
1619    Sendrecv,
1620    Setup,
1621    Simulcast,
1622    Ssrc,
1623    SsrcGroup,
1624}
1625
1626impl<'a> From<&'a SdpAttribute> for SdpAttributeType {
1627    fn from(other: &SdpAttribute) -> Self {
1628        match *other {
1629            SdpAttribute::BundleOnly { .. } => SdpAttributeType::BundleOnly,
1630            SdpAttribute::Candidate { .. } => SdpAttributeType::Candidate,
1631            SdpAttribute::DtlsMessage { .. } => SdpAttributeType::DtlsMessage,
1632            SdpAttribute::EndOfCandidates { .. } => SdpAttributeType::EndOfCandidates,
1633            SdpAttribute::Extmap { .. } => SdpAttributeType::Extmap,
1634            SdpAttribute::ExtmapAllowMixed { .. } => SdpAttributeType::ExtmapAllowMixed,
1635            SdpAttribute::Fingerprint { .. } => SdpAttributeType::Fingerprint,
1636            SdpAttribute::Fmtp { .. } => SdpAttributeType::Fmtp,
1637            SdpAttribute::FrameRate { .. } => SdpAttributeType::FrameRate,
1638            SdpAttribute::Group { .. } => SdpAttributeType::Group,
1639            SdpAttribute::IceLite { .. } => SdpAttributeType::IceLite,
1640            SdpAttribute::IceMismatch { .. } => SdpAttributeType::IceMismatch,
1641            SdpAttribute::IceOptions { .. } => SdpAttributeType::IceOptions,
1642            SdpAttribute::IcePacing { .. } => SdpAttributeType::IcePacing,
1643            SdpAttribute::IcePwd { .. } => SdpAttributeType::IcePwd,
1644            SdpAttribute::IceUfrag { .. } => SdpAttributeType::IceUfrag,
1645            SdpAttribute::Identity { .. } => SdpAttributeType::Identity,
1646            SdpAttribute::ImageAttr { .. } => SdpAttributeType::ImageAttr,
1647            SdpAttribute::Inactive { .. } => SdpAttributeType::Inactive,
1648            SdpAttribute::Label { .. } => SdpAttributeType::Label,
1649            SdpAttribute::MaxMessageSize { .. } => SdpAttributeType::MaxMessageSize,
1650            SdpAttribute::MaxPtime { .. } => SdpAttributeType::MaxPtime,
1651            SdpAttribute::Mid { .. } => SdpAttributeType::Mid,
1652            SdpAttribute::Msid { .. } => SdpAttributeType::Msid,
1653            SdpAttribute::MsidSemantic { .. } => SdpAttributeType::MsidSemantic,
1654            SdpAttribute::Ptime { .. } => SdpAttributeType::Ptime,
1655            SdpAttribute::Rid { .. } => SdpAttributeType::Rid,
1656            SdpAttribute::Recvonly { .. } => SdpAttributeType::Recvonly,
1657            SdpAttribute::RemoteCandidate { .. } => SdpAttributeType::RemoteCandidate,
1658            SdpAttribute::Rtcp { .. } => SdpAttributeType::Rtcp,
1659            SdpAttribute::Rtcpfb { .. } => SdpAttributeType::Rtcpfb,
1660            SdpAttribute::RtcpMux { .. } => SdpAttributeType::RtcpMux,
1661            SdpAttribute::RtcpMuxOnly { .. } => SdpAttributeType::RtcpMuxOnly,
1662            SdpAttribute::RtcpRsize { .. } => SdpAttributeType::RtcpRsize,
1663            SdpAttribute::Rtpmap { .. } => SdpAttributeType::Rtpmap,
1664            SdpAttribute::Sctpmap { .. } => SdpAttributeType::Sctpmap,
1665            SdpAttribute::SctpPort { .. } => SdpAttributeType::SctpPort,
1666            SdpAttribute::Sendonly { .. } => SdpAttributeType::Sendonly,
1667            SdpAttribute::Sendrecv { .. } => SdpAttributeType::Sendrecv,
1668            SdpAttribute::Setup { .. } => SdpAttributeType::Setup,
1669            SdpAttribute::Simulcast { .. } => SdpAttributeType::Simulcast,
1670            SdpAttribute::Ssrc { .. } => SdpAttributeType::Ssrc,
1671            SdpAttribute::SsrcGroup { .. } => SdpAttributeType::SsrcGroup,
1672        }
1673    }
1674}
1675
1676impl fmt::Display for SdpAttributeType {
1677    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1678        match *self {
1679            SdpAttributeType::BundleOnly => "bundle-only",
1680            SdpAttributeType::Candidate => "candidate",
1681            SdpAttributeType::DtlsMessage => "dtls-message",
1682            SdpAttributeType::EndOfCandidates => "end-of-candidates",
1683            SdpAttributeType::Extmap => "extmap",
1684            SdpAttributeType::ExtmapAllowMixed => "extmap-allow-mixed",
1685            SdpAttributeType::Fingerprint => "fingerprint",
1686            SdpAttributeType::Fmtp => "fmtp",
1687            SdpAttributeType::FrameRate => "framerate",
1688            SdpAttributeType::Group => "group",
1689            SdpAttributeType::IceLite => "ice-lite",
1690            SdpAttributeType::IceMismatch => "ice-mismatch",
1691            SdpAttributeType::IceOptions => "ice-options",
1692            SdpAttributeType::IcePacing => "ice-pacing",
1693            SdpAttributeType::IcePwd => "ice-pwd",
1694            SdpAttributeType::IceUfrag => "ice-ufrag",
1695            SdpAttributeType::Identity => "identity",
1696            SdpAttributeType::ImageAttr => "imageattr",
1697            SdpAttributeType::Inactive => "inactive",
1698            SdpAttributeType::Label => "label",
1699            SdpAttributeType::MaxMessageSize => "max-message-size",
1700            SdpAttributeType::MaxPtime => "maxptime",
1701            SdpAttributeType::Mid => "mid",
1702            SdpAttributeType::Msid => "msid",
1703            SdpAttributeType::MsidSemantic => "msid-semantic",
1704            SdpAttributeType::Ptime => "ptime",
1705            SdpAttributeType::Rid => "rid",
1706            SdpAttributeType::Recvonly => "recvonly",
1707            SdpAttributeType::RemoteCandidate => "remote-candidates",
1708            SdpAttributeType::Rtpmap => "rtpmap",
1709            SdpAttributeType::Rtcp => "rtcp",
1710            SdpAttributeType::Rtcpfb => "rtcp-fb",
1711            SdpAttributeType::RtcpMux => "rtcp-mux",
1712            SdpAttributeType::RtcpMuxOnly => "rtcp-mux-only",
1713            SdpAttributeType::RtcpRsize => "rtcp-rsize",
1714            SdpAttributeType::Sctpmap => "sctpmap",
1715            SdpAttributeType::SctpPort => "sctp-port",
1716            SdpAttributeType::Sendonly => "sendonly",
1717            SdpAttributeType::Sendrecv => "sendrecv",
1718            SdpAttributeType::Setup => "setup",
1719            SdpAttributeType::Simulcast => "simulcast",
1720            SdpAttributeType::Ssrc => "ssrc",
1721            SdpAttributeType::SsrcGroup => "ssrc-group",
1722        }
1723        .fmt(f)
1724    }
1725}
1726
1727fn string_or_empty(to_parse: &str) -> Result<String, SdpParserInternalError> {
1728    if to_parse.is_empty() {
1729        Err(SdpParserInternalError::Generic(
1730            "This attribute is required to have a value".to_string(),
1731        ))
1732    } else {
1733        Ok(to_parse.to_string())
1734    }
1735}
1736
1737fn parse_payload_type(to_parse: &str) -> Result<SdpAttributePayloadType, SdpParserInternalError> {
1738    Ok(match to_parse {
1739        "*" => SdpAttributePayloadType::Wildcard,
1740        _ => SdpAttributePayloadType::PayloadType(to_parse.parse::<u8>()?),
1741    })
1742}
1743
1744fn parse_single_direction(to_parse: &str) -> Result<SdpSingleDirection, SdpParserInternalError> {
1745    match to_parse {
1746        "send" => Ok(SdpSingleDirection::Send),
1747        "recv" => Ok(SdpSingleDirection::Recv),
1748        x => Err(SdpParserInternalError::Generic(format!(
1749            "Unknown direction description found: '{x:}'"
1750        ))),
1751    }
1752}
1753
1754///////////////////////////////////////////////////////////////////////////
1755// a=ssrc-group, RFC5576
1756//-------------------------------------------------------------------------
1757// a=ssrc-group:<semantics> <ssrc-id> ...
1758fn parse_ssrc_group(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
1759    let mut tokens = to_parse.split_whitespace();
1760    let semantics = match tokens.next() {
1761        None => {
1762            return Err(SdpParserInternalError::Generic(
1763                "Ssrc group attribute is missing semantics".to_string(),
1764            ));
1765        }
1766        Some(x) => match x.to_uppercase().as_ref() {
1767            "DUP" => SdpSsrcGroupSemantic::Duplication,
1768            "FID" => SdpSsrcGroupSemantic::FlowIdentification,
1769            "FEC" => SdpSsrcGroupSemantic::ForwardErrorCorrection,
1770            "FEC-FR" => SdpSsrcGroupSemantic::ForwardErrorCorrectionFr,
1771            "SIM" => SdpSsrcGroupSemantic::Sim,
1772            unknown => {
1773                return Err(SdpParserInternalError::Unsupported(format!(
1774                    "Unknown ssrc semantic '{unknown:?}' found"
1775                )));
1776            }
1777        },
1778    };
1779
1780    let mut ssrcs = Vec::new();
1781    for token in tokens {
1782        match parse_ssrc(token) {
1783            Ok(SdpAttribute::Ssrc(ssrc)) => {
1784                ssrcs.push(ssrc);
1785            }
1786            Err(err) => {
1787                return Err(err);
1788            }
1789            _ => unreachable!(),
1790        }
1791    }
1792
1793    if ssrcs.is_empty() {
1794        return Err(SdpParserInternalError::Generic(
1795            "Ssrc group must contain at least one ssrc".to_string(),
1796        ));
1797    }
1798
1799    Ok(SdpAttribute::SsrcGroup(semantics, ssrcs))
1800}
1801
1802///////////////////////////////////////////////////////////////////////////
1803// a=sctp-port, draft-ietf-mmusic-sctp-sdp-26#section-15.2.1
1804//-------------------------------------------------------------------------
1805// no ABNF given
1806fn parse_sctp_port(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
1807    let port = to_parse.parse()?;
1808    if port > 65535 {
1809        return Err(SdpParserInternalError::Generic(format!(
1810            "Sctpport port {port} can only be a bit 16bit number"
1811        )));
1812    }
1813    Ok(SdpAttribute::SctpPort(port))
1814}
1815
1816///////////////////////////////////////////////////////////////////////////
1817// a=candidate, RFC5245
1818//-------------------------------------------------------------------------
1819//
1820// candidate-attribute   = "candidate" ":" foundation SP component-id SP
1821//                          transport SP
1822//                          priority SP
1823//                          connection-address SP     ;from RFC 4566
1824//                          port         ;port from RFC 4566
1825//                          SP cand-type
1826//                          [SP rel-addr]
1827//                          [SP rel-port]
1828//                          *(SP extension-att-name SP
1829//                               extension-att-value)
1830// foundation            = 1*32ice-char
1831// component-id          = 1*5DIGIT
1832// transport             = "UDP" / transport-extension
1833// transport-extension   = token              ; from RFC 3261
1834// priority              = 1*10DIGIT
1835// cand-type             = "typ" SP candidate-types
1836// candidate-types       = "host" / "srflx" / "prflx" / "relay" / token
1837// rel-addr              = "raddr" SP connection-address
1838// rel-port              = "rport" SP port
1839// extension-att-name    = byte-string    ;from RFC 4566
1840// extension-att-value   = byte-string
1841// ice-char              = ALPHA / DIGIT / "+" / "/"
1842fn parse_candidate(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
1843    let tokens: Vec<&str> = to_parse.split_whitespace().collect();
1844    if tokens.len() < 8 {
1845        return Err(SdpParserInternalError::Generic(
1846            "Candidate needs to have minimum eigth tokens".to_string(),
1847        ));
1848    }
1849    let component = tokens[1].parse::<u32>()?;
1850    let transport = match tokens[2].to_lowercase().as_ref() {
1851        "udp" => SdpAttributeCandidateTransport::Udp,
1852        "tcp" => SdpAttributeCandidateTransport::Tcp,
1853        _ => {
1854            return Err(SdpParserInternalError::Generic(
1855                "Unknonw candidate transport value".to_string(),
1856            ));
1857        }
1858    };
1859    let priority = tokens[3].parse::<u64>()?;
1860    let address = Address::from_str(tokens[4])?;
1861    let port = tokens[5].parse::<u32>()?;
1862    if port > 65535 {
1863        return Err(SdpParserInternalError::Generic(
1864            "ICE candidate port can only be a bit 16bit number".to_string(),
1865        ));
1866    }
1867    match tokens[6].to_lowercase().as_ref() {
1868        "typ" => (),
1869        _ => {
1870            return Err(SdpParserInternalError::Generic(
1871                "Candidate attribute token must be 'typ'".to_string(),
1872            ));
1873        }
1874    };
1875    let cand_type = match tokens[7].to_lowercase().as_ref() {
1876        "host" => SdpAttributeCandidateType::Host,
1877        "srflx" => SdpAttributeCandidateType::Srflx,
1878        "prflx" => SdpAttributeCandidateType::Prflx,
1879        "relay" => SdpAttributeCandidateType::Relay,
1880        _ => {
1881            return Err(SdpParserInternalError::Generic(
1882                "Unknow candidate type value".to_string(),
1883            ));
1884        }
1885    };
1886    let mut cand = SdpAttributeCandidate::new(
1887        tokens[0].to_string(),
1888        component,
1889        transport,
1890        priority,
1891        address,
1892        port,
1893        cand_type,
1894    );
1895    if tokens.len() > 8 {
1896        let mut index = 8;
1897        while tokens.len() > index + 1 {
1898            match tokens[index].to_lowercase().as_ref() {
1899                "generation" => {
1900                    let generation = tokens[index + 1].parse::<u32>()?;
1901                    cand.set_generation(generation);
1902                    index += 2;
1903                }
1904                "network-cost" => {
1905                    let cost = tokens[index + 1].parse::<u32>()?;
1906                    cand.set_network_cost(cost);
1907                    index += 2;
1908                }
1909                "raddr" => {
1910                    let addr = parse_unicast_address(tokens[index + 1])?;
1911                    cand.set_remote_address(addr);
1912                    index += 2;
1913                }
1914                "rport" => {
1915                    let port = tokens[index + 1].parse::<u32>()?;
1916                    if port > 65535 {
1917                        return Err(SdpParserInternalError::Generic(
1918                            "ICE candidate rport can only be a bit 16bit number".to_string(),
1919                        ));
1920                    }
1921                    cand.set_remote_port(port);
1922                    index += 2;
1923                }
1924                "tcptype" => {
1925                    cand.set_tcp_type(match tokens[index + 1].to_lowercase().as_ref() {
1926                        "active" => SdpAttributeCandidateTcpType::Active,
1927                        "passive" => SdpAttributeCandidateTcpType::Passive,
1928                        "so" => SdpAttributeCandidateTcpType::Simultaneous,
1929                        _ => {
1930                            return Err(SdpParserInternalError::Generic(
1931                                "Unknown tcptype value in candidate line".to_string(),
1932                            ));
1933                        }
1934                    });
1935                    index += 2;
1936                }
1937                "ufrag" => {
1938                    let ufrag = tokens[index + 1];
1939                    cand.set_ufrag(ufrag.to_string());
1940                    index += 2;
1941                }
1942                _ => {
1943                    let name = tokens[index].to_string();
1944                    let value = tokens[index + 1].to_string();
1945                    cand.add_unknown_extension(name, value);
1946                    index += 2;
1947                }
1948            };
1949        }
1950        if tokens.len() > index {
1951            return Err(SdpParserInternalError::Unsupported(
1952                "Ice candidate extension name without value".to_string(),
1953            ));
1954        }
1955    }
1956    Ok(SdpAttribute::Candidate(cand))
1957}
1958
1959///////////////////////////////////////////////////////////////////////////
1960// a=dtls-message, draft-rescorla-dtls-in-sdp
1961//-------------------------------------------------------------------------
1962//   attribute               =/   dtls-message-attribute
1963//
1964//   dtls-message-attribute  =    "dtls-message" ":" role SP value
1965//
1966//   role                    =    "client" / "server"
1967//
1968//   value                   =    1*(ALPHA / DIGIT / "+" / "/" / "=" )
1969//                                ; base64 encoded message
1970fn parse_dtls_message(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
1971    let tokens: Vec<&str> = to_parse.split(' ').collect();
1972
1973    if tokens.len() != 2 {
1974        return Err(SdpParserInternalError::Generic(
1975            "dtls-message must have a role token and a value token.".to_string(),
1976        ));
1977    }
1978
1979    Ok(SdpAttribute::DtlsMessage(match tokens[0] {
1980        "client" => SdpAttributeDtlsMessage::Client(tokens[1].to_string()),
1981        "server" => SdpAttributeDtlsMessage::Server(tokens[1].to_string()),
1982        e => {
1983            return Err(SdpParserInternalError::Generic(format!(
1984                "dtls-message has unknown role token '{e}'"
1985            )));
1986        }
1987    }))
1988}
1989
1990// Returns true if valid byte-string as defined by RFC 4566
1991// https://tools.ietf.org/html/rfc4566
1992fn valid_byte_string(input: &str) -> bool {
1993    !(input.contains(0x00 as char) || input.contains(0x0A as char) || input.contains(0x0D as char))
1994}
1995
1996///////////////////////////////////////////////////////////////////////////
1997// a=extmap, RFC5285
1998//-------------------------------------------------------------------------
1999// RFC5285
2000//        extmap = mapentry SP extensionname [SP extensionattributes]
2001//
2002//        extensionname = URI
2003//
2004//        direction = "sendonly" / "recvonly" / "sendrecv" / "inactive"
2005//
2006//        mapentry = "extmap:" 1*5DIGIT ["/" direction]
2007//
2008//        extensionattributes = byte-string
2009//
2010//        URI = <Defined in RFC 3986>
2011//
2012//        byte-string = <Defined in RFC 4566>
2013//
2014//        SP = <Defined in RFC 5234>
2015//
2016//        DIGIT = <Defined in RFC 5234>
2017fn parse_extmap(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2018    let tokens: Vec<&str> = to_parse.split_whitespace().collect();
2019    if tokens.len() < 2 {
2020        return Err(SdpParserInternalError::Generic(
2021            "Extmap needs to have at least two tokens".to_string(),
2022        ));
2023    }
2024    let id: u16;
2025    let mut direction: Option<SdpAttributeDirection> = None;
2026    if tokens[0].find('/').is_none() {
2027        id = tokens[0].parse::<u16>()?;
2028    } else {
2029        let id_dir: Vec<&str> = tokens[0].splitn(2, '/').collect();
2030        id = id_dir[0].parse::<u16>()?;
2031        direction = Some(match id_dir[1].to_lowercase().as_ref() {
2032            "recvonly" => SdpAttributeDirection::Recvonly,
2033            "sendonly" => SdpAttributeDirection::Sendonly,
2034            "sendrecv" => SdpAttributeDirection::Sendrecv,
2035            _ => {
2036                return Err(SdpParserInternalError::Generic(
2037                    "Unsupported direction in extmap value".to_string(),
2038                ));
2039            }
2040        })
2041    }
2042    // Consider replacing to_parse.split_whitespace() above with splitn on space. Would we want the pattern to split on any amout of any kind of whitespace?
2043    let extension_attributes = if tokens.len() == 2 {
2044        None
2045    } else {
2046        let ext_string: String = tokens[2..].join(" ");
2047        if !valid_byte_string(&ext_string) {
2048            return Err(SdpParserInternalError::Generic(
2049                "Illegal character in extmap extension attributes".to_string(),
2050            ));
2051        }
2052        Some(ext_string)
2053    };
2054    Ok(SdpAttribute::Extmap(SdpAttributeExtmap {
2055        id,
2056        direction,
2057        url: tokens[1].to_string(),
2058        extension_attributes,
2059    }))
2060}
2061
2062///////////////////////////////////////////////////////////////////////////
2063// a=fingerprint, RFC4572
2064//-------------------------------------------------------------------------
2065//   fingerprint-attribute  =  "fingerprint" ":" hash-func SP fingerprint
2066//
2067//   hash-func              =  "sha-1" / "sha-224" / "sha-256" /
2068//                             "sha-384" / "sha-512" /
2069//                             "md5" / "md2" / token
2070//                             ; Additional hash functions can only come
2071//                             ; from updates to RFC 3279
2072//
2073//   fingerprint            =  2UHEX *(":" 2UHEX)
2074//                             ; Each byte in upper-case hex, separated
2075//                             ; by colons.
2076//
2077//   UHEX                   =  DIGIT / %x41-46 ; A-F uppercase
2078fn parse_fingerprint(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2079    let tokens: Vec<&str> = to_parse.split_whitespace().collect();
2080    if tokens.len() != 2 {
2081        return Err(SdpParserInternalError::Generic(
2082            "Fingerprint needs to have two tokens".to_string(),
2083        ));
2084    }
2085
2086    let hash_algorithm = SdpAttributeFingerprintHashType::try_from_name(tokens[0])?;
2087    let bytes = hash_algorithm.parse_octets(tokens[1])?;
2088    let fingerprint = SdpAttributeFingerprint::try_from((hash_algorithm, bytes))?;
2089    Ok(SdpAttribute::Fingerprint(fingerprint))
2090}
2091
2092///////////////////////////////////////////////////////////////////////////
2093// a=fmtp, RFC4566, RFC5576
2094//-------------------------------------------------------------------------
2095//       a=fmtp:<format> <format specific parameters>
2096fn parse_fmtp(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2097    let tokens: Vec<&str> = to_parse.splitn(2, ' ').collect();
2098
2099    // Support space seperated parameter blocks
2100    if tokens.len() != 2 {
2101        return Err(SdpParserInternalError::Unsupported(
2102            "Fmtp attributes require a payload type and a parameter block.".to_string(),
2103        ));
2104    }
2105
2106    let payload_token = tokens[0];
2107
2108    // Default initiliaze SdpAttributeFmtpParameters
2109    let mut parameters = SdpAttributeFmtpParameters {
2110        packetization_mode: 0,
2111        level_asymmetry_allowed: false,
2112        profile_level_id: 0x0042_0010,
2113        max_fs: 0,
2114        max_cpb: 0,
2115        max_dpb: 0,
2116        max_br: 0,
2117        max_mbps: 0,
2118        usedtx: false,
2119        stereo: false,
2120        useinbandfec: false,
2121        cbr: false,
2122        max_fr: 0,
2123        profile: None,
2124        level_idx: None,
2125        tier: None,
2126        maxplaybackrate: 48000,
2127        maxaveragebitrate: 0,
2128        ptime: 0,
2129        minptime: 0,
2130        maxptime: 0,
2131        encodings: Vec::new(),
2132        dtmf_tones: "".to_string(),
2133        rtx: None,
2134        unknown_tokens: Vec::new(),
2135    };
2136
2137    for parameter_token in tokens[1..].iter() {
2138        if parameter_token.contains('=') {
2139            // Permit Leading/Trailing/Inner ';' by filtering out empty splits
2140            let parameter_tokens: Vec<&str> = parameter_token
2141                .split(';')
2142                .filter(|token| !token.is_empty())
2143                .collect();
2144            for parameter_token in parameter_tokens.iter() {
2145                let name_value_pair: Vec<&str> = parameter_token.splitn(2, '=').collect();
2146                if name_value_pair.len() != 2 {
2147                    return Err(SdpParserInternalError::Generic(
2148                        "A fmtp parameter must be either a telephone event, a parameter list or a red codec list"
2149                            .to_string(),
2150                    ));
2151                }
2152
2153                let parse_bool =
2154                    |val: &str, param_name: &str| -> Result<bool, SdpParserInternalError> {
2155                        match val.parse::<u8>()? {
2156                            0 => Ok(false),
2157                            1 => Ok(true),
2158                            _ => Err(SdpParserInternalError::Generic(format!(
2159                                "The fmtp parameter '{param_name:}' must be 0 or 1"
2160                            ))),
2161                        }
2162                    };
2163
2164                let parameter_name = name_value_pair[0];
2165                let parameter_val = name_value_pair[1];
2166
2167                match parameter_name.to_uppercase().as_str() {
2168                    // H264
2169                    "PROFILE-LEVEL-ID" => parameters.profile_level_id = match u32::from_str_radix(
2170                        parameter_val,
2171                        16,
2172                    )? {
2173                        x @ 0..=0x00ff_ffff => x,
2174                        _ => return Err(SdpParserInternalError::Generic(
2175                            "The fmtp parameter 'profile-level-id' must be in range [0,0xffffff]"
2176                                .to_string(),
2177                        )),
2178                    },
2179                    "PACKETIZATION-MODE" => {
2180                        parameters.packetization_mode = match parameter_val.parse::<u32>()? {
2181                            x @ 0..=2 => x,
2182                            _ => {
2183                                return Err(SdpParserInternalError::Generic(
2184                                    "The fmtp parameter 'packetization-mode' must be 0,1 or 2"
2185                                        .to_string(),
2186                                ));
2187                            }
2188                        }
2189                    }
2190                    "LEVEL-ASYMMETRY-ALLOWED" => {
2191                        parameters.level_asymmetry_allowed =
2192                            parse_bool(parameter_val, "level-asymmetry-allowed")?
2193                    }
2194                    "MAX-MBPS" => parameters.max_mbps = parameter_val.parse::<u32>()?,
2195                    "MAX-FS" => parameters.max_fs = parameter_val.parse::<u32>()?,
2196                    "MAX-CPB" => parameters.max_cpb = parameter_val.parse::<u32>()?,
2197                    "MAX-DPB" => parameters.max_dpb = parameter_val.parse::<u32>()?,
2198                    "MAX-BR" => parameters.max_br = parameter_val.parse::<u32>()?,
2199
2200                    // VP8 and VP9
2201                    "MAX-FR" => parameters.max_fr = parameter_val.parse::<u32>()?,
2202
2203                    // AV1
2204                    "PROFILE" => {
2205                        parameters.profile = match parameter_val.parse::<u8>()? {
2206                            x @ 0..=2 => Some(x),
2207                            _ => {
2208                                return Err(SdpParserInternalError::Generic(
2209                                    "The fmtp parameter 'profile' must be in the range [0,2]"
2210                                        .to_string(),
2211                                ));
2212                            }
2213                        }
2214                    }
2215                    "LEVEL-IDX" => {
2216                        parameters.level_idx = match parameter_val.parse::<u8>()? {
2217                            x @ 0..=31 => Some(x),
2218                            _ => {
2219                                return Err(SdpParserInternalError::Generic(
2220                                    "The fmtp parameter 'level-idx' must be in the range [0,31]"
2221                                        .to_string(),
2222                                ));
2223                            }
2224                        }
2225                    }
2226                    "TIER" => {
2227                        parameters.tier = match parameter_val.parse::<u8>()? {
2228                            x @ 0..=1 => Some(x),
2229                            _ => {
2230                                return Err(SdpParserInternalError::Generic(
2231                                    "The fmtp parameter 'tier' must be in the range [0,1]"
2232                                        .to_string(),
2233                                ));
2234                            }
2235                        }
2236                    }
2237                    //Opus https://tools.ietf.org/html/rfc7587
2238                    "MAXPLAYBACKRATE" => {
2239                        parameters.maxplaybackrate = parameter_val.parse::<u32>()?
2240                    }
2241                    "MAXAVERAGEBITRATE" => {
2242                        parameters.maxaveragebitrate = parameter_val.parse::<u32>()?
2243                    }
2244                    "PTIME" => parameters.ptime = parameter_val.parse::<u32>()?,
2245                    "MAXPTIME" => parameters.maxptime = parameter_val.parse::<u32>()?,
2246                    "MINPTIME" => parameters.minptime = parameter_val.parse::<u32>()?,
2247                    "USEDTX" => parameters.usedtx = parse_bool(parameter_val, "usedtx")?,
2248                    "STEREO" => parameters.stereo = parse_bool(parameter_val, "stereo")?,
2249                    "USEINBANDFEC" => {
2250                        parameters.useinbandfec = parse_bool(parameter_val, "useinbandfec")?
2251                    }
2252                    "CBR" => parameters.cbr = parse_bool(parameter_val, "cbr")?,
2253                    "APT" => {
2254                        parameters.rtx = Some(RtxFmtpParameters {
2255                            apt: parameter_val.parse::<u8>()?,
2256                            rtx_time: None,
2257                        })
2258                    }
2259                    "RTX-TIME" => {
2260                        if let Some(ref mut rtx) = parameters.rtx {
2261                            rtx.rtx_time = Some(parameter_val.parse::<u32>()?)
2262                        } else {
2263                            return Err(SdpParserInternalError::Generic(
2264                                "RTX codec must have an APT field".to_string(),
2265                            ));
2266                        }
2267                    }
2268                    _ => parameters
2269                        .unknown_tokens
2270                        .push((*parameter_token).to_string()),
2271                }
2272            }
2273        } else if parameter_token.contains('/') {
2274            let encodings: Vec<&str> = parameter_token.split('/').collect();
2275
2276            for encoding in encodings {
2277                match encoding.parse::<u8>()? {
2278                    x @ 0..=128 => parameters.encodings.push(x),
2279                    _ => {
2280                        return Err(SdpParserInternalError::Generic(
2281                            "Red codec must be in range [0,128]".to_string(),
2282                        ));
2283                    }
2284                }
2285            }
2286        } else {
2287            // This is the case for the 'telephone-event' codec
2288            let dtmf_tones: Vec<&str> = parameter_token.split(',').collect();
2289            let mut dtmf_tone_is_ok = true;
2290
2291            // This closure verifies the output of some_number_as_string.parse::<u8>().ok() like calls
2292            let validate_digits = |digit_option: Option<u8>| -> Option<u8> {
2293                match digit_option {
2294                    Some(x) => match x {
2295                        0..=100 => Some(x),
2296                        _ => None,
2297                    },
2298                    None => None,
2299                }
2300            };
2301
2302            // This loop does some sanity checking on the passed dtmf tones
2303            for dtmf_tone in dtmf_tones {
2304                let dtmf_tone_range: Vec<&str> = dtmf_tone.splitn(2, '-').collect();
2305
2306                dtmf_tone_is_ok = match dtmf_tone_range.len() {
2307                    // In this case the dtmf tone is a range
2308                    2 => {
2309                        match validate_digits(dtmf_tone_range[0].parse::<u8>().ok()) {
2310                            Some(l) => match validate_digits(dtmf_tone_range[1].parse::<u8>().ok())
2311                            {
2312                                Some(u) => {
2313                                    // Check that the first part of the range is smaller than the second part
2314                                    l < u
2315                                }
2316                                None => false,
2317                            },
2318                            None => false,
2319                        }
2320                    }
2321                    // In this case the dtmf tone is a single tone
2322                    1 => validate_digits(dtmf_tone.parse::<u8>().ok()).is_some(),
2323                    _ => false,
2324                };
2325
2326                if !dtmf_tone_is_ok {
2327                    break;
2328                }
2329            }
2330
2331            // Set the parsed dtmf tones or in case the parsing was insuccessfull, set it to the default "0-15"
2332            parameters.dtmf_tones = if dtmf_tone_is_ok {
2333                (*parameter_token).to_string()
2334            } else {
2335                "0-15".to_string()
2336            };
2337        }
2338    }
2339    Ok(SdpAttribute::Fmtp(SdpAttributeFmtp {
2340        payload_type: payload_token.parse::<u8>()?,
2341        parameters,
2342    }))
2343}
2344
2345///////////////////////////////////////////////////////////////////////////
2346// a=framerate, RFC4566, RFC8866
2347//-------------------------------------------------------------------------
2348//       a=framerate:<framerate-value>
2349fn parse_framerate(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2350    let framerate: f64 = to_parse.parse()?;
2351
2352    if framerate.is_nan() {
2353        return Err(SdpParserInternalError::Generic(
2354            "FrameRate attribute must be a number".to_string(),
2355        ));
2356    }
2357
2358    if framerate.is_infinite() {
2359        return Err(SdpParserInternalError::Generic(
2360            "FrameRate attribute cannot be finite".to_string(),
2361        ));
2362    }
2363
2364    if framerate == 0.0 {
2365        return Err(SdpParserInternalError::Generic(
2366            "FrameRate attribute cannot be zero".to_string(),
2367        ));
2368    }
2369
2370    Ok(SdpAttribute::FrameRate(framerate))
2371}
2372
2373///////////////////////////////////////////////////////////////////////////
2374// a=group, RFC5888
2375//-------------------------------------------------------------------------
2376//         group-attribute     = "a=group:" semantics
2377//                               *(SP identification-tag)
2378//         semantics           = "LS" / "FID" / semantics-extension
2379//         semantics-extension = token
2380//         identification-tag  = token
2381fn parse_group(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2382    let mut tokens = to_parse.split_whitespace();
2383    let semantics = match tokens.next() {
2384        None => {
2385            return Err(SdpParserInternalError::Generic(
2386                "Group attribute is missing semantics token".to_string(),
2387            ));
2388        }
2389        Some(x) => match x.to_uppercase().as_ref() {
2390            "LS" => SdpAttributeGroupSemantic::LipSynchronization,
2391            "FID" => SdpAttributeGroupSemantic::FlowIdentification,
2392            "SRF" => SdpAttributeGroupSemantic::SingleReservationFlow,
2393            "ANAT" => SdpAttributeGroupSemantic::AlternateNetworkAddressType,
2394            "FEC" => SdpAttributeGroupSemantic::ForwardErrorCorrection,
2395            "DDP" => SdpAttributeGroupSemantic::DecodingDependency,
2396            "BUNDLE" => SdpAttributeGroupSemantic::Bundle,
2397            unknown => {
2398                return Err(SdpParserInternalError::Unsupported(format!(
2399                    "Unknown group semantic '{unknown:?}' found",
2400                )));
2401            }
2402        },
2403    };
2404    Ok(SdpAttribute::Group(SdpAttributeGroup {
2405        semantics,
2406        tags: tokens.map(ToString::to_string).collect(),
2407    }))
2408}
2409
2410///////////////////////////////////////////////////////////////////////////
2411// a=ice-options, draft-ietf-mmusic-ice-sip-sdp
2412//-------------------------------------------------------------------------
2413//  ice-options           = "ice-options:" ice-option-tag
2414//                           0*(SP ice-option-tag)
2415//  ice-option-tag        = 1*ice-char
2416fn parse_ice_options(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2417    if to_parse.is_empty() {
2418        return Err(SdpParserInternalError::Generic(
2419            "ice-options is required to have a value".to_string(),
2420        ));
2421    }
2422    Ok(SdpAttribute::IceOptions(
2423        to_parse
2424            .split_whitespace()
2425            .map(ToString::to_string)
2426            .collect(),
2427    ))
2428}
2429
2430///////////////////////////////////////////////////////////////////////////
2431// a=ice-pacing, draft-ietf-mmusic-ice-sip-sdp
2432//-------------------------------------------------------------------------
2433//  ice-pacing-att            = "ice-pacing:" pacing-value
2434//  pacing-value              = 1*10DIGIT
2435fn parse_ice_pacing(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2436    let parsed = to_parse.parse::<u64>()?;
2437    if parsed >= 1_00_00_00_00_00 {
2438        return Err(SdpParserInternalError::Generic(
2439            "ice-pacing value is not a 10 digit integer".to_string(),
2440        ));
2441    }
2442    Ok(SdpAttribute::IcePacing(parsed))
2443}
2444
2445fn parse_imageattr_tokens(to_parse: &str, separator: char) -> Vec<String> {
2446    let mut tokens = Vec::new();
2447    let mut open_braces_counter = 0;
2448    let mut current_tokens = Vec::new();
2449
2450    for token in to_parse.split(separator) {
2451        if token.contains('[') {
2452            open_braces_counter += 1;
2453        }
2454        if token.contains(']') {
2455            open_braces_counter -= 1;
2456        }
2457
2458        current_tokens.push(token.to_string());
2459
2460        if open_braces_counter == 0 {
2461            tokens.push(current_tokens.join(&separator.to_string()));
2462            current_tokens = Vec::new();
2463        }
2464    }
2465
2466    tokens
2467}
2468
2469fn parse_imagettr_braced_token(to_parse: &str) -> Option<&str> {
2470    if !to_parse.starts_with('[') {
2471        return None;
2472    }
2473
2474    if !to_parse.ends_with(']') {
2475        return None;
2476    }
2477
2478    Some(&to_parse[1..to_parse.len() - 1])
2479}
2480
2481fn parse_image_attr_xyrange(
2482    to_parse: &str,
2483) -> Result<SdpAttributeImageAttrXyRange, SdpParserInternalError> {
2484    if to_parse.starts_with('[') {
2485        let value_tokens = parse_imagettr_braced_token(to_parse).ok_or_else(|| {
2486            SdpParserInternalError::Generic(
2487                "imageattr's xyrange has no closing tag ']'".to_string(),
2488            )
2489        })?;
2490
2491        if to_parse.contains(':') {
2492            // Range values
2493            let range_tokens: Vec<&str> = value_tokens.split(':').collect();
2494
2495            if range_tokens.len() == 3 {
2496                Ok(SdpAttributeImageAttrXyRange::Range(
2497                    range_tokens[0].parse::<u32>()?,
2498                    range_tokens[2].parse::<u32>()?,
2499                    Some(range_tokens[1].parse::<u32>()?),
2500                ))
2501            } else if range_tokens.len() == 2 {
2502                Ok(SdpAttributeImageAttrXyRange::Range(
2503                    range_tokens[0].parse::<u32>()?,
2504                    range_tokens[1].parse::<u32>()?,
2505                    None,
2506                ))
2507            } else {
2508                Err(SdpParserInternalError::Generic(
2509                    "imageattr's xyrange must contain 2 or 3 fields".to_string(),
2510                ))
2511            }
2512        } else {
2513            // Discrete values
2514            let values = value_tokens
2515                .split(',')
2516                .map(str::parse::<u32>)
2517                .collect::<Result<Vec<u32>, _>>()?;
2518
2519            if values.len() < 2 {
2520                return Err(SdpParserInternalError::Generic(
2521                    "imageattr's discrete value list must have at least two elements".to_string(),
2522                ));
2523            }
2524
2525            Ok(SdpAttributeImageAttrXyRange::DiscreteValues(values))
2526        }
2527    } else {
2528        Ok(SdpAttributeImageAttrXyRange::DiscreteValues(vec![
2529            to_parse.parse::<u32>()?
2530        ]))
2531    }
2532}
2533
2534fn parse_image_attr_set(
2535    to_parse: &str,
2536) -> Result<SdpAttributeImageAttrSet, SdpParserInternalError> {
2537    let mut tokens = parse_imageattr_tokens(to_parse, ',').into_iter();
2538
2539    let x_token = tokens.next().ok_or_else(|| {
2540        SdpParserInternalError::Generic("imageattr set is missing the 'x=' token".to_string())
2541    })?;
2542    if !x_token.starts_with("x=") {
2543        return Err(SdpParserInternalError::Generic(
2544            "The first token in an imageattr set must begin with 'x='".to_string(),
2545        ));
2546    }
2547    let x = parse_image_attr_xyrange(&x_token[2..])?;
2548
2549    let y_token = tokens.next().ok_or_else(|| {
2550        SdpParserInternalError::Generic("imageattr set is missing the 'y=' token".to_string())
2551    })?;
2552    if !y_token.starts_with("y=") {
2553        return Err(SdpParserInternalError::Generic(
2554            "The second token in an imageattr set must begin with 'y='".to_string(),
2555        ));
2556    }
2557    let y = parse_image_attr_xyrange(&y_token[2..])?;
2558
2559    let mut sar = None;
2560    let mut par = None;
2561    let mut q = None;
2562
2563    let parse_ps_range = |resolution_range: &str| -> Result<(f32, f32), SdpParserInternalError> {
2564        let minmax_pair: Vec<&str> = resolution_range.split('-').collect();
2565
2566        if minmax_pair.len() != 2 {
2567            return Err(SdpParserInternalError::Generic(
2568                "imageattr's par and sar ranges must have two components".to_string(),
2569            ));
2570        }
2571
2572        let min = minmax_pair[0].parse::<f32>()?;
2573        let max = minmax_pair[1].parse::<f32>()?;
2574
2575        if min >= max {
2576            return Err(SdpParserInternalError::Generic(
2577                "In imageattr's par and sar ranges, first must be < than the second".to_string(),
2578            ));
2579        }
2580
2581        Ok((min, max))
2582    };
2583
2584    for current_token in tokens {
2585        if let Some(value_token) = current_token.strip_prefix("sar=") {
2586            if value_token.starts_with('[') {
2587                let sar_values = parse_imagettr_braced_token(value_token).ok_or_else(|| {
2588                    SdpParserInternalError::Generic(
2589                        "imageattr's sar value is missing closing tag ']'".to_string(),
2590                    )
2591                })?;
2592
2593                if value_token.contains('-') {
2594                    // Range
2595                    let range = parse_ps_range(sar_values)?;
2596                    sar = Some(SdpAttributeImageAttrSRange::Range(range.0, range.1))
2597                } else if value_token.contains(',') {
2598                    // Discrete values
2599                    let values = sar_values
2600                        .split(',')
2601                        .map(str::parse::<f32>)
2602                        .collect::<Result<Vec<f32>, _>>()?;
2603
2604                    if values.len() < 2 {
2605                        return Err(SdpParserInternalError::Generic(
2606                            "imageattr's sar discrete value list must have at least two values"
2607                                .to_string(),
2608                        ));
2609                    }
2610
2611                    // Check that all the values are ascending
2612                    let mut last_value = 0.0;
2613                    for value in &values {
2614                        if last_value >= *value {
2615                            return Err(SdpParserInternalError::Generic(
2616                                "imageattr's sar discrete value list must contain ascending values"
2617                                    .to_string(),
2618                            ));
2619                        }
2620                        last_value = *value;
2621                    }
2622                    sar = Some(SdpAttributeImageAttrSRange::DiscreteValues(values))
2623                }
2624            } else {
2625                sar = Some(SdpAttributeImageAttrSRange::DiscreteValues(vec![
2626                    value_token.parse::<f32>()?,
2627                ]))
2628            }
2629        } else if let Some(braced_value_token) = current_token.strip_prefix("par=") {
2630            if !braced_value_token.starts_with('[') {
2631                return Err(SdpParserInternalError::Generic(
2632                    "imageattr's par value must start with '['".to_string(),
2633                ));
2634            }
2635
2636            let par_values = parse_imagettr_braced_token(braced_value_token).ok_or_else(|| {
2637                SdpParserInternalError::Generic(
2638                    "imageattr's par value must be enclosed with ']'".to_string(),
2639                )
2640            })?;
2641            let range = parse_ps_range(par_values)?;
2642            par = Some(SdpAttributeImageAttrPRange {
2643                min: range.0,
2644                max: range.1,
2645            })
2646        } else if let Some(qval) = current_token.strip_prefix("q=") {
2647            q = Some(qval.parse::<f32>()?);
2648        }
2649    }
2650
2651    Ok(SdpAttributeImageAttrSet { x, y, sar, par, q })
2652}
2653
2654fn parse_image_attr_set_list<I>(
2655    tokens: &mut iter::Peekable<I>,
2656) -> Result<SdpAttributeImageAttrSetList, SdpParserInternalError>
2657where
2658    I: Iterator<Item = String> + Clone,
2659{
2660    let parse_set = |set_token: &str| -> Result<SdpAttributeImageAttrSet, SdpParserInternalError> {
2661        parse_image_attr_set(parse_imagettr_braced_token(set_token).ok_or_else(|| {
2662            SdpParserInternalError::Generic("imageattr sets must be enclosed by ']'".to_string())
2663        })?)
2664    };
2665
2666    match tokens
2667        .next()
2668        .ok_or_else(|| {
2669            SdpParserInternalError::Generic(
2670                "imageattr must have a parameter set after a direction token".to_string(),
2671            )
2672        })?
2673        .as_str()
2674    {
2675        "*" => Ok(SdpAttributeImageAttrSetList::Wildcard),
2676        x => {
2677            let mut sets = vec![parse_set(x)?];
2678            while let Some(set_str) = tokens.clone().peek() {
2679                if set_str.starts_with('[') {
2680                    sets.push(parse_set(&tokens.next().unwrap())?);
2681                } else {
2682                    break;
2683                }
2684            }
2685
2686            Ok(SdpAttributeImageAttrSetList::Sets(sets))
2687        }
2688    }
2689}
2690
2691///////////////////////////////////////////////////////////////////////////
2692// a=imageattr, RFC6236
2693//-------------------------------------------------------------------------
2694//     image-attr = "imageattr:" PT 1*2( 1*WSP ( "send" / "recv" )
2695//                                       1*WSP attr-list )
2696//     PT = 1*DIGIT / "*"
2697//     attr-list = ( set *(1*WSP set) ) / "*"
2698//       ;  WSP and DIGIT defined in [RFC5234]
2699//
2700//     set= "[" "x=" xyrange "," "y=" xyrange *( "," key-value ) "]"
2701//                ; x is the horizontal image size range (pixel count)
2702//                ; y is the vertical image size range (pixel count)
2703//
2704//     key-value = ( "sar=" srange )
2705//               / ( "par=" prange )
2706//               / ( "q=" qvalue )
2707//                ; Key-value MAY be extended with other keyword
2708//                ;  parameters.
2709//                ; At most, one instance each of sar, par, or q
2710//                ;  is allowed in a set.
2711//                ;
2712//                ; sar (sample aspect ratio) is the sample aspect ratio
2713//                ;  associated with the set (optional, MAY be ignored)
2714//                ; par (picture aspect ratio) is the allowed
2715//                ;  ratio between the display's x and y physical
2716//                ;  size (optional)
2717//                ; q (optional, range [0.0..1.0], default value 0.5)
2718//                ;  is the preference for the given set,
2719//                ;  a higher value means a higher preference
2720//
2721//     onetonine = "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
2722//                ; Digit between 1 and 9
2723//     xyvalue = onetonine *5DIGIT
2724//                ; Digit between 1 and 9 that is
2725//                ; followed by 0 to 5 other digits
2726//     step = xyvalue
2727//     xyrange = ( "[" xyvalue ":" [ step ":" ] xyvalue "]" )
2728//                ; Range between a lower and an upper value
2729//                ; with an optional step, default step = 1
2730//                ; The rightmost occurrence of xyvalue MUST have a
2731//                ; higher value than the leftmost occurrence.
2732//             / ( "[" xyvalue 1*( "," xyvalue ) "]" )
2733//                ; Discrete values separated by ','
2734//             / ( xyvalue )
2735//                ; A single value
2736//     spvalue = ( "0" "." onetonine *3DIGIT )
2737//                ; Values between 0.1000 and 0.9999
2738//             / ( onetonine "." 1*4DIGIT )
2739//                ; Values between 1.0000 and 9.9999
2740//     srange =  ( "[" spvalue 1*( "," spvalue ) "]" )
2741//                ; Discrete values separated by ','.
2742//                ; Each occurrence of spvalue MUST be
2743//                ; greater than the previous occurrence.
2744//             / ( "[" spvalue "-" spvalue "]" )
2745//                ; Range between a lower and an upper level (inclusive)
2746//                ; The second occurrence of spvalue MUST have a higher
2747//                ; value than the first
2748//             / ( spvalue )
2749//                ; A single value
2750//
2751//     prange =  ( "[" spvalue "-" spvalue "]" )
2752//                ; Range between a lower and an upper level (inclusive)
2753//                ; The second occurrence of spvalue MUST have a higher
2754//                ; value than the first
2755//
2756//     qvalue  = ( "0" "." 1*2DIGIT )
2757//             / ( "1" "." 1*2("0") )
2758//                ; Values between 0.00 and 1.00
2759fn parse_image_attr(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2760    let mut tokens = parse_imageattr_tokens(to_parse, ' ').into_iter().peekable();
2761
2762    let pt = parse_payload_type(
2763        tokens
2764            .next()
2765            .ok_or_else(|| {
2766                SdpParserInternalError::Generic("imageattr requires a payload token".to_string())
2767            })?
2768            .as_str(),
2769    )?;
2770    let first_direction = parse_single_direction(
2771        tokens
2772            .next()
2773            .ok_or_else(|| {
2774                SdpParserInternalError::Generic(
2775                    "imageattr's second token must be a direction token".to_string(),
2776                )
2777            })?
2778            .as_str(),
2779    )?;
2780
2781    let first_set_list = parse_image_attr_set_list(&mut tokens)?;
2782
2783    let mut second_set_list = SdpAttributeImageAttrSetList::Sets(Vec::new());
2784
2785    // Check if there is a second direction defined
2786    if let Some(direction_token) = tokens.next() {
2787        if parse_single_direction(direction_token.as_str())? == first_direction {
2788            return Err(SdpParserInternalError::Generic(
2789                "imageattr's second direction token must be different from the first one"
2790                    .to_string(),
2791            ));
2792        }
2793
2794        second_set_list = parse_image_attr_set_list(&mut tokens)?;
2795    }
2796
2797    if tokens.next().is_some() {
2798        return Err(SdpParserInternalError::Generic(
2799            "imageattr must not contain any token after the second set list".to_string(),
2800        ));
2801    }
2802
2803    Ok(SdpAttribute::ImageAttr(match first_direction {
2804        SdpSingleDirection::Send => SdpAttributeImageAttr {
2805            pt,
2806            send: first_set_list,
2807            recv: second_set_list,
2808        },
2809        SdpSingleDirection::Recv => SdpAttributeImageAttr {
2810            pt,
2811            send: second_set_list,
2812            recv: first_set_list,
2813        },
2814    }))
2815}
2816
2817///////////////////////////////////////////////////////////////////////////
2818// a=msid, draft-ietf-mmusic-msid
2819//-------------------------------------------------------------------------
2820//   msid-attr = "msid:" identifier [ SP appdata ]
2821//   identifier = 1*64token-char ; see RFC 4566
2822//   appdata = 1*64token-char  ; see RFC 4566
2823fn parse_msid(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2824    let mut tokens = to_parse.split_whitespace();
2825    let id = match tokens.next() {
2826        None => {
2827            return Err(SdpParserInternalError::Generic(
2828                "Msid attribute is missing msid-id token".to_string(),
2829            ));
2830        }
2831        Some(x) => x.to_string(),
2832    };
2833    let appdata = tokens.next().map(|x| x.to_string());
2834    Ok(SdpAttribute::Msid(SdpAttributeMsid { id, appdata }))
2835}
2836
2837///////////////////////////////////////////////////////////////////////////
2838// a=msid-semantic, draft-ietf-mmusic-msid
2839//-------------------------------------------------------------------------
2840//   msid-semantic-attr = "msid-semantic:" msid-semantic msid-list
2841//   msid-semantic = token ; see RFC 4566
2842//   msid-list = *(" " msid-id) / " *"
2843fn parse_msid_semantic(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2844    let tokens: Vec<_> = to_parse.split_whitespace().collect();
2845    if tokens.is_empty() {
2846        return Err(SdpParserInternalError::Generic(
2847            "Msid-semantic attribute is missing msid-semantic token".to_string(),
2848        ));
2849    }
2850    // TODO: Should msids be checked to ensure they are non empty?
2851    let semantic = SdpAttributeMsidSemantic {
2852        semantic: tokens[0].to_string(),
2853        msids: tokens[1..].iter().map(ToString::to_string).collect(),
2854    };
2855    Ok(SdpAttribute::MsidSemantic(semantic))
2856}
2857
2858///////////////////////////////////////////////////////////////////////////
2859// a=rid, draft-ietf-mmusic-rid
2860//-------------------------------------------------------------------------
2861// rid-syntax        = %s"a=rid:" rid-id SP rid-dir
2862//                     [ rid-pt-param-list / rid-param-list ]
2863// rid-id            = 1*(alpha-numeric / "-" / "_")
2864// alpha-numeric     = < as defined in {{RFC4566}} >
2865// rid-dir           = %s"send" / %s"recv"
2866// rid-pt-param-list = SP rid-fmt-list *(";" rid-param)
2867// rid-param-list    = SP rid-param *(";" rid-param)
2868// rid-fmt-list      = %s"pt=" fmt *( "," fmt )
2869// fmt               = < as defined in {{RFC4566}} >
2870// rid-param         = rid-width-param
2871//                     / rid-height-param
2872//                     / rid-fps-param
2873//                     / rid-fs-param
2874//                     / rid-br-param
2875//                     / rid-pps-param
2876//                     / rid-bpp-param
2877//                     / rid-depend-param
2878//                     / rid-param-other
2879// rid-width-param   = %s"max-width" [ "=" int-param-val ]
2880// rid-height-param  = %s"max-height" [ "=" int-param-val ]
2881// rid-fps-param     = %s"max-fps" [ "=" int-param-val ]
2882// rid-fs-param      = %s"max-fs" [ "=" int-param-val ]
2883// rid-br-param      = %s"max-br" [ "=" int-param-val ]
2884// rid-pps-param     = %s"max-pps" [ "=" int-param-val ]
2885// rid-bpp-param     = %s"max-bpp" [ "=" float-param-val ]
2886// rid-depend-param  = %s"depend=" rid-list
2887// rid-param-other   = 1*(alpha-numeric / "-") [ "=" param-val ]
2888// rid-list          = rid-id *( "," rid-id )
2889// int-param-val     = 1*DIGIT
2890// float-param-val   = 1*DIGIT "." 1*DIGIT
2891// param-val         = *( %x20-58 / %x60-7E )
2892//                     ; Any printable character except semicolon
2893fn parse_rid(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2894    let tokens: Vec<&str> = to_parse.splitn(3, ' ').collect();
2895
2896    if tokens.len() < 2 {
2897        return Err(SdpParserInternalError::Generic(
2898            "A rid attribute must at least have an id and a direction token.".to_string(),
2899        ));
2900    }
2901
2902    // Default initilize
2903    let mut params = SdpAttributeRidParameters {
2904        max_width: 0,
2905        max_height: 0,
2906        max_fps: 0,
2907        max_fs: 0,
2908        max_br: 0,
2909        max_pps: 0,
2910        unknown: Vec::new(),
2911    };
2912    let mut formats: Vec<u16> = Vec::new();
2913    let mut depends: Vec<String> = Vec::new();
2914
2915    if let Some(param_token) = tokens.get(2) {
2916        let mut parameters = param_token.split(';').peekable();
2917
2918        // The 'pt' parameter must be the first parameter if present, so it
2919        // cannot be checked along with the other parameters below
2920        if let Some(maybe_fmt_parameter) = parameters.clone().peek() {
2921            if let Some(fmt_list) = maybe_fmt_parameter.strip_prefix("pt=") {
2922                for fmt in fmt_list.split(',') {
2923                    formats.push(fmt.trim().parse::<u16>()?);
2924                }
2925                parameters.next();
2926            }
2927        }
2928
2929        for param in parameters {
2930            // TODO: Bug 1225877. Add support for params without '='
2931            let param_value_pair: Vec<&str> = param.splitn(2, '=').collect();
2932            if param_value_pair.len() != 2 {
2933                return Err(SdpParserInternalError::Generic(
2934                    "A rid parameter needs to be of form 'param=value'".to_string(),
2935                ));
2936            }
2937
2938            match param_value_pair[0] {
2939                "max-width" => params.max_width = param_value_pair[1].parse::<u32>()?,
2940                "max-height" => params.max_height = param_value_pair[1].parse::<u32>()?,
2941                "max-fps" => params.max_fps = param_value_pair[1].parse::<u32>()?,
2942                "max-fs" => params.max_fs = param_value_pair[1].parse::<u32>()?,
2943                "max-br" => params.max_br = param_value_pair[1].parse::<u32>()?,
2944                "max-pps" => params.max_pps = param_value_pair[1].parse::<u32>()?,
2945                "depends" => {
2946                    depends.extend(param_value_pair[1].split(',').map(ToString::to_string));
2947                }
2948                _ => params.unknown.push(param.to_string()),
2949            }
2950        }
2951    }
2952
2953    Ok(SdpAttribute::Rid(SdpAttributeRid {
2954        id: tokens[0].to_string(),
2955        direction: parse_single_direction(tokens[1])?,
2956        formats,
2957        params,
2958        depends,
2959    }))
2960}
2961
2962///////////////////////////////////////////////////////////////////////////
2963// a=remote-candiate, RFC5245
2964//-------------------------------------------------------------------------
2965//   remote-candidate-att = "remote-candidates" ":" remote-candidate
2966//                           0*(SP remote-candidate)
2967//   remote-candidate = component-ID SP connection-address SP port
2968fn parse_remote_candidates(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
2969    let mut tokens = to_parse.split_whitespace();
2970    let component = match tokens.next() {
2971        None => {
2972            return Err(SdpParserInternalError::Generic(
2973                "Remote-candidate attribute is missing component ID".to_string(),
2974            ));
2975        }
2976        Some(x) => x.parse::<u32>()?,
2977    };
2978    let address = match tokens.next() {
2979        None => {
2980            return Err(SdpParserInternalError::Generic(
2981                "Remote-candidate attribute is missing connection address".to_string(),
2982            ));
2983        }
2984        Some(x) => parse_unicast_address(x)?,
2985    };
2986    let port = match tokens.next() {
2987        None => {
2988            return Err(SdpParserInternalError::Generic(
2989                "Remote-candidate attribute is missing port number".to_string(),
2990            ));
2991        }
2992        Some(x) => x.parse::<u32>()?,
2993    };
2994    if port > 65535 {
2995        return Err(SdpParserInternalError::Generic(
2996            "Remote-candidate port can only be a bit 16bit number".to_string(),
2997        ));
2998    };
2999    Ok(SdpAttribute::RemoteCandidate(SdpAttributeRemoteCandidate {
3000        component,
3001        address,
3002        port,
3003    }))
3004}
3005
3006///////////////////////////////////////////////////////////////////////////
3007// a=rtpmap, RFC4566
3008//-------------------------------------------------------------------------
3009// a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
3010fn parse_rtpmap(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
3011    let mut tokens = to_parse.split_whitespace();
3012    let payload_type: u8 = match tokens.next() {
3013        None => {
3014            return Err(SdpParserInternalError::Generic(
3015                "Rtpmap missing payload type".to_string(),
3016            ));
3017        }
3018        Some(x) => {
3019            let pt = x.parse::<u8>()?;
3020            if pt > 127 {
3021                return Err(SdpParserInternalError::Generic(
3022                    "Rtpmap payload type must be less then 127".to_string(),
3023                ));
3024            };
3025            pt
3026        }
3027    };
3028    let mut parameters = match tokens.next() {
3029        None => {
3030            return Err(SdpParserInternalError::Generic(
3031                "Rtpmap missing payload type".to_string(),
3032            ));
3033        }
3034        Some(x) => x.split('/'),
3035    };
3036    let name = match parameters.next() {
3037        None => {
3038            return Err(SdpParserInternalError::Generic(
3039                "Rtpmap missing codec name".to_string(),
3040            ));
3041        }
3042        Some(x) => x.to_string(),
3043    };
3044    let frequency = match parameters.next() {
3045        None => {
3046            return Err(SdpParserInternalError::Generic(
3047                "Rtpmap missing codec name".to_string(),
3048            ));
3049        }
3050        Some(x) => x.parse::<u32>()?,
3051    };
3052    let mut rtpmap = SdpAttributeRtpmap::new(payload_type, name, frequency);
3053    if let Some(x) = parameters.next() {
3054        rtpmap.set_channels(x.parse::<u32>()?)
3055    };
3056    Ok(SdpAttribute::Rtpmap(rtpmap))
3057}
3058
3059///////////////////////////////////////////////////////////////////////////
3060// a=rtcp, RFC3605
3061//-------------------------------------------------------------------------
3062//   rtcp-attribute =  "a=rtcp:" port  [nettype space addrtype space
3063//                         connection-address] CRLF
3064fn parse_rtcp(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
3065    let mut tokens = to_parse.split_whitespace();
3066    let port = match tokens.next() {
3067        None => {
3068            return Err(SdpParserInternalError::Generic(
3069                "Rtcp attribute is missing port number".to_string(),
3070            ));
3071        }
3072        Some(x) => x.parse::<u16>()?,
3073    };
3074    let mut rtcp = SdpAttributeRtcp::new(port);
3075    match tokens.next() {
3076        None => (),
3077        Some(x) => {
3078            parse_network_type(x)?;
3079            match tokens.next() {
3080                None => {
3081                    return Err(SdpParserInternalError::Generic(
3082                        "Rtcp attribute is missing address type token".to_string(),
3083                    ));
3084                }
3085                Some(x) => {
3086                    let addrtype = AddressType::from_str(x)?;
3087                    let addr = match tokens.next() {
3088                        None => {
3089                            return Err(SdpParserInternalError::Generic(
3090                                "Rtcp attribute is missing ip address token".to_string(),
3091                            ));
3092                        }
3093                        Some(x) => match ExplicitlyTypedAddress::try_from((addrtype, x)) {
3094                            Ok(address) => address,
3095                            Err(e) => return Err(e),
3096                        },
3097                    };
3098                    rtcp.set_addr(addr);
3099                }
3100            };
3101        }
3102    };
3103    Ok(SdpAttribute::Rtcp(rtcp))
3104}
3105
3106///////////////////////////////////////////////////////////////////////////
3107// a=rtcp-fb, RFC4585
3108//-------------------------------------------------------------------------
3109//    rtcp-fb-syntax = "a=rtcp-fb:" rtcp-fb-pt SP rtcp-fb-val CRLF
3110//
3111//    rtcp-fb-pt         = "*"   ; wildcard: applies to all formats
3112//                       / fmt   ; as defined in SDP spec
3113//
3114//    rtcp-fb-val        = "ack" rtcp-fb-ack-param
3115//                       / "nack" rtcp-fb-nack-param
3116//                       / "trr-int" SP 1*DIGIT
3117//                       / rtcp-fb-id rtcp-fb-param
3118//
3119//    rtcp-fb-id         = 1*(alpha-numeric / "-" / "_")
3120//
3121//    rtcp-fb-param      = SP "app" [SP byte-string]
3122//                       / SP token [SP byte-string]
3123//                       / ; empty
3124//
3125//    rtcp-fb-ack-param  = SP "rpsi"
3126//                       / SP "app" [SP byte-string]
3127//                       / SP token [SP byte-string]
3128//                       / ; empty
3129//
3130//    rtcp-fb-nack-param = SP "pli"
3131//                       / SP "sli"
3132//                       / SP "rpsi"
3133//                       / SP "app" [SP byte-string]
3134//                       / SP token [SP byte-string]
3135//                       / ; empty
3136fn parse_rtcp_fb(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
3137    let tokens: Vec<&str> = to_parse.splitn(4, ' ').collect();
3138
3139    // Parse this in advance to use it later in the parameter switch
3140    let feedback_type = match tokens.get(1) {
3141        Some(x) => match *x {
3142            "ack" => SdpAttributeRtcpFbType::Ack,
3143            "ccm" => SdpAttributeRtcpFbType::Ccm,
3144            "nack" => SdpAttributeRtcpFbType::Nack,
3145            "trr-int" => SdpAttributeRtcpFbType::TrrInt,
3146            "goog-remb" => SdpAttributeRtcpFbType::Remb,
3147            "transport-cc" => SdpAttributeRtcpFbType::TransCc,
3148            _ => {
3149                return Err(SdpParserInternalError::Unsupported(format!(
3150                    "Unknown rtcpfb feedback type: {x:?}"
3151                )));
3152            }
3153        },
3154        None => {
3155            return Err(SdpParserInternalError::Generic(
3156                "Error parsing rtcpfb: no feedback type".to_string(),
3157            ));
3158        }
3159    };
3160
3161    // Parse this in advance to make the initilization block below better readable
3162    let parameter = match feedback_type {
3163        SdpAttributeRtcpFbType::Ack => match tokens.get(2) {
3164            Some(x) => match *x {
3165                "rpsi" | "app" => (*x).to_string(),
3166                _ => {
3167                    return Err(SdpParserInternalError::Unsupported(format!(
3168                        "Unknown rtcpfb ack parameter: {x:?}"
3169                    )));
3170                }
3171            },
3172            None => {
3173                return Err(SdpParserInternalError::Unsupported(
3174                    "The rtcpfb ack feeback type needs a parameter:".to_string(),
3175                ));
3176            }
3177        },
3178        SdpAttributeRtcpFbType::Ccm => match tokens.get(2) {
3179            Some(x) => match *x {
3180                "fir" | "tmmbr" | "tstr" | "vbcm" => (*x).to_string(),
3181                _ => {
3182                    return Err(SdpParserInternalError::Unsupported(format!(
3183                        "Unknown rtcpfb ccm parameter: {x:?}"
3184                    )));
3185                }
3186            },
3187            None => "".to_string(),
3188        },
3189        SdpAttributeRtcpFbType::Nack => match tokens.get(2) {
3190            Some(x) => match *x {
3191                "sli" | "pli" | "rpsi" | "app" => (*x).to_string(),
3192                _ => {
3193                    return Err(SdpParserInternalError::Unsupported(format!(
3194                        "Unknown rtcpfb nack parameter: {x:?}"
3195                    )));
3196                }
3197            },
3198            None => "".to_string(),
3199        },
3200        SdpAttributeRtcpFbType::TrrInt => match tokens.get(2) {
3201            Some(x) => match x {
3202                _ if x.parse::<u32>().is_ok() => (*x).to_string(),
3203                _ => {
3204                    return Err(SdpParserInternalError::Generic(format!(
3205                        "Unknown rtcpfb trr-int parameter: {x:?}"
3206                    )));
3207                }
3208            },
3209            None => {
3210                return Err(SdpParserInternalError::Generic(
3211                    "The rtcpfb trr-int feedback type needs a parameter".to_string(),
3212                ));
3213            }
3214        },
3215        SdpAttributeRtcpFbType::Remb | SdpAttributeRtcpFbType::TransCc => match tokens.get(2) {
3216            Some(x) => {
3217                return Err(SdpParserInternalError::Unsupported(format!(
3218                    "Unknown rtcpfb {feedback_type} parameter: {x:?}"
3219                )));
3220            }
3221            None => "".to_string(),
3222        },
3223    };
3224
3225    Ok(SdpAttribute::Rtcpfb(SdpAttributeRtcpFb {
3226        payload_type: parse_payload_type(tokens[0])?,
3227        feedback_type,
3228        parameter,
3229        extra: match tokens.get(3) {
3230            Some(x) => (*x).to_string(),
3231            None => "".to_string(),
3232        },
3233    }))
3234}
3235
3236///////////////////////////////////////////////////////////////////////////
3237// a=sctpmap, draft-ietf-mmusic-sctp-sdp-05
3238//-------------------------------------------------------------------------
3239//      sctpmap-attr        =  "a=sctpmap:" sctpmap-number media-subtypes
3240// [streams]
3241//      sctpmap-number      =  1*DIGIT
3242//      protocol            =  labelstring
3243//        labelstring         =  text
3244//        text                =  byte-string
3245//      streams      =  1*DIGIT
3246//
3247//  Note: this was replace in later versions of the draft by sctp-port
3248fn parse_sctpmap(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
3249    let tokens: Vec<&str> = to_parse.split_whitespace().collect();
3250    if tokens.len() != 3 {
3251        return Err(SdpParserInternalError::Generic(
3252            "Sctpmap needs to have three tokens".to_string(),
3253        ));
3254    }
3255    let port = tokens[0].parse::<u16>()?;
3256    if tokens[1].to_lowercase() != "webrtc-datachannel" {
3257        return Err(SdpParserInternalError::Generic(
3258            "Unsupported sctpmap type token".to_string(),
3259        ));
3260    }
3261    Ok(SdpAttribute::Sctpmap(SdpAttributeSctpmap {
3262        port,
3263        channels: tokens[2].parse::<u32>()?,
3264    }))
3265}
3266
3267///////////////////////////////////////////////////////////////////////////
3268// a=setup, RFC4145
3269//-------------------------------------------------------------------------
3270//       setup-attr           =  "a=setup:" role
3271//       role                 =  "active" / "passive" / "actpass" / "holdconn"
3272fn parse_setup(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
3273    Ok(SdpAttribute::Setup(
3274        match to_parse.to_lowercase().as_ref() {
3275            "active" => SdpAttributeSetup::Active,
3276            "actpass" => SdpAttributeSetup::Actpass,
3277            "holdconn" => SdpAttributeSetup::Holdconn,
3278            "passive" => SdpAttributeSetup::Passive,
3279            _ => {
3280                return Err(SdpParserInternalError::Generic(
3281                    "Unsupported setup value".to_string(),
3282                ));
3283            }
3284        },
3285    ))
3286}
3287
3288fn parse_simulcast_version_list(
3289    to_parse: &str,
3290) -> Result<Vec<SdpAttributeSimulcastVersion>, SdpParserInternalError> {
3291    let make_version_list = |to_parse: &str| {
3292        to_parse
3293            .split(';')
3294            .map(SdpAttributeSimulcastVersion::new)
3295            .collect()
3296    };
3297    if to_parse.contains('=') {
3298        let mut descriptor_versionlist_pair = to_parse.splitn(2, '=');
3299        match descriptor_versionlist_pair.next().unwrap() {
3300            // TODO Bug 1470568
3301            "rid" => Ok(make_version_list(
3302                descriptor_versionlist_pair.next().unwrap(),
3303            )),
3304            descriptor => Err(SdpParserInternalError::Generic(format!(
3305                "Simulcast attribute has unknown list descriptor '{descriptor:?}'"
3306            ))),
3307        }
3308    } else {
3309        Ok(make_version_list(to_parse))
3310    }
3311}
3312
3313///////////////////////////////////////////////////////////////////////////
3314// a=simulcast, draft-ietf-mmusic-sdp-simulcast
3315//-------------------------------------------------------------------------
3316// Old draft-04
3317// sc-attr     = "a=simulcast:" 1*2( WSP sc-str-list ) [WSP sc-pause-list]
3318// sc-str-list = sc-dir WSP sc-id-type "=" sc-alt-list *( ";" sc-alt-list )
3319// sc-pause-list = "paused=" sc-alt-list
3320// sc-dir      = "send" / "recv"
3321// sc-id-type  = "pt" / "rid" / token
3322// sc-alt-list = sc-id *( "," sc-id )
3323// sc-id       = fmt / rid-identifier / token
3324// ; WSP defined in [RFC5234]
3325// ; fmt, token defined in [RFC4566]
3326// ; rid-identifier defined in [I-D.pthatcher-mmusic-rid]
3327//
3328// New draft 14, need to parse this for now, will eventually emit it
3329// sc-value     = ( sc-send [SP sc-recv] ) / ( sc-recv [SP sc-send] )
3330// sc-send      = %s"send" SP sc-str-list
3331// sc-recv      = %s"recv" SP sc-str-list
3332// sc-str-list  = sc-alt-list *( ";" sc-alt-list )
3333// sc-alt-list  = sc-id *( "," sc-id )
3334// sc-id-paused = "~"
3335// sc-id        = [sc-id-paused] rid-id
3336// ; SP defined in [RFC5234]
3337// ; rid-id defined in [I-D.ietf-mmusic-rid]
3338fn parse_simulcast(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
3339    // TODO: Bug 1225877: Stop accepting all kinds of whitespace here, and only accept SP
3340    let mut tokens = to_parse.split_whitespace();
3341    let first_direction = match tokens.next() {
3342        Some(x) => parse_single_direction(x)?,
3343        None => {
3344            return Err(SdpParserInternalError::Generic(
3345                "Simulcast attribute is missing send/recv value".to_string(),
3346            ));
3347        }
3348    };
3349
3350    let first_version_list = match tokens.next() {
3351        Some(x) => parse_simulcast_version_list(x)?,
3352        None => {
3353            return Err(SdpParserInternalError::Generic(
3354                "Simulcast attribute must have an alternatives list after the direction token"
3355                    .to_string(),
3356            ));
3357        }
3358    };
3359
3360    let mut second_version_list = Vec::new();
3361    if let Some(x) = tokens.next() {
3362        if parse_single_direction(x)? == first_direction {
3363            return Err(SdpParserInternalError::Generic(
3364                "Simulcast attribute has defined two times the same direction".to_string(),
3365            ));
3366        }
3367
3368        second_version_list = match tokens.next() {
3369            Some(x) => parse_simulcast_version_list(x)?,
3370            None => {
3371                return Err(SdpParserInternalError::Generic(format!(
3372                    "{:?}{:?}",
3373                    "Simulcast has defined a second direction but",
3374                    "no second list of simulcast stream versions"
3375                )));
3376            }
3377        }
3378    }
3379
3380    Ok(SdpAttribute::Simulcast(match first_direction {
3381        SdpSingleDirection::Send => SdpAttributeSimulcast {
3382            send: first_version_list,
3383            receive: second_version_list,
3384        },
3385        SdpSingleDirection::Recv => SdpAttributeSimulcast {
3386            send: second_version_list,
3387            receive: first_version_list,
3388        },
3389    }))
3390}
3391
3392///////////////////////////////////////////////////////////////////////////
3393// a=ssrc, RFC5576
3394//-------------------------------------------------------------------------
3395// ssrc-attr = "ssrc:" ssrc-id SP attribute
3396// ; The base definition of "attribute" is in RFC 4566.
3397// ; (It is the content of "a=" lines.)
3398//
3399// ssrc-id = integer ; 0 .. 2**32 - 1
3400fn parse_ssrc(to_parse: &str) -> Result<SdpAttribute, SdpParserInternalError> {
3401    let mut tokens = to_parse.splitn(2, ' ');
3402    let ssrc_id = match tokens.next() {
3403        None => {
3404            return Err(SdpParserInternalError::Generic(
3405                "Ssrc attribute is missing ssrc-id value".to_string(),
3406            ));
3407        }
3408        Some(x) => x.parse::<u32>()?,
3409    };
3410    let mut ssrc = SdpAttributeSsrc::new(ssrc_id);
3411    match tokens.next() {
3412        None => (),
3413        Some(x) => ssrc.set_attribute(x),
3414    };
3415    Ok(SdpAttribute::Ssrc(ssrc))
3416}
3417
3418pub fn parse_attribute(value: &str) -> Result<SdpType, SdpParserInternalError> {
3419    Ok(SdpType::Attribute(value.trim().parse()?))
3420}
3421
3422#[cfg(test)]
3423#[path = "./attribute_type_tests.rs"]
3424mod tests;