ice-state.https.html (4703B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <meta name="timeout" content="long"> 4 <title>RTCPeerConnection Failed State</title> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="../RTCPeerConnection-helper.js"></script> 8 <script> 9 'use strict'; 10 11 // Tests for correct behavior of ICE state. 12 13 // SDP copied from JSEP Example 7.1 14 // It contains two media streams with different ufrags, and bundle 15 // turned on. 16 const kSdp = `v=0 17 o=- 4962303333179871722 1 IN IP4 0.0.0.0 18 s=- 19 t=0 0 20 a=ice-options:trickle 21 a=group:BUNDLE a1 v1 22 a=group:LS a1 v1 23 m=audio 10100 UDP/TLS/RTP/SAVPF 96 0 8 97 98 24 c=IN IP4 203.0.113.100 25 a=mid:a1 26 a=sendrecv 27 a=rtpmap:96 opus/48000/2 28 a=rtpmap:0 PCMU/8000 29 a=rtpmap:8 PCMA/8000 30 a=rtpmap:97 telephone-event/8000 31 a=rtpmap:98 telephone-event/48000 32 a=maxptime:120 33 a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid 34 a=extmap:2 urn:ietf:params:rtp-hdrext:ssrc-audio-level 35 a=msid:47017fee-b6c1-4162-929c-a25110252400 f83006c5-a0ff-4e0a-9ed9-d3e6747be7d9 36 a=ice-ufrag:ETEn 37 a=ice-pwd:OtSK0WpNtpUjkY4+86js7ZQl 38 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 39 a=setup:actpass 40 a=dtls-id:1 41 a=rtcp:10101 IN IP4 203.0.113.100 42 a=rtcp-mux 43 a=rtcp-rsize 44 m=video 10102 UDP/TLS/RTP/SAVPF 100 101 45 c=IN IP4 203.0.113.100 46 a=mid:v1 47 a=sendrecv 48 a=rtpmap:100 VP8/90000 49 a=rtpmap:101 rtx/90000 50 a=fmtp:101 apt=100 51 a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid 52 a=rtcp-fb:100 ccm fir 53 a=rtcp-fb:100 nack 54 a=rtcp-fb:100 nack pli 55 a=msid:47017fee-b6c1-4162-929c-a25110252400 f30bdb4a-5db8-49b5-bcdc-e0c9a23172e0 56 a=ice-ufrag:BGKk 57 a=ice-pwd:mqyWsAjvtKwTGnvhPztQ9mIf 58 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 59 a=setup:actpass 60 a=dtls-id:1 61 a=rtcp:10103 IN IP4 203.0.113.100 62 a=rtcp-mux 63 a=rtcp-rsize 64 `; 65 66 // Returns a promise that resolves when |pc.iceConnectionState| is in one of the 67 // wanted states, and rejects if it is in one of the unwanted states. 68 // This is a variant of the function in RTCPeerConnection-helper.js. 69 function waitForIceStateChange(pc, wantedStates, unwantedStates=[]) { 70 return new Promise((resolve, reject) => { 71 if (wantedStates.includes(pc.iceConnectionState)) { 72 resolve(); 73 return; 74 } else if (unwantedStates.includes(pc.iceConnectionState)) { 75 reject('Unexpected state encountered: ' + pc.iceConnectionState); 76 return; 77 } 78 pc.addEventListener('iceconnectionstatechange', () => { 79 if (wantedStates.includes(pc.iceConnectionState)) { 80 resolve(); 81 } else if (unwantedStates.includes(pc.iceConnectionState)) { 82 reject('Unexpected state encountered: ' + pc.iceConnectionState); 83 } 84 }); 85 }); 86 } 87 88 promise_test(async t => { 89 const pc1 = new RTCPeerConnection(); 90 const pc2 = new RTCPeerConnection(); 91 t.add_cleanup(() => pc1.close()); 92 t.add_cleanup(() => pc2.close()); 93 let [track, streams] = await getTrackFromUserMedia('video'); 94 const sender = pc1.addTrack(track); 95 exchangeIceCandidates(pc1, pc2); 96 await exchangeOfferAnswer(pc1, pc2); 97 await waitForIceStateChange(pc1, ['connected', 'completed']); 98 }, 'PC should enter connected (or completed) state when candidates are sent'); 99 100 promise_test(async t => { 101 const pc1 = new RTCPeerConnection(); 102 t.add_cleanup(() => pc1.close()); 103 let [track, streams] = await getTrackFromUserMedia('video'); 104 const sender = pc1.addTrack(track); 105 const offer = await pc1.createOffer(); 106 assert_greater_than_equal(offer.sdp.search('a=ice-options:trickle'), 0); 107 }, 'PC should generate offer with a=ice-options:trickle'); 108 109 promise_test(async t => { 110 const pc1 = new RTCPeerConnection(); 111 t.add_cleanup(() => pc1.close()); 112 await pc1.setRemoteDescription({type: 'offer', sdp: kSdp}); 113 const answer = await pc1.createAnswer(); 114 await pc1.setLocalDescription(answer); 115 assert_greater_than_equal(answer.sdp.search('a=ice-options:trickle'), 0); 116 // When we use trickle ICE, and don't signal end-of-caniddates, we 117 // expect failure to result in 'disconnected' state rather than 'failed'. 118 const stateWaiter = waitForIceStateChange(pc1, ['disconnected'], 119 ['failed']); 120 // Add a bogus candidate. The candidate is drawn from the 121 // IANA "test-net-3" pool (RFC5737), so is guaranteed not to respond. 122 const candidateStr1 = 123 'candidate:1 1 udp 2113929471 203.0.113.100 10100 typ host'; 124 await pc1.addIceCandidate({candidate: candidateStr1, 125 sdpMid: 'a1', 126 usernameFragment: 'ETEn'}); 127 await stateWaiter; 128 }, 'PC should enter disconnected state when a failing candidate is sent'); 129 130 </script>