sdp_nom/attributes/
rtpmap.rs

1use std::borrow::Cow;
2
3use derive_into_owned::IntoOwned;
4use nom::{
5    branch::alt,
6    bytes::complete::tag,
7    character::complete::multispace1,
8    combinator::{map, opt},
9    sequence::{preceded, tuple},
10    IResult,
11};
12
13use crate::parsers::*;
14#[cfg(test)]
15use crate::{assert_line, assert_line_print};
16
17#[derive(Clone, PartialEq, Eq)]
18#[cfg_attr(feature = "debug", derive(Debug))]
19#[cfg_attr(
20    feature = "serde",
21    derive(serde::Serialize, serde::Deserialize),
22    serde(rename_all = "camelCase")
23)]
24#[non_exhaustive]
25pub enum PTime {
26    MaxPTime(u32),
27    MinPTime(u32),
28    PTime(u32),
29}
30
31pub fn read_p_time(input: &str) -> IResult<&str, PTime> {
32    alt((
33        attribute("ptime", map(read_number, PTime::PTime)),
34        attribute("minptime", map(read_number, PTime::MinPTime)),
35        attribute("maxptime", map(read_number, PTime::MaxPTime)),
36    ))(input)
37}
38
39#[test]
40fn test_read_p_time() {
41    assert_line!(read_p_time, "a=ptime:1", PTime::PTime(1), print);
42    assert_line!(read_p_time, "a=minptime:20", PTime::MinPTime(20), print);
43    assert_line!(read_p_time, "a=maxptime:120", PTime::MaxPTime(120), print);
44}
45
46/// RtpMap
47/// `a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding` parameters>]
48///<https://tools.ietf.org/html/rfc4566#section-6>
49#[derive(Clone, IntoOwned, PartialEq, Eq)]
50#[cfg_attr(feature = "debug", derive(Debug))]
51#[cfg_attr(
52    feature = "serde",
53    derive(serde::Serialize, serde::Deserialize),
54    serde(rename_all = "camelCase")
55)]
56pub struct RtpMap<'a> {
57    pub payload: u32,
58    pub encoding_name: Cow<'a, str>,
59    pub clock_rate: Option<u32>,
60    pub encoding: Option<u32>,
61}
62
63pub fn rtpmap_line(input: &str) -> IResult<&str, RtpMap> {
64    attribute(
65        "rtpmap",
66        map(
67            tuple((
68                read_number,                                          // payload_typ
69                preceded(multispace1, cowify(read_non_slash_string)), // encoding_name
70                opt(preceded(tag("/"), read_number)),                 // clock_rate
71                opt(preceded(
72                    tag("/"),
73                    read_number, // encoding
74                )),
75            )),
76            |(payload, encoding_name, clock_rate, encoding)| RtpMap {
77                payload,
78                encoding_name,
79                clock_rate,
80                encoding,
81            },
82        ),
83    )(input)
84}
85
86#[test]
87fn test_rtpmap_line() {
88    assert_line!(
89        rtpmap_line,
90        "a=rtpmap:96 VP8/90000",
91        RtpMap {
92            payload: 96,
93            encoding_name: "VP8".into(),
94            clock_rate: Some(90000),
95            encoding: None,
96        },
97        print
98    );
99    assert_line!(
100        rtpmap_line,
101        "a=rtpmap:97 rtx/90000",
102        RtpMap {
103            payload: 97,
104            encoding_name: "rtx".into(),
105            clock_rate: Some(90000),
106            encoding: None,
107        },
108        print
109    );
110    assert_line!(
111        rtpmap_line,
112        "a=rtpmap:111 opus/48000/2",
113        RtpMap {
114            payload: 111,
115            encoding_name: "opus".into(),
116            clock_rate: Some(48000),
117            encoding: Some(2),
118        },
119        print
120    );
121    assert_line_print!(rtpmap_line, "a=rtpmap:98 VP9/90000");
122    assert_line_print!(rtpmap_line, "a=rtpmap:99 rtx/90000");
123    assert_line_print!(rtpmap_line, "a=rtpmap:100 H264/90000");
124    assert_line_print!(rtpmap_line, "a=rtpmap:101 rtx/90000");
125    assert_line_print!(rtpmap_line, "a=rtpmap:102 H264/90000");
126    assert_line_print!(rtpmap_line, "a=rtpmap:124 rtx/90000");
127    assert_line_print!(rtpmap_line, "a=rtpmap:127 red/90000");
128    assert_line_print!(rtpmap_line, "a=rtpmap:123 rtx/90000");
129    assert_line_print!(rtpmap_line, "a=rtpmap:125 ulpfec/90000");
130    assert_line!(
131        rtpmap_line,
132        "a=rtpmap:122 red/90000",
133        RtpMap {
134            payload: 122,
135            encoding_name: "red".into(),
136            clock_rate: Some(90_000),
137            encoding: None,
138        },
139        print
140    );
141    assert_line!(
142        rtpmap_line,
143        "a=rtpmap:113 telephone-event/16000",
144        RtpMap {
145            payload: 113,
146            encoding_name: "telephone-event".into(),
147            clock_rate: Some(16000),
148            encoding: None,
149        },
150        print
151    );
152    assert_line!(rtpmap_line, "a=rtpmap:96 AppleLossless");
153}