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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
<!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
// exchangeOfferAnswer
// 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();
}
}));
});
}
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 = exchangeIceCandidates(pc1, pc2);
await exchangeOfferAnswer(pc1, pc2);
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')]);
let fired = false;
dtlsTransport1.onstatechange = t.step_func(() => fired = true);
dtlsTransport1.addEventListener('statechange', t.step_func(() => fired = true));
pc1.close();
assert_equals(dtlsTransport1.state, 'closed');
await new Promise(r => t.step_timeout(r, 10));
assert_false(fired, 'close() should not see a statechange event on close');
}, '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');
promise_test(async t => {
const config = {bundlePolicy: "max-bundle"};
const pc1 = new RTCPeerConnection(config);
const pc2 = new RTCPeerConnection(config);
t.add_cleanup(() => pc1.close());
t.add_cleanup(() => pc2.close());
pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
pc1.addTransceiver("video");
pc1.addTransceiver("audio");
await pc1.setLocalDescription(await pc1.createOffer());
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription(await pc2.createAnswer());
await pc1.setRemoteDescription(pc2.localDescription);
const [videoTc, audioTc] = pc1.getTransceivers();
const [videoTp, audioTp] =
pc1.getTransceivers().map(tc => tc.sender.transport);
const [videoPc2Tp, audioPc2Tp] =
pc2.getTransceivers().map(tc => tc.sender.transport);
assert_equals(pc1.getTransceivers().length, 2, 'pc1 transceiver count');
assert_equals(pc2.getTransceivers().length, 2, 'pc2 transceiver count');
assert_equals(videoTc.sender.transport, videoTc.receiver.transport);
assert_equals(videoTc.sender.transport, audioTc.sender.transport);
await Promise.all([resolveWhen(t, videoTp, 'connected'),
resolveWhen(t, videoPc2Tp, 'connected')]);
assert_equals(audioTc.sender, pc1.getSenders()[1]);
let stoppedTransceiver = pc1.getTransceivers()[0];
assert_equals(stoppedTransceiver, videoTc); // sanity
let onended = new Promise(resolve => {
stoppedTransceiver.receiver.track.onended = resolve;
});
stoppedTransceiver.stop();
await onended;
assert_equals(audioTc.sender, pc1.getSenders()[1]); // sanity
assert_equals(audioTc.sender.transport, audioTp); // sanity
assert_equals(audioTp.state, 'connected');
}, 'stop bundled transceiver retains dtls transport state');
</script>
|