blob: c68e442a2d5094f22d508ec8b6804bc2a58d072f [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
Byron Campen [:bwc]c65630a2019-03-22 02:25:2688 function is_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine) {
Soares Chenb20cf6b2017-05-19 12:28:4389 const line1 = escapeRegExp(beforeMediaLine);
90 const line2 = escapeRegExp(candidateLine);
91 const line3 = escapeRegExp(afterMediaLine);
92
93 const regex = new RegExp(`${line1}[^]+${line2}[^]+${line3}`);
Byron Campen [:bwc]c65630a2019-03-22 02:25:2694 return regex.test(sdp);
95 }
Soares Chenb20cf6b2017-05-19 12:28:4396
Byron Campen [:bwc]c65630a2019-03-22 02:25:2697 // Check that a candidate line is found after the first media line
98 // but before the second, i.e. it belongs to the first media stream
99 function assert_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine) {
100 assert_true(is_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine),
Soares Chenb20cf6b2017-05-19 12:28:43101 `Expect candidate line to be found between media lines ${beforeMediaLine} and ${afterMediaLine}`);
102 }
103
104 // Check that a candidate line is found after the second media line
105 // i.e. it belongs to the second media stream
Byron Campen [:bwc]c65630a2019-03-22 02:25:26106 function is_candidate_line_after(sdp, beforeMediaLine, candidateLine) {
Soares Chenb20cf6b2017-05-19 12:28:43107 const line1 = escapeRegExp(beforeMediaLine);
108 const line2 = escapeRegExp(candidateLine);
109
110 const regex = new RegExp(`${line1}[^]+${line2}`);
111
Byron Campen [:bwc]c65630a2019-03-22 02:25:26112 return regex.test(sdp);
113 }
114
115 function assert_candidate_line_after(sdp, beforeMediaLine, candidateLine) {
116 assert_true(is_candidate_line_after(sdp, beforeMediaLine, candidateLine),
Soares Chenb20cf6b2017-05-19 12:28:43117 `Expect candidate line to be found after media line ${beforeMediaLine}`);
118 }
119
Soares Chen25c23902017-06-27 15:32:57120 /*
Soares Chen5b9920a2018-02-08 07:48:48121 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57122 4. Return the result of enqueuing the following steps:
123 1. If remoteDescription is null return a promise rejected with a
124 newly created InvalidStateError.
125 */
Soares Chenb20cf6b2017-05-19 12:28:43126 promise_test(t => {
127 const pc = new RTCPeerConnection();
128
Philipp Hancke1622a022018-06-11 10:00:53129 t.add_cleanup(() => pc.close());
130
Boris Zbarskyb7f2dd32020-02-04 21:26:48131 return promise_rejects_dom(t, 'InvalidStateError',
Soares Chenb20cf6b2017-05-19 12:28:43132 pc.addIceCandidate({
133 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51134 sdpMid: sdpMid1,
135 sdpMLineIndex: sdpMLineIndex1,
136 usernameFragment: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43137 }));
138 }, 'Add ICE candidate before setting remote description should reject with InvalidStateError');
139
Soares Chen25c23902017-06-27 15:32:57140 /*
Soares Chen25c23902017-06-27 15:32:57141 Success cases
142 */
Byron Campen [:bwc]c65630a2019-03-22 02:25:26143
144 // All of these should work, because all of these end up being equivalent to the
145 // same thing; an end-of-candidates signal for all levels/mids/ufrags.
146 [
147 // This is just the default. Everything else here is equivalent to this.
148 {
149 candidate: '',
150 sdpMid: null,
151 sdpMLineIndex: null,
152 usernameFragment: undefined
153 },
154 // The arg is optional, so when passing undefined we'll just get the default
155 undefined,
156 // The arg is optional, but not nullable, so we get the default again
157 null,
158 // Members in the dictionary take their default values
159 {}
160 ].forEach(init => promise_test(async t => {
Byron Campen [:bwc]2ed31652019-03-22 02:25:24161 const pc = new RTCPeerConnection();
162
163 t.add_cleanup(() => pc.close());
164
165 await pc.setRemoteDescription(sessionDesc);
Byron Campen [:bwc]902f2712019-05-07 10:21:29166 await pc.addIceCandidate(init);
Byron Campen [:bwc]c65630a2019-03-22 02:25:26167 assert_candidate_line_between(pc.remoteDescription.sdp,
168 mediaLine1, endOfCandidateLine, mediaLine2);
169 assert_candidate_line_after(pc.remoteDescription.sdp,
170 mediaLine2, endOfCandidateLine);
171 }, `addIceCandidate(${JSON.stringify(init)}) should work, and add a=end-of-candidates to both m-sections`));
Byron Campen [:bwc]2ed31652019-03-22 02:25:24172
173 promise_test(async t => {
174 const pc = new RTCPeerConnection();
Byron Campen [:bwc]902f2712019-05-07 10:21:29175 t.add_cleanup(() => pc.close());
176 await pc.setRemoteDescription(sessionDesc);
177 await pc.setLocalDescription(await pc.createAnswer());
178 await pc.addIceCandidate({});
179 assert_candidate_line_between(pc.remoteDescription.sdp,
180 mediaLine1, endOfCandidateLine, mediaLine2);
181 assert_candidate_line_after(pc.remoteDescription.sdp,
182 mediaLine2, endOfCandidateLine);
183 }, 'addIceCandidate({}) in stable should work, and add a=end-of-candidates to both m-sections');
184
185 promise_test(async t => {
186 const pc = new RTCPeerConnection();
Byron Campen [:bwc]2ed31652019-03-22 02:25:24187
188 t.add_cleanup(() => pc.close());
189
190 await pc.setRemoteDescription(sessionDesc);
Byron Campen [:bwc]2221fe32019-04-07 11:55:17191 await pc.addIceCandidate({
192 usernameFragment: usernameFragment1,
193 sdpMid: sdpMid1
194 });
Byron Campen [:bwc]c65630a2019-03-22 02:25:26195 assert_candidate_line_between(pc.remoteDescription.sdp,
196 mediaLine1, endOfCandidateLine, mediaLine2);
197 assert_false(is_candidate_line_after(pc.remoteDescription.sdp,
198 mediaLine2, endOfCandidateLine));
Byron Campen [:bwc]2221fe32019-04-07 11:55:17199 }, 'addIceCandidate({usernameFragment: usernameFragment1, sdpMid: sdpMid1}) should work, and add a=end-of-candidates to the first m-section');
Byron Campen [:bwc]2ed31652019-03-22 02:25:24200
201 promise_test(async t => {
202 const pc = new RTCPeerConnection();
203
204 t.add_cleanup(() => pc.close());
205
206 await pc.setRemoteDescription(sessionDesc);
Byron Campen [:bwc]2221fe32019-04-07 11:55:17207 await pc.addIceCandidate({
208 usernameFragment: usernameFragment2,
209 sdpMLineIndex: 1
210 });
Byron Campen [:bwc]c65630a2019-03-22 02:25:26211 assert_false(is_candidate_line_between(pc.remoteDescription.sdp,
212 mediaLine1, endOfCandidateLine, mediaLine2));
213 assert_true(is_candidate_line_after(pc.remoteDescription.sdp,
214 mediaLine2, endOfCandidateLine));
Byron Campen [:bwc]2221fe32019-04-07 11:55:17215 }, 'addIceCandidate({usernameFragment: usernameFragment2, sdpMLineIndex: 1}) should work, and add a=end-of-candidates to the first m-section');
Byron Campen [:bwc]c65630a2019-03-22 02:25:26216
217 promise_test(async t => {
218 const pc = new RTCPeerConnection();
219
220 t.add_cleanup(() => pc.close());
221
222 await pc.setRemoteDescription(sessionDesc);
Boris Zbarskyb7f2dd32020-02-04 21:26:48223 await promise_rejects_dom(t, 'OperationError',
Byron Campen [:bwc]2221fe32019-04-07 11:55:17224 pc.addIceCandidate({usernameFragment: "no such ufrag"}));
225 }, 'addIceCandidate({usernameFragment: "no such ufrag"}) should not work');
Byron Campen [:bwc]2ed31652019-03-22 02:25:24226
Soares Chenb20cf6b2017-05-19 12:28:43227 promise_test(t => {
228 const pc = new RTCPeerConnection();
229
Philipp Hancke1622a022018-06-11 10:00:53230 t.add_cleanup(() => pc.close());
231
Soares Chenb20cf6b2017-05-19 12:28:43232 return pc.setRemoteDescription(sessionDesc)
233 .then(() => pc.addIceCandidate({
234 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51235 sdpMid: sdpMid1,
236 sdpMLineIndex: sdpMLineIndex1,
237 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43238 }));
239 }, 'Add ICE candidate after setting remote description should succeed');
240
241 promise_test(t => {
242 const pc = new RTCPeerConnection();
243
Philipp Hancke1622a022018-06-11 10:00:53244 t.add_cleanup(() => pc.close());
245
Soares Chenb20cf6b2017-05-19 12:28:43246 return pc.setRemoteDescription(sessionDesc)
247 .then(() => pc.addIceCandidate(new RTCIceCandidate({
248 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51249 sdpMid: sdpMid1,
250 sdpMLineIndex: sdpMLineIndex1,
251 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43252 })));
253 }, 'Add ICE candidate with RTCIceCandidate should succeed');
254
255 promise_test(t => {
256 const pc = new RTCPeerConnection();
257
Philipp Hancke1622a022018-06-11 10:00:53258 t.add_cleanup(() => pc.close());
259
Soares Chenb20cf6b2017-05-19 12:28:43260 return pc.setRemoteDescription(sessionDesc)
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51261 .then(() => pc.addIceCandidate({
262 candidate: candidateStr1,
263 sdpMid: sdpMid1 }));
Soares Chen25c23902017-06-27 15:32:57264 }, 'Add candidate with only valid sdpMid should succeed');
265
266 promise_test(t => {
267 const pc = new RTCPeerConnection();
268
Philipp Hancke1622a022018-06-11 10:00:53269 t.add_cleanup(() => pc.close());
270
Soares Chen25c23902017-06-27 15:32:57271 return pc.setRemoteDescription(sessionDesc)
Philipp Hancke740915b2019-05-27 15:35:45272 .then(() => pc.addIceCandidate(new RTCIceCandidate({
273 candidate: candidateStr1,
274 sdpMid: sdpMid1 })));
275 }, 'Add candidate with only valid sdpMid and RTCIceCandidate should succeed');
276
277 promise_test(t => {
278 const pc = new RTCPeerConnection();
279
280 t.add_cleanup(() => pc.close());
281
282 return pc.setRemoteDescription(sessionDesc)
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51283 .then(() => pc.addIceCandidate({
284 candidate: candidateStr1,
285 sdpMLineIndex: sdpMLineIndex1 }));
Soares Chen25c23902017-06-27 15:32:57286 }, 'Add candidate with only valid sdpMLineIndex should succeed');
287
288 /*
Soares Chen5b9920a2018-02-08 07:48:48289 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57290 4.6.2. If candidate is applied successfully, the user agent MUST queue
291 a task that runs the following steps:
Soares Chen5b9920a2018-02-08 07:48:48292 2. If connection.pendingRemoteDescription is non-null, and represents
293 the ICE generation for which candidate was processed, add
294 candidate to connection.pendingRemoteDescription.
295 3. If connection.currentRemoteDescription is non-null, and represents
296 the ICE generation for which candidate was processed, add
297 candidate to connection.currentRemoteDescription.
Soares Chen25c23902017-06-27 15:32:57298 */
299 promise_test(t => {
300 const pc = new RTCPeerConnection();
301
Philipp Hancke1622a022018-06-11 10:00:53302 t.add_cleanup(() => pc.close());
303
Soares Chen25c23902017-06-27 15:32:57304 return pc.setRemoteDescription(sessionDesc)
Soares Chenb20cf6b2017-05-19 12:28:43305 .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(() => {
312 assert_candidate_line_between(pc.remoteDescription.sdp,
313 mediaLine1, candidateLine1, mediaLine2);
314 });
Soares Chen25c23902017-06-27 15:32:57315 }, 'addIceCandidate with first sdpMid and sdpMLineIndex add candidate to first media stream');
Soares Chenb20cf6b2017-05-19 12:28:43316
317 promise_test(t => {
318 const pc = new RTCPeerConnection();
319
Philipp Hancke1622a022018-06-11 10:00:53320 t.add_cleanup(() => pc.close());
321
Soares Chenb20cf6b2017-05-19 12:28:43322 return pc.setRemoteDescription(sessionDesc)
323 .then(() => pc.addIceCandidate({
324 candidate: candidateStr2,
325 sdpMid: sdpMid2,
326 sdpMLineIndex: sdpMLineIndex2,
Soares Chen5b9920a2018-02-08 07:48:48327 usernameFragment: usernameFragment2
Soares Chenb20cf6b2017-05-19 12:28:43328 }))
329 .then(() => {
330 assert_candidate_line_after(pc.remoteDescription.sdp,
331 mediaLine2, candidateLine2);
332 });
Soares Chen25c23902017-06-27 15:32:57333 }, 'addIceCandidate with second sdpMid and sdpMLineIndex should add candidate to second media stream');
334
335 promise_test(t => {
336 const pc = new RTCPeerConnection();
337
Philipp Hancke1622a022018-06-11 10:00:53338 t.add_cleanup(() => pc.close());
339
Soares Chen25c23902017-06-27 15:32:57340 return pc.setRemoteDescription(sessionDesc)
341 .then(() => pc.addIceCandidate({
342 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51343 sdpMid: sdpMid1,
344 sdpMLineIndex: sdpMLineIndex1,
Byron Campen [:bwc]2221fe32019-04-07 11:55:17345 usernameFragment: null
Soares Chen25c23902017-06-27 15:32:57346 }))
347 .then(() => {
348 assert_candidate_line_between(pc.remoteDescription.sdp,
349 mediaLine1, candidateLine1, mediaLine2);
350 });
Soares Chen5b9920a2018-02-08 07:48:48351 }, 'Add candidate for first media stream with null usernameFragment should add candidate to first media stream');
Soares Chenb20cf6b2017-05-19 12:28:43352
353 promise_test(t => {
354 const pc = new RTCPeerConnection();
355
Philipp Hancke1622a022018-06-11 10:00:53356 t.add_cleanup(() => pc.close());
357
Soares Chenb20cf6b2017-05-19 12:28:43358 return pc.setRemoteDescription(sessionDesc)
359 .then(() => pc.addIceCandidate({
360 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51361 sdpMid: sdpMid1,
362 sdpMLineIndex: sdpMLineIndex1,
363 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43364 }))
365 .then(() => pc.addIceCandidate({
366 candidate: candidateStr2,
367 sdpMid: sdpMid2,
368 sdpMLineIndex: sdpMLineIndex2,
Soares Chen5b9920a2018-02-08 07:48:48369 usernameFragment: usernameFragment2
Soares Chenb20cf6b2017-05-19 12:28:43370 }))
371 .then(() => {
372 assert_candidate_line_between(pc.remoteDescription.sdp,
373 mediaLine1, candidateLine1, mediaLine2);
374
375 assert_candidate_line_after(pc.remoteDescription.sdp,
376 mediaLine2, candidateLine2);
377 });
Soares Chen25c23902017-06-27 15:32:57378 }, 'Adding multiple candidates should add candidates to their corresponding media stream');
Soares Chenb20cf6b2017-05-19 12:28:43379
Soares Chen25c23902017-06-27 15:32:57380 /*
Soares Chen5b9920a2018-02-08 07:48:48381 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57382 4.6. If candidate.candidate is an empty string, process candidate as an
383 end-of-candidates indication for the corresponding media description
384 and ICE candidate generation.
385 2. If candidate is applied successfully, the user agent MUST queue
386 a task that runs the following steps:
Soares Chen5b9920a2018-02-08 07:48:48387 2. If connection.pendingRemoteDescription is non-null, and represents
388 the ICE generation for which candidate was processed, add
389 candidate to connection.pendingRemoteDescription.
390 3. If connection.currentRemoteDescription is non-null, and represents
391 the ICE generation for which candidate was processed, add
392 candidate to connection.currentRemoteDescription.
Soares Chen25c23902017-06-27 15:32:57393 */
Soares Chenb20cf6b2017-05-19 12:28:43394 promise_test(t => {
395 const pc = new RTCPeerConnection();
396
Philipp Hancke1622a022018-06-11 10:00:53397 t.add_cleanup(() => pc.close());
398
Soares Chenb20cf6b2017-05-19 12:28:43399 return pc.setRemoteDescription(sessionDesc)
400 .then(() => pc.addIceCandidate({
401 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51402 sdpMid: sdpMid1,
403 sdpMLineIndex: sdpMLineIndex1,
404 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43405 }))
406 .then(() => pc.addIceCandidate({
407 candidate: '',
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51408 sdpMid: sdpMid1,
409 sdpMLineIndex: sdpMLineIndex1,
410 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43411 }))
412 .then(() => {
413 assert_candidate_line_between(pc.remoteDescription.sdp,
414 mediaLine1, candidateLine1, mediaLine2);
415
416 assert_candidate_line_between(pc.remoteDescription.sdp,
417 mediaLine1, endOfCandidateLine, mediaLine2);
418 });
419 }, 'Add with empty candidate string (end of candidate) should succeed');
420
Soares Chen25c23902017-06-27 15:32:57421 /*
Soares Chen5b9920a2018-02-08 07:48:48422 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57423 3. If both sdpMid and sdpMLineIndex are null, return a promise rejected
424 with a newly created TypeError.
425 */
Soares Chenb20cf6b2017-05-19 12:28:43426 promise_test(t => {
427 const pc = new RTCPeerConnection();
428
Philipp Hancke1622a022018-06-11 10:00:53429 t.add_cleanup(() => pc.close());
430
Soares Chenb20cf6b2017-05-19 12:28:43431 return pc.setRemoteDescription(sessionDesc)
432 .then(() =>
Boris Zbarskyab733fd2020-02-04 21:19:03433 promise_rejects_js(t, TypeError,
Soares Chenb20cf6b2017-05-19 12:28:43434 pc.addIceCandidate({
435 candidate: candidateStr1,
436 sdpMid: null,
437 sdpMLineIndex: null
438 })));
439 }, 'Add candidate with both sdpMid and sdpMLineIndex manually set to null should reject with TypeError');
440
441 promise_test(t => {
442 const pc = new RTCPeerConnection();
443
Philipp Hancke1622a022018-06-11 10:00:53444 t.add_cleanup(() => pc.close());
445
Soares Chenb20cf6b2017-05-19 12:28:43446 return pc.setRemoteDescription(sessionDesc)
447 .then(() =>
Boris Zbarskyab733fd2020-02-04 21:19:03448 promise_rejects_js(t, TypeError,
Soares Chenb20cf6b2017-05-19 12:28:43449 pc.addIceCandidate({
Soares Chen25c23902017-06-27 15:32:57450 candidate: candidateStr1
Soares Chenb20cf6b2017-05-19 12:28:43451 })));
Soares Chen25c23902017-06-27 15:32:57452 }, 'Add candidate with only valid candidate string should reject with TypeError');
Soares Chenb20cf6b2017-05-19 12:28:43453
454 promise_test(t => {
455 const pc = new RTCPeerConnection();
456
Philipp Hancke1622a022018-06-11 10:00:53457 t.add_cleanup(() => pc.close());
458
Soares Chenb20cf6b2017-05-19 12:28:43459 return pc.setRemoteDescription(sessionDesc)
460 .then(() =>
Boris Zbarskyab733fd2020-02-04 21:19:03461 promise_rejects_js(t, TypeError,
Soares Chenb20cf6b2017-05-19 12:28:43462 pc.addIceCandidate({
463 candidate: invalidCandidateStr,
464 sdpMid: null,
465 sdpMLineIndex: null
466 })));
467 }, 'Add candidate with invalid candidate string and both sdpMid and sdpMLineIndex null should reject with TypeError');
468
Soares Chen25c23902017-06-27 15:32:57469 /*
Soares Chen5b9920a2018-02-08 07:48:48470 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57471 4.3. If candidate.sdpMid is not null, run the following steps:
472 1. If candidate.sdpMid is not equal to the mid of any media
473 description in remoteDescription , reject p with a newly
474 created OperationError and abort these steps.
475 */
Soares Chenb20cf6b2017-05-19 12:28:43476 promise_test(t => {
477 const pc = new RTCPeerConnection();
478
Philipp Hancke1622a022018-06-11 10:00:53479 t.add_cleanup(() => pc.close());
480
Soares Chenb20cf6b2017-05-19 12:28:43481 return pc.setRemoteDescription(sessionDesc)
482 .then(() =>
Boris Zbarskyb7f2dd32020-02-04 21:26:48483 promise_rejects_dom(t, 'OperationError',
Soares Chenb20cf6b2017-05-19 12:28:43484 pc.addIceCandidate({
485 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51486 sdpMid: 'invalid',
487 sdpMLineIndex: sdpMLineIndex1,
488 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43489 })));
490 }, 'Add candidate with invalid sdpMid should reject with OperationError');
491
Soares Chen25c23902017-06-27 15:32:57492 /*
Soares Chen5b9920a2018-02-08 07:48:48493 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57494 4.4. Else, if candidate.sdpMLineIndex is not null, run the following
495 steps:
496 1. If candidate.sdpMLineIndex is equal to or larger than the
497 number of media descriptions in remoteDescription , reject p
498 with a newly created OperationError and abort these steps.
499 */
Soares Chenb20cf6b2017-05-19 12:28:43500 promise_test(t => {
501 const pc = new RTCPeerConnection();
502
Philipp Hancke1622a022018-06-11 10:00:53503 t.add_cleanup(() => pc.close());
504
Soares Chenb20cf6b2017-05-19 12:28:43505 return pc.setRemoteDescription(sessionDesc)
506 .then(() =>
Boris Zbarskyb7f2dd32020-02-04 21:26:48507 promise_rejects_dom(t, 'OperationError',
Soares Chenb20cf6b2017-05-19 12:28:43508 pc.addIceCandidate({
509 candidate: candidateStr1,
510 sdpMLineIndex: 2,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51511 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43512 })));
513 }, 'Add candidate with invalid sdpMLineIndex should reject with OperationError');
514
515 // There is an "Else" for the statement:
516 // "Else, if candidate.sdpMLineIndex is not null, ..."
517 promise_test(t => {
518 const pc = new RTCPeerConnection();
519
Philipp Hancke1622a022018-06-11 10:00:53520 t.add_cleanup(() => pc.close());
521
Soares Chenb20cf6b2017-05-19 12:28:43522 return pc.setRemoteDescription(sessionDesc)
523 .then(() => pc.addIceCandidate({
524 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51525 sdpMid: sdpMid1,
Soares Chenb20cf6b2017-05-19 12:28:43526 sdpMLineIndex: 2,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51527 usernameFragement: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43528 }));
529 }, 'Invalid sdpMLineIndex should be ignored if valid sdpMid is provided');
530
531 promise_test(t => {
532 const pc = new RTCPeerConnection();
533
Philipp Hancke1622a022018-06-11 10:00:53534 t.add_cleanup(() => pc.close());
535
Soares Chenb20cf6b2017-05-19 12:28:43536 return pc.setRemoteDescription(sessionDesc)
Soares Chenb20cf6b2017-05-19 12:28:43537 .then(() => pc.addIceCandidate({
538 candidate: candidateStr2,
539 sdpMid: sdpMid2,
540 sdpMLineIndex: sdpMLineIndex2,
Soares Chen5b9920a2018-02-08 07:48:48541 usernameFragment: null
Soares Chenb20cf6b2017-05-19 12:28:43542 }))
543 .then(() => {
544 assert_candidate_line_after(pc.remoteDescription.sdp,
545 mediaLine2, candidateLine2);
546 });
Soares Chen5b9920a2018-02-08 07:48:48547 }, 'Add candidate for media stream 2 with null usernameFragment should succeed');
Soares Chenb20cf6b2017-05-19 12:28:43548
Soares Chen25c23902017-06-27 15:32:57549 /*
550 4.3.2. addIceCandidate
Soares Chen5b9920a2018-02-08 07:48:48551 4.5. If candidate.usernameFragment is neither undefined nor null, and is not equal
552 to any usernameFragment present in the corresponding media description of an
Soares Chen25c23902017-06-27 15:32:57553 applied remote description, reject p with a newly created
554 OperationError and abort these steps.
555 */
556 promise_test(t => {
557 const pc = new RTCPeerConnection();
558
Philipp Hancke1622a022018-06-11 10:00:53559 t.add_cleanup(() => pc.close());
560
Soares Chen25c23902017-06-27 15:32:57561 return pc.setRemoteDescription(sessionDesc)
562 .then(() =>
Boris Zbarskyb7f2dd32020-02-04 21:26:48563 promise_rejects_dom(t, 'OperationError',
Soares Chen25c23902017-06-27 15:32:57564 pc.addIceCandidate({
565 candidate: candidateStr1,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51566 sdpMid: sdpMid1,
567 sdpMLineIndex: sdpMLineIndex1,
Byron Campen [:bwc]2221fe32019-04-07 11:55:17568 usernameFragment: 'invalid'
Soares Chen25c23902017-06-27 15:32:57569 })));
Soares Chen5b9920a2018-02-08 07:48:48570 }, 'Add candidate with invalid usernameFragment should reject with OperationError');
Soares Chen25c23902017-06-27 15:32:57571
572 /*
Soares Chen5b9920a2018-02-08 07:48:48573 4.4.2. addIceCandidate
Soares Chen25c23902017-06-27 15:32:57574 4.6.1. If candidate could not be successfully added the user agent MUST
575 queue a task that runs the following steps:
576 2. Reject p with a DOMException object whose name attribute has
577 the value OperationError and abort these steps.
578 */
579 promise_test(t => {
580 const pc = new RTCPeerConnection();
581
Philipp Hancke1622a022018-06-11 10:00:53582 t.add_cleanup(() => pc.close());
583
Soares Chen25c23902017-06-27 15:32:57584 return pc.setRemoteDescription(sessionDesc)
585 .then(() =>
Boris Zbarskyb7f2dd32020-02-04 21:26:48586 promise_rejects_dom(t, 'OperationError',
Soares Chen25c23902017-06-27 15:32:57587 pc.addIceCandidate({
588 candidate: invalidCandidateStr,
Nils Ohlmeier [:drno]b9a2d892018-11-14 03:47:51589 sdpMid: sdpMid1,
590 sdpMLineIndex: sdpMLineIndex1,
591 usernameFragement: usernameFragment1
Soares Chen25c23902017-06-27 15:32:57592 })));
593 }, 'Add candidate with invalid candidate string should reject with OperationError');
594
Soares Chenb20cf6b2017-05-19 12:28:43595 promise_test(t => {
596 const pc = new RTCPeerConnection();
597
Philipp Hancke1622a022018-06-11 10:00:53598 t.add_cleanup(() => pc.close());
599
Soares Chenb20cf6b2017-05-19 12:28:43600 return pc.setRemoteDescription(sessionDesc)
601 .then(() =>
Boris Zbarskyb7f2dd32020-02-04 21:26:48602 promise_rejects_dom(t, 'OperationError',
Soares Chenb20cf6b2017-05-19 12:28:43603 pc.addIceCandidate({
604 candidate: candidateStr2,
605 sdpMid: sdpMid2,
606 sdpMLineIndex: sdpMLineIndex2,
Byron Campen [:bwc]2221fe32019-04-07 11:55:17607 usernameFragment: usernameFragment1
Soares Chenb20cf6b2017-05-19 12:28:43608 })));
Soares Chen5b9920a2018-02-08 07:48:48609 }, 'Add candidate with sdpMid belonging to different usernameFragment should reject with OperationError');
Soares Chenb20cf6b2017-05-19 12:28:43610
Soares Chenb20cf6b2017-05-19 12:28:43611</script>