node-datachannel 0.11.0 → 0.20.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +5 -1
- package/.eslintrc.json +27 -0
- package/.prettierrc +12 -0
- package/CMakeLists.txt +13 -13
- package/jest.config.ts +14 -0
- package/package.json +47 -44
- package/rollup.config.mjs +63 -0
- package/src/index.ts +10 -0
- package/{lib/datachannel-stream.js → src/lib/datachannel-stream.ts} +16 -11
- package/src/lib/index.ts +180 -0
- package/src/lib/node-datachannel.ts +13 -0
- package/src/lib/types.ts +126 -0
- package/{lib/websocket-server.js → src/lib/websocket-server.ts} +10 -8
- package/src/lib/websocket.ts +26 -0
- package/src/polyfill/Events.ts +33 -0
- package/src/polyfill/Exception.ts +37 -0
- package/src/polyfill/RTCCertificate.ts +17 -0
- package/{polyfill/RTCDataChannel.js → src/polyfill/RTCDataChannel.ts} +43 -40
- package/src/polyfill/RTCDtlsTransport.ts +47 -0
- package/src/polyfill/RTCError.ts +71 -0
- package/src/polyfill/RTCIceCandidate.ts +125 -0
- package/{polyfill/RTCIceTransport.js → src/polyfill/RTCIceTransport.ts} +22 -20
- package/{polyfill/RTCPeerConnection.js → src/polyfill/RTCPeerConnection.ts} +137 -115
- package/{polyfill/RTCSctpTransport.js → src/polyfill/RTCSctpTransport.ts} +16 -14
- package/{polyfill/RTCSessionDescription.js → src/polyfill/RTCSessionDescription.ts} +7 -12
- package/{polyfill/index.js → src/polyfill/index.ts} +12 -9
- package/tsconfig.json +20 -13
- package/.eslintrc.cjs +0 -8
- package/.github/FUNDING.yml +0 -2
- package/.github/workflows/build-linux.yml +0 -104
- package/.github/workflows/build-mac-m1.yml +0 -38
- package/.github/workflows/build-mac-x64.yml +0 -40
- package/.github/workflows/build-win.yml +0 -74
- package/.github/workflows/lint.yml +0 -20
- package/.github/workflows/npm-publish-manual.yml +0 -23
- package/.prettierrc.cjs +0 -8
- package/build-containers/Dockerfile.alpine +0 -6
- package/build-containers/Dockerfile.debian +0 -7
- package/cmake/toolchain/ci.cmake +0 -23
- package/examples/client-server/README.md +0 -22
- package/examples/client-server/client-benchmark.js +0 -230
- package/examples/client-server/client-periodic.js +0 -189
- package/examples/client-server/client.js +0 -111
- package/examples/client-server/package-lock.json +0 -289
- package/examples/client-server/package.json +0 -16
- package/examples/client-server/signaling-server.js +0 -39
- package/examples/electron-demo/README.md +0 -58
- package/examples/electron-demo/forge.config.js +0 -49
- package/examples/electron-demo/package-lock.json +0 -15933
- package/examples/electron-demo/package.json +0 -43
- package/examples/electron-demo/src/index.css +0 -7
- package/examples/electron-demo/src/index.html +0 -29
- package/examples/electron-demo/src/main.js +0 -53
- package/examples/electron-demo/src/node-datachannel.js +0 -123
- package/examples/electron-demo/src/preload.js +0 -28
- package/examples/electron-demo/src/renderer.js +0 -58
- package/examples/electron-demo/webpack.main.config.js +0 -11
- package/examples/electron-demo/webpack.renderer.config.js +0 -13
- package/examples/electron-demo/webpack.rules.js +0 -35
- package/examples/media/README.md +0 -34
- package/examples/media/main.html +0 -45
- package/examples/media/media.js +0 -54
- package/examples/simple-peer-usage/main.js +0 -28
- package/examples/simple-peer-usage/package-lock.json +0 -317
- package/examples/simple-peer-usage/package.json +0 -16
- package/examples/websocket/websocket-client.js +0 -20
- package/examples/websocket/websocket-server.js +0 -22
- package/jest.config.cjs +0 -7
- package/lib/index.cjs +0 -194
- package/lib/index.d.cts +0 -300
- package/lib/index.d.ts +0 -300
- package/lib/index.js +0 -58
- package/lib/node-datachannel.js +0 -7
- package/polyfill/Events.d.ts +0 -9
- package/polyfill/Events.js +0 -29
- package/polyfill/Exception.js +0 -23
- package/polyfill/RTCCertificate.d.ts +0 -7
- package/polyfill/RTCCertificate.js +0 -17
- package/polyfill/RTCDataChannel.d.ts +0 -35
- package/polyfill/RTCDtlsTransport.d.ts +0 -10
- package/polyfill/RTCDtlsTransport.js +0 -47
- package/polyfill/RTCIceCandidate.d.ts +0 -20
- package/polyfill/RTCIceCandidate.js +0 -126
- package/polyfill/RTCIceTransport.d.ts +0 -18
- package/polyfill/RTCPeerConnection.d.ts +0 -62
- package/polyfill/RTCSctpTransport.d.ts +0 -10
- package/polyfill/RTCSessionDescription.d.ts +0 -8
- package/polyfill/index.cjs +0 -1258
- package/polyfill/index.d.cts +0 -37
- package/polyfill/index.d.ts +0 -37
- package/test/connectivity.js +0 -86
- package/test/jest-tests/basic.test.js +0 -37
- package/test/jest-tests/multiple-run.test.js +0 -73
- package/test/jest-tests/p2p.test.js +0 -99
- package/test/jest-tests/polyfill.test.js +0 -10
- package/test/jest-tests/streams.test.js +0 -48
- package/test/jest-tests/websocket.test.js +0 -69
- package/test/polyfill-connectivity.js +0 -89
- package/test/websockets.js +0 -50
- package/test/wpt-tests/README.md +0 -46
- package/test/wpt-tests/chrome-failed-tests.js +0 -42
- package/test/wpt-tests/index.js +0 -96
- package/test/wpt-tests/last-test-results.md +0 -205
- package/test/wpt-tests/package-lock.json +0 -1712
- package/test/wpt-tests/package.json +0 -19
- package/test/wpt-tests/wpt-test-list.js +0 -137
- package/test/wpt-tests/wpt.js +0 -131
- /package/src/{data-channel-wrapper.cpp → cpp/data-channel-wrapper.cpp} +0 -0
- /package/src/{data-channel-wrapper.h → cpp/data-channel-wrapper.h} +0 -0
- /package/src/{main.cpp → cpp/main.cpp} +0 -0
- /package/src/{media-audio-wrapper.cpp → cpp/media-audio-wrapper.cpp} +0 -0
- /package/src/{media-audio-wrapper.h → cpp/media-audio-wrapper.h} +0 -0
- /package/src/{media-direction.cpp → cpp/media-direction.cpp} +0 -0
- /package/src/{media-direction.h → cpp/media-direction.h} +0 -0
- /package/src/{media-rtcpreceivingsession-wrapper.cpp → cpp/media-rtcpreceivingsession-wrapper.cpp} +0 -0
- /package/src/{media-rtcpreceivingsession-wrapper.h → cpp/media-rtcpreceivingsession-wrapper.h} +0 -0
- /package/src/{media-track-wrapper.cpp → cpp/media-track-wrapper.cpp} +0 -0
- /package/src/{media-track-wrapper.h → cpp/media-track-wrapper.h} +0 -0
- /package/src/{media-video-wrapper.cpp → cpp/media-video-wrapper.cpp} +0 -0
- /package/src/{media-video-wrapper.h → cpp/media-video-wrapper.h} +0 -0
- /package/src/{peer-connection-wrapper.cpp → cpp/peer-connection-wrapper.cpp} +0 -0
- /package/src/{peer-connection-wrapper.h → cpp/peer-connection-wrapper.h} +0 -0
- /package/src/{rtc-wrapper.cpp → cpp/rtc-wrapper.cpp} +0 -0
- /package/src/{rtc-wrapper.h → cpp/rtc-wrapper.h} +0 -0
- /package/src/{thread-safe-callback.cpp → cpp/thread-safe-callback.cpp} +0 -0
- /package/src/{thread-safe-callback.h → cpp/thread-safe-callback.h} +0 -0
- /package/src/{web-socket-server-wrapper.cpp → cpp/web-socket-server-wrapper.cpp} +0 -0
- /package/src/{web-socket-server-wrapper.h → cpp/web-socket-server-wrapper.h} +0 -0
- /package/src/{web-socket-wrapper.cpp → cpp/web-socket-wrapper.cpp} +0 -0
- /package/src/{web-socket-wrapper.h → cpp/web-socket-wrapper.h} +0 -0
- /package/{polyfill → src/polyfill}/README.md +0 -0
|
@@ -1,40 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
import RTCSessionDescription from './RTCSessionDescription.js';
|
|
3
|
-
import RTCDataChannel from './RTCDataChannel.js';
|
|
4
|
-
import RTCIceCandidate from './RTCIceCandidate.js';
|
|
5
|
-
import { RTCDataChannelEvent, RTCPeerConnectionIceEvent } from './Events.js';
|
|
6
|
-
import RTCSctpTransport from './RTCSctpTransport.js';
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
7
2
|
import 'node-domexception';
|
|
8
|
-
import
|
|
3
|
+
import { SelectedCandidateInfo } from '../lib/types';
|
|
4
|
+
import { PeerConnection } from '../lib/index';
|
|
5
|
+
import RTCSessionDescription from './RTCSessionDescription';
|
|
6
|
+
import RTCDataChannel from './RTCDataChannel';
|
|
7
|
+
import RTCIceCandidate from './RTCIceCandidate';
|
|
8
|
+
import { RTCDataChannelEvent, RTCPeerConnectionIceEvent } from './Events';
|
|
9
|
+
import RTCSctpTransport from './RTCSctpTransport';
|
|
10
|
+
import * as exceptions from './Exception';
|
|
11
|
+
import RTCCertificate from './RTCCertificate';
|
|
12
|
+
|
|
13
|
+
// extend RTCConfiguration with peerIdentity
|
|
14
|
+
interface RTCConfiguration extends globalThis.RTCConfiguration {
|
|
15
|
+
peerIdentity?: string;
|
|
16
|
+
}
|
|
9
17
|
|
|
10
|
-
export default class
|
|
11
|
-
static async generateCertificate() {
|
|
18
|
+
export default class RTCPeerConnection extends EventTarget implements globalThis.RTCPeerConnection {
|
|
19
|
+
static async generateCertificate(): Promise<RTCCertificate> {
|
|
12
20
|
throw new DOMException('Not implemented');
|
|
13
21
|
}
|
|
14
22
|
|
|
15
|
-
#peerConnection;
|
|
16
|
-
#localOffer;
|
|
17
|
-
#localAnswer;
|
|
18
|
-
#dataChannels
|
|
23
|
+
#peerConnection: PeerConnection;
|
|
24
|
+
#localOffer: any;
|
|
25
|
+
#localAnswer: any;
|
|
26
|
+
#dataChannels: Set<RTCDataChannel>;
|
|
19
27
|
#dataChannelsClosed = 0;
|
|
20
|
-
#config;
|
|
21
|
-
#canTrickleIceCandidates;
|
|
22
|
-
#sctp;
|
|
23
|
-
|
|
24
|
-
#localCandidates = [];
|
|
25
|
-
#remoteCandidates = [];
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
28
|
+
#config: RTCConfiguration;
|
|
29
|
+
#canTrickleIceCandidates: boolean | null;
|
|
30
|
+
#sctp: RTCSctpTransport;
|
|
31
|
+
|
|
32
|
+
#localCandidates: RTCIceCandidate[] = [];
|
|
33
|
+
#remoteCandidates: RTCIceCandidate[] = [];
|
|
34
|
+
|
|
35
|
+
// events
|
|
36
|
+
onconnectionstatechange: ((this: RTCPeerConnection, ev: Event) => any) | null;
|
|
37
|
+
ondatachannel: ((this: RTCPeerConnection, ev: RTCDataChannelEvent) => any) | null;
|
|
38
|
+
onicecandidate: ((this: RTCPeerConnection, ev: RTCPeerConnectionIceEvent) => any) | null;
|
|
39
|
+
onicecandidateerror: ((this: RTCPeerConnection, ev: Event) => any) | null;
|
|
40
|
+
oniceconnectionstatechange: ((this: RTCPeerConnection, ev: Event) => any) | null;
|
|
41
|
+
onicegatheringstatechange: ((this: RTCPeerConnection, ev: Event) => any) | null;
|
|
42
|
+
onnegotiationneeded: ((this: RTCPeerConnection, ev: Event) => any) | null;
|
|
43
|
+
onsignalingstatechange: ((this: RTCPeerConnection, ev: Event) => any) | null;
|
|
44
|
+
ontrack: ((this: RTCPeerConnection, ev: globalThis.RTCTrackEvent) => any) | null;
|
|
45
|
+
|
|
46
|
+
private _checkConfiguration(config: RTCConfiguration): void {
|
|
38
47
|
if (config && config.iceServers === undefined) config.iceServers = [];
|
|
39
48
|
if (config && config.iceTransportPolicy === undefined) config.iceTransportPolicy = 'all';
|
|
40
49
|
|
|
@@ -49,31 +58,39 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
49
58
|
|
|
50
59
|
// If iceServers is string convert to array
|
|
51
60
|
if (typeof config.iceServers[i].urls === 'string')
|
|
52
|
-
config.iceServers[i].urls = [config.iceServers[i].urls];
|
|
61
|
+
config.iceServers[i].urls = [config.iceServers[i].urls as string];
|
|
53
62
|
|
|
54
63
|
// urls can not be empty
|
|
55
|
-
if (config.iceServers[i].urls?.some((url) => url == ''))
|
|
56
|
-
throw exceptions.SyntaxError('IceServers urls cannot be empty');
|
|
64
|
+
if ((config.iceServers[i].urls as string[])?.some((url) => url == ''))
|
|
65
|
+
throw new exceptions.SyntaxError('IceServers urls cannot be empty');
|
|
57
66
|
|
|
58
|
-
// urls should match the
|
|
67
|
+
// urls should be valid URLs and match the protocols "stun:|turn:|turns:"
|
|
59
68
|
if (
|
|
60
|
-
config.iceServers[i].urls?.some(
|
|
61
|
-
(url) =>
|
|
69
|
+
(config.iceServers[i].urls as string[])?.some(
|
|
70
|
+
(url) => {
|
|
71
|
+
try {
|
|
72
|
+
const parsedURL = new URL(url)
|
|
73
|
+
|
|
74
|
+
return !/^(stun:|turn:|turns:)$/.test(parsedURL.protocol)
|
|
75
|
+
} catch (error) {
|
|
76
|
+
return true
|
|
77
|
+
}
|
|
78
|
+
},
|
|
62
79
|
)
|
|
63
80
|
)
|
|
64
|
-
throw exceptions.SyntaxError('IceServers urls wrong format');
|
|
81
|
+
throw new exceptions.SyntaxError('IceServers urls wrong format');
|
|
65
82
|
|
|
66
83
|
// If this is a turn server check for username and credential
|
|
67
|
-
if (config.iceServers[i].urls?.some((url) => url.startsWith('turn'))) {
|
|
84
|
+
if ((config.iceServers[i].urls as string[])?.some((url) => url.startsWith('turn'))) {
|
|
68
85
|
if (!config.iceServers[i].username)
|
|
69
|
-
throw exceptions.InvalidAccessError('IceServers username cannot be null');
|
|
86
|
+
throw new exceptions.InvalidAccessError('IceServers username cannot be null');
|
|
70
87
|
if (!config.iceServers[i].credential)
|
|
71
|
-
throw exceptions.InvalidAccessError('IceServers username cannot be undefined');
|
|
88
|
+
throw new exceptions.InvalidAccessError('IceServers username cannot be undefined');
|
|
72
89
|
}
|
|
73
90
|
|
|
74
91
|
// length of urls can not be 0
|
|
75
92
|
if (config.iceServers[i].urls?.length === 0)
|
|
76
|
-
throw exceptions.SyntaxError('IceServers urls cannot be empty');
|
|
93
|
+
throw new exceptions.SyntaxError('IceServers urls cannot be empty');
|
|
77
94
|
}
|
|
78
95
|
}
|
|
79
96
|
|
|
@@ -86,12 +103,14 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
86
103
|
throw new TypeError('IceTransportPolicy must be either "all" or "relay"');
|
|
87
104
|
}
|
|
88
105
|
|
|
89
|
-
setConfiguration(config) {
|
|
106
|
+
setConfiguration(config: RTCConfiguration): void {
|
|
90
107
|
this._checkConfiguration(config);
|
|
91
108
|
this.#config = config;
|
|
92
109
|
}
|
|
93
110
|
|
|
94
|
-
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
constructor(config: RTCConfiguration = { iceServers: [], iceTransportPolicy: 'all' }) {
|
|
95
114
|
super();
|
|
96
115
|
|
|
97
116
|
this._checkConfiguration(config);
|
|
@@ -102,8 +121,8 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
102
121
|
this.#canTrickleIceCandidates = null;
|
|
103
122
|
|
|
104
123
|
try {
|
|
105
|
-
|
|
106
|
-
|
|
124
|
+
const peerIdentity = (config as any)?.peerIdentity ?? `peer-${getRandomString(7)}`;
|
|
125
|
+
this.#peerConnection = new PeerConnection(peerIdentity,
|
|
107
126
|
{
|
|
108
127
|
...config,
|
|
109
128
|
iceServers:
|
|
@@ -123,8 +142,8 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
123
142
|
},
|
|
124
143
|
);
|
|
125
144
|
} catch (error) {
|
|
126
|
-
if (!error || !error.message) throw exceptions.NotFoundError('Unknown error');
|
|
127
|
-
throw exceptions.SyntaxError(error.message);
|
|
145
|
+
if (!error || !error.message) throw new exceptions.NotFoundError('Unknown error');
|
|
146
|
+
throw new exceptions.SyntaxError(error.message);
|
|
128
147
|
}
|
|
129
148
|
|
|
130
149
|
// forward peerConnection events
|
|
@@ -184,43 +203,43 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
184
203
|
if (this.onicegatheringstatechange) this.onicegatheringstatechange(e);
|
|
185
204
|
});
|
|
186
205
|
this.addEventListener('datachannel', (e) => {
|
|
187
|
-
if (this.ondatachannel) this.ondatachannel(e);
|
|
206
|
+
if (this.ondatachannel) this.ondatachannel(e as RTCDataChannelEvent);
|
|
188
207
|
});
|
|
189
208
|
this.addEventListener('icecandidate', (e) => {
|
|
190
|
-
if (this.onicecandidate) this.onicecandidate(e);
|
|
209
|
+
if (this.onicecandidate) this.onicecandidate(e as RTCPeerConnectionIceEvent);
|
|
191
210
|
});
|
|
192
211
|
|
|
193
212
|
this.#sctp = new RTCSctpTransport({
|
|
194
213
|
pc: this,
|
|
195
214
|
extraFunctions: {
|
|
196
|
-
maxDataChannelId: () => {
|
|
215
|
+
maxDataChannelId: (): number => {
|
|
197
216
|
return this.#peerConnection.maxDataChannelId();
|
|
198
217
|
},
|
|
199
|
-
maxMessageSize: () => {
|
|
218
|
+
maxMessageSize: (): number => {
|
|
200
219
|
return this.#peerConnection.maxMessageSize();
|
|
201
220
|
},
|
|
202
|
-
localCandidates: () => {
|
|
221
|
+
localCandidates: (): RTCIceCandidate[] => {
|
|
203
222
|
return this.#localCandidates;
|
|
204
223
|
},
|
|
205
|
-
remoteCandidates: () => {
|
|
224
|
+
remoteCandidates: (): RTCIceCandidate[] => {
|
|
206
225
|
return this.#remoteCandidates;
|
|
207
226
|
},
|
|
208
|
-
selectedCandidatePair: () => {
|
|
227
|
+
selectedCandidatePair: (): { local: SelectedCandidateInfo; remote: SelectedCandidateInfo } | null => {
|
|
209
228
|
return this.#peerConnection.getSelectedCandidatePair();
|
|
210
229
|
},
|
|
211
230
|
},
|
|
212
231
|
});
|
|
213
232
|
}
|
|
214
233
|
|
|
215
|
-
get canTrickleIceCandidates() {
|
|
234
|
+
get canTrickleIceCandidates(): boolean | null {
|
|
216
235
|
return this.#canTrickleIceCandidates;
|
|
217
236
|
}
|
|
218
237
|
|
|
219
|
-
get connectionState() {
|
|
238
|
+
get connectionState(): globalThis.RTCPeerConnectionState {
|
|
220
239
|
return this.#peerConnection.state();
|
|
221
240
|
}
|
|
222
241
|
|
|
223
|
-
get iceConnectionState() {
|
|
242
|
+
get iceConnectionState(): globalThis.RTCIceConnectionState {
|
|
224
243
|
let state = this.#peerConnection.iceState();
|
|
225
244
|
// libdatachannel uses 'completed' instead of 'connected'
|
|
226
245
|
// see /webrtc/getstats.html
|
|
@@ -228,43 +247,43 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
228
247
|
return state;
|
|
229
248
|
}
|
|
230
249
|
|
|
231
|
-
get iceGatheringState() {
|
|
250
|
+
get iceGatheringState(): globalThis.RTCIceGatheringState {
|
|
232
251
|
return this.#peerConnection.gatheringState();
|
|
233
252
|
}
|
|
234
253
|
|
|
235
|
-
get currentLocalDescription() {
|
|
236
|
-
return new RTCSessionDescription(this.#peerConnection.localDescription());
|
|
254
|
+
get currentLocalDescription(): RTCSessionDescription {
|
|
255
|
+
return new RTCSessionDescription(this.#peerConnection.localDescription() as any);
|
|
237
256
|
}
|
|
238
257
|
|
|
239
|
-
get currentRemoteDescription() {
|
|
240
|
-
return new RTCSessionDescription(this.#peerConnection.remoteDescription());
|
|
258
|
+
get currentRemoteDescription(): RTCSessionDescription {
|
|
259
|
+
return new RTCSessionDescription(this.#peerConnection.remoteDescription() as any);
|
|
241
260
|
}
|
|
242
261
|
|
|
243
|
-
get localDescription() {
|
|
244
|
-
return new RTCSessionDescription(this.#peerConnection.localDescription());
|
|
262
|
+
get localDescription(): RTCSessionDescription {
|
|
263
|
+
return new RTCSessionDescription(this.#peerConnection.localDescription() as any);
|
|
245
264
|
}
|
|
246
265
|
|
|
247
|
-
get pendingLocalDescription() {
|
|
248
|
-
return new RTCSessionDescription(this.#peerConnection.localDescription());
|
|
266
|
+
get pendingLocalDescription(): RTCSessionDescription {
|
|
267
|
+
return new RTCSessionDescription(this.#peerConnection.localDescription() as any);
|
|
249
268
|
}
|
|
250
269
|
|
|
251
|
-
get pendingRemoteDescription() {
|
|
252
|
-
return new RTCSessionDescription(this.#peerConnection.remoteDescription());
|
|
270
|
+
get pendingRemoteDescription(): RTCSessionDescription {
|
|
271
|
+
return new RTCSessionDescription(this.#peerConnection.remoteDescription() as any);
|
|
253
272
|
}
|
|
254
273
|
|
|
255
|
-
get remoteDescription() {
|
|
256
|
-
return new RTCSessionDescription(this.#peerConnection.remoteDescription());
|
|
274
|
+
get remoteDescription(): RTCSessionDescription {
|
|
275
|
+
return new RTCSessionDescription(this.#peerConnection.remoteDescription() as any);
|
|
257
276
|
}
|
|
258
277
|
|
|
259
|
-
get sctp() {
|
|
278
|
+
get sctp(): RTCSctpTransport {
|
|
260
279
|
return this.#sctp;
|
|
261
280
|
}
|
|
262
281
|
|
|
263
|
-
get signalingState() {
|
|
282
|
+
get signalingState(): globalThis.RTCSignalingState {
|
|
264
283
|
return this.#peerConnection.signalingState();
|
|
265
284
|
}
|
|
266
285
|
|
|
267
|
-
async addIceCandidate(candidate) {
|
|
286
|
+
async addIceCandidate(candidate?: globalThis.RTCIceCandidateInit | RTCIceCandidate): Promise<void> {
|
|
268
287
|
if (!candidate || !candidate.candidate) {
|
|
269
288
|
return;
|
|
270
289
|
}
|
|
@@ -281,12 +300,12 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
281
300
|
// ??
|
|
282
301
|
if (candidate.sdpMid && candidate.sdpMid.length > 3) {
|
|
283
302
|
// console.log(candidate.sdpMid);
|
|
284
|
-
throw exceptions.OperationError('Invalid sdpMid format');
|
|
303
|
+
throw new exceptions.OperationError('Invalid sdpMid format');
|
|
285
304
|
}
|
|
286
305
|
|
|
287
306
|
// We don't care about sdpMLineIndex, just for test
|
|
288
307
|
if (!candidate.sdpMid && candidate.sdpMLineIndex > 1) {
|
|
289
|
-
throw exceptions.OperationError('This is only for test case.');
|
|
308
|
+
throw new exceptions.OperationError('This is only for test case.');
|
|
290
309
|
}
|
|
291
310
|
|
|
292
311
|
try {
|
|
@@ -295,26 +314,28 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
295
314
|
new RTCIceCandidate({ candidate: candidate.candidate, sdpMid: candidate.sdpMid || '0' }),
|
|
296
315
|
);
|
|
297
316
|
} catch (error) {
|
|
298
|
-
if (!error || !error.message) throw exceptions.NotFoundError('Unknown error');
|
|
317
|
+
if (!error || !error.message) throw new exceptions.NotFoundError('Unknown error');
|
|
299
318
|
|
|
300
319
|
// Check error Message if contains specific message
|
|
301
320
|
if (error.message.includes('remote candidate without remote description'))
|
|
302
|
-
throw exceptions.InvalidStateError(error.message);
|
|
303
|
-
if (error.message.includes('Invalid candidate format')) throw exceptions.OperationError(error.message);
|
|
321
|
+
throw new exceptions.InvalidStateError(error.message);
|
|
322
|
+
if (error.message.includes('Invalid candidate format')) throw new exceptions.OperationError(error.message);
|
|
304
323
|
|
|
305
|
-
throw exceptions.NotFoundError(error.message);
|
|
324
|
+
throw new exceptions.NotFoundError(error.message);
|
|
306
325
|
}
|
|
307
326
|
}
|
|
308
327
|
|
|
309
|
-
|
|
328
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
329
|
+
addTrack(_track, ..._streams): globalThis.RTCRtpSender {
|
|
310
330
|
throw new DOMException('Not implemented');
|
|
311
331
|
}
|
|
312
332
|
|
|
313
|
-
|
|
333
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
334
|
+
addTransceiver(_trackOrKind, _init): globalThis.RTCRtpTransceiver {
|
|
314
335
|
throw new DOMException('Not implemented');
|
|
315
336
|
}
|
|
316
337
|
|
|
317
|
-
close() {
|
|
338
|
+
close(): void {
|
|
318
339
|
// close all channels before shutting down
|
|
319
340
|
this.#dataChannels.forEach((channel) => {
|
|
320
341
|
channel.close();
|
|
@@ -324,11 +345,12 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
324
345
|
this.#peerConnection.close();
|
|
325
346
|
}
|
|
326
347
|
|
|
327
|
-
createAnswer() {
|
|
348
|
+
createAnswer(): Promise<globalThis.RTCSessionDescriptionInit | any> {
|
|
328
349
|
return this.#localAnswer;
|
|
329
350
|
}
|
|
330
351
|
|
|
331
|
-
|
|
352
|
+
|
|
353
|
+
createDataChannel(label, opts = {}): RTCDataChannel {
|
|
332
354
|
const channel = this.#peerConnection.createDataChannel(label, opts);
|
|
333
355
|
const dataChannel = new RTCDataChannel(channel, opts);
|
|
334
356
|
|
|
@@ -342,32 +364,32 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
342
364
|
return dataChannel;
|
|
343
365
|
}
|
|
344
366
|
|
|
345
|
-
createOffer() {
|
|
367
|
+
createOffer(): Promise<globalThis.RTCSessionDescriptionInit | any> {
|
|
346
368
|
return this.#localOffer;
|
|
347
369
|
}
|
|
348
370
|
|
|
349
|
-
getConfiguration() {
|
|
371
|
+
getConfiguration(): globalThis.RTCConfiguration {
|
|
350
372
|
return this.#config;
|
|
351
373
|
}
|
|
352
374
|
|
|
353
|
-
getReceivers() {
|
|
375
|
+
getReceivers(): globalThis.RTCRtpReceiver[] {
|
|
354
376
|
throw new DOMException('Not implemented');
|
|
355
377
|
}
|
|
356
378
|
|
|
357
|
-
getSenders() {
|
|
379
|
+
getSenders(): globalThis.RTCRtpSender[] {
|
|
358
380
|
throw new DOMException('Not implemented');
|
|
359
381
|
}
|
|
360
382
|
|
|
361
|
-
getStats() {
|
|
383
|
+
getStats(): Promise<globalThis.RTCStatsReport> {
|
|
362
384
|
return new Promise((resolve) => {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
385
|
+
const report = new Map();
|
|
386
|
+
const cp = this.#peerConnection.getSelectedCandidatePair();
|
|
387
|
+
const bytesSent = this.#peerConnection.bytesSent();
|
|
388
|
+
const bytesReceived = this.#peerConnection.bytesReceived();
|
|
389
|
+
const rtt = this.#peerConnection.rtt();
|
|
390
|
+
|
|
391
|
+
const localIdRs = getRandomString(8);
|
|
392
|
+
const localId = 'RTCIceCandidate_' + localIdRs;
|
|
371
393
|
report.set(localId, {
|
|
372
394
|
id: localId,
|
|
373
395
|
type: 'local-candidate',
|
|
@@ -377,8 +399,8 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
377
399
|
port: cp.local.port,
|
|
378
400
|
});
|
|
379
401
|
|
|
380
|
-
|
|
381
|
-
|
|
402
|
+
const remoteIdRs = getRandomString(8);
|
|
403
|
+
const remoteId = 'RTCIceCandidate_' + remoteIdRs;
|
|
382
404
|
report.set(remoteId, {
|
|
383
405
|
id: remoteId,
|
|
384
406
|
type: 'remote-candidate',
|
|
@@ -388,7 +410,7 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
388
410
|
port: cp.remote.port,
|
|
389
411
|
});
|
|
390
412
|
|
|
391
|
-
|
|
413
|
+
const candidateId = 'RTCIceCandidatePair_' + localIdRs + '_' + remoteIdRs;
|
|
392
414
|
report.set(candidateId, {
|
|
393
415
|
id: candidateId,
|
|
394
416
|
type: 'candidate-pair',
|
|
@@ -404,7 +426,7 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
404
426
|
currentRoundTripTime: rtt,
|
|
405
427
|
});
|
|
406
428
|
|
|
407
|
-
|
|
429
|
+
const transportId = 'RTCTransport_0_1';
|
|
408
430
|
report.set(transportId, {
|
|
409
431
|
id: transportId,
|
|
410
432
|
timestamp: Date.now(),
|
|
@@ -429,50 +451,50 @@ export default class _RTCPeerConnection extends EventTarget {
|
|
|
429
451
|
});
|
|
430
452
|
}
|
|
431
453
|
|
|
432
|
-
getTransceivers() {
|
|
454
|
+
getTransceivers(): globalThis.RTCRtpTransceiver[] {
|
|
433
455
|
return []; // throw new DOMException('Not implemented');
|
|
434
456
|
}
|
|
435
457
|
|
|
436
|
-
removeTrack() {
|
|
458
|
+
removeTrack(): void {
|
|
437
459
|
throw new DOMException('Not implemented');
|
|
438
460
|
}
|
|
439
461
|
|
|
440
|
-
restartIce() {
|
|
462
|
+
restartIce(): Promise<void> {
|
|
441
463
|
throw new DOMException('Not implemented');
|
|
442
464
|
}
|
|
443
465
|
|
|
444
|
-
async setLocalDescription(description) {
|
|
466
|
+
async setLocalDescription(description: globalThis.RTCSessionDescriptionInit): Promise<void> {
|
|
445
467
|
if (description?.type !== 'offer') {
|
|
446
468
|
// any other type causes libdatachannel to throw
|
|
447
469
|
return;
|
|
448
470
|
}
|
|
449
471
|
|
|
450
|
-
this.#peerConnection.setLocalDescription(description?.type);
|
|
472
|
+
this.#peerConnection.setLocalDescription(description?.type as any);
|
|
451
473
|
}
|
|
452
474
|
|
|
453
|
-
async setRemoteDescription(description) {
|
|
475
|
+
async setRemoteDescription(description: globalThis.RTCSessionDescriptionInit): Promise<void> {
|
|
454
476
|
if (description.sdp == null) {
|
|
455
477
|
throw new DOMException('Remote SDP must be set');
|
|
456
478
|
}
|
|
457
479
|
|
|
458
|
-
this.#peerConnection.setRemoteDescription(description.sdp, description.type);
|
|
480
|
+
this.#peerConnection.setRemoteDescription(description.sdp, description.type as any);
|
|
459
481
|
}
|
|
460
482
|
}
|
|
461
483
|
|
|
462
|
-
function createDeferredPromise() {
|
|
463
|
-
let resolve, reject;
|
|
484
|
+
function createDeferredPromise(): any {
|
|
485
|
+
let resolve: any, reject: any;
|
|
464
486
|
|
|
465
|
-
|
|
487
|
+
const promise = new Promise(function (_resolve, _reject) {
|
|
466
488
|
resolve = _resolve;
|
|
467
489
|
reject = _reject;
|
|
468
490
|
});
|
|
469
491
|
|
|
470
|
-
promise.resolve = resolve;
|
|
471
|
-
promise.reject = reject;
|
|
492
|
+
(promise as any).resolve = resolve;
|
|
493
|
+
(promise as any).reject = reject;
|
|
472
494
|
return promise;
|
|
473
495
|
}
|
|
474
496
|
|
|
475
|
-
function getRandomString(length) {
|
|
497
|
+
function getRandomString(length): string {
|
|
476
498
|
return Math.random()
|
|
477
499
|
.toString(36)
|
|
478
500
|
.substring(2, 2 + length);
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import RTCDtlsTransport from './RTCDtlsTransport';
|
|
3
|
+
import RTCPeerConnection from './RTCPeerConnection';
|
|
2
4
|
|
|
3
|
-
export default class
|
|
4
|
-
#pc = null;
|
|
5
|
+
export default class RTCSctpTransport extends EventTarget implements globalThis.RTCSctpTransport {
|
|
6
|
+
#pc: RTCPeerConnection = null;
|
|
5
7
|
#extraFunctions = null;
|
|
6
|
-
#transport = null;
|
|
8
|
+
#transport: RTCDtlsTransport = null;
|
|
7
9
|
|
|
8
|
-
onstatechange = null;
|
|
10
|
+
onstatechange: ((this: RTCSctpTransport, ev: Event) => any) | null = null;
|
|
9
11
|
|
|
10
|
-
constructor({ pc, extraFunctions }) {
|
|
12
|
+
constructor(initial: { pc: RTCPeerConnection, extraFunctions }) {
|
|
11
13
|
super();
|
|
12
|
-
this.#pc = pc;
|
|
13
|
-
this.#extraFunctions = extraFunctions;
|
|
14
|
+
this.#pc = initial.pc;
|
|
15
|
+
this.#extraFunctions = initial.extraFunctions;
|
|
14
16
|
|
|
15
|
-
this.#transport = new RTCDtlsTransport({ pc, extraFunctions });
|
|
17
|
+
this.#transport = new RTCDtlsTransport({ pc: initial.pc, extraFunctions: initial.extraFunctions });
|
|
16
18
|
|
|
17
19
|
// forward peerConnection events
|
|
18
20
|
this.#pc.addEventListener('connectionstatechange', () => {
|
|
@@ -25,29 +27,29 @@ export default class _RTCSctpTransport extends EventTarget {
|
|
|
25
27
|
});
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
get maxChannels() {
|
|
30
|
+
get maxChannels(): number | null {
|
|
29
31
|
if (this.state !== 'connected') return null;
|
|
30
32
|
return this.#pc ? this.#extraFunctions.maxDataChannelId() : 0;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
get maxMessageSize() {
|
|
35
|
+
get maxMessageSize(): number {
|
|
34
36
|
if (this.state !== 'connected') return null;
|
|
35
37
|
return this.#pc ? this.#extraFunctions.maxMessageSize() : 0;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
|
-
get state() {
|
|
40
|
+
get state(): globalThis.RTCSctpTransportState {
|
|
39
41
|
// reduce state from new, connecting, connected, disconnected, failed, closed, unknown
|
|
40
42
|
// to RTCSctpTransport states connecting, connected, closed
|
|
41
43
|
let state = this.#pc.connectionState;
|
|
42
44
|
if (state === 'new' || state === 'connecting') {
|
|
43
45
|
state = 'connecting';
|
|
44
|
-
} else if (state === 'disconnected' || state === 'failed' || state === 'closed'
|
|
46
|
+
} else if (state === 'disconnected' || state === 'failed' || state === 'closed') {
|
|
45
47
|
state = 'closed';
|
|
46
48
|
}
|
|
47
49
|
return state;
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
get transport() {
|
|
52
|
+
get transport(): RTCDtlsTransport {
|
|
51
53
|
return this.#transport;
|
|
52
54
|
}
|
|
53
55
|
}
|
|
@@ -6,29 +6,24 @@
|
|
|
6
6
|
// sdp: 'v=0\r\no=- 1234567890 1234567890 IN IP4 192.168.1.1\r\ns=-\r\nt=0 0\r\na=ice-ufrag:abcd\r\na=ice-pwd:efgh\r\n'
|
|
7
7
|
// };
|
|
8
8
|
|
|
9
|
-
export default class
|
|
10
|
-
#type;
|
|
11
|
-
#sdp;
|
|
12
|
-
|
|
13
|
-
constructor(init = {}) {
|
|
14
|
-
// Allow Empty Constructor
|
|
15
|
-
// if (!init || !init.type || !init.sdp) {
|
|
16
|
-
// throw new DOMException('Type and sdp properties are required.');
|
|
17
|
-
// }
|
|
9
|
+
export default class RTCSessionDescription implements globalThis.RTCSessionDescriptionInit {
|
|
10
|
+
#type: globalThis.RTCSdpType;
|
|
11
|
+
#sdp: string;
|
|
18
12
|
|
|
13
|
+
constructor(init: globalThis.RTCSessionDescriptionInit) {
|
|
19
14
|
this.#type = init ? init.type : null;
|
|
20
15
|
this.#sdp = init ? init.sdp : null;
|
|
21
16
|
}
|
|
22
17
|
|
|
23
|
-
get type() {
|
|
18
|
+
get type(): globalThis.RTCSdpType {
|
|
24
19
|
return this.#type;
|
|
25
20
|
}
|
|
26
21
|
|
|
27
|
-
get sdp() {
|
|
22
|
+
get sdp(): string {
|
|
28
23
|
return this.#sdp;
|
|
29
24
|
}
|
|
30
25
|
|
|
31
|
-
toJSON() {
|
|
26
|
+
toJSON(): globalThis.RTCSessionDescriptionInit {
|
|
32
27
|
return {
|
|
33
28
|
sdp: this.#sdp,
|
|
34
29
|
type: this.#type,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import RTCCertificate from './RTCCertificate
|
|
2
|
-
import RTCDataChannel from './RTCDataChannel
|
|
3
|
-
import RTCDtlsTransport from './RTCDtlsTransport
|
|
4
|
-
import RTCIceCandidate from './RTCIceCandidate
|
|
5
|
-
import RTCIceTransport from './RTCIceTransport
|
|
6
|
-
import RTCPeerConnection from './RTCPeerConnection
|
|
7
|
-
import RTCSctpTransport from './RTCSctpTransport
|
|
8
|
-
import RTCSessionDescription from './RTCSessionDescription
|
|
9
|
-
import { RTCDataChannelEvent, RTCPeerConnectionIceEvent } from './Events
|
|
1
|
+
import RTCCertificate from './RTCCertificate';
|
|
2
|
+
import RTCDataChannel from './RTCDataChannel';
|
|
3
|
+
import RTCDtlsTransport from './RTCDtlsTransport';
|
|
4
|
+
import RTCIceCandidate from './RTCIceCandidate';
|
|
5
|
+
import RTCIceTransport from './RTCIceTransport';
|
|
6
|
+
import RTCPeerConnection from './RTCPeerConnection';
|
|
7
|
+
import RTCSctpTransport from './RTCSctpTransport';
|
|
8
|
+
import RTCSessionDescription from './RTCSessionDescription';
|
|
9
|
+
import { RTCDataChannelEvent, RTCPeerConnectionIceEvent } from './Events';
|
|
10
|
+
import RTCError from './RTCError';
|
|
10
11
|
|
|
11
12
|
export {
|
|
12
13
|
RTCCertificate,
|
|
@@ -19,6 +20,7 @@ export {
|
|
|
19
20
|
RTCSessionDescription,
|
|
20
21
|
RTCDataChannelEvent,
|
|
21
22
|
RTCPeerConnectionIceEvent,
|
|
23
|
+
RTCError,
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
export default {
|
|
@@ -32,4 +34,5 @@ export default {
|
|
|
32
34
|
RTCSessionDescription,
|
|
33
35
|
RTCDataChannelEvent,
|
|
34
36
|
RTCPeerConnectionIceEvent,
|
|
37
|
+
RTCError,
|
|
35
38
|
};
|
package/tsconfig.json
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"moduleResolution": "Node",
|
|
5
|
+
"rootDir": ".",
|
|
6
|
+
"importsNotUsedAsValues": "remove",
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"noImplicitAny": false,
|
|
11
|
+
"noImplicitThis": false,
|
|
12
|
+
"noImplicitReturns": true,
|
|
13
|
+
"strictNullChecks": false,
|
|
14
|
+
"noUnusedLocals": true,
|
|
15
|
+
"alwaysStrict": true,
|
|
16
|
+
"outDir": "./dist",
|
|
17
|
+
"module": "CommonJS"
|
|
18
|
+
},
|
|
19
|
+
"include": ["src/**/*", "test/**/*"],
|
|
20
|
+
"exclude": ["node_modules", "dist", "src/cpp", "test/wpt-tests/wpt"]
|
|
21
|
+
}
|