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#[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, preceded(multispace1, cowify(read_non_slash_string)), opt(preceded(tag("/"), read_number)), opt(preceded(
72 tag("/"),
73 read_number, )),
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}