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
14generate_attribute!(
15 BwType, "type", {
20 Ct => "CT",
22
23 As => "AS",
25
26 Rs => "RS",
29
30 Rr => "RR",
33
34 Tias => "TIAS",
37 }
38);
39
40#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
42#[xml(namespace = ns::JINGLE_RTP, name = "description")]
43pub struct Bandwidth {
44 #[xml(attribute)]
47 type_: BwType,
48
49 #[xml(text)]
50 value: u32,
51}
52
53#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
55#[xml(namespace = ns::JINGLE_RTP, name = "description")]
56pub struct Description {
57 #[xml(attribute)]
60 pub media: String,
61
62 #[xml(attribute(default))]
64 pub ssrc: Option<u32>,
65
66 #[xml(child(n = ..))]
68 pub payload_types: Vec<PayloadType>,
69
70 #[xml(flag(name = "rtcp-mux"))]
73 pub rtcp_mux: bool,
74
75 #[xml(child(n = ..))]
77 pub ssrc_groups: Vec<Group>,
78
79 #[xml(child(n = ..))]
81 pub ssrcs: Vec<Source>,
82
83 #[xml(child(n = ..))]
85 pub hdrexts: Vec<RtpHdrext>,
86
87 #[xml(child(default))]
89 pub bandwidth: Option<Bandwidth>,
90 }
92
93impl Description {
94 pub fn new(media: String) -> Description {
96 Description {
97 media,
98 ssrc: None,
99 payload_types: Vec::new(),
100 rtcp_mux: false,
101 ssrc_groups: Vec::new(),
102 ssrcs: Vec::new(),
103 hdrexts: Vec::new(),
104 bandwidth: None,
105 }
106 }
107}
108
109generate_attribute!(
110 Channels,
112 "channels",
113 u8,
114 Default = 1
115);
116
117#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
119#[xml(namespace = ns::JINGLE_RTP, name = "payload-type")]
120pub struct PayloadType {
121 #[xml(attribute(default))]
123 pub channels: Channels,
124
125 #[xml(attribute(default))]
127 pub clockrate: Option<u32>,
128
129 #[xml(attribute)]
131 pub id: u8,
132
133 #[xml(attribute(default))]
135 pub maxptime: Option<u32>,
136
137 #[xml(attribute(default))]
139 pub name: Option<String>,
140
141 #[xml(attribute(default))]
143 pub ptime: Option<u32>,
144
145 #[xml(child(n = ..))]
149 pub parameters: Vec<Parameter>,
150
151 #[xml(child(n = ..))]
153 pub rtcp_fbs: Vec<RtcpFb>,
154}
155
156impl PayloadType {
157 pub fn new(id: u8, name: String, clockrate: u32, channels: u8) -> PayloadType {
159 PayloadType {
160 channels: Channels(channels),
161 clockrate: Some(clockrate),
162 id,
163 maxptime: None,
164 name: Some(name),
165 ptime: None,
166 parameters: Vec::new(),
167 rtcp_fbs: Vec::new(),
168 }
169 }
170
171 pub fn without_clockrate(id: u8, name: String) -> PayloadType {
174 PayloadType {
175 channels: Default::default(),
176 clockrate: None,
177 id,
178 maxptime: None,
179 name: Some(name),
180 ptime: None,
181 parameters: Vec::new(),
182 rtcp_fbs: Vec::new(),
183 }
184 }
185}
186
187#[derive(FromXml, AsXml, PartialEq, Debug, Clone)]
189#[xml(namespace = ns::JINGLE_RTP, name = "parameter")]
190pub struct Parameter {
191 #[xml(attribute)]
194 pub name: String,
195
196 #[xml(attribute)]
198 pub value: String,
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204 use minidom::Element;
205
206 #[cfg(target_pointer_width = "32")]
207 #[test]
208 fn test_size() {
209 assert_size!(BwType, 1);
210 assert_size!(Bandwidth, 8);
211 assert_size!(Description, 80);
212 assert_size!(Channels, 1);
213 assert_size!(PayloadType, 64);
214 assert_size!(Parameter, 24);
215 }
216
217 #[cfg(target_pointer_width = "64")]
218 #[test]
219 fn test_size() {
220 assert_size!(BwType, 1);
221 assert_size!(Bandwidth, 8);
222 assert_size!(Description, 144);
223 assert_size!(Channels, 1);
224 assert_size!(PayloadType, 104);
225 assert_size!(Parameter, 48);
226 }
227
228 #[test]
229 fn test_simple() {
230 let elem: Element = "<description xmlns='urn:xmpp:jingle:apps:rtp:1' media='audio'>
231 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='2' clockrate='48000' id='96' name='OPUS'/>
232 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='32000' id='105' name='SPEEX'/>
233 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='9' name='G722'/>
234 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='16000' id='106' name='SPEEX'/>
235 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='8' name='PCMA'/>
236 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='0' name='PCMU'/>
237 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='107' name='SPEEX'/>
238 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' channels='1' clockrate='8000' id='99' name='AMR'>
239 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='octet-align' value='1'/>
240 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='crc' value='0'/>
241 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='robust-sorting' value='0'/>
242 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='interleaving' value='0'/>
243 </payload-type>
244 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='48000' id='100' name='telephone-event'>
245 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
246 </payload-type>
247 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='16000' id='101' name='telephone-event'>
248 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
249 </payload-type>
250 <payload-type xmlns='urn:xmpp:jingle:apps:rtp:1' clockrate='8000' id='102' name='telephone-event'>
251 <parameter xmlns='urn:xmpp:jingle:apps:rtp:1' name='events' value='0-15'/>
252 </payload-type>
253 <rtcp-mux/>
254</description>"
255 .parse()
256 .unwrap();
257 let desc = Description::try_from(elem).unwrap();
258 assert_eq!(desc.media, "audio");
259 assert_eq!(desc.ssrc, None);
260 assert_eq!(desc.rtcp_mux, true);
261 }
262}