RTCDtlsTransport-state.html (5159B)
1 <!doctype html> 2 <meta charset="utf-8"> 3 <title>RTCDtlsTransport</title> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script src="RTCPeerConnection-helper.js"></script> 7 <script> 8 'use strict'; 9 10 // The following helper functions are called from RTCPeerConnection-helper.js: 11 // exchangeIceCandidates 12 // exchangeOfferAnswer 13 // trackFactories.audio() 14 15 /* 16 5.5. RTCDtlsTransport Interface 17 interface RTCDtlsTransport : EventTarget { 18 readonly attribute RTCDtlsTransportState state; 19 sequence<ArrayBuffer> getRemoteCertificates(); 20 attribute EventHandler onstatechange; 21 attribute EventHandler onerror; 22 ... 23 }; 24 25 enum RTCDtlsTransportState { 26 "new", 27 "connecting", 28 "connected", 29 "closed", 30 "failed" 31 }; 32 33 */ 34 function resolveWhen(t, dtlstransport, state) { 35 return new Promise((resolve, reject) => { 36 if (dtlstransport.state == state) { resolve(); } 37 dtlstransport.addEventListener('statechange', t.step_func(e => { 38 if (dtlstransport.state == state) { 39 resolve(); 40 } 41 })); 42 }); 43 } 44 45 46 async function setupConnections(t) { 47 const pc1 = new RTCPeerConnection(); 48 t.add_cleanup(() => pc1.close()); 49 const pc2 = new RTCPeerConnection(); 50 t.add_cleanup(() => pc2.close()); 51 52 pc1.addTrack(trackFactories.audio()); 53 const channels = exchangeIceCandidates(pc1, pc2); 54 await exchangeOfferAnswer(pc1, pc2); 55 return [pc1, pc2]; 56 } 57 58 promise_test(async t => { 59 const [pc1, pc2] = await setupConnections(t); 60 const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport; 61 const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport; 62 assert_true(dtlsTransport1 instanceof RTCDtlsTransport); 63 assert_true(dtlsTransport2 instanceof RTCDtlsTransport); 64 await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'), 65 resolveWhen(t, dtlsTransport2, 'connected')]); 66 }, 'DTLS transport goes to connected state'); 67 68 promise_test(async t => { 69 const [pc1, pc2] = await setupConnections(t); 70 71 const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport; 72 const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport; 73 await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'), 74 resolveWhen(t, dtlsTransport2, 'connected')]); 75 let fired = false; 76 dtlsTransport1.onstatechange = t.step_func(() => fired = true); 77 dtlsTransport1.addEventListener('statechange', t.step_func(() => fired = true)); 78 pc1.close(); 79 assert_equals(dtlsTransport1.state, 'closed'); 80 await new Promise(r => t.step_timeout(r, 10)); 81 assert_false(fired, 'close() should not see a statechange event on close'); 82 }, 'close() causes the local transport to close immediately'); 83 84 promise_test(async t => { 85 const [pc1, pc2] = await setupConnections(t); 86 const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport; 87 const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport; 88 await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'), 89 resolveWhen(t, dtlsTransport2, 'connected')]); 90 pc1.close(); 91 await resolveWhen(t, dtlsTransport2, 'closed'); 92 }, 'close() causes the other end\'s DTLS transport to close'); 93 94 promise_test(async t => { 95 const config = {bundlePolicy: "max-bundle"}; 96 const pc1 = new RTCPeerConnection(config); 97 const pc2 = new RTCPeerConnection(config); 98 t.add_cleanup(() => pc1.close()); 99 t.add_cleanup(() => pc2.close()); 100 101 pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate); 102 pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate); 103 104 pc1.addTransceiver("video"); 105 pc1.addTransceiver("audio"); 106 await pc1.setLocalDescription(await pc1.createOffer()); 107 await pc2.setRemoteDescription(pc1.localDescription); 108 await pc2.setLocalDescription(await pc2.createAnswer()); 109 await pc1.setRemoteDescription(pc2.localDescription); 110 111 const [videoTc, audioTc] = pc1.getTransceivers(); 112 const [videoTp, audioTp] = 113 pc1.getTransceivers().map(tc => tc.sender.transport); 114 115 const [videoPc2Tp, audioPc2Tp] = 116 pc2.getTransceivers().map(tc => tc.sender.transport); 117 118 assert_equals(pc1.getTransceivers().length, 2, 'pc1 transceiver count'); 119 assert_equals(pc2.getTransceivers().length, 2, 'pc2 transceiver count'); 120 assert_equals(videoTc.sender.transport, videoTc.receiver.transport); 121 assert_equals(videoTc.sender.transport, audioTc.sender.transport); 122 123 await Promise.all([resolveWhen(t, videoTp, 'connected'), 124 resolveWhen(t, videoPc2Tp, 'connected')]); 125 126 assert_equals(audioTc.sender, pc1.getSenders()[1]); 127 128 let stoppedTransceiver = pc1.getTransceivers()[0]; 129 assert_equals(stoppedTransceiver, videoTc); // sanity 130 let onended = new Promise(resolve => { 131 stoppedTransceiver.receiver.track.onended = resolve; 132 }); 133 stoppedTransceiver.stop(); 134 await onended; 135 136 assert_equals(audioTc.sender, pc1.getSenders()[1]); // sanity 137 assert_equals(audioTc.sender.transport, audioTp); // sanity 138 assert_equals(audioTp.state, 'connected'); 139 }, 'stop bundled transceiver retains dtls transport state'); 140 141 </script>