| 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 |  | 
|  | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 113 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 114 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 115 | 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 Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 119 | promise_test(t => { | 
|  | 120 | const pc = new RTCPeerConnection(); | 
|  | 121 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 122 | t.add_cleanup(() => pc.close()); | 
|  | 123 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 124 | return promise_rejects(t, 'InvalidStateError', | 
|  | 125 | pc.addIceCandidate({ | 
|  | 126 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 127 | sdpMid: sdpMid1, | 
|  | 128 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 129 | usernameFragment: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 130 | })); | 
|  | 131 | }, 'Add ICE candidate before setting remote description should reject with InvalidStateError'); | 
|  | 132 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 133 | /* | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 134 | Success cases | 
|  | 135 | */ | 
| Byron Campen [:bwc] | 2ed3165 | 2019-03-22 02:25:24 | [diff] [blame^] | 136 | // 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 Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 184 | promise_test(t => { | 
|  | 185 | const pc = new RTCPeerConnection(); | 
|  | 186 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 187 | t.add_cleanup(() => pc.close()); | 
|  | 188 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 189 | return pc.setRemoteDescription(sessionDesc) | 
|  | 190 | .then(() => pc.addIceCandidate({ | 
|  | 191 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 192 | sdpMid: sdpMid1, | 
|  | 193 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 194 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 195 | })); | 
|  | 196 | }, 'Add ICE candidate after setting remote description should succeed'); | 
|  | 197 |  | 
|  | 198 | promise_test(t => { | 
|  | 199 | const pc = new RTCPeerConnection(); | 
|  | 200 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 201 | t.add_cleanup(() => pc.close()); | 
|  | 202 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 203 | return pc.setRemoteDescription(sessionDesc) | 
|  | 204 | .then(() => pc.addIceCandidate(new RTCIceCandidate({ | 
|  | 205 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 206 | sdpMid: sdpMid1, | 
|  | 207 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 208 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 209 | }))); | 
|  | 210 | }, 'Add ICE candidate with RTCIceCandidate should succeed'); | 
|  | 211 |  | 
|  | 212 | promise_test(t => { | 
|  | 213 | const pc = new RTCPeerConnection(); | 
|  | 214 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 215 | t.add_cleanup(() => pc.close()); | 
|  | 216 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 217 | return pc.setRemoteDescription(sessionDesc) | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 218 | .then(() => pc.addIceCandidate({ | 
|  | 219 | candidate: candidateStr1, | 
|  | 220 | sdpMid: sdpMid1 })); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 221 | }, 'Add candidate with only valid sdpMid should succeed'); | 
|  | 222 |  | 
|  | 223 | promise_test(t => { | 
|  | 224 | const pc = new RTCPeerConnection(); | 
|  | 225 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 226 | t.add_cleanup(() => pc.close()); | 
|  | 227 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 228 | return pc.setRemoteDescription(sessionDesc) | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 229 | .then(() => pc.addIceCandidate({ | 
|  | 230 | candidate: candidateStr1, | 
|  | 231 | sdpMLineIndex: sdpMLineIndex1 })); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 232 | }, 'Add candidate with only valid sdpMLineIndex should succeed'); | 
|  | 233 |  | 
|  | 234 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 235 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 236 | 4.6.2. If candidate is applied successfully, the user agent MUST queue | 
|  | 237 | a task that runs the following steps: | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 238 | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 244 | */ | 
|  | 245 | promise_test(t => { | 
|  | 246 | const pc = new RTCPeerConnection(); | 
|  | 247 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 248 | t.add_cleanup(() => pc.close()); | 
|  | 249 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 250 | return pc.setRemoteDescription(sessionDesc) | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 251 | .then(() => pc.addIceCandidate({ | 
|  | 252 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 253 | sdpMid: sdpMid1, | 
|  | 254 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 255 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 256 | })) | 
|  | 257 | .then(() => { | 
|  | 258 | assert_candidate_line_between(pc.remoteDescription.sdp, | 
|  | 259 | mediaLine1, candidateLine1, mediaLine2); | 
|  | 260 | }); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 261 | }, 'addIceCandidate with first sdpMid and sdpMLineIndex add candidate to first media stream'); | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 262 |  | 
|  | 263 | promise_test(t => { | 
|  | 264 | const pc = new RTCPeerConnection(); | 
|  | 265 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 266 | t.add_cleanup(() => pc.close()); | 
|  | 267 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 268 | return pc.setRemoteDescription(sessionDesc) | 
|  | 269 | .then(() => pc.addIceCandidate({ | 
|  | 270 | candidate: candidateStr2, | 
|  | 271 | sdpMid: sdpMid2, | 
|  | 272 | sdpMLineIndex: sdpMLineIndex2, | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 273 | usernameFragment: usernameFragment2 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 274 | })) | 
|  | 275 | .then(() => { | 
|  | 276 | assert_candidate_line_after(pc.remoteDescription.sdp, | 
|  | 277 | mediaLine2, candidateLine2); | 
|  | 278 | }); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 279 | }, '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 Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 284 | t.add_cleanup(() => pc.close()); | 
|  | 285 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 286 | return pc.setRemoteDescription(sessionDesc) | 
|  | 287 | .then(() => pc.addIceCandidate({ | 
|  | 288 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 289 | sdpMid: sdpMid1, | 
|  | 290 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 291 | ufrag: null | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 292 | })) | 
|  | 293 | .then(() => { | 
|  | 294 | assert_candidate_line_between(pc.remoteDescription.sdp, | 
|  | 295 | mediaLine1, candidateLine1, mediaLine2); | 
|  | 296 | }); | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 297 | }, '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] | 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 | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 304 | return pc.setRemoteDescription(sessionDesc) | 
|  | 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(() => pc.addIceCandidate({ | 
|  | 312 | candidate: candidateStr2, | 
|  | 313 | sdpMid: sdpMid2, | 
|  | 314 | sdpMLineIndex: sdpMLineIndex2, | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 315 | usernameFragment: usernameFragment2 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 316 | })) | 
|  | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 324 | }, 'Adding multiple candidates should add candidates to their corresponding media stream'); | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 325 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 326 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 327 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 328 | 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 Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 333 | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 339 | */ | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 340 | promise_test(t => { | 
|  | 341 | const pc = new RTCPeerConnection(); | 
|  | 342 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 343 | t.add_cleanup(() => pc.close()); | 
|  | 344 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 345 | return pc.setRemoteDescription(sessionDesc) | 
|  | 346 | .then(() => pc.addIceCandidate({ | 
|  | 347 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 348 | sdpMid: sdpMid1, | 
|  | 349 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 350 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 351 | })) | 
|  | 352 | .then(() => pc.addIceCandidate({ | 
|  | 353 | candidate: '', | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 354 | sdpMid: sdpMid1, | 
|  | 355 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 356 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 357 | })) | 
|  | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 367 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 368 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 369 | 3. If both sdpMid and sdpMLineIndex are null, return a promise rejected | 
|  | 370 | with a newly created TypeError. | 
|  | 371 | */ | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 372 | promise_test(t => { | 
|  | 373 | const pc = new RTCPeerConnection(); | 
|  | 374 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 375 | t.add_cleanup(() => pc.close()); | 
|  | 376 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 377 | 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 Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 390 | t.add_cleanup(() => pc.close()); | 
|  | 391 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 392 | return pc.setRemoteDescription(sessionDesc) | 
|  | 393 | .then(() => | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 394 | promise_rejects(t, new TypeError(), | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 395 | pc.addIceCandidate({ | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 396 | candidate: candidateStr1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 397 | }))); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 398 | }, 'Add candidate with only valid candidate string should reject with TypeError'); | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 399 |  | 
|  | 400 | promise_test(t => { | 
|  | 401 | const pc = new RTCPeerConnection(); | 
|  | 402 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 403 | t.add_cleanup(() => pc.close()); | 
|  | 404 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 405 | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 415 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 416 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 417 | 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 Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 422 | promise_test(t => { | 
|  | 423 | const pc = new RTCPeerConnection(); | 
|  | 424 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 425 | t.add_cleanup(() => pc.close()); | 
|  | 426 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 427 | return pc.setRemoteDescription(sessionDesc) | 
|  | 428 | .then(() => | 
|  | 429 | promise_rejects(t, 'OperationError', | 
|  | 430 | pc.addIceCandidate({ | 
|  | 431 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 432 | sdpMid: 'invalid', | 
|  | 433 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 434 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 435 | }))); | 
|  | 436 | }, 'Add candidate with invalid sdpMid should reject with OperationError'); | 
|  | 437 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 438 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 439 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 440 | 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 Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 446 | promise_test(t => { | 
|  | 447 | const pc = new RTCPeerConnection(); | 
|  | 448 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 449 | t.add_cleanup(() => pc.close()); | 
|  | 450 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 451 | return pc.setRemoteDescription(sessionDesc) | 
|  | 452 | .then(() => | 
|  | 453 | promise_rejects(t, 'OperationError', | 
|  | 454 | pc.addIceCandidate({ | 
|  | 455 | candidate: candidateStr1, | 
|  | 456 | sdpMLineIndex: 2, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 457 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 458 | }))); | 
|  | 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 Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 466 | t.add_cleanup(() => pc.close()); | 
|  | 467 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 468 | return pc.setRemoteDescription(sessionDesc) | 
|  | 469 | .then(() => pc.addIceCandidate({ | 
|  | 470 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 471 | sdpMid: sdpMid1, | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 472 | sdpMLineIndex: 2, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 473 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 474 | })); | 
|  | 475 | }, 'Invalid sdpMLineIndex should be ignored if valid sdpMid is provided'); | 
|  | 476 |  | 
|  | 477 | promise_test(t => { | 
|  | 478 | const pc = new RTCPeerConnection(); | 
|  | 479 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 480 | t.add_cleanup(() => pc.close()); | 
|  | 481 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 482 | return pc.setRemoteDescription(sessionDesc) | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 483 | .then(() => pc.addIceCandidate({ | 
|  | 484 | candidate: candidateStr2, | 
|  | 485 | sdpMid: sdpMid2, | 
|  | 486 | sdpMLineIndex: sdpMLineIndex2, | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 487 | usernameFragment: null | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 488 | })) | 
|  | 489 | .then(() => { | 
|  | 490 | assert_candidate_line_after(pc.remoteDescription.sdp, | 
|  | 491 | mediaLine2, candidateLine2); | 
|  | 492 | }); | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 493 | }, 'Add candidate for media stream 2 with null usernameFragment should succeed'); | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 494 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 495 | /* | 
|  | 496 | 4.3.2. addIceCandidate | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 497 | 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 Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 499 | 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 Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 505 | t.add_cleanup(() => pc.close()); | 
|  | 506 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 507 | return pc.setRemoteDescription(sessionDesc) | 
|  | 508 | .then(() => | 
|  | 509 | promise_rejects(t, 'OperationError', | 
|  | 510 | pc.addIceCandidate({ | 
|  | 511 | candidate: candidateStr1, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 512 | sdpMid: sdpMid1, | 
|  | 513 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 514 | ufrag: 'invalid' | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 515 | }))); | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 516 | }, 'Add candidate with invalid usernameFragment should reject with OperationError'); | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 517 |  | 
|  | 518 | /* | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 519 | 4.4.2. addIceCandidate | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 520 | 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 Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 528 | t.add_cleanup(() => pc.close()); | 
|  | 529 |  | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 530 | return pc.setRemoteDescription(sessionDesc) | 
|  | 531 | .then(() => | 
|  | 532 | promise_rejects(t, 'OperationError', | 
|  | 533 | pc.addIceCandidate({ | 
|  | 534 | candidate: invalidCandidateStr, | 
| Nils Ohlmeier [:drno] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 535 | sdpMid: sdpMid1, | 
|  | 536 | sdpMLineIndex: sdpMLineIndex1, | 
|  | 537 | usernameFragement: usernameFragment1 | 
| Soares Chen | 25c2390 | 2017-06-27 15:32:57 | [diff] [blame] | 538 | }))); | 
|  | 539 | }, 'Add candidate with invalid candidate string should reject with OperationError'); | 
|  | 540 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 541 | promise_test(t => { | 
|  | 542 | const pc = new RTCPeerConnection(); | 
|  | 543 |  | 
| Philipp Hancke | 1622a02 | 2018-06-11 10:00:53 | [diff] [blame] | 544 | t.add_cleanup(() => pc.close()); | 
|  | 545 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 546 | 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] | b9a2d89 | 2018-11-14 03:47:51 | [diff] [blame] | 553 | usernameFragement: usernameFragment1 | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 554 | }))); | 
| Soares Chen | 5b9920a | 2018-02-08 07:48:48 | [diff] [blame] | 555 | }, 'Add candidate with sdpMid belonging to different usernameFragment should reject with OperationError'); | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 556 |  | 
| Soares Chen | b20cf6b | 2017-05-19 12:28:43 | [diff] [blame] | 557 | </script> |