@lng2004/node-datachannel 0.31.0-20251228
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/.clang-format +17 -0
- package/.editorconfig +12 -0
- package/.eslintignore +8 -0
- package/.eslintrc.json +27 -0
- package/.gitmodules +3 -0
- package/.prettierignore +7 -0
- package/.prettierrc +13 -0
- package/API.md +247 -0
- package/BULDING.md +33 -0
- package/CMakeLists.txt +134 -0
- package/LICENSE +373 -0
- package/README.md +130 -0
- package/dist/cjs/index.cjs +11 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/lib/datachannel-stream.cjs +101 -0
- package/dist/cjs/lib/datachannel-stream.cjs.map +1 -0
- package/dist/cjs/lib/index.cjs +88 -0
- package/dist/cjs/lib/index.cjs.map +1 -0
- package/dist/cjs/lib/node-datachannel.cjs +8 -0
- package/dist/cjs/lib/node-datachannel.cjs.map +1 -0
- package/dist/cjs/lib/websocket-server.cjs +45 -0
- package/dist/cjs/lib/websocket-server.cjs.map +1 -0
- package/dist/cjs/lib/websocket.cjs +8 -0
- package/dist/cjs/lib/websocket.cjs.map +1 -0
- package/dist/cjs/polyfill/Events.cjs +86 -0
- package/dist/cjs/polyfill/Events.cjs.map +1 -0
- package/dist/cjs/polyfill/Exception.cjs +34 -0
- package/dist/cjs/polyfill/Exception.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCCertificate.cjs +34 -0
- package/dist/cjs/polyfill/RTCCertificate.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCDataChannel.cjs +214 -0
- package/dist/cjs/polyfill/RTCDataChannel.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCDtlsTransport.cjs +53 -0
- package/dist/cjs/polyfill/RTCDtlsTransport.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCError.cjs +83 -0
- package/dist/cjs/polyfill/RTCError.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCIceCandidate.cjs +132 -0
- package/dist/cjs/polyfill/RTCIceCandidate.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCIceTransport.cjs +94 -0
- package/dist/cjs/polyfill/RTCIceTransport.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCPeerConnection.cjs +434 -0
- package/dist/cjs/polyfill/RTCPeerConnection.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCSctpTransport.cjs +59 -0
- package/dist/cjs/polyfill/RTCSctpTransport.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCSessionDescription.cjs +45 -0
- package/dist/cjs/polyfill/RTCSessionDescription.cjs.map +1 -0
- package/dist/cjs/polyfill/index.cjs +42 -0
- package/dist/cjs/polyfill/index.cjs.map +1 -0
- package/dist/esm/index.mjs +8 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/lib/datachannel-stream.mjs +78 -0
- package/dist/esm/lib/datachannel-stream.mjs.map +1 -0
- package/dist/esm/lib/index.mjs +62 -0
- package/dist/esm/lib/index.mjs.map +1 -0
- package/dist/esm/lib/node-datachannel.mjs +12 -0
- package/dist/esm/lib/node-datachannel.mjs.map +1 -0
- package/dist/esm/lib/websocket-server.mjs +43 -0
- package/dist/esm/lib/websocket-server.mjs.map +1 -0
- package/dist/esm/lib/websocket.mjs +6 -0
- package/dist/esm/lib/websocket.mjs.map +1 -0
- package/dist/esm/polyfill/Events.mjs +82 -0
- package/dist/esm/polyfill/Events.mjs.map +1 -0
- package/dist/esm/polyfill/Exception.mjs +28 -0
- package/dist/esm/polyfill/Exception.mjs.map +1 -0
- package/dist/esm/polyfill/RTCCertificate.mjs +30 -0
- package/dist/esm/polyfill/RTCCertificate.mjs.map +1 -0
- package/dist/esm/polyfill/RTCDataChannel.mjs +210 -0
- package/dist/esm/polyfill/RTCDataChannel.mjs.map +1 -0
- package/dist/esm/polyfill/RTCDtlsTransport.mjs +49 -0
- package/dist/esm/polyfill/RTCDtlsTransport.mjs.map +1 -0
- package/dist/esm/polyfill/RTCError.mjs +79 -0
- package/dist/esm/polyfill/RTCError.mjs.map +1 -0
- package/dist/esm/polyfill/RTCIceCandidate.mjs +128 -0
- package/dist/esm/polyfill/RTCIceCandidate.mjs.map +1 -0
- package/dist/esm/polyfill/RTCIceTransport.mjs +89 -0
- package/dist/esm/polyfill/RTCIceTransport.mjs.map +1 -0
- package/dist/esm/polyfill/RTCPeerConnection.mjs +430 -0
- package/dist/esm/polyfill/RTCPeerConnection.mjs.map +1 -0
- package/dist/esm/polyfill/RTCSctpTransport.mjs +55 -0
- package/dist/esm/polyfill/RTCSctpTransport.mjs.map +1 -0
- package/dist/esm/polyfill/RTCSessionDescription.mjs +41 -0
- package/dist/esm/polyfill/RTCSessionDescription.mjs.map +1 -0
- package/dist/esm/polyfill/index.mjs +27 -0
- package/dist/esm/polyfill/index.mjs.map +1 -0
- package/dist/types/lib/datachannel-stream.d.ts +24 -0
- package/dist/types/lib/index.d.ts +235 -0
- package/dist/types/lib/types.d.ts +118 -0
- package/dist/types/lib/websocket-server.d.ts +13 -0
- package/dist/types/lib/websocket.d.ts +25 -0
- package/dist/types/polyfill/Events.d.ts +15 -0
- package/dist/types/polyfill/RTCCertificate.d.ts +9 -0
- package/dist/types/polyfill/RTCDataChannel.d.ts +29 -0
- package/dist/types/polyfill/RTCDtlsTransport.d.ts +15 -0
- package/dist/types/polyfill/RTCError.d.ts +17 -0
- package/dist/types/polyfill/RTCIceCandidate.d.ts +21 -0
- package/dist/types/polyfill/RTCIceTransport.d.ts +30 -0
- package/dist/types/polyfill/RTCPeerConnection.d.ts +64 -0
- package/dist/types/polyfill/RTCSctpTransport.d.ts +15 -0
- package/dist/types/polyfill/RTCSessionDescription.d.ts +10 -0
- package/dist/types/polyfill/index.d.ts +26 -0
- package/jest.config.ts +14 -0
- package/package.json +121 -0
- package/rollup.config.mjs +72 -0
- package/src/cpp/data-channel-wrapper.cpp +530 -0
- package/src/cpp/data-channel-wrapper.h +63 -0
- package/src/cpp/ice-udp-mux-listener-wrapper.cpp +157 -0
- package/src/cpp/ice-udp-mux-listener-wrapper.h +43 -0
- package/src/cpp/main.cpp +58 -0
- package/src/cpp/media-audio-wrapper.cpp +457 -0
- package/src/cpp/media-audio-wrapper.h +52 -0
- package/src/cpp/media-av1packetization.cpp +24 -0
- package/src/cpp/media-av1packetization.h +11 -0
- package/src/cpp/media-av1rtppacketizer-wrapper.cpp +126 -0
- package/src/cpp/media-av1rtppacketizer-wrapper.h +29 -0
- package/src/cpp/media-direction.cpp +43 -0
- package/src/cpp/media-direction.h +10 -0
- package/src/cpp/media-h264rtppacketizer-wrapper.cpp +126 -0
- package/src/cpp/media-h264rtppacketizer-wrapper.h +30 -0
- package/src/cpp/media-h265rtppacketizer-wrapper.cpp +126 -0
- package/src/cpp/media-h265rtppacketizer-wrapper.h +30 -0
- package/src/cpp/media-h26xseparator.cpp +32 -0
- package/src/cpp/media-h26xseparator.h +11 -0
- package/src/cpp/media-mediahandler-helper.cpp +31 -0
- package/src/cpp/media-mediahandler-helper.h +11 -0
- package/src/cpp/media-pacinghandler-wrapper.cpp +79 -0
- package/src/cpp/media-pacinghandler-wrapper.h +28 -0
- package/src/cpp/media-rtcpnackresponder-wrapper.cpp +68 -0
- package/src/cpp/media-rtcpnackresponder-wrapper.h +28 -0
- package/src/cpp/media-rtcpreceivingsession-wrapper.cpp +57 -0
- package/src/cpp/media-rtcpreceivingsession-wrapper.h +28 -0
- package/src/cpp/media-rtcpsrreporter-wrapper.cpp +93 -0
- package/src/cpp/media-rtcpsrreporter-wrapper.h +30 -0
- package/src/cpp/media-rtppacketizationconfig-wrapper.cpp +167 -0
- package/src/cpp/media-rtppacketizationconfig-wrapper.h +35 -0
- package/src/cpp/media-rtppacketizer-wrapper.cpp +95 -0
- package/src/cpp/media-rtppacketizer-wrapper.h +30 -0
- package/src/cpp/media-track-wrapper.cpp +458 -0
- package/src/cpp/media-track-wrapper.h +61 -0
- package/src/cpp/media-video-wrapper.cpp +526 -0
- package/src/cpp/media-video-wrapper.h +56 -0
- package/src/cpp/peer-connection-wrapper.cpp +1298 -0
- package/src/cpp/peer-connection-wrapper.h +89 -0
- package/src/cpp/rtc-wrapper.cpp +205 -0
- package/src/cpp/rtc-wrapper.h +24 -0
- package/src/cpp/thread-safe-callback.cpp +57 -0
- package/src/cpp/thread-safe-callback.h +47 -0
- package/src/cpp/web-socket-server-wrapper.cpp +275 -0
- package/src/cpp/web-socket-server-wrapper.h +41 -0
- package/src/cpp/web-socket-wrapper.cpp +796 -0
- package/src/cpp/web-socket-wrapper.h +63 -0
- package/src/index.ts +9 -0
- package/src/lib/datachannel-stream.ts +100 -0
- package/src/lib/index.ts +283 -0
- package/src/lib/node-datachannel.ts +3 -0
- package/src/lib/types.ts +168 -0
- package/src/lib/websocket-server.ts +37 -0
- package/src/lib/websocket.ts +26 -0
- package/src/polyfill/Events.ts +82 -0
- package/src/polyfill/Exception.ts +37 -0
- package/src/polyfill/README.md +41 -0
- package/src/polyfill/RTCCertificate.ts +21 -0
- package/src/polyfill/RTCDataChannel.ts +225 -0
- package/src/polyfill/RTCDtlsTransport.ts +46 -0
- package/src/polyfill/RTCError.ts +78 -0
- package/src/polyfill/RTCIceCandidate.ts +128 -0
- package/src/polyfill/RTCIceTransport.ts +90 -0
- package/src/polyfill/RTCPeerConnection.ts +527 -0
- package/src/polyfill/RTCSctpTransport.ts +51 -0
- package/src/polyfill/RTCSessionDescription.ts +41 -0
- package/src/polyfill/index.ts +38 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import RTCDataChannel from './RTCDataChannel';
|
|
2
|
+
import RTCError from './RTCError';
|
|
3
|
+
|
|
4
|
+
export class RTCPeerConnectionIceEvent
|
|
5
|
+
extends Event
|
|
6
|
+
implements globalThis.RTCPeerConnectionIceEvent
|
|
7
|
+
{
|
|
8
|
+
#candidate: globalThis.RTCIceCandidate;
|
|
9
|
+
|
|
10
|
+
constructor(candidate: globalThis.RTCIceCandidate) {
|
|
11
|
+
super('icecandidate');
|
|
12
|
+
|
|
13
|
+
this.#candidate = candidate;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get candidate(): globalThis.RTCIceCandidate {
|
|
17
|
+
return this.#candidate;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get url(): string {
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class RTCDataChannelEvent extends Event implements globalThis.RTCDataChannelEvent {
|
|
26
|
+
#channel: RTCDataChannel;
|
|
27
|
+
|
|
28
|
+
constructor(type: string = 'datachannel', eventInitDict: globalThis.RTCDataChannelEventInit) {
|
|
29
|
+
super(type);
|
|
30
|
+
|
|
31
|
+
if (arguments.length === 0)
|
|
32
|
+
throw new TypeError(
|
|
33
|
+
`Failed to construct 'RTCDataChannelEvent': 2 arguments required, but only ${arguments.length} present.`,
|
|
34
|
+
);
|
|
35
|
+
if (typeof eventInitDict !== 'object')
|
|
36
|
+
throw new TypeError(
|
|
37
|
+
"Failed to construct 'RTCDataChannelEvent': The provided value is not of type 'RTCDataChannelEventInit'.",
|
|
38
|
+
);
|
|
39
|
+
if (!eventInitDict.channel)
|
|
40
|
+
throw new TypeError(
|
|
41
|
+
"Failed to construct 'RTCDataChannelEvent': Failed to read the 'channel' property from 'RTCDataChannelEventInit': Required member is undefined.",
|
|
42
|
+
);
|
|
43
|
+
if (eventInitDict.channel.constructor !== RTCDataChannel)
|
|
44
|
+
throw new TypeError(
|
|
45
|
+
"Failed to construct 'RTCDataChannelEvent': Failed to read the 'channel' property from 'RTCDataChannelEventInit': Failed to convert value to 'RTCDataChannel'.",
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
this.#channel = eventInitDict?.channel;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get channel(): RTCDataChannel {
|
|
52
|
+
return this.#channel;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export class RTCErrorEvent extends Event implements globalThis.RTCErrorEvent {
|
|
57
|
+
#error: RTCError;
|
|
58
|
+
constructor(type: string, init: globalThis.RTCErrorEventInit) {
|
|
59
|
+
if (arguments.length < 2)
|
|
60
|
+
throw new TypeError(
|
|
61
|
+
`Failed to construct 'RTCErrorEvent': 2 arguments required, but only ${arguments.length} present.`,
|
|
62
|
+
);
|
|
63
|
+
if (typeof init !== 'object')
|
|
64
|
+
throw new TypeError(
|
|
65
|
+
"Failed to construct 'RTCErrorEvent': The provided value is not of type 'RTCErrorEventInit'.",
|
|
66
|
+
);
|
|
67
|
+
if (!init.error)
|
|
68
|
+
throw new TypeError(
|
|
69
|
+
"Failed to construct 'RTCErrorEvent': Failed to read the 'error' property from 'RTCErrorEventInit': Required member is undefined.",
|
|
70
|
+
);
|
|
71
|
+
if (init.error.constructor !== RTCError)
|
|
72
|
+
throw new TypeError(
|
|
73
|
+
"Failed to construct 'RTCErrorEvent': Failed to read the 'error' property from 'RTCErrorEventInit': Failed to convert value to 'RTCError'.",
|
|
74
|
+
);
|
|
75
|
+
super(type || 'error');
|
|
76
|
+
this.#error = init.error;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get error(): RTCError {
|
|
80
|
+
return this.#error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
|
|
3
|
+
export class InvalidStateError extends DOMException {
|
|
4
|
+
constructor(msg: string) {
|
|
5
|
+
super(msg, 'InvalidStateError');
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class TypeError extends DOMException {
|
|
10
|
+
constructor(msg: string) {
|
|
11
|
+
super(msg, 'TypeError');
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class OperationError extends DOMException {
|
|
16
|
+
constructor(msg: string) {
|
|
17
|
+
super(msg, 'OperationError');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class NotFoundError extends DOMException {
|
|
22
|
+
constructor(msg: string) {
|
|
23
|
+
super(msg, 'NotFoundError');
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class InvalidAccessError extends DOMException {
|
|
28
|
+
constructor(msg: string) {
|
|
29
|
+
super(msg, 'InvalidAccessError');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class SyntaxError extends DOMException {
|
|
34
|
+
constructor(msg: string) {
|
|
35
|
+
super(msg, 'SyntaxError');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# WebRTC Polyfills
|
|
2
|
+
|
|
3
|
+
WebRTC polyfills to be used for libraries like `simple-peer`.
|
|
4
|
+
|
|
5
|
+
# web-platform-tests
|
|
6
|
+
|
|
7
|
+
Please check actual situation [here](/test/wpt-tests/)
|
|
8
|
+
|
|
9
|
+
## Example Usage
|
|
10
|
+
|
|
11
|
+
> For a native usage example please check test folder.
|
|
12
|
+
|
|
13
|
+
`simple-peer` usage example
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
import Peer from 'simple-peer';
|
|
17
|
+
import nodeDatachannelPolyfill from 'node-datachannel/polyfill';
|
|
18
|
+
|
|
19
|
+
var peer1 = new Peer({ initiator: true, wrtc: nodeDatachannelPolyfill });
|
|
20
|
+
var peer2 = new Peer({ wrtc: nodeDatachannelPolyfill });
|
|
21
|
+
|
|
22
|
+
peer1.on('signal', (data) => {
|
|
23
|
+
// when peer1 has signaling data, give it to peer2 somehow
|
|
24
|
+
peer2.signal(data);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
peer2.on('signal', (data) => {
|
|
28
|
+
// when peer2 has signaling data, give it to peer1 somehow
|
|
29
|
+
peer1.signal(data);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
peer1.on('connect', () => {
|
|
33
|
+
// wait for 'connect' event before using the data channel
|
|
34
|
+
peer1.send('hey peer2, how is it going?');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
peer2.on('data', (data) => {
|
|
38
|
+
// got a data channel message
|
|
39
|
+
console.log('got a message from peer1: ' + data);
|
|
40
|
+
});
|
|
41
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export default class RTCCertificate implements globalThis.RTCCertificate {
|
|
2
|
+
#expires: number = 0;
|
|
3
|
+
#fingerprints: globalThis.RTCDtlsFingerprint[] = [];
|
|
4
|
+
|
|
5
|
+
constructor() {
|
|
6
|
+
this.#expires = null;
|
|
7
|
+
this.#fingerprints = [];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
get expires(): number {
|
|
11
|
+
return this.#expires;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getFingerprints(): globalThis.RTCDtlsFingerprint[] {
|
|
15
|
+
return this.#fingerprints;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getAlgorithm(): string {
|
|
19
|
+
return '';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import * as exceptions from './Exception';
|
|
3
|
+
import { DataChannel } from '../lib/index';
|
|
4
|
+
import { RTCErrorEvent } from './Events';
|
|
5
|
+
|
|
6
|
+
export default class RTCDataChannel extends EventTarget implements globalThis.RTCDataChannel {
|
|
7
|
+
#dataChannel: DataChannel;
|
|
8
|
+
#readyState: globalThis.RTCDataChannelState;
|
|
9
|
+
#bufferedAmountLowThreshold: number;
|
|
10
|
+
#binaryType: BinaryType;
|
|
11
|
+
#maxPacketLifeTime: number | null;
|
|
12
|
+
#maxRetransmits: number | null;
|
|
13
|
+
#negotiated: boolean;
|
|
14
|
+
#ordered: boolean;
|
|
15
|
+
#id: number;
|
|
16
|
+
#label: string;
|
|
17
|
+
#protocol: string;
|
|
18
|
+
|
|
19
|
+
#closeRequested = false;
|
|
20
|
+
|
|
21
|
+
// events
|
|
22
|
+
onbufferedamountlow: globalThis.RTCDataChannel['onbufferedamountlow'] = null;
|
|
23
|
+
onclose: globalThis.RTCDataChannel['onclose'] = null;
|
|
24
|
+
onclosing: globalThis.RTCDataChannel['onclosing'] = null;
|
|
25
|
+
onerror: globalThis.RTCDataChannel['onerror'] = null;
|
|
26
|
+
onmessage: globalThis.RTCDataChannel['onmessage'] = null;
|
|
27
|
+
onopen: globalThis.RTCDataChannel['onopen'] = null;
|
|
28
|
+
|
|
29
|
+
constructor(dataChannel: DataChannel, opts: globalThis.RTCDataChannelInit = {}) {
|
|
30
|
+
super();
|
|
31
|
+
|
|
32
|
+
this.#dataChannel = dataChannel;
|
|
33
|
+
this.#binaryType = 'arraybuffer';
|
|
34
|
+
this.#readyState = this.#dataChannel.isOpen() ? 'open' : 'connecting';
|
|
35
|
+
this.#bufferedAmountLowThreshold = 0;
|
|
36
|
+
this.#maxPacketLifeTime = opts.maxPacketLifeTime ?? null;
|
|
37
|
+
this.#maxRetransmits = opts.maxRetransmits ?? null;
|
|
38
|
+
this.#negotiated = opts.negotiated ?? false;
|
|
39
|
+
this.#ordered = opts.ordered ?? true;
|
|
40
|
+
this.#id = this.#dataChannel.getId();
|
|
41
|
+
this.#label = this.#dataChannel.getLabel();
|
|
42
|
+
this.#protocol = this.#dataChannel.getProtocol();
|
|
43
|
+
|
|
44
|
+
// forward dataChannel events
|
|
45
|
+
this.#dataChannel.onOpen(() => {
|
|
46
|
+
this.#readyState = 'open';
|
|
47
|
+
this.dispatchEvent(new Event('open', {}));
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
this.#dataChannel.onClosed(() => {
|
|
51
|
+
// Simulate closing event
|
|
52
|
+
if (!this.#closeRequested) {
|
|
53
|
+
this.#readyState = 'closing';
|
|
54
|
+
this.dispatchEvent(new Event('closing'));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
setImmediate(() => {
|
|
58
|
+
this.#readyState = 'closed';
|
|
59
|
+
this.dispatchEvent(new Event('close'));
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
this.#dataChannel.onError((msg) => {
|
|
64
|
+
this.dispatchEvent(
|
|
65
|
+
new RTCErrorEvent('error', {
|
|
66
|
+
error: new RTCError(
|
|
67
|
+
{
|
|
68
|
+
errorDetail: 'data-channel-failure',
|
|
69
|
+
},
|
|
70
|
+
msg,
|
|
71
|
+
),
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
this.#dataChannel.onBufferedAmountLow(() => {
|
|
77
|
+
this.dispatchEvent(new Event('bufferedamountlow'));
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
this.#dataChannel.onMessage((message) => {
|
|
81
|
+
if (typeof message === 'string') {
|
|
82
|
+
this.dispatchEvent(new MessageEvent('message', { data: message }));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let data: Blob | ArrayBuffer;
|
|
87
|
+
|
|
88
|
+
if (message instanceof ArrayBuffer) {
|
|
89
|
+
data = message;
|
|
90
|
+
} else {
|
|
91
|
+
data = message.buffer;
|
|
92
|
+
|
|
93
|
+
if (message.byteOffset !== 0 || message.byteLength !== message.buffer.byteLength) {
|
|
94
|
+
// message is view on underlying buffer, must create new
|
|
95
|
+
// ArrayBuffer that only contains message data
|
|
96
|
+
data = new ArrayBuffer(message.byteLength);
|
|
97
|
+
new Uint8Array(data, 0, message.byteLength).set(message);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (this.#binaryType === 'blob') {
|
|
102
|
+
data = new Blob([data]);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.dispatchEvent(new MessageEvent('message', { data }));
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// forward events to properties
|
|
109
|
+
this.addEventListener('message', (e) => {
|
|
110
|
+
if (this.onmessage) this.onmessage(e as MessageEvent);
|
|
111
|
+
});
|
|
112
|
+
this.addEventListener('bufferedamountlow', (e) => {
|
|
113
|
+
if (this.onbufferedamountlow) this.onbufferedamountlow(e);
|
|
114
|
+
});
|
|
115
|
+
this.addEventListener('error', (e) => {
|
|
116
|
+
if (this.onerror) this.onerror(e as RTCErrorEvent);
|
|
117
|
+
});
|
|
118
|
+
this.addEventListener('close', (e) => {
|
|
119
|
+
if (this.onclose) this.onclose(e);
|
|
120
|
+
});
|
|
121
|
+
this.addEventListener('closing', (e) => {
|
|
122
|
+
if (this.onclosing) this.onclosing(e);
|
|
123
|
+
});
|
|
124
|
+
this.addEventListener('open', (e) => {
|
|
125
|
+
if (this.onopen) this.onopen(e);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
set binaryType(type) {
|
|
130
|
+
if (type !== 'blob' && type !== 'arraybuffer') {
|
|
131
|
+
throw new DOMException(
|
|
132
|
+
"Failed to set the 'binaryType' property on 'RTCDataChannel': Unknown binary type : " +
|
|
133
|
+
type,
|
|
134
|
+
'TypeMismatchError',
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
this.#binaryType = type;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
get binaryType(): BinaryType {
|
|
141
|
+
return this.#binaryType;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
get bufferedAmount(): number {
|
|
145
|
+
return this.#dataChannel.bufferedAmount();
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
get bufferedAmountLowThreshold(): number {
|
|
149
|
+
return this.#bufferedAmountLowThreshold;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
set bufferedAmountLowThreshold(value) {
|
|
153
|
+
const number = Number(value) || 0;
|
|
154
|
+
this.#bufferedAmountLowThreshold = number;
|
|
155
|
+
this.#dataChannel.setBufferedAmountLowThreshold(number);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get id(): number | null {
|
|
159
|
+
return this.#id;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
get label(): string {
|
|
163
|
+
return this.#label;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
get maxPacketLifeTime(): number | null {
|
|
167
|
+
return this.#maxPacketLifeTime;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
get maxRetransmits(): number | null {
|
|
171
|
+
return this.#maxRetransmits;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
get negotiated(): boolean {
|
|
175
|
+
return this.#negotiated;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
get ordered(): boolean {
|
|
179
|
+
return this.#ordered;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
get protocol(): string {
|
|
183
|
+
return this.#protocol;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
get readyState(): globalThis.RTCDataChannelState {
|
|
187
|
+
return this.#readyState;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
send(data): void {
|
|
191
|
+
if (this.#readyState !== 'open') {
|
|
192
|
+
throw new exceptions.InvalidStateError(
|
|
193
|
+
"Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel.readyState is not 'open'",
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Needs network error, type error implemented
|
|
198
|
+
if (typeof data === 'string') {
|
|
199
|
+
this.#dataChannel.sendMessage(data);
|
|
200
|
+
} else if (data instanceof Blob) {
|
|
201
|
+
data.arrayBuffer().then((ab) => {
|
|
202
|
+
if (process?.versions?.bun) {
|
|
203
|
+
this.#dataChannel.sendMessageBinary(Buffer.from(ab));
|
|
204
|
+
} else {
|
|
205
|
+
this.#dataChannel.sendMessageBinary(new Uint8Array(ab));
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
} else if (data instanceof Uint8Array) {
|
|
209
|
+
this.#dataChannel.sendMessageBinary(data);
|
|
210
|
+
} else {
|
|
211
|
+
if (process?.versions?.bun) {
|
|
212
|
+
this.#dataChannel.sendMessageBinary(Buffer.from(data));
|
|
213
|
+
} else {
|
|
214
|
+
this.#dataChannel.sendMessageBinary(new Uint8Array(data));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
close(): void {
|
|
220
|
+
this.#closeRequested = true;
|
|
221
|
+
setImmediate(() => {
|
|
222
|
+
this.#dataChannel.close();
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import RTCIceTransport from './RTCIceTransport';
|
|
3
|
+
import RTCPeerConnection from './RTCPeerConnection';
|
|
4
|
+
|
|
5
|
+
export default class RTCDtlsTransport extends EventTarget implements globalThis.RTCDtlsTransport {
|
|
6
|
+
#pc: RTCPeerConnection = null;
|
|
7
|
+
#iceTransport = null;
|
|
8
|
+
|
|
9
|
+
onstatechange: globalThis.RTCDtlsTransport['onstatechange'] = null;
|
|
10
|
+
onerror: globalThis.RTCDtlsTransport['onstatechange'] = null;
|
|
11
|
+
|
|
12
|
+
constructor(init: { pc: RTCPeerConnection }) {
|
|
13
|
+
super();
|
|
14
|
+
this.#pc = init.pc;
|
|
15
|
+
|
|
16
|
+
this.#iceTransport = new RTCIceTransport({
|
|
17
|
+
pc: init.pc,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// forward peerConnection events
|
|
21
|
+
this.#pc.addEventListener('connectionstatechange', () => {
|
|
22
|
+
const e = new Event('statechange');
|
|
23
|
+
this.dispatchEvent(e);
|
|
24
|
+
this.onstatechange?.(e);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get iceTransport(): globalThis.RTCIceTransport {
|
|
29
|
+
return this.#iceTransport;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get state(): globalThis.RTCDtlsTransportState {
|
|
33
|
+
// reduce state from new, connecting, connected, disconnected, failed, closed, unknown
|
|
34
|
+
// to RTCDtlsTRansport states new, connecting, connected, closed, failed
|
|
35
|
+
let state = this.#pc ? this.#pc.connectionState : 'new';
|
|
36
|
+
if (state === 'disconnected') {
|
|
37
|
+
state = 'closed';
|
|
38
|
+
}
|
|
39
|
+
return state;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getRemoteCertificates(): ArrayBuffer[] {
|
|
43
|
+
// TODO: implement
|
|
44
|
+
return [new ArrayBuffer(0)];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export default class RTCError extends DOMException implements globalThis.RTCError {
|
|
2
|
+
#errorDetail: globalThis.RTCErrorDetailType;
|
|
3
|
+
#receivedAlert: number | null;
|
|
4
|
+
#sctpCauseCode: number | null;
|
|
5
|
+
#sdpLineNumber: number | null;
|
|
6
|
+
#sentAlert: number | null;
|
|
7
|
+
#httpRequestStatusCode: number | null;
|
|
8
|
+
|
|
9
|
+
constructor(init: globalThis.RTCErrorInit, message?: string) {
|
|
10
|
+
super(message, 'OperationError');
|
|
11
|
+
|
|
12
|
+
if (!init || !init.errorDetail)
|
|
13
|
+
throw new TypeError('Cannot construct RTCError, errorDetail is required');
|
|
14
|
+
if (
|
|
15
|
+
[
|
|
16
|
+
'data-channel-failure',
|
|
17
|
+
'dtls-failure',
|
|
18
|
+
'fingerprint-failure',
|
|
19
|
+
'hardware-encoder-error',
|
|
20
|
+
'hardware-encoder-not-available',
|
|
21
|
+
'sctp-failure',
|
|
22
|
+
'sdp-syntax-error',
|
|
23
|
+
].indexOf(init.errorDetail) === -1
|
|
24
|
+
)
|
|
25
|
+
throw new TypeError('Cannot construct RTCError, errorDetail is invalid');
|
|
26
|
+
|
|
27
|
+
this.#errorDetail = init.errorDetail;
|
|
28
|
+
this.#receivedAlert = init.receivedAlert ?? null;
|
|
29
|
+
this.#sctpCauseCode = init.sctpCauseCode ?? null;
|
|
30
|
+
this.#sdpLineNumber = init.sdpLineNumber ?? null;
|
|
31
|
+
this.#sentAlert = init.sentAlert ?? null;
|
|
32
|
+
this.#httpRequestStatusCode = init.httpRequestStatusCode ?? null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get errorDetail(): globalThis.RTCErrorDetailType {
|
|
36
|
+
return this.#errorDetail;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
set errorDetail(_value) {
|
|
40
|
+
throw new TypeError('Cannot set errorDetail, it is read-only');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get receivedAlert(): number | null {
|
|
44
|
+
return this.#receivedAlert;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
set receivedAlert(_value) {
|
|
48
|
+
throw new TypeError('Cannot set receivedAlert, it is read-only');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get sctpCauseCode(): number | null {
|
|
52
|
+
return this.#sctpCauseCode;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
set sctpCauseCode(_value) {
|
|
56
|
+
throw new TypeError('Cannot set sctpCauseCode, it is read-only');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get httpRequestStatusCode(): number | null {
|
|
60
|
+
return this.#httpRequestStatusCode;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get sdpLineNumber(): number | null {
|
|
64
|
+
return this.#sdpLineNumber;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
set sdpLineNumber(_value) {
|
|
68
|
+
throw new TypeError('Cannot set sdpLineNumber, it is read-only');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get sentAlert(): number | null {
|
|
72
|
+
return this.#sentAlert;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
set sentAlert(_value) {
|
|
76
|
+
throw new TypeError('Cannot set sentAlert, it is read-only');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// https://developer.mozilla.org/docs/Web/API/RTCIceCandidate
|
|
2
|
+
//
|
|
3
|
+
// Example: candidate:123456 1 UDP 123456 192.168.1.1 12345 typ host raddr=10.0.0.1 rport=54321 generation 0
|
|
4
|
+
|
|
5
|
+
export default class RTCIceCandidate implements globalThis.RTCIceCandidate {
|
|
6
|
+
#address: string | null;
|
|
7
|
+
#candidate: string;
|
|
8
|
+
#component: globalThis.RTCIceComponent | null;
|
|
9
|
+
#foundation: string | null;
|
|
10
|
+
#port: number | null;
|
|
11
|
+
#priority: number | null;
|
|
12
|
+
#protocol: globalThis.RTCIceProtocol | null;
|
|
13
|
+
#relatedAddress: string | null;
|
|
14
|
+
#relatedPort: number | null;
|
|
15
|
+
#sdpMLineIndex: number | null;
|
|
16
|
+
#sdpMid: string | null;
|
|
17
|
+
#tcpType: globalThis.RTCIceTcpCandidateType | null;
|
|
18
|
+
#type: globalThis.RTCIceCandidateType | null;
|
|
19
|
+
#usernameFragment: string | null;
|
|
20
|
+
|
|
21
|
+
constructor({
|
|
22
|
+
candidate,
|
|
23
|
+
sdpMLineIndex,
|
|
24
|
+
sdpMid,
|
|
25
|
+
usernameFragment,
|
|
26
|
+
}: globalThis.RTCIceCandidateInit) {
|
|
27
|
+
if (sdpMLineIndex == null && sdpMid == null)
|
|
28
|
+
throw new TypeError('At least one of sdpMLineIndex or sdpMid must be specified');
|
|
29
|
+
|
|
30
|
+
this.#candidate = candidate === null ? 'null' : (candidate ?? '');
|
|
31
|
+
this.#sdpMLineIndex = sdpMLineIndex ?? null;
|
|
32
|
+
this.#sdpMid = sdpMid ?? null;
|
|
33
|
+
this.#usernameFragment = usernameFragment ?? null;
|
|
34
|
+
|
|
35
|
+
if (candidate) {
|
|
36
|
+
const fields = candidate.split(' ');
|
|
37
|
+
this.#foundation = fields[0]!.replace('candidate:', ''); // remove text candidate:
|
|
38
|
+
this.#component = fields[1] == '1' ? 'rtp' : 'rtcp';
|
|
39
|
+
this.#protocol = fields[2] as globalThis.RTCIceProtocol;
|
|
40
|
+
this.#priority = parseInt(fields[3], 10);
|
|
41
|
+
this.#address = fields[4];
|
|
42
|
+
this.#port = parseInt(fields[5], 10);
|
|
43
|
+
this.#type = fields[7] as globalThis.RTCIceCandidateType;
|
|
44
|
+
this.#tcpType = null;
|
|
45
|
+
this.#relatedAddress = null;
|
|
46
|
+
this.#relatedPort = null;
|
|
47
|
+
|
|
48
|
+
// Parse the candidate string to extract relatedPort and relatedAddress
|
|
49
|
+
for (let i = 8; i < fields.length; i++) {
|
|
50
|
+
const field = fields[i];
|
|
51
|
+
if (field === 'raddr') {
|
|
52
|
+
this.#relatedAddress = fields[i + 1];
|
|
53
|
+
} else if (field === 'rport') {
|
|
54
|
+
this.#relatedPort = parseInt(fields[i + 1], 10);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (this.#protocol === 'tcp' && field === 'tcptype') {
|
|
58
|
+
this.#tcpType = fields[i + 1] as globalThis.RTCIceTcpCandidateType;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get address(): string | null {
|
|
65
|
+
return this.#address ?? null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
get candidate(): string {
|
|
69
|
+
return this.#candidate;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get component(): globalThis.RTCIceComponent | null {
|
|
73
|
+
return this.#component;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get foundation(): string | null {
|
|
77
|
+
return this.#foundation ?? null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get port(): number | null {
|
|
81
|
+
return this.#port ?? null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
get priority(): number | null {
|
|
85
|
+
return this.#priority ?? null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
get protocol(): globalThis.RTCIceProtocol | null {
|
|
89
|
+
return this.#protocol ?? null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get relatedAddress(): string | null {
|
|
93
|
+
return this.#relatedAddress;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get relatedPort(): number | null {
|
|
97
|
+
return this.#relatedPort ?? null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get sdpMLineIndex(): number | null {
|
|
101
|
+
return this.#sdpMLineIndex;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get sdpMid(): string | null {
|
|
105
|
+
return this.#sdpMid;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get tcpType(): globalThis.RTCIceTcpCandidateType | null {
|
|
109
|
+
return this.#tcpType;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
get type(): globalThis.RTCIceCandidateType | null {
|
|
113
|
+
return this.#type ?? null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
get usernameFragment(): string | null {
|
|
117
|
+
return this.#usernameFragment;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
toJSON(): globalThis.RTCIceCandidateInit {
|
|
121
|
+
return {
|
|
122
|
+
candidate: this.#candidate,
|
|
123
|
+
sdpMLineIndex: this.#sdpMLineIndex,
|
|
124
|
+
sdpMid: this.#sdpMid,
|
|
125
|
+
usernameFragment: this.#usernameFragment,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|