blob: 7a098850274c74d814fb6b887535aa4950610b9f [file] [log] [blame]
Soares Chenb20cf6b2017-05-19 12:28:431<!doctype html>
2<title>Test RTCPeerConnection.prototype.addIceCandidate</title>
3<script src="/resources/testharness.js"></script>
4<script src="/resources/testharnessreport.js"></script>
5<script>
6 'use strict';
7
Soares Chenb20cf6b2017-05-19 12:28:438 // SDP copied from JSEP Example 7.1
9 // It contains two media streams with different ufrags
10 // to test if candidate is added to the correct stream
11 const sdp = `v=0
12o=- 4962303333179871722 1 IN IP4 0.0.0.0
13s=-
14t=0 0
15a=ice-options:trickle
16a=group:BUNDLE a1 v1
17a=group:LS a1 v1
18m=audio 10100 UDP/TLS/RTP/SAVPF 96 0 8 97 98
19c=IN IP4 203.0.113.100
20a=mid:a1
21a=sendrecv
22a=rtpmap:96 opus/48000/2
23a=rtpmap:0 PCMU/8000
24a=rtpmap:8 PCMA/8000
25a=rtpmap:97 telephone-event/8000
26a=rtpmap:98 telephone-event/48000
27a=maxptime:120
28a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
29a=extmap:2 urn:ietf:params:rtp-hdrext:ssrc-audio-level
30a=msid:47017fee-b6c1-4162-929c-a25110252400 f83006c5-a0ff-4e0a-9ed9-d3e6747be7d9
31a=ice-ufrag:ETEn
32a=ice-pwd:OtSK0WpNtpUjkY4+86js7ZQl
33a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
34a=setup:actpass
35a=dtls-id:1
36a=rtcp:10101 IN IP4 203.0.113.100
37a=rtcp-mux
38a=rtcp-rsize
39m=video 10102 UDP/TLS/RTP/SAVPF 100 101
40c=IN IP4 203.0.113.100
41a=mid:v1
42a=sendrecv
43a=rtpmap:100 VP8/90000
44a=rtpmap:101 rtx/90000
45a=fmtp:101 apt=100
46a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
47a=rtcp-fb:100 ccm fir
48a=rtcp-fb:100 nack
49a=rtcp-fb:100 nack pli
50a=msid:47017fee-b6c1-4162-929c-a25110252400 f30bdb4a-5db8-49b5-bcdc-e0c9a23172e0
51a=ice-ufrag:BGKk
52a=ice-pwd:mqyWsAjvtKwTGnvhPztQ9mIf
53a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
54a=setup:actpass
55a=dtls-id:1
56a=rtcp:10103 IN IP4 203.0.113.100
57a=rtcp-mux
58a=rtcp-rsize
59`;
60
61 const sessionDesc = { type: 'offer', sdp };
62
63 // valid candidate attributes
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:5164 const sdpMid1 = 'a1';
65 const sdpMLineIndex1 = 0;
66 const usernameFragment1 = 'ETEn';
Soares Chenb20cf6b2017-05-19 12:28:4367
68 const sdpMid2 = 'v1';
69 const sdpMLineIndex2 = 1;
Soares Chen5b9920a2018-02-08 07:48:4870 const usernameFragment2 = 'BGKk';
Soares Chenb20cf6b2017-05-19 12:28:4371
72 const mediaLine1 = 'm=audio';
73 const mediaLine2 = 'm=video';
74
75 const candidateStr1 = 'candidate:1 1 udp 2113929471 203.0.113.100 10100 typ host';
76 const candidateStr2 = 'candidate:1 2 udp 2113929470 203.0.113.100 10101 typ host';
77 const invalidCandidateStr = '(Invalid) candidate \r\n string';
78
79 const candidateLine1 = `a=${candidateStr1}`;
80 const candidateLine2 = `a=${candidateStr2}`;
81 const endOfCandidateLine = 'a=end-of-candidates';
82
83 // Copied from MDN
84 function escapeRegExp(string) {
85 return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
86 }
87
88 // Check that a candidate line is found after the first media line
89 // but before the second, i.e. it belongs to the first media stream
90 function assert_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine) {
91 const line1 = escapeRegExp(beforeMediaLine);
92 const line2 = escapeRegExp(candidateLine);
93 const line3 = escapeRegExp(afterMediaLine);
94
95 const regex = new RegExp(`${line1}[^]+${line2}[^]+${line3}`);
96
97 assert_true(regex.test(sdp),
98 `Expect candidate line to be found between media lines ${beforeMediaLine} and ${afterMediaLine}`);
99 }
100
101 // Check that a candidate line is found after the second media line
102 // i.e. it belongs to the second media stream
103 function assert_candidate_line_after(sdp, beforeMediaLine, candidateLine) {
104 const line1 = escapeRegExp(beforeMediaLine);
105 const line2 = escapeRegExp(candidateLine);
106
107 const regex = new RegExp(`${line1}[^]+${line2}`);
108
109 assert_true(regex.test(sdp),
110 `Expect candidate line to be found after media line ${beforeMediaLine}`);
111 }
112
Soares Chen25c23902017-06-27 15:32:57113 /*
Soares Chen5b9920a2018-02-08 07:48:48114 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57115 4. Return the result of enqueuing the following steps:
116 1. If remoteDescription is null return a promise rejected with a
117 newly created InvalidStateError.
118 */
Soares Chenb20cf6b2017-05-19 12:28:43119 promise_test(t => {
120 const pc = new RTCPeerConnection();
121
Philipp Hancke1622a022018-06-11 10:00:53122 t.add_cleanup(() => pc.close());
123
Soares Chenb20cf6b2017-05-19 12:28:43124 return promise_rejects(t, 'InvalidStateError',
125 pc.addIceCandidate({
126 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51127 sdpMid: sdpMid1,
128 sdpMLineIndex: sdpMLineIndex1,
129 usernameFragment: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43130 }));
131 }, 'Add ICE candidate before setting remote description should reject with InvalidStateError');
132
Soares Chen25c23902017-06-27 15:32:57133 /*
Soares Chen25c23902017-06-27 15:32:57134 Success cases
135 */
Byron Campen [:bwc]2ed31652019-03-22 02:25:24136 // The RTCIceCandidateInit arg to addIceCandidate is optional, and is converted
137 // to the default RTCIceCandidateInit. Then, because the default candidate is
138 // "", addIceCandidate will allow both sdpMid and sdpMLineIndex to be absent.
139 promise_test(async t => {
140 const pc = new RTCPeerConnection();
141
142 t.add_cleanup(() => pc.close());
143
144 await pc.setRemoteDescription(sessionDesc);
145 await pc.addIceCandidate();
146 }, 'addIceCandidate() should work');
147
148 // The RTCIceCandidateInit arg to addIceCandidate is optional, and not
149 // nullable, so null is converted to the default RTCIceCandidateInit. Then,
150 // because the default candidate is "", addIceCandidate will allow both
151 // sdpMid and sdpMLineIndex to be absent.
152 promise_test(async t => {
153 const pc = new RTCPeerConnection();
154
155 t.add_cleanup(() => pc.close());
156
157 await pc.setRemoteDescription(sessionDesc);
158 await pc.addIceCandidate(null);
159 }, 'Add null candidate should work');
160
161 promise_test(async t => {
162 const pc = new RTCPeerConnection();
163
164 t.add_cleanup(() => pc.close());
165
166 await pc.setRemoteDescription(sessionDesc);
167 await pc.addIceCandidate({});
168 }, 'Add candidate with empty dict should work');
169
170 promise_test(async t => {
171 const pc = new RTCPeerConnection();
172
173 t.add_cleanup(() => pc.close());
174
175 await pc.setRemoteDescription(sessionDesc);
176 await pc.addIceCandidate({
177 candidate: '',
178 sdpMid: null,
179 sdpMLineIndex: null,
180 usernameFragment: undefined
181 });
182 }, 'Add candidate with manually filled default values should work');
183
Soares Chenb20cf6b2017-05-19 12:28:43184 promise_test(t => {
185 const pc = new RTCPeerConnection();
186
Philipp Hancke1622a022018-06-11 10:00:53187 t.add_cleanup(() => pc.close());
188
Soares Chenb20cf6b2017-05-19 12:28:43189 return pc.setRemoteDescription(sessionDesc)
190 .then(() => pc.addIceCandidate({
191 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51192 sdpMid: sdpMid1,
193 sdpMLineIndex: sdpMLineIndex1,
194 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43195 }));
196 }, 'Add ICE candidate after setting remote description should succeed');
197
198 promise_test(t => {
199 const pc = new RTCPeerConnection();
200
Philipp Hancke1622a022018-06-11 10:00:53201 t.add_cleanup(() => pc.close());
202
Soares Chenb20cf6b2017-05-19 12:28:43203 return pc.setRemoteDescription(sessionDesc)
204 .then(() => pc.addIceCandidate(new RTCIceCandidate({
205 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51206 sdpMid: sdpMid1,
207 sdpMLineIndex: sdpMLineIndex1,
208 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43209 })));
210 }, 'Add ICE candidate with RTCIceCandidate should succeed');
211
212 promise_test(t => {
213 const pc = new RTCPeerConnection();
214
Philipp Hancke1622a022018-06-11 10:00:53215 t.add_cleanup(() => pc.close());
216
Soares Chenb20cf6b2017-05-19 12:28:43217 return pc.setRemoteDescription(sessionDesc)
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51218 .then(() => pc.addIceCandidate({
219 candidate: candidateStr1,
220 sdpMid: sdpMid1 }));
Soares Chen25c23902017-06-27 15:32:57221 }, 'Add candidate with only valid sdpMid should succeed');
222
223 promise_test(t => {
224 const pc = new RTCPeerConnection();
225
Philipp Hancke1622a022018-06-11 10:00:53226 t.add_cleanup(() => pc.close());
227
Soares Chen25c23902017-06-27 15:32:57228 return pc.setRemoteDescription(sessionDesc)
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51229 .then(() => pc.addIceCandidate({
230 candidate: candidateStr1,
231 sdpMLineIndex: sdpMLineIndex1 }));
Soares Chen25c23902017-06-27 15:32:57232 }, 'Add candidate with only valid sdpMLineIndex should succeed');
233
234 /*
Soares Chen5b9920a2018-02-08 07:48:48235 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57236 4.6.2. If candidate is applied successfully, the user agent MUST queue
237 a task that runs the following steps:
Soares Chen5b9920a2018-02-08 07:48:48238 2. If connection.pendingRemoteDescription is non-null, and represents
239 the ICE generation for which candidate was processed, add
240 candidate to connection.pendingRemoteDescription.
241 3. If connection.currentRemoteDescription is non-null, and represents
242 the ICE generation for which candidate was processed, add
243 candidate to connection.currentRemoteDescription.
Soares Chen25c23902017-06-27 15:32:57244 */
245 promise_test(t => {
246 const pc = new RTCPeerConnection();
247
Philipp Hancke1622a022018-06-11 10:00:53248 t.add_cleanup(() => pc.close());
249
Soares Chen25c23902017-06-27 15:32:57250 return pc.setRemoteDescription(sessionDesc)
Soares Chenb20cf6b2017-05-19 12:28:43251 .then(() => pc.addIceCandidate({
252 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51253 sdpMid: sdpMid1,
254 sdpMLineIndex: sdpMLineIndex1,
255 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43256 }))
257 .then(() => {
258 assert_candidate_line_between(pc.remoteDescription.sdp,
259 mediaLine1, candidateLine1, mediaLine2);
260 });
Soares Chen25c23902017-06-27 15:32:57261 }, 'addIceCandidate with first sdpMid and sdpMLineIndex add candidate to first media stream');
Soares Chenb20cf6b2017-05-19 12:28:43262
263 promise_test(t => {
264 const pc = new RTCPeerConnection();
265
Philipp Hancke1622a022018-06-11 10:00:53266 t.add_cleanup(() => pc.close());
267
Soares Chenb20cf6b2017-05-19 12:28:43268 return pc.setRemoteDescription(sessionDesc)
269 .then(() => pc.addIceCandidate({
270 candidate: candidateStr2,
271 sdpMid: sdpMid2,
272 sdpMLineIndex: sdpMLineIndex2,
Soares Chen5b9920a2018-02-08 07:48:48273 usernameFragment: usernameFragment2
Soares Chenb20cf6b2017-05-19 12:28:43274 }))
275 .then(() => {
276 assert_candidate_line_after(pc.remoteDescription.sdp,
277 mediaLine2, candidateLine2);
278 });
Soares Chen25c23902017-06-27 15:32:57279 }, 'addIceCandidate with second sdpMid and sdpMLineIndex should add candidate to second media stream');
280
281 promise_test(t => {
282 const pc = new RTCPeerConnection();
283
Philipp Hancke1622a022018-06-11 10:00:53284 t.add_cleanup(() => pc.close());
285
Soares Chen25c23902017-06-27 15:32:57286 return pc.setRemoteDescription(sessionDesc)
287 .then(() => pc.addIceCandidate({
288 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51289 sdpMid: sdpMid1,
290 sdpMLineIndex: sdpMLineIndex1,
291 ufrag: null
Soares Chen25c23902017-06-27 15:32:57292 }))
293 .then(() => {
294 assert_candidate_line_between(pc.remoteDescription.sdp,
295 mediaLine1, candidateLine1, mediaLine2);
296 });
Soares Chen5b9920a2018-02-08 07:48:48297 }, 'Add candidate for first media stream with null usernameFragment should add candidate to first media stream');
Soares Chenb20cf6b2017-05-19 12:28:43298
299 promise_test(t => {
300 const pc = new RTCPeerConnection();
301
Philipp Hancke1622a022018-06-11 10:00:53302 t.add_cleanup(() => pc.close());
303
Soares Chenb20cf6b2017-05-19 12:28:43304 return pc.setRemoteDescription(sessionDesc)
305 .then(() => pc.addIceCandidate({
306 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51307 sdpMid: sdpMid1,
308 sdpMLineIndex: sdpMLineIndex1,
309 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43310 }))
311 .then(() => pc.addIceCandidate({
312 candidate: candidateStr2,
313 sdpMid: sdpMid2,
314 sdpMLineIndex: sdpMLineIndex2,
Soares Chen5b9920a2018-02-08 07:48:48315 usernameFragment: usernameFragment2
Soares Chenb20cf6b2017-05-19 12:28:43316 }))
317 .then(() => {
318 assert_candidate_line_between(pc.remoteDescription.sdp,
319 mediaLine1, candidateLine1, mediaLine2);
320
321 assert_candidate_line_after(pc.remoteDescription.sdp,
322 mediaLine2, candidateLine2);
323 });
Soares Chen25c23902017-06-27 15:32:57324 }, 'Adding multiple candidates should add candidates to their corresponding media stream');
Soares Chenb20cf6b2017-05-19 12:28:43325
Soares Chen25c23902017-06-27 15:32:57326 /*
Soares Chen5b9920a2018-02-08 07:48:48327 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57328 4.6. If candidate.candidate is an empty string, process candidate as an
329 end-of-candidates indication for the corresponding media description
330 and ICE candidate generation.
331 2. If candidate is applied successfully, the user agent MUST queue
332 a task that runs the following steps:
Soares Chen5b9920a2018-02-08 07:48:48333 2. If connection.pendingRemoteDescription is non-null, and represents
334 the ICE generation for which candidate was processed, add
335 candidate to connection.pendingRemoteDescription.
336 3. If connection.currentRemoteDescription is non-null, and represents
337 the ICE generation for which candidate was processed, add
338 candidate to connection.currentRemoteDescription.
Soares Chen25c23902017-06-27 15:32:57339 */
Soares Chenb20cf6b2017-05-19 12:28:43340 promise_test(t => {
341 const pc = new RTCPeerConnection();
342
Philipp Hancke1622a022018-06-11 10:00:53343 t.add_cleanup(() => pc.close());
344
Soares Chenb20cf6b2017-05-19 12:28:43345 return pc.setRemoteDescription(sessionDesc)
346 .then(() => pc.addIceCandidate({
347 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51348 sdpMid: sdpMid1,
349 sdpMLineIndex: sdpMLineIndex1,
350 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43351 }))
352 .then(() => pc.addIceCandidate({
353 candidate: '',
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51354 sdpMid: sdpMid1,
355 sdpMLineIndex: sdpMLineIndex1,
356 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43357 }))
358 .then(() => {
359 assert_candidate_line_between(pc.remoteDescription.sdp,
360 mediaLine1, candidateLine1, mediaLine2);
361
362 assert_candidate_line_between(pc.remoteDescription.sdp,
363 mediaLine1, endOfCandidateLine, mediaLine2);
364 });
365 }, 'Add with empty candidate string (end of candidate) should succeed');
366
Soares Chen25c23902017-06-27 15:32:57367 /*
Soares Chen5b9920a2018-02-08 07:48:48368 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57369 3. If both sdpMid and sdpMLineIndex are null, return a promise rejected
370 with a newly created TypeError.
371 */
Soares Chenb20cf6b2017-05-19 12:28:43372 promise_test(t => {
373 const pc = new RTCPeerConnection();
374
Philipp Hancke1622a022018-06-11 10:00:53375 t.add_cleanup(() => pc.close());
376
Soares Chenb20cf6b2017-05-19 12:28:43377 return pc.setRemoteDescription(sessionDesc)
378 .then(() =>
379 promise_rejects(t, new TypeError(),
380 pc.addIceCandidate({
381 candidate: candidateStr1,
382 sdpMid: null,
383 sdpMLineIndex: null
384 })));
385 }, 'Add candidate with both sdpMid and sdpMLineIndex manually set to null should reject with TypeError');
386
387 promise_test(t => {
388 const pc = new RTCPeerConnection();
389
Philipp Hancke1622a022018-06-11 10:00:53390 t.add_cleanup(() => pc.close());
391
Soares Chenb20cf6b2017-05-19 12:28:43392 return pc.setRemoteDescription(sessionDesc)
393 .then(() =>
Soares Chen25c23902017-06-27 15:32:57394 promise_rejects(t, new TypeError(),
Soares Chenb20cf6b2017-05-19 12:28:43395 pc.addIceCandidate({
Soares Chen25c23902017-06-27 15:32:57396 candidate: candidateStr1
Soares Chenb20cf6b2017-05-19 12:28:43397 })));
Soares Chen25c23902017-06-27 15:32:57398 }, 'Add candidate with only valid candidate string should reject with TypeError');
Soares Chenb20cf6b2017-05-19 12:28:43399
400 promise_test(t => {
401 const pc = new RTCPeerConnection();
402
Philipp Hancke1622a022018-06-11 10:00:53403 t.add_cleanup(() => pc.close());
404
Soares Chenb20cf6b2017-05-19 12:28:43405 return pc.setRemoteDescription(sessionDesc)
406 .then(() =>
407 promise_rejects(t, new TypeError(),
408 pc.addIceCandidate({
409 candidate: invalidCandidateStr,
410 sdpMid: null,
411 sdpMLineIndex: null
412 })));
413 }, 'Add candidate with invalid candidate string and both sdpMid and sdpMLineIndex null should reject with TypeError');
414
Soares Chen25c23902017-06-27 15:32:57415 /*
Soares Chen5b9920a2018-02-08 07:48:48416 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57417 4.3. If candidate.sdpMid is not null, run the following steps:
418 1. If candidate.sdpMid is not equal to the mid of any media
419 description in remoteDescription , reject p with a newly
420 created OperationError and abort these steps.
421 */
Soares Chenb20cf6b2017-05-19 12:28:43422 promise_test(t => {
423 const pc = new RTCPeerConnection();
424
Philipp Hancke1622a022018-06-11 10:00:53425 t.add_cleanup(() => pc.close());
426
Soares Chenb20cf6b2017-05-19 12:28:43427 return pc.setRemoteDescription(sessionDesc)
428 .then(() =>
429 promise_rejects(t, 'OperationError',
430 pc.addIceCandidate({
431 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51432 sdpMid: 'invalid',
433 sdpMLineIndex: sdpMLineIndex1,
434 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43435 })));
436 }, 'Add candidate with invalid sdpMid should reject with OperationError');
437
Soares Chen25c23902017-06-27 15:32:57438 /*
Soares Chen5b9920a2018-02-08 07:48:48439 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57440 4.4. Else, if candidate.sdpMLineIndex is not null, run the following
441 steps:
442 1. If candidate.sdpMLineIndex is equal to or larger than the
443 number of media descriptions in remoteDescription , reject p
444 with a newly created OperationError and abort these steps.
445 */
Soares Chenb20cf6b2017-05-19 12:28:43446 promise_test(t => {
447 const pc = new RTCPeerConnection();
448
Philipp Hancke1622a022018-06-11 10:00:53449 t.add_cleanup(() => pc.close());
450
Soares Chenb20cf6b2017-05-19 12:28:43451 return pc.setRemoteDescription(sessionDesc)
452 .then(() =>
453 promise_rejects(t, 'OperationError',
454 pc.addIceCandidate({
455 candidate: candidateStr1,
456 sdpMLineIndex: 2,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51457 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43458 })));
459 }, 'Add candidate with invalid sdpMLineIndex should reject with OperationError');
460
461 // There is an "Else" for the statement:
462 // "Else, if candidate.sdpMLineIndex is not null, ..."
463 promise_test(t => {
464 const pc = new RTCPeerConnection();
465
Philipp Hancke1622a022018-06-11 10:00:53466 t.add_cleanup(() => pc.close());
467
Soares Chenb20cf6b2017-05-19 12:28:43468 return pc.setRemoteDescription(sessionDesc)
469 .then(() => pc.addIceCandidate({
470 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51471 sdpMid: sdpMid1,
Soares Chenb20cf6b2017-05-19 12:28:43472 sdpMLineIndex: 2,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51473 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43474 }));
475 }, 'Invalid sdpMLineIndex should be ignored if valid sdpMid is provided');
476
477 promise_test(t => {
478 const pc = new RTCPeerConnection();
479
Philipp Hancke1622a022018-06-11 10:00:53480 t.add_cleanup(() => pc.close());
481
Soares Chenb20cf6b2017-05-19 12:28:43482 return pc.setRemoteDescription(sessionDesc)
Soares Chenb20cf6b2017-05-19 12:28:43483 .then(() => pc.addIceCandidate({
484 candidate: candidateStr2,
485 sdpMid: sdpMid2,
486 sdpMLineIndex: sdpMLineIndex2,
Soares Chen5b9920a2018-02-08 07:48:48487 usernameFragment: null
Soares Chenb20cf6b2017-05-19 12:28:43488 }))
489 .then(() => {
490 assert_candidate_line_after(pc.remoteDescription.sdp,
491 mediaLine2, candidateLine2);
492 });
Soares Chen5b9920a2018-02-08 07:48:48493 }, 'Add candidate for media stream 2 with null usernameFragment should succeed');
Soares Chenb20cf6b2017-05-19 12:28:43494
Soares Chen25c23902017-06-27 15:32:57495 /*
496 4.3.2. addIceCandidate
Soares Chen5b9920a2018-02-08 07:48:48497 4.5. If candidate.usernameFragment is neither undefined nor null, and is not equal
498 to any usernameFragment present in the corresponding media description of an
Soares Chen25c23902017-06-27 15:32:57499 applied remote description, reject p with a newly created
500 OperationError and abort these steps.
501 */
502 promise_test(t => {
503 const pc = new RTCPeerConnection();
504
Philipp Hancke1622a022018-06-11 10:00:53505 t.add_cleanup(() => pc.close());
506
Soares Chen25c23902017-06-27 15:32:57507 return pc.setRemoteDescription(sessionDesc)
508 .then(() =>
509 promise_rejects(t, 'OperationError',
510 pc.addIceCandidate({
511 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51512 sdpMid: sdpMid1,
513 sdpMLineIndex: sdpMLineIndex1,
514 ufrag: 'invalid'
Soares Chen25c23902017-06-27 15:32:57515 })));
Soares Chen5b9920a2018-02-08 07:48:48516 }, 'Add candidate with invalid usernameFragment should reject with OperationError');
Soares Chen25c23902017-06-27 15:32:57517
518 /*
Soares Chen5b9920a2018-02-08 07:48:48519 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57520 4.6.1. If candidate could not be successfully added the user agent MUST
521 queue a task that runs the following steps:
522 2. Reject p with a DOMException object whose name attribute has
523 the value OperationError and abort these steps.
524 */
525 promise_test(t => {
526 const pc = new RTCPeerConnection();
527
Philipp Hancke1622a022018-06-11 10:00:53528 t.add_cleanup(() => pc.close());
529
Soares Chen25c23902017-06-27 15:32:57530 return pc.setRemoteDescription(sessionDesc)
531 .then(() =>
532 promise_rejects(t, 'OperationError',
533 pc.addIceCandidate({
534 candidate: invalidCandidateStr,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51535 sdpMid: sdpMid1,
536 sdpMLineIndex: sdpMLineIndex1,
537 usernameFragement: usernameFragment1
Soares Chen25c23902017-06-27 15:32:57538 })));
539 }, 'Add candidate with invalid candidate string should reject with OperationError');
540
Soares Chenb20cf6b2017-05-19 12:28:43541 promise_test(t => {
542 const pc = new RTCPeerConnection();
543
Philipp Hancke1622a022018-06-11 10:00:53544 t.add_cleanup(() => pc.close());
545
Soares Chenb20cf6b2017-05-19 12:28:43546 return pc.setRemoteDescription(sessionDesc)
547 .then(() =>
548 promise_rejects(t, 'OperationError',
549 pc.addIceCandidate({
550 candidate: candidateStr2,
551 sdpMid: sdpMid2,
552 sdpMLineIndex: sdpMLineIndex2,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51553 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43554 })));
Soares Chen5b9920a2018-02-08 07:48:48555 }, 'Add candidate with sdpMid belonging to different usernameFragment should reject with OperationError');
Soares Chenb20cf6b2017-05-19 12:28:43556
Soares Chenb20cf6b2017-05-19 12:28:43557</script>