1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
<!doctype html>
<meta charset="utf-8">
<title>RTCDtlsTransport</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="RTCPeerConnection-helper.js"></script>
<script>
'use strict';
// The following helper functions are called from RTCPeerConnection-helper.js:
// exchangeIceCandidates
// doSignalingHandshake
// trackFactories.audio()
/*
5.5. RTCDtlsTransport Interface
interface RTCDtlsTransport : EventTarget {
readonly attribute RTCDtlsTransportState state;
sequence<ArrayBuffer> getRemoteCertificates();
attribute EventHandler onstatechange;
attribute EventHandler onerror;
...
};
enum RTCDtlsTransportState {
"new",
"connecting",
"connected",
"closed",
"failed"
};
*/
function resolveWhen(t, dtlstransport, state) {
return new Promise((resolve, reject) => {
if (dtlstransport.state == state) { resolve(); }
dtlstransport.addEventListener('statechange', t.step_func(e => {
if (dtlstransport.state == state) {
resolve();
}
}));
});
}
// Helper class to exchange ice candidates between
// two local peer connections
class CandidateChannel {
constructor(source, dest) {
source.addEventListener('icecandidate', event => {
const { candidate } = event;
if (candidate && this.activated
&& this.destination.signalingState !== 'closed') {
this.destination.addIceCandidate(candidate);
} else {
this.queue.push(candidate);
}
});
this.destination = dest;
this.activated = false;
this.queue = [];
}
activate() {
this.activated = true;
for (const candidate of this.queue) {
this.destination.addIceCandidate(candidate);
}
}
}
function coupleCandidates(pc1, pc2) {
const ch1 = new CandidateChannel(pc1, pc2);
const ch2 = new CandidateChannel(pc2, pc1);
return [ch1, ch2];
}
async function setupConnections(t) {
const pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc2.close());
pc1.addTrack(trackFactories.audio());
const channels = coupleCandidates(pc1, pc2);
await doSignalingHandshake(pc1, pc2);
for (const channel of channels) {
channel.activate();
}
return [pc1, pc2];
}
promise_test(async t => {
const [pc1, pc2] = await setupConnections(t);
const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
assert_true(dtlsTransport1 instanceof RTCDtlsTransport);
assert_true(dtlsTransport2 instanceof RTCDtlsTransport);
await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'),
resolveWhen(t, dtlsTransport2, 'connected')]);
}, 'DTLS transport goes to connected state');
promise_test(async t => {
const [pc1, pc2] = await setupConnections(t);
const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'),
resolveWhen(t, dtlsTransport2, 'connected')]);
pc1.close();
assert_equals(dtlsTransport1.state, 'closed');
}, 'close() causes the local transport to close immediately');
promise_test(async t => {
const [pc1, pc2] = await setupConnections(t);
const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'),
resolveWhen(t, dtlsTransport2, 'connected')]);
pc1.close();
await resolveWhen(t, dtlsTransport2, 'closed');
}, 'close() causes the other end\'s DTLS transport to close');
</script>
|