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
5 use super::*;
6 use address::{AddressType, ExplicitlyTypedAddress};
7 use attribute_type::{
8 SdpAttributeFmtp, SdpAttributeFmtpParameters, SdpAttributePayloadType, SdpAttributeRtcpFb,
9 SdpAttributeRtcpFbType,
10 };
11 use std::convert::TryFrom;
12
create_dummy_media_section() -> SdpMedia13 pub fn create_dummy_media_section() -> SdpMedia {
14 let media_line = SdpMediaLine {
15 media: SdpMediaValue::Audio,
16 port: 9,
17 port_count: 0,
18 proto: SdpProtocolValue::RtpSavpf,
19 formats: SdpFormatList::Integers(Vec::new()),
20 };
21 SdpMedia::new(media_line)
22 }
23
24 // TODO is this useful outside of tests?
25 impl SdpFormatList {
len(&self) -> usize26 fn len(&self) -> usize {
27 match *self {
28 SdpFormatList::Integers(ref x) => x.len(),
29 SdpFormatList::Strings(ref x) => x.len(),
30 }
31 }
32 }
33
add_dummy_attributes(media: &mut SdpMedia)34 pub fn add_dummy_attributes(media: &mut SdpMedia) {
35 assert!(media
36 .add_attribute(SdpAttribute::Rtcpfb(SdpAttributeRtcpFb {
37 payload_type: SdpAttributePayloadType::Wildcard,
38 feedback_type: SdpAttributeRtcpFbType::Ack,
39 parameter: "".to_string(),
40 extra: "".to_string(),
41 },))
42 .is_ok());
43 assert!(media
44 .add_attribute(SdpAttribute::Fmtp(SdpAttributeFmtp {
45 payload_type: 1,
46 parameters: SdpAttributeFmtpParameters {
47 packetization_mode: 0,
48 level_asymmetry_allowed: false,
49 profile_level_id: 0x0042_0010,
50 max_fs: 0,
51 max_cpb: 0,
52 max_dpb: 0,
53 max_br: 0,
54 max_mbps: 0,
55 usedtx: false,
56 stereo: false,
57 useinbandfec: false,
58 cbr: false,
59 max_fr: 0,
60 maxplaybackrate: 48000,
61 maxaveragebitrate: 0,
62 ptime: 0,
63 minptime: 0,
64 maxptime: 0,
65 encodings: Vec::new(),
66 dtmf_tones: "".to_string(),
67 rtx: None,
68 unknown_tokens: Vec::new()
69 }
70 },))
71 .is_ok());
72 assert!(media
73 .add_attribute(SdpAttribute::Sctpmap(SdpAttributeSctpmap {
74 port: 5000,
75 channels: 2,
76 }))
77 .is_ok());
78 assert!(media.add_attribute(SdpAttribute::BundleOnly).is_ok());
79 assert!(media.add_attribute(SdpAttribute::SctpPort(5000)).is_ok());
80
81 assert!(media.get_attribute(SdpAttributeType::Rtpmap).is_some());
82 assert!(media.get_attribute(SdpAttributeType::Rtcpfb).is_some());
83 assert!(media.get_attribute(SdpAttributeType::Fmtp).is_some());
84 assert!(media.get_attribute(SdpAttributeType::Sctpmap).is_some());
85 assert!(media.get_attribute(SdpAttributeType::SctpPort).is_some());
86 assert!(media.get_attribute(SdpAttributeType::BundleOnly).is_some());
87 }
88
check_parse(media_line_str: &str) -> SdpMediaLine89 fn check_parse(media_line_str: &str) -> SdpMediaLine {
90 if let Ok(SdpType::Media(media_line)) = parse_media(media_line_str) {
91 media_line
92 } else {
93 unreachable!()
94 }
95 }
96
check_parse_and_serialize(media_line_str: &str)97 fn check_parse_and_serialize(media_line_str: &str) {
98 let parsed = check_parse(media_line_str);
99 assert_eq!(parsed.to_string(), media_line_str.to_string());
100 }
101
102 #[test]
test_get_set_port()103 fn test_get_set_port() {
104 let mut msection = create_dummy_media_section();
105 assert_eq!(msection.get_port(), 9);
106 msection.set_port(2048);
107 assert_eq!(msection.get_port(), 2048);
108 }
109
110 #[test]
test_add_codec() -> Result<(), SdpParserInternalError>111 fn test_add_codec() -> Result<(), SdpParserInternalError> {
112 let mut msection = create_dummy_media_section();
113 msection.add_codec(SdpAttributeRtpmap::new(96, "foobar".to_string(), 1000))?;
114 assert_eq!(msection.get_formats().len(), 1);
115 assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_some());
116
117 let mut msection = create_dummy_media_section();
118 msection.media.formats = SdpFormatList::Strings(Vec::new());
119 msection.add_codec(SdpAttributeRtpmap::new(97, "boofar".to_string(), 1001))?;
120 assert_eq!(msection.get_formats().len(), 1);
121 assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_some());
122 Ok(())
123 }
124
125 #[test]
test_remove_codecs() -> Result<(), SdpParserInternalError>126 fn test_remove_codecs() -> Result<(), SdpParserInternalError> {
127 let mut msection = create_dummy_media_section();
128 msection.add_codec(SdpAttributeRtpmap::new(96, "foobar".to_string(), 1000))?;
129 assert_eq!(msection.get_formats().len(), 1);
130 assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_some());
131 msection.remove_codecs();
132 assert_eq!(msection.get_formats().len(), 0);
133 assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_none());
134
135 let mut msection = create_dummy_media_section();
136 msection.media.formats = SdpFormatList::Strings(Vec::new());
137 msection.add_codec(SdpAttributeRtpmap::new(97, "boofar".to_string(), 1001))?;
138 assert_eq!(msection.get_formats().len(), 1);
139
140 add_dummy_attributes(&mut msection);
141
142 msection.remove_codecs();
143 assert_eq!(msection.get_formats().len(), 0);
144 assert!(msection.get_attribute(SdpAttributeType::Rtpmap).is_none());
145 assert!(msection.get_attribute(SdpAttributeType::Rtcpfb).is_none());
146 assert!(msection.get_attribute(SdpAttributeType::Fmtp).is_none());
147 assert!(msection.get_attribute(SdpAttributeType::Sctpmap).is_none());
148 assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_none());
149 Ok(())
150 }
151
152 #[test]
test_add_datachannel() -> Result<(), SdpParserInternalError>153 fn test_add_datachannel() -> Result<(), SdpParserInternalError> {
154 let mut msection = create_dummy_media_section();
155 msection.add_datachannel("foo".to_string(), 5000, 256, 0)?;
156 assert_eq!(*msection.get_type(), SdpMediaValue::Application);
157 assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_none());
158 assert!(msection
159 .get_attribute(SdpAttributeType::MaxMessageSize)
160 .is_none());
161 assert!(msection.get_attribute(SdpAttributeType::Sctpmap).is_some());
162 match *msection.get_attribute(SdpAttributeType::Sctpmap).unwrap() {
163 SdpAttribute::Sctpmap(ref s) => {
164 assert_eq!(s.port, 5000);
165 assert_eq!(s.channels, 256);
166 }
167 _ => unreachable!(),
168 }
169
170 let mut msection = create_dummy_media_section();
171 msection.add_datachannel("foo".to_string(), 5000, 256, 1234)?;
172 assert_eq!(*msection.get_type(), SdpMediaValue::Application);
173 assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_none());
174 assert!(msection
175 .get_attribute(SdpAttributeType::MaxMessageSize)
176 .is_some());
177 match *msection
178 .get_attribute(SdpAttributeType::MaxMessageSize)
179 .unwrap()
180 {
181 SdpAttribute::MaxMessageSize(m) => {
182 assert_eq!(m, 1234);
183 }
184 _ => unreachable!(),
185 }
186
187 let mut msection = create_dummy_media_section();
188 msection.media.proto = SdpProtocolValue::UdpDtlsSctp;
189 msection.add_datachannel("foo".to_string(), 5000, 256, 5678)?;
190 assert_eq!(*msection.get_type(), SdpMediaValue::Application);
191 assert!(msection.get_attribute(SdpAttributeType::Sctpmap).is_none());
192 assert!(msection.get_attribute(SdpAttributeType::SctpPort).is_some());
193 match *msection.get_attribute(SdpAttributeType::SctpPort).unwrap() {
194 SdpAttribute::SctpPort(s) => {
195 assert_eq!(s, 5000);
196 }
197 _ => unreachable!(),
198 }
199 assert!(msection
200 .get_attribute(SdpAttributeType::MaxMessageSize)
201 .is_some());
202 match *msection
203 .get_attribute(SdpAttributeType::MaxMessageSize)
204 .unwrap()
205 {
206 SdpAttribute::MaxMessageSize(m) => {
207 assert_eq!(m, 5678);
208 }
209 _ => unreachable!(),
210 }
211 Ok(())
212 }
213
214 #[test]
test_parse_media_token() -> Result<(), SdpParserInternalError>215 fn test_parse_media_token() -> Result<(), SdpParserInternalError> {
216 let audio = parse_media_token("audio")?;
217 assert_eq!(audio, SdpMediaValue::Audio);
218 let video = parse_media_token("VIDEO")?;
219 assert_eq!(video, SdpMediaValue::Video);
220 let app = parse_media_token("aPplIcatIOn")?;
221 assert_eq!(app, SdpMediaValue::Application);
222
223 assert!(parse_media_token("").is_err());
224 assert!(parse_media_token("foobar").is_err());
225 Ok(())
226 }
227
228 #[test]
test_parse_protocol_rtp_token() -> Result<(), SdpParserInternalError>229 fn test_parse_protocol_rtp_token() -> Result<(), SdpParserInternalError> {
230 fn parse_and_serialize_protocol_token(
231 token: &str,
232 result: SdpProtocolValue,
233 ) -> Result<(), SdpParserInternalError> {
234 let rtps = parse_protocol_token(token)?;
235 assert_eq!(rtps, result);
236 assert_eq!(rtps.to_string(), token.to_uppercase());
237 Ok(())
238 }
239 parse_and_serialize_protocol_token("rtp/avp", SdpProtocolValue::RtpAvp)?;
240 parse_and_serialize_protocol_token("rtp/avpf", SdpProtocolValue::RtpAvpf)?;
241 parse_and_serialize_protocol_token("rtp/savp", SdpProtocolValue::RtpSavp)?;
242 parse_and_serialize_protocol_token("rtp/savpf", SdpProtocolValue::RtpSavpf)?;
243 parse_and_serialize_protocol_token("udp/tls/rtp/savp", SdpProtocolValue::UdpTlsRtpSavp)?;
244 parse_and_serialize_protocol_token("udp/tls/rtp/savpf", SdpProtocolValue::UdpTlsRtpSavpf)?;
245 parse_and_serialize_protocol_token("TCP/dtls/rtp/savp", SdpProtocolValue::TcpDtlsRtpSavp)?;
246 parse_and_serialize_protocol_token("tcp/DTLS/rtp/savpf", SdpProtocolValue::TcpDtlsRtpSavpf)?;
247
248 assert!(parse_protocol_token("").is_err());
249 assert!(parse_protocol_token("foobar").is_err());
250 Ok(())
251 }
252
253 #[test]
test_parse_protocol_sctp_token() -> Result<(), SdpParserInternalError>254 fn test_parse_protocol_sctp_token() -> Result<(), SdpParserInternalError> {
255 fn parse_and_serialize_protocol_token(
256 token: &str,
257 result: SdpProtocolValue,
258 ) -> Result<(), SdpParserInternalError> {
259 let rtps = parse_protocol_token(token)?;
260 assert_eq!(rtps, result);
261 assert_eq!(rtps.to_string(), token.to_uppercase());
262 Ok(())
263 }
264 parse_and_serialize_protocol_token("dtLs/ScTP", SdpProtocolValue::DtlsSctp)?;
265 parse_and_serialize_protocol_token("udp/DTLS/sctp", SdpProtocolValue::UdpDtlsSctp)?;
266 parse_and_serialize_protocol_token("tcp/dtls/SCTP", SdpProtocolValue::TcpDtlsSctp)?;
267 Ok(())
268 }
269
270 #[test]
test_media_works()271 fn test_media_works() {
272 check_parse_and_serialize("audio 9 UDP/TLS/RTP/SAVPF 109");
273 check_parse_and_serialize("video 9 UDP/TLS/RTP/SAVPF 126");
274 check_parse_and_serialize("application 9 DTLS/SCTP 5000");
275 check_parse_and_serialize("application 9 UDP/DTLS/SCTP webrtc-datachannel");
276
277 check_parse_and_serialize("audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8");
278 check_parse_and_serialize("audio 0 UDP/TLS/RTP/SAVPF 8");
279 check_parse_and_serialize("audio 9/2 UDP/TLS/RTP/SAVPF 8");
280 }
281
282 #[test]
test_media_missing_token()283 fn test_media_missing_token() {
284 assert!(parse_media("video 9 UDP/TLS/RTP/SAVPF").is_err());
285 }
286
287 #[test]
test_media_invalid_port_number()288 fn test_media_invalid_port_number() {
289 assert!(parse_media("video 75123 UDP/TLS/RTP/SAVPF 8").is_err());
290 }
291
292 #[test]
test_media_invalid_type()293 fn test_media_invalid_type() {
294 assert!(parse_media("invalid 9 UDP/TLS/RTP/SAVPF 8").is_err());
295 }
296
297 #[test]
test_media_invalid_port()298 fn test_media_invalid_port() {
299 assert!(parse_media("audio / UDP/TLS/RTP/SAVPF 8").is_err());
300 }
301
302 #[test]
test_media_invalid_transport()303 fn test_media_invalid_transport() {
304 assert!(parse_media("audio 9 invalid/invalid 8").is_err());
305 }
306
307 #[test]
test_media_invalid_payload()308 fn test_media_invalid_payload() {
309 assert!(parse_media("audio 9 UDP/TLS/RTP/SAVPF 300").is_err());
310 }
311
312 #[test]
test_media_vector_first_line_failure()313 fn test_media_vector_first_line_failure() {
314 let mut sdp_lines: Vec<SdpLine> = Vec::new();
315 let line = SdpLine {
316 line_number: 0,
317 sdp_type: SdpType::Session("hello".to_string()),
318 text: "".to_owned(),
319 };
320 sdp_lines.push(line);
321 assert!(parse_media_vector(&mut sdp_lines).is_err());
322 }
323
324 #[test]
test_media_vector_multiple_connections()325 fn test_media_vector_multiple_connections() {
326 let mut sdp_lines: Vec<SdpLine> = Vec::new();
327 let media_line = SdpMediaLine {
328 media: SdpMediaValue::Audio,
329 port: 9,
330 port_count: 0,
331 proto: SdpProtocolValue::RtpSavpf,
332 formats: SdpFormatList::Integers(Vec::new()),
333 };
334 let media = SdpLine {
335 line_number: 0,
336 sdp_type: SdpType::Media(media_line),
337 text: "".to_owned(),
338 };
339 sdp_lines.push(media);
340 let c = SdpConnection {
341 address: ExplicitlyTypedAddress::try_from((AddressType::IpV4, "127.0.0.1")).unwrap(),
342 ttl: None,
343 amount: None,
344 };
345 let c1 = SdpLine {
346 line_number: 1,
347 sdp_type: SdpType::Connection(c.clone()),
348 text: "".to_owned(),
349 };
350 sdp_lines.push(c1);
351 let c2 = SdpLine {
352 line_number: 2,
353 sdp_type: SdpType::Connection(c),
354 text: "".to_owned(),
355 };
356 sdp_lines.push(c2);
357 assert!(parse_media_vector(&mut sdp_lines).is_err());
358 }
359
360 #[test]
test_media_vector_invalid_types()361 fn test_media_vector_invalid_types() {
362 let mut sdp_lines: Vec<SdpLine> = Vec::new();
363 let media_line = SdpMediaLine {
364 media: SdpMediaValue::Audio,
365 port: 9,
366 port_count: 0,
367 proto: SdpProtocolValue::RtpSavpf,
368 formats: SdpFormatList::Integers(Vec::new()),
369 };
370 let media = SdpLine {
371 line_number: 0,
372 sdp_type: SdpType::Media(media_line),
373 text: "".to_owned(),
374 };
375 sdp_lines.push(media);
376 use SdpTiming;
377 let t = SdpTiming { start: 0, stop: 0 };
378 let tline = SdpLine {
379 line_number: 1,
380 sdp_type: SdpType::Timing(t),
381 text: "".to_owned(),
382 };
383 sdp_lines.push(tline);
384 assert!(parse_media_vector(&mut sdp_lines).is_err());
385 }
386
387 #[test]
test_media_vector_invalid_media_level_attribute()388 fn test_media_vector_invalid_media_level_attribute() {
389 let mut sdp_lines: Vec<SdpLine> = Vec::new();
390 let media_line = SdpMediaLine {
391 media: SdpMediaValue::Audio,
392 port: 9,
393 port_count: 0,
394 proto: SdpProtocolValue::RtpSavpf,
395 formats: SdpFormatList::Integers(Vec::new()),
396 };
397 let media = SdpLine {
398 line_number: 0,
399 sdp_type: SdpType::Media(media_line),
400 text: "".to_owned(),
401 };
402 sdp_lines.push(media);
403 let a = SdpAttribute::IceLite;
404 let aline = SdpLine {
405 line_number: 1,
406 sdp_type: SdpType::Attribute(a),
407 text: "".to_owned(),
408 };
409 sdp_lines.push(aline);
410 assert!(parse_media_vector(&mut sdp_lines).is_err());
411 }
412