| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 1 | <!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 Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 8 | // 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 | 
|  | 12 | o=- 4962303333179871722 1 IN IP4 0.0.0.0 | 
|  | 13 | s=- | 
|  | 14 | t=0 0 | 
|  | 15 | a=ice-options:trickle | 
|  | 16 | a=group:BUNDLE a1 v1 | 
|  | 17 | a=group:LS a1 v1 | 
|  | 18 | m=audio 10100 UDP/TLS/RTP/SAVPF 96 0 8 97 98 | 
|  | 19 | c=IN IP4 203.0.113.100 | 
|  | 20 | a=mid:a1 | 
|  | 21 | a=sendrecv | 
|  | 22 | a=rtpmap:96 opus/48000/2 | 
|  | 23 | a=rtpmap:0 PCMU/8000 | 
|  | 24 | a=rtpmap:8 PCMA/8000 | 
|  | 25 | a=rtpmap:97 telephone-event/8000 | 
|  | 26 | a=rtpmap:98 telephone-event/48000 | 
|  | 27 | a=maxptime:120 | 
|  | 28 | a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid | 
|  | 29 | a=extmap:2 urn:ietf:params:rtp-hdrext:ssrc-audio-level | 
|  | 30 | a=msid:47017fee-b6c1-4162-929c-a25110252400 f83006c5-a0ff-4e0a-9ed9-d3e6747be7d9 | 
|  | 31 | a=ice-ufrag:ETEn | 
|  | 32 | a=ice-pwd:OtSK0WpNtpUjkY4+86js7ZQl | 
|  | 33 | a=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 | 
|  | 34 | a=setup:actpass | 
|  | 35 | a=dtls-id:1 | 
|  | 36 | a=rtcp:10101 IN IP4 203.0.113.100 | 
|  | 37 | a=rtcp-mux | 
|  | 38 | a=rtcp-rsize | 
|  | 39 | m=video 10102 UDP/TLS/RTP/SAVPF 100 101 | 
|  | 40 | c=IN IP4 203.0.113.100 | 
|  | 41 | a=mid:v1 | 
|  | 42 | a=sendrecv | 
|  | 43 | a=rtpmap:100 VP8/90000 | 
|  | 44 | a=rtpmap:101 rtx/90000 | 
|  | 45 | a=fmtp:101 apt=100 | 
|  | 46 | a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid | 
|  | 47 | a=rtcp-fb:100 ccm fir | 
|  | 48 | a=rtcp-fb:100 nack | 
|  | 49 | a=rtcp-fb:100 nack pli | 
|  | 50 | a=msid:47017fee-b6c1-4162-929c-a25110252400 f30bdb4a-5db8-49b5-bcdc-e0c9a23172e0 | 
|  | 51 | a=ice-ufrag:BGKk | 
|  | 52 | a=ice-pwd:mqyWsAjvtKwTGnvhPztQ9mIf | 
|  | 53 | a=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 | 
|  | 54 | a=setup:actpass | 
|  | 55 | a=dtls-id:1 | 
|  | 56 | a=rtcp:10103 IN IP4 203.0.113.100 | 
|  | 57 | a=rtcp-mux | 
|  | 58 | a=rtcp-rsize | 
|  | 59 | `; | 
|  | 60 |  | 
|  | 61 | const sessionDesc = { type: 'offer', sdp }; | 
|  | 62 |  | 
|  | 63 | // valid candidate attributes | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 64 | const sdpMid1 = 'a1'; | 
|  | 65 | const sdpMLineIndex1 = 0; | 
|  | 66 | const usernameFragment1 = 'ETEn'; | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 67 |  | 
|  | 68 | const sdpMid2 = 'v1'; | 
|  | 69 | const sdpMLineIndex2 = 1; | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 70 | const usernameFragment2 = 'BGKk'; | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 71 |  | 
|  | 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] | c65630a | 2019-03-22 02:25:26 | [diff] [blame] | 88 | function is_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine) { | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 89 | 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] | c65630a | 2019-03-22 02:25:26 | [diff] [blame] | 94 | return regex.test(sdp); | 
|  | 95 | } | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 96 |  | 
| Byron Campen [:bwc] | c65630a | 2019-03-22 02:25:26 | [diff] [blame] | 97 | // 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 Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 101 | `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] | c65630a | 2019-03-22 02:25:26 | [diff] [blame] | 106 | function is_candidate_line_after(sdp, beforeMediaLine, candidateLine) { | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 107 | const line1 = escapeRegExp(beforeMediaLine); | 
|  | 108 | const line2 = escapeRegExp(candidateLine); | 
|  | 109 |  | 
|  | 110 | const regex = new RegExp(`${line1}[^]+${line2}`); | 
|  | 111 |  | 
| Byron Campen [:bwc] | c65630a | 2019-03-22 02:25:26 | [diff] [blame] | 112 | 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 Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 117 | `Expect candidate line to be found after media line ${beforeMediaLine}`); | 
|  | 118 | } | 
|  | 119 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 120 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 121 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 122 | 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 Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 126 | promise_test(t => { | 
|  | 127 | const pc = new RTCPeerConnection(); | 
|  | 128 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 129 | t.add_cleanup(() => pc.close()); | 
|  | 130 |  | 
| Boris Zbarsky | b7f2dd3 | 2020-02-04 21:26:48 | [diff] [blame] | 131 | return promise_rejects_dom(t, 'InvalidStateError', | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 132 | pc.addIceCandidate({ | 
|  | 133 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 134 | sdpMid: sdpMid1, | 
|  | 135 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 136 | usernameFragment: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 137 | })); | 
|  | 138 | }, 'Add ICE candidate before setting remote description should reject with InvalidStateError'); | 
|  | 139 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 140 | /* | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 141 | Success cases | 
|  | 142 | */ | 
| Byron Campen [:bwc] | c65630a | 2019-03-22 02:25:26 | [diff] [blame] | 143 |  | 
|  | 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] | 2ed3165 | 2019-03-22 02:25:24 | [diff] [blame] | 161 | const pc = new RTCPeerConnection(); | 
|  | 162 |  | 
|  | 163 | t.add_cleanup(() => pc.close()); | 
|  | 164 |  | 
|  | 165 | await pc.setRemoteDescription(sessionDesc); | 
| Byron Campen [:bwc] | 902f271 | 2019-05-07 10:21:29 | [diff] [blame] | 166 | await pc.addIceCandidate(init); | 
| Byron Campen [:bwc] | c65630a | 2019-03-22 02:25:26 | [diff] [blame] | 167 | 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] | 2ed3165 | 2019-03-22 02:25:24 | [diff] [blame] | 172 |  | 
|  | 173 | promise_test(async t => { | 
|  | 174 | const pc = new RTCPeerConnection(); | 
| Byron Campen [:bwc] | 902f271 | 2019-05-07 10:21:29 | [diff] [blame] | 175 | 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] | 2ed3165 | 2019-03-22 02:25:24 | [diff] [blame] | 187 |  | 
|  | 188 | t.add_cleanup(() => pc.close()); | 
|  | 189 |  | 
|  | 190 | await pc.setRemoteDescription(sessionDesc); | 
| Byron Campen [:bwc] | 2221fe3 | 2019-04-07 11:55:17 | [diff] [blame] | 191 | await pc.addIceCandidate({ | 
|  | 192 | usernameFragment: usernameFragment1, | 
|  | 193 | sdpMid: sdpMid1 | 
|  | 194 | }); | 
| Byron Campen [:bwc] | c65630a | 2019-03-22 02:25:26 | [diff] [blame] | 195 | 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] | 2221fe3 | 2019-04-07 11:55:17 | [diff] [blame] | 199 | }, 'addIceCandidate({usernameFragment: usernameFragment1, sdpMid: sdpMid1}) should work, and add a=end-of-candidates to the first m-section'); | 
| Byron Campen [:bwc] | 2ed3165 | 2019-03-22 02:25:24 | [diff] [blame] | 200 |  | 
|  | 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] | 2221fe3 | 2019-04-07 11:55:17 | [diff] [blame] | 207 | await pc.addIceCandidate({ | 
|  | 208 | usernameFragment: usernameFragment2, | 
|  | 209 | sdpMLineIndex: 1 | 
|  | 210 | }); | 
| Byron Campen [:bwc] | c65630a | 2019-03-22 02:25:26 | [diff] [blame] | 211 | 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] | 2221fe3 | 2019-04-07 11:55:17 | [diff] [blame] | 215 | }, 'addIceCandidate({usernameFragment: usernameFragment2, sdpMLineIndex: 1}) should work, and add a=end-of-candidates to the first m-section'); | 
| Byron Campen [:bwc] | c65630a | 2019-03-22 02:25:26 | [diff] [blame] | 216 |  | 
|  | 217 | promise_test(async t => { | 
|  | 218 | const pc = new RTCPeerConnection(); | 
|  | 219 |  | 
|  | 220 | t.add_cleanup(() => pc.close()); | 
|  | 221 |  | 
|  | 222 | await pc.setRemoteDescription(sessionDesc); | 
| Boris Zbarsky | b7f2dd3 | 2020-02-04 21:26:48 | [diff] [blame] | 223 | await promise_rejects_dom(t, 'OperationError', | 
| Byron Campen [:bwc] | 2221fe3 | 2019-04-07 11:55:17 | [diff] [blame] | 224 | pc.addIceCandidate({usernameFragment: "no such ufrag"})); | 
|  | 225 | }, 'addIceCandidate({usernameFragment: "no such ufrag"}) should not work'); | 
| Byron Campen [:bwc] | 2ed3165 | 2019-03-22 02:25:24 | [diff] [blame] | 226 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 227 | promise_test(t => { | 
|  | 228 | const pc = new RTCPeerConnection(); | 
|  | 229 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 230 | t.add_cleanup(() => pc.close()); | 
|  | 231 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 232 | return pc.setRemoteDescription(sessionDesc) | 
|  | 233 | .then(() => pc.addIceCandidate({ | 
|  | 234 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 235 | sdpMid: sdpMid1, | 
|  | 236 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 237 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 238 | })); | 
|  | 239 | }, 'Add ICE candidate after setting remote description should succeed'); | 
|  | 240 |  | 
|  | 241 | promise_test(t => { | 
|  | 242 | const pc = new RTCPeerConnection(); | 
|  | 243 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 244 | t.add_cleanup(() => pc.close()); | 
|  | 245 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 246 | return pc.setRemoteDescription(sessionDesc) | 
|  | 247 | .then(() => pc.addIceCandidate(new RTCIceCandidate({ | 
|  | 248 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 249 | sdpMid: sdpMid1, | 
|  | 250 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 251 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 252 | }))); | 
|  | 253 | }, 'Add ICE candidate with RTCIceCandidate should succeed'); | 
|  | 254 |  | 
|  | 255 | promise_test(t => { | 
|  | 256 | const pc = new RTCPeerConnection(); | 
|  | 257 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 258 | t.add_cleanup(() => pc.close()); | 
|  | 259 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 260 | return pc.setRemoteDescription(sessionDesc) | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 261 | .then(() => pc.addIceCandidate({ | 
|  | 262 | candidate: candidateStr1, | 
|  | 263 | sdpMid: sdpMid1 })); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 264 | }, 'Add candidate with only valid sdpMid should succeed'); | 
|  | 265 |  | 
|  | 266 | promise_test(t => { | 
|  | 267 | const pc = new RTCPeerConnection(); | 
|  | 268 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 269 | t.add_cleanup(() => pc.close()); | 
|  | 270 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 271 | return pc.setRemoteDescription(sessionDesc) | 
| Philipp Hancke | 740915b | 2019-05-27 15:35:45 | [diff] [blame] | 272 | .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] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 283 | .then(() => pc.addIceCandidate({ | 
|  | 284 | candidate: candidateStr1, | 
|  | 285 | sdpMLineIndex: sdpMLineIndex1 })); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 286 | }, 'Add candidate with only valid sdpMLineIndex should succeed'); | 
|  | 287 |  | 
|  | 288 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 289 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 290 | 4.6.2. If candidate is applied successfully, the user agent MUST queue | 
|  | 291 | a task that runs the following steps: | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 292 | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 298 | */ | 
|  | 299 | promise_test(t => { | 
|  | 300 | const pc = new RTCPeerConnection(); | 
|  | 301 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 302 | t.add_cleanup(() => pc.close()); | 
|  | 303 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 304 | return pc.setRemoteDescription(sessionDesc) | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 305 | .then(() => pc.addIceCandidate({ | 
|  | 306 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 307 | sdpMid: sdpMid1, | 
|  | 308 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 309 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 310 | })) | 
|  | 311 | .then(() => { | 
|  | 312 | assert_candidate_line_between(pc.remoteDescription.sdp, | 
|  | 313 | mediaLine1, candidateLine1, mediaLine2); | 
|  | 314 | }); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 315 | }, 'addIceCandidate with first sdpMid and sdpMLineIndex add candidate to first media stream'); | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 316 |  | 
|  | 317 | promise_test(t => { | 
|  | 318 | const pc = new RTCPeerConnection(); | 
|  | 319 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 320 | t.add_cleanup(() => pc.close()); | 
|  | 321 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 322 | return pc.setRemoteDescription(sessionDesc) | 
|  | 323 | .then(() => pc.addIceCandidate({ | 
|  | 324 | candidate: candidateStr2, | 
|  | 325 | sdpMid: sdpMid2, | 
|  | 326 | sdpMLineIndex: sdpMLineIndex2, | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 327 | usernameFragment: usernameFragment2 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 328 | })) | 
|  | 329 | .then(() => { | 
|  | 330 | assert_candidate_line_after(pc.remoteDescription.sdp, | 
|  | 331 | mediaLine2, candidateLine2); | 
|  | 332 | }); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 333 | }, '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 Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 338 | t.add_cleanup(() => pc.close()); | 
|  | 339 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 340 | return pc.setRemoteDescription(sessionDesc) | 
|  | 341 | .then(() => pc.addIceCandidate({ | 
|  | 342 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 343 | sdpMid: sdpMid1, | 
|  | 344 | sdpMLineIndex: sdpMLineIndex1, | 
| Byron Campen [:bwc] | 2221fe3 | 2019-04-07 11:55:17 | [diff] [blame] | 345 | usernameFragment: null | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 346 | })) | 
|  | 347 | .then(() => { | 
|  | 348 | assert_candidate_line_between(pc.remoteDescription.sdp, | 
|  | 349 | mediaLine1, candidateLine1, mediaLine2); | 
|  | 350 | }); | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 351 | }, 'Add candidate for first media stream with null usernameFragment should add candidate to first media stream'); | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 352 |  | 
|  | 353 | promise_test(t => { | 
|  | 354 | const pc = new RTCPeerConnection(); | 
|  | 355 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 356 | t.add_cleanup(() => pc.close()); | 
|  | 357 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 358 | return pc.setRemoteDescription(sessionDesc) | 
|  | 359 | .then(() => pc.addIceCandidate({ | 
|  | 360 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 361 | sdpMid: sdpMid1, | 
|  | 362 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 363 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 364 | })) | 
|  | 365 | .then(() => pc.addIceCandidate({ | 
|  | 366 | candidate: candidateStr2, | 
|  | 367 | sdpMid: sdpMid2, | 
|  | 368 | sdpMLineIndex: sdpMLineIndex2, | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 369 | usernameFragment: usernameFragment2 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 370 | })) | 
|  | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 378 | }, 'Adding multiple candidates should add candidates to their corresponding media stream'); | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 379 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 380 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 381 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 382 | 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 Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 387 | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 393 | */ | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 394 | promise_test(t => { | 
|  | 395 | const pc = new RTCPeerConnection(); | 
|  | 396 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 397 | t.add_cleanup(() => pc.close()); | 
|  | 398 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 399 | return pc.setRemoteDescription(sessionDesc) | 
|  | 400 | .then(() => pc.addIceCandidate({ | 
|  | 401 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 402 | sdpMid: sdpMid1, | 
|  | 403 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 404 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 405 | })) | 
|  | 406 | .then(() => pc.addIceCandidate({ | 
|  | 407 | candidate: '', | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 408 | sdpMid: sdpMid1, | 
|  | 409 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 410 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 411 | })) | 
|  | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 421 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 422 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 423 | 3. If both sdpMid and sdpMLineIndex are null, return a promise rejected | 
|  | 424 | with a newly created TypeError. | 
|  | 425 | */ | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 426 | promise_test(t => { | 
|  | 427 | const pc = new RTCPeerConnection(); | 
|  | 428 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 429 | t.add_cleanup(() => pc.close()); | 
|  | 430 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 431 | return pc.setRemoteDescription(sessionDesc) | 
|  | 432 | .then(() => | 
| Boris Zbarsky | ab733fd | 2020-02-04 21:19:03 | [diff] [blame] | 433 | promise_rejects_js(t, TypeError, | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 434 | 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 Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 444 | t.add_cleanup(() => pc.close()); | 
|  | 445 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 446 | return pc.setRemoteDescription(sessionDesc) | 
|  | 447 | .then(() => | 
| Boris Zbarsky | ab733fd | 2020-02-04 21:19:03 | [diff] [blame] | 448 | promise_rejects_js(t, TypeError, | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 449 | pc.addIceCandidate({ | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 450 | candidate: candidateStr1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 451 | }))); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 452 | }, 'Add candidate with only valid candidate string should reject with TypeError'); | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 453 |  | 
|  | 454 | promise_test(t => { | 
|  | 455 | const pc = new RTCPeerConnection(); | 
|  | 456 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 457 | t.add_cleanup(() => pc.close()); | 
|  | 458 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 459 | return pc.setRemoteDescription(sessionDesc) | 
|  | 460 | .then(() => | 
| Boris Zbarsky | ab733fd | 2020-02-04 21:19:03 | [diff] [blame] | 461 | promise_rejects_js(t, TypeError, | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 462 | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 469 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 470 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 471 | 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 Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 476 | promise_test(t => { | 
|  | 477 | const pc = new RTCPeerConnection(); | 
|  | 478 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 479 | t.add_cleanup(() => pc.close()); | 
|  | 480 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 481 | return pc.setRemoteDescription(sessionDesc) | 
|  | 482 | .then(() => | 
| Boris Zbarsky | b7f2dd3 | 2020-02-04 21:26:48 | [diff] [blame] | 483 | promise_rejects_dom(t, 'OperationError', | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 484 | pc.addIceCandidate({ | 
|  | 485 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 486 | sdpMid: 'invalid', | 
|  | 487 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 488 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 489 | }))); | 
|  | 490 | }, 'Add candidate with invalid sdpMid should reject with OperationError'); | 
|  | 491 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 492 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 493 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 494 | 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 Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 500 | promise_test(t => { | 
|  | 501 | const pc = new RTCPeerConnection(); | 
|  | 502 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 503 | t.add_cleanup(() => pc.close()); | 
|  | 504 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 505 | return pc.setRemoteDescription(sessionDesc) | 
|  | 506 | .then(() => | 
| Boris Zbarsky | b7f2dd3 | 2020-02-04 21:26:48 | [diff] [blame] | 507 | promise_rejects_dom(t, 'OperationError', | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 508 | pc.addIceCandidate({ | 
|  | 509 | candidate: candidateStr1, | 
|  | 510 | sdpMLineIndex: 2, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 511 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 512 | }))); | 
|  | 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 Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 520 | t.add_cleanup(() => pc.close()); | 
|  | 521 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 522 | return pc.setRemoteDescription(sessionDesc) | 
|  | 523 | .then(() => pc.addIceCandidate({ | 
|  | 524 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 525 | sdpMid: sdpMid1, | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 526 | sdpMLineIndex: 2, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 527 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 528 | })); | 
|  | 529 | }, 'Invalid sdpMLineIndex should be ignored if valid sdpMid is provided'); | 
|  | 530 |  | 
|  | 531 | promise_test(t => { | 
|  | 532 | const pc = new RTCPeerConnection(); | 
|  | 533 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 534 | t.add_cleanup(() => pc.close()); | 
|  | 535 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 536 | return pc.setRemoteDescription(sessionDesc) | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 537 | .then(() => pc.addIceCandidate({ | 
|  | 538 | candidate: candidateStr2, | 
|  | 539 | sdpMid: sdpMid2, | 
|  | 540 | sdpMLineIndex: sdpMLineIndex2, | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 541 | usernameFragment: null | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 542 | })) | 
|  | 543 | .then(() => { | 
|  | 544 | assert_candidate_line_after(pc.remoteDescription.sdp, | 
|  | 545 | mediaLine2, candidateLine2); | 
|  | 546 | }); | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 547 | }, 'Add candidate for media stream 2 with null usernameFragment should succeed'); | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 548 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 549 | /* | 
|  | 550 | 4.3.2. addIceCandidate | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 551 | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 553 | 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 Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 559 | t.add_cleanup(() => pc.close()); | 
|  | 560 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 561 | return pc.setRemoteDescription(sessionDesc) | 
|  | 562 | .then(() => | 
| Boris Zbarsky | b7f2dd3 | 2020-02-04 21:26:48 | [diff] [blame] | 563 | promise_rejects_dom(t, 'OperationError', | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 564 | pc.addIceCandidate({ | 
|  | 565 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 566 | sdpMid: sdpMid1, | 
|  | 567 | sdpMLineIndex: sdpMLineIndex1, | 
| Byron Campen [:bwc] | 2221fe3 | 2019-04-07 11:55:17 | [diff] [blame] | 568 | usernameFragment: 'invalid' | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 569 | }))); | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 570 | }, 'Add candidate with invalid usernameFragment should reject with OperationError'); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 571 |  | 
|  | 572 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 573 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 574 | 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 Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 582 | t.add_cleanup(() => pc.close()); | 
|  | 583 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 584 | return pc.setRemoteDescription(sessionDesc) | 
|  | 585 | .then(() => | 
| Boris Zbarsky | b7f2dd3 | 2020-02-04 21:26:48 | [diff] [blame] | 586 | promise_rejects_dom(t, 'OperationError', | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 587 | pc.addIceCandidate({ | 
|  | 588 | candidate: invalidCandidateStr, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 589 | sdpMid: sdpMid1, | 
|  | 590 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 591 | usernameFragement: usernameFragment1 | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 592 | }))); | 
|  | 593 | }, 'Add candidate with invalid candidate string should reject with OperationError'); | 
|  | 594 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 595 | promise_test(t => { | 
|  | 596 | const pc = new RTCPeerConnection(); | 
|  | 597 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 598 | t.add_cleanup(() => pc.close()); | 
|  | 599 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 600 | return pc.setRemoteDescription(sessionDesc) | 
|  | 601 | .then(() => | 
| Boris Zbarsky | b7f2dd3 | 2020-02-04 21:26:48 | [diff] [blame] | 602 | promise_rejects_dom(t, 'OperationError', | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 603 | pc.addIceCandidate({ | 
|  | 604 | candidate: candidateStr2, | 
|  | 605 | sdpMid: sdpMid2, | 
|  | 606 | sdpMLineIndex: sdpMLineIndex2, | 
| Byron Campen [:bwc] | 2221fe3 | 2019-04-07 11:55:17 | [diff] [blame] | 607 | usernameFragment: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 608 | }))); | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 609 | }, 'Add candidate with sdpMid belonging to different usernameFragment should reject with OperationError'); | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 610 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 611 | </script> |