1use xso::{AsXml, FromXml};
8
9use crate::jingle_rtcp_fb::RtcpFb;
10use crate::jingle_rtp_hdrext::RtpHdrext;
11use crate::jingle_ssma::{Group, Source};
12use crate::ns;
13
14#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
17#[xml(namespace = ns::JINGLE_RTP, name = "rtcp-mux")]
18pub struct RtcpMux;
19
20generate_attribute!(
21 BwType, "type", {
26 Ct => "CT",
28
29 As => "AS",
31
32 Rs => "RS",
35
36 Rr => "RR",
39
40 Tias => "TIAS",
43 }
44);
45
46#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
48#[xml(namespace = ns::JINGLE_RTP, name = "description")]
49pub struct Bandwidth {
50 #[xml(attribute)]
53 type_: BwType,
54
55 #[xml(text)]
56 value: u32,
57}
58
59#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
61#[xml(namespace = ns::JINGLE_RTP, name = "description")]
62pub struct Description {
63 #[xml(attribute)]
66 pub media: String,
67
68 #[xml(attribute(default))]
70 pub ssrc: Option<u32>,
71
72 #[xml(child(n = ..))]
74 pub payload_types: Vec<PayloadType>,
75
76 #[xml(child(default))]
79 pub rtcp_mux: Option<RtcpMux>,
80
81 #[xml(child(n = ..))]
83 pub ssrc_groups: Vec<Group>,
84
85 #[xml(child(n = ..))]
87 pub ssrcs: Vec<Source>,
88
89 #[xml(child(n = ..))]
91 pub hdrexts: Vec<RtpHdrext>,
92
93 #[xml(child(default))]
95 pub bandwidth: Option<Bandwidth>,
96 }
98
99impl Description {
100 pub fn new(media: String) -> Description {
102 Description {
103 media,
104 ssrc: None,
105 payload_types: Vec::new(),
106 rtcp_mux: None,
107 ssrc_groups: Vec::new(),
108 ssrcs: Vec::new(),
109 hdrexts: Vec::new(),
110 bandwidth: None,
111 }
112 }
113}
114
115generate_attribute!(
116 Channels,
118 "channels",
119 u8,
120 Default = 1
121);
122
123#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
125#[xml(namespace = ns::JINGLE_RTP, name = "payload-type")]
126pub struct PayloadType {
127 #[xml(attribute(default))]
129 pub channels: Channels,
130
131 #[xml(attribute(default))]
133 pub clockrate: Option<u32>,
134
135 #[xml(attribute)]
137 pub id: u8,
138
139 #[xml(attribute(default))]
141 pub maxptime: Option<u32>,
142
143 #[xml(attribute(default))]
145 pub name: Option<String>,
146
147 #[xml(attribute(default))]
149 pub ptime: Option<u32>,
150
151 #[xml(child(n = ..))]
155 pub parameters: Vec<Parameter>,
156
157 #[xml(child(n = ..))]
159 pub rtcp_fbs: Vec<RtcpFb>,
160}
161
162impl PayloadType {
163 pub fn new(id: u8, name: String, clockrate: u32, channels: u8) -> PayloadType {
165 PayloadType {
166 channels: Channels(channels),
167 clockrate: Some(clockrate),
168 id,
169 maxptime: None,
170 name: Some(name),
171 ptime: None,
172 parameters: Vec::new(),
173 rtcp_fbs: Vec::new(),
174 }
175 }
176
177 pub fn without_clockrate(id: u8, name: String) -> PayloadType {
180 PayloadType {
181 channels: Default::default(),
182 clockrate: None,
183 id,
184 maxptime: None,
185 name: Some(name),
186 ptime: None,
187 parameters: Vec::new(),
188 rtcp_fbs: Vec::new(),
189 }
190 }
191}
192
193#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
195#[xml(namespace = ns::JINGLE_RTP, name = "parameter")]
196pub struct Parameter {
197 #[xml(attribute)]
200 pub name: String,
201
202 #[xml(attribute)]
204 pub value: String,
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210 use minidom::Element;
211
212 #[cfg(target_pointer_width = "32")]
213 #[test]
214 fn test_size() {
215 assert_size!(BwType, 1);
216 assert_size!(Bandwidth, 8);
217 assert_size!(Description, 80);
218 assert_size!(Channels, 1);
219 assert_size!(PayloadType, 64);
220 assert_size!(Parameter, 24);
221 }
222
223 #[cfg(target_pointer_width = "64")]
224 #[test]
225 fn test_size() {
226 assert_size!(BwType, 1);
227 assert_size!(Bandwidth, 8);
228 assert_size!(Description, 144);
229 assert_size!(Channels, 1);
230 assert_size!(PayloadType, 104);
231 assert_size!(Parameter, 48);
232 }
233
234 #[test]
235 fn test_simple() {
236 let elem: Element = "<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>
237 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='2' clockrate='48000' id='96' name='OPUS'/>
238 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='32000' id='105' name='SPEEX'/>
239 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='9' name='G722'/>
240 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='16000' id='106' name='SPEEX'/>
241 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='8' name='PCMA'/>
242 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='0' name='PCMU'/>
243 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='107' name='SPEEX'/>
244 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='99' name='AMR'>
245 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='octet-align' value='1'/>
246 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='crc' value='0'/>
247 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='robust-sorting' value='0'/>
248 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='interleaving' value='0'/>
249 </payload-type>
250 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='48000' id='100' name='telephone-event'>
251 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
252 </payload-type>
253 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='16000' id='101' name='telephone-event'>
254 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
255 </payload-type>
256 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='102' name='telephone-event'>
257 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
258 </payload-type>
259</description>"
260 .parse()
261 .unwrap();
262 let desc = Description::try_from(elem).unwrap();
263 assert_eq!(desc.media, "audio");
264 assert_eq!(desc.ssrc, None);
265 }
266}