node-datachannel 0.5.5 → 0.7.0
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/.github/workflows/build-linux.yml +2 -2
- package/CMakeLists.txt +6 -10
- package/examples/electron-demo/package-lock.json +6 -6
- package/examples/media/README.md +12 -0
- package/jest.config.cjs +7 -0
- package/lib/index.cjs +142 -0
- package/lib/index.d.ts +66 -2
- package/lib/index.js +4 -0
- package/package.json +15 -6
- package/polyfill/RTCPeerConnection.js +0 -1
- package/polyfill/polyfill.cjs +1069 -0
- package/src/data-channel-wrapper.cpp +15 -1
- package/src/data-channel-wrapper.h +5 -1
- package/src/main.cpp +4 -0
- package/src/media-track-wrapper.cpp +25 -5
- package/src/media-track-wrapper.h +7 -3
- package/src/peer-connection-wrapper.cpp +21 -27
- package/src/peer-connection-wrapper.h +2 -5
- package/src/rtc-wrapper.cpp +9 -2
- package/src/thread-safe-callback.cpp +6 -2
- package/src/thread-safe-callback.h +3 -1
- package/src/web-socket-server-wrapper.cpp +265 -0
- package/src/web-socket-server-wrapper.h +43 -0
- package/src/web-socket-wrapper.cpp +664 -0
- package/src/web-socket-wrapper.h +62 -0
- package/test/jest-tests/basic.test.js +37 -0
- package/test/jest-tests/multiple-run.test.js +73 -0
- package/test/jest-tests/p2p.test.js +99 -0
- package/test/jest-tests/streams.test.js +48 -0
- package/test/jest-tests/websocket.test.js +69 -0
- package/test/websockets.js +48 -0
- package/test/test.js +0 -185
|
@@ -76,8 +76,8 @@ jobs:
|
|
|
76
76
|
sudo apt update
|
|
77
77
|
sudo apt install -y g++-aarch64-linux-gnu gcc-aarch64-linux-gnu
|
|
78
78
|
mkdir sysroot && cd sysroot
|
|
79
|
-
wget https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/
|
|
80
|
-
tar xf
|
|
79
|
+
wget https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/41a6c8dec4c4304d6509e30cbaf9218dffb4438e/debian_bullseye_arm64_sysroot.tar.xz
|
|
80
|
+
tar xf debian_bullseye_arm64_sysroot.tar.xz
|
|
81
81
|
echo "ARM64_SYSROOT=$(pwd)" >> $GITHUB_ENV
|
|
82
82
|
ls -l
|
|
83
83
|
- name: Use Node.js ${{ matrix.node-version }}
|
package/CMakeLists.txt
CHANGED
|
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.15)
|
|
|
2
2
|
cmake_policy(SET CMP0091 NEW)
|
|
3
3
|
cmake_policy(SET CMP0042 NEW)
|
|
4
4
|
|
|
5
|
-
project(node_datachannel VERSION 0.
|
|
5
|
+
project(node_datachannel VERSION 0.7.0)
|
|
6
6
|
|
|
7
7
|
# -Dnapi_build_version=8
|
|
8
8
|
add_definitions(-DNAPI_VERSION=8)
|
|
@@ -20,14 +20,8 @@ if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Android")
|
|
|
20
20
|
set(CMAKE_C_FLAGS "-Wno-error=unused-but-set-variable -Wno-error=strict-prototypes")
|
|
21
21
|
endif()
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
# ../sysroot/usr/lib/aarch64-linux-gnu/libcrypto.a(sha1-armv8.o): in function `sha1_block_armv8':
|
|
26
|
-
# (.text+0x1240): dangerous relocation: unsupported relocation
|
|
27
|
-
if(NOT ${NODE_ARCH} STREQUAL "arm64")
|
|
28
|
-
set(OPENSSL_USE_STATIC_LIBS TRUE)
|
|
29
|
-
find_package(OpenSSL REQUIRED)
|
|
30
|
-
endif()
|
|
23
|
+
set(OPENSSL_USE_STATIC_LIBS TRUE)
|
|
24
|
+
find_package(OpenSSL REQUIRED)
|
|
31
25
|
|
|
32
26
|
include(FetchContent)
|
|
33
27
|
|
|
@@ -39,7 +33,7 @@ FetchContent_Declare(
|
|
|
39
33
|
)
|
|
40
34
|
|
|
41
35
|
option(NO_MEDIA "Disable media transport support in libdatachannel" OFF)
|
|
42
|
-
option(NO_WEBSOCKET "Disable WebSocket support in libdatachannel"
|
|
36
|
+
option(NO_WEBSOCKET "Disable WebSocket support in libdatachannel" OFF)
|
|
43
37
|
|
|
44
38
|
FetchContent_GetProperties(libdatachannel)
|
|
45
39
|
|
|
@@ -58,6 +52,8 @@ add_library(${PROJECT_NAME} SHARED
|
|
|
58
52
|
src/data-channel-wrapper.cpp
|
|
59
53
|
src/peer-connection-wrapper.cpp
|
|
60
54
|
src/thread-safe-callback.cpp
|
|
55
|
+
src/web-socket-wrapper.cpp
|
|
56
|
+
src/web-socket-server-wrapper.cpp
|
|
61
57
|
src/main.cpp
|
|
62
58
|
${CMAKE_JS_SRC}
|
|
63
59
|
)
|
|
@@ -3832,9 +3832,9 @@
|
|
|
3832
3832
|
}
|
|
3833
3833
|
},
|
|
3834
3834
|
"node_modules/follow-redirects": {
|
|
3835
|
-
"version": "1.15.
|
|
3836
|
-
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.
|
|
3837
|
-
"integrity": "sha512-
|
|
3835
|
+
"version": "1.15.6",
|
|
3836
|
+
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
|
|
3837
|
+
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
|
|
3838
3838
|
"dev": true,
|
|
3839
3839
|
"funding": [
|
|
3840
3840
|
{
|
|
@@ -11877,9 +11877,9 @@
|
|
|
11877
11877
|
}
|
|
11878
11878
|
},
|
|
11879
11879
|
"follow-redirects": {
|
|
11880
|
-
"version": "1.15.
|
|
11881
|
-
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.
|
|
11882
|
-
"integrity": "sha512-
|
|
11880
|
+
"version": "1.15.6",
|
|
11881
|
+
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
|
|
11882
|
+
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
|
|
11883
11883
|
"dev": true
|
|
11884
11884
|
},
|
|
11885
11885
|
"foreground-child": {
|
package/examples/media/README.md
CHANGED
|
@@ -20,3 +20,15 @@ Use the following gstreamer demo pipeline to display the traffic
|
|
|
20
20
|
```
|
|
21
21
|
$ gst-launch-1.0 udpsrc address=127.0.0.1 port=5000 caps="application/x-rtp" ! queue ! rtph264depay ! video/x-h264,stream-format=byte-stream ! queue ! avdec_h264 ! queue ! autovideosink
|
|
22
22
|
```
|
|
23
|
+
|
|
24
|
+
For saving the stream to a file, use the following pipeline (mp4):
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
gst-launch-1.0 -e udpsrc address=127.0.0.1 port=5000 caps="application/x-rtp" ! queue ! rtph264depay ! h264parse ! mp4mux ! filesink location=out.mp4
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Requirements
|
|
31
|
+
|
|
32
|
+
- GStreamer 1.0
|
|
33
|
+
- gstreamer1.0-libav (sudo apt-get install gstreamer1.0-libav)
|
|
34
|
+
- h264enc (sudo apt-get install h264enc)
|
package/jest.config.cjs
ADDED
package/lib/index.cjs
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var module$1 = require('module');
|
|
6
|
+
var stream = require('stream');
|
|
7
|
+
|
|
8
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
9
|
+
/**
|
|
10
|
+
* Turns a node-datachannel DataChannel into a real Node.js stream, complete with buffering,
|
|
11
|
+
* backpressure (up to a point - if the buffer fills up, messages are dropped), and
|
|
12
|
+
* support for piping data elsewhere.
|
|
13
|
+
*
|
|
14
|
+
* Read & written data may be either UTF-8 strings or Buffers - this difference exists at
|
|
15
|
+
* the protocol level, and is preserved here throughout.
|
|
16
|
+
*/
|
|
17
|
+
class DataChannelStream extends stream.Duplex {
|
|
18
|
+
constructor(rawChannel, streamOptions) {
|
|
19
|
+
super({
|
|
20
|
+
allowHalfOpen: false, // Default to autoclose on end().
|
|
21
|
+
...streamOptions,
|
|
22
|
+
objectMode: true, // Preserve the string/buffer distinction (WebRTC treats them differently)
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
this._rawChannel = rawChannel;
|
|
26
|
+
this._readActive = true;
|
|
27
|
+
|
|
28
|
+
rawChannel.onMessage((msg) => {
|
|
29
|
+
if (!this._readActive) return; // If the buffer is full, drop messages.
|
|
30
|
+
|
|
31
|
+
// If the push is rejected, we pause reading until the next call to _read().
|
|
32
|
+
this._readActive = this.push(msg);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// When the DataChannel closes, the readable & writable ends close
|
|
36
|
+
rawChannel.onClosed(() => {
|
|
37
|
+
this.push(null);
|
|
38
|
+
this.destroy();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
rawChannel.onError((errMsg) => {
|
|
42
|
+
this.destroy(new Error(`DataChannel error: ${errMsg}`));
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Buffer all writes until the DataChannel opens
|
|
46
|
+
if (!rawChannel.isOpen()) {
|
|
47
|
+
this.cork();
|
|
48
|
+
rawChannel.onOpen(() => this.uncork());
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
_read() {
|
|
53
|
+
// Stop dropping messages, if the buffer filling up meant we were doing so before.
|
|
54
|
+
this._readActive = true;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
_write(chunk, encoding, callback) {
|
|
58
|
+
let sentOk;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
if (Buffer.isBuffer(chunk)) {
|
|
62
|
+
sentOk = this._rawChannel.sendMessageBinary(chunk);
|
|
63
|
+
} else if (typeof chunk === 'string') {
|
|
64
|
+
sentOk = this._rawChannel.sendMessage(chunk);
|
|
65
|
+
} else {
|
|
66
|
+
const typeName = chunk.constructor.name || typeof chunk;
|
|
67
|
+
throw new Error(`Cannot write ${typeName} to DataChannel stream`);
|
|
68
|
+
}
|
|
69
|
+
} catch (err) {
|
|
70
|
+
return callback(err);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (sentOk) {
|
|
74
|
+
callback(null);
|
|
75
|
+
} else {
|
|
76
|
+
callback(new Error('Failed to write to DataChannel'));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_final(callback) {
|
|
81
|
+
if (!this.allowHalfOpen) this.destroy();
|
|
82
|
+
callback(null);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
_destroy(maybeErr, callback) {
|
|
86
|
+
// When the stream is destroyed, we close the DataChannel.
|
|
87
|
+
this._rawChannel.close();
|
|
88
|
+
callback(maybeErr);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get label() {
|
|
92
|
+
return this._rawChannel.getLabel();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get id() {
|
|
96
|
+
return this._rawChannel.getId();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get protocol() {
|
|
100
|
+
return this._rawChannel.getProtocol();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// createRequire is native in node version >= 12
|
|
105
|
+
const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
106
|
+
|
|
107
|
+
const nodeDataChannel = require$1('../build/Release/node_datachannel.node');
|
|
108
|
+
|
|
109
|
+
const {
|
|
110
|
+
initLogger,
|
|
111
|
+
cleanup,
|
|
112
|
+
preload,
|
|
113
|
+
setSctpSettings,
|
|
114
|
+
RtcpReceivingSession,
|
|
115
|
+
Track,
|
|
116
|
+
Video,
|
|
117
|
+
Audio,
|
|
118
|
+
DataChannel,
|
|
119
|
+
PeerConnection,
|
|
120
|
+
WebSocket,
|
|
121
|
+
WebSocketServer,
|
|
122
|
+
} = nodeDataChannel;
|
|
123
|
+
|
|
124
|
+
var index = {
|
|
125
|
+
...nodeDataChannel,
|
|
126
|
+
DataChannelStream,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
exports.Audio = Audio;
|
|
130
|
+
exports.DataChannel = DataChannel;
|
|
131
|
+
exports.DataChannelStream = DataChannelStream;
|
|
132
|
+
exports.PeerConnection = PeerConnection;
|
|
133
|
+
exports.RtcpReceivingSession = RtcpReceivingSession;
|
|
134
|
+
exports.Track = Track;
|
|
135
|
+
exports.Video = Video;
|
|
136
|
+
exports.WebSocket = WebSocket;
|
|
137
|
+
exports.WebSocketServer = WebSocketServer;
|
|
138
|
+
exports.cleanup = cleanup;
|
|
139
|
+
exports.default = index;
|
|
140
|
+
exports.initLogger = initLogger;
|
|
141
|
+
exports.preload = preload;
|
|
142
|
+
exports.setSctpSettings = setSctpSettings;
|
package/lib/index.d.ts
CHANGED
|
@@ -189,11 +189,58 @@ export class Track {
|
|
|
189
189
|
onMessage(cb: (msg: Buffer) => void): void;
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
export
|
|
192
|
+
export interface Channel {
|
|
193
193
|
close(): void;
|
|
194
|
+
sendMessage(msg: string): boolean;
|
|
195
|
+
sendMessageBinary(buffer: Uint8Array): boolean;
|
|
196
|
+
isOpen(): boolean;
|
|
197
|
+
bufferedAmount(): number;
|
|
198
|
+
maxMessageSize(): number;
|
|
199
|
+
setBufferedAmountLowThreshold(newSize: number): void;
|
|
200
|
+
onOpen(cb: () => void): void;
|
|
201
|
+
onClosed(cb: () => void): void;
|
|
202
|
+
onError(cb: (err: string) => void): void;
|
|
203
|
+
onBufferedAmountLow(cb: () => void): void;
|
|
204
|
+
onMessage(cb: (msg: string | Buffer) => void): void;
|
|
205
|
+
}
|
|
206
|
+
export class DataChannel implements Channel {
|
|
194
207
|
getLabel(): string;
|
|
195
208
|
getId(): number;
|
|
196
209
|
getProtocol(): string;
|
|
210
|
+
|
|
211
|
+
// Channel implementation
|
|
212
|
+
close(): void;
|
|
213
|
+
sendMessage(msg: string): boolean;
|
|
214
|
+
sendMessageBinary(buffer: Uint8Array): boolean;
|
|
215
|
+
isOpen(): boolean;
|
|
216
|
+
bufferedAmount(): number;
|
|
217
|
+
maxMessageSize(): number;
|
|
218
|
+
setBufferedAmountLowThreshold(newSize: number): void;
|
|
219
|
+
onOpen(cb: () => void): void;
|
|
220
|
+
onClosed(cb: () => void): void;
|
|
221
|
+
onError(cb: (err: string) => void): void;
|
|
222
|
+
onBufferedAmountLow(cb: () => void): void;
|
|
223
|
+
onMessage(cb: (msg: string | Buffer) => void): void;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export interface WebSocketConfiguration {
|
|
227
|
+
disableTlsVerification?: boolean; // default = false, if true, don't verify the TLS certificate
|
|
228
|
+
proxyServer?: ProxyServer; // only non-authenticated http supported for now
|
|
229
|
+
protocols?: string[];
|
|
230
|
+
connectionTimeout?: number; // miliseconds, zero to disable
|
|
231
|
+
pingInterval?: number; // millisecondrs, zero to disable
|
|
232
|
+
maxOutstandingPings?: number;
|
|
233
|
+
caCertificatePemFile?: string;
|
|
234
|
+
certificatePemFile?: string;
|
|
235
|
+
keyPemFile?: string;
|
|
236
|
+
keyPemPass?: string;
|
|
237
|
+
maxMessageSize: number;
|
|
238
|
+
}
|
|
239
|
+
export class WebSocket implements Channel {
|
|
240
|
+
constructor(config?: WebSocketConfiguration);
|
|
241
|
+
|
|
242
|
+
// Channel implementation
|
|
243
|
+
close(): void;
|
|
197
244
|
sendMessage(msg: string): boolean;
|
|
198
245
|
sendMessageBinary(buffer: Uint8Array): boolean;
|
|
199
246
|
isOpen(): boolean;
|
|
@@ -207,10 +254,27 @@ export class DataChannel {
|
|
|
207
254
|
onMessage(cb: (msg: string | Buffer) => void): void;
|
|
208
255
|
}
|
|
209
256
|
|
|
257
|
+
export interface WebSocketServerConfiguration {
|
|
258
|
+
port?: number; // default 8080
|
|
259
|
+
enableTls?: boolean; // default = false;
|
|
260
|
+
certificatePemFile?: string;
|
|
261
|
+
keyPemFile?: string;
|
|
262
|
+
keyPemPass?: string;
|
|
263
|
+
bindAddress?: string;
|
|
264
|
+
connectionTimeout?: number; // milliseconds
|
|
265
|
+
maxMessageSize?: number;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export class WebSocketServer {
|
|
269
|
+
constructor(config?: WebSocketServerConfiguration);
|
|
270
|
+
port(): number;
|
|
271
|
+
stop(): void;
|
|
272
|
+
onClient(cb: (ws: WebSocket) => void): void;
|
|
273
|
+
}
|
|
274
|
+
|
|
210
275
|
export class PeerConnection {
|
|
211
276
|
constructor(peerName: string, config: RtcConfig);
|
|
212
277
|
close(): void;
|
|
213
|
-
destroy(): void;
|
|
214
278
|
setLocalDescription(type?: DescriptionType): void;
|
|
215
279
|
setRemoteDescription(sdp: string, type: DescriptionType): void;
|
|
216
280
|
localDescription(): { type: string; sdp: string } | null;
|
package/lib/index.js
CHANGED
|
@@ -16,6 +16,8 @@ const {
|
|
|
16
16
|
Audio,
|
|
17
17
|
DataChannel,
|
|
18
18
|
PeerConnection,
|
|
19
|
+
WebSocket,
|
|
20
|
+
WebSocketServer,
|
|
19
21
|
} = nodeDataChannel;
|
|
20
22
|
|
|
21
23
|
export {
|
|
@@ -29,6 +31,8 @@ export {
|
|
|
29
31
|
Audio,
|
|
30
32
|
DataChannel,
|
|
31
33
|
PeerConnection,
|
|
34
|
+
WebSocket,
|
|
35
|
+
WebSocketServer,
|
|
32
36
|
// Extra exports
|
|
33
37
|
DataChannelStream,
|
|
34
38
|
};
|
package/package.json
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-datachannel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "libdatachannel node bindings",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
|
-
".":
|
|
8
|
-
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./lib/index.js",
|
|
9
|
+
"require": "./lib/index.cjs"
|
|
10
|
+
},
|
|
11
|
+
"./polyfill": {
|
|
12
|
+
"import": "./polyfill/index.js",
|
|
13
|
+
"require": "./polyfill/polyfill.cjs"
|
|
14
|
+
}
|
|
9
15
|
},
|
|
10
16
|
"typings": "lib/index.d.ts",
|
|
11
17
|
"engines": {
|
|
@@ -27,7 +33,8 @@
|
|
|
27
33
|
"lint": "eslint lib/**/* test/**/*",
|
|
28
34
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
29
35
|
"wpt-test": "node test/wpt.js",
|
|
30
|
-
"test-types": "tsc"
|
|
36
|
+
"test-types": "tsc",
|
|
37
|
+
"prepublishOnly": "rollup lib/index.js --file lib/index.cjs --format cjs && rollup polyfill/index.js --file polyfill/polyfill.cjs --format cjs"
|
|
31
38
|
},
|
|
32
39
|
"binary": {
|
|
33
40
|
"napi_versions": [
|
|
@@ -44,7 +51,8 @@
|
|
|
44
51
|
"p2p",
|
|
45
52
|
"peer-to-peer",
|
|
46
53
|
"datachannel",
|
|
47
|
-
"data channel"
|
|
54
|
+
"data channel",
|
|
55
|
+
"websocket"
|
|
48
56
|
],
|
|
49
57
|
"contributors": [
|
|
50
58
|
{
|
|
@@ -77,6 +85,7 @@
|
|
|
77
85
|
},
|
|
78
86
|
"dependencies": {
|
|
79
87
|
"node-domexception": "^2.0.1",
|
|
80
|
-
"prebuild-install": "^7.0.1"
|
|
88
|
+
"prebuild-install": "^7.0.1",
|
|
89
|
+
"rollup": "^4.14.1"
|
|
81
90
|
}
|
|
82
91
|
}
|