node-datachannel 0.7.0 → 0.9.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/npm-publish-manual.yml +1 -1
- package/CMakeLists.txt +2 -2
- package/examples/electron-demo/package.json +1 -1
- package/lib/index.d.cts +314 -0
- package/lib/index.d.ts +5 -0
- package/package.json +19 -8
- package/polyfill/{polyfill.cjs → index.cjs} +1 -1
- package/polyfill/index.d.cts +37 -0
- package/src/data-channel-wrapper.cpp +4 -0
- package/src/media-audio-wrapper.cpp +5 -6
- package/src/media-rtcpreceivingsession-wrapper.cpp +3 -4
- package/src/media-track-wrapper.cpp +27 -0
- package/src/media-track-wrapper.h +1 -0
- package/src/media-video-wrapper.cpp +6 -8
- package/src/peer-connection-wrapper.cpp +25 -14
- package/src/thread-safe-callback.cpp +11 -10
- package/src/thread-safe-callback.h +3 -4
- package/src/web-socket-wrapper.cpp +103 -8
- package/src/web-socket-wrapper.h +4 -0
- package/test/websockets.js +4 -2
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.9.0)
|
|
6
6
|
|
|
7
7
|
# -Dnapi_build_version=8
|
|
8
8
|
add_definitions(-DNAPI_VERSION=8)
|
|
@@ -29,7 +29,7 @@ include(FetchContent)
|
|
|
29
29
|
FetchContent_Declare(
|
|
30
30
|
libdatachannel
|
|
31
31
|
GIT_REPOSITORY https://github.com/paullouisageneau/libdatachannel.git
|
|
32
|
-
GIT_TAG "v0.
|
|
32
|
+
GIT_TAG "v0.21.0"
|
|
33
33
|
)
|
|
34
34
|
|
|
35
35
|
option(NO_MEDIA "Disable media transport support in libdatachannel" OFF)
|
package/lib/index.d.cts
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import * as stream from 'stream';
|
|
2
|
+
|
|
3
|
+
export as namespace NodeDataChannel;
|
|
4
|
+
|
|
5
|
+
// Enum in d.ts is tricky
|
|
6
|
+
export type LogLevel = 'Verbose' | 'Debug' | 'Info' | 'Warning' | 'Error' | 'Fatal';
|
|
7
|
+
|
|
8
|
+
// SCTP Settings
|
|
9
|
+
export interface SctpSettings {
|
|
10
|
+
recvBufferSize?: number;
|
|
11
|
+
sendBufferSize?: number;
|
|
12
|
+
maxChunksOnQueue?: number;
|
|
13
|
+
initialCongestionWindow?: number;
|
|
14
|
+
congestionControlModule?: number;
|
|
15
|
+
delayedSackTime?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Functions
|
|
19
|
+
export function preload(): void;
|
|
20
|
+
export function initLogger(level: LogLevel, callback?: (level: LogLevel, message: string) => void): void;
|
|
21
|
+
export function cleanup(): void;
|
|
22
|
+
export function setSctpSettings(settings: SctpSettings): void;
|
|
23
|
+
|
|
24
|
+
// Proxy Server
|
|
25
|
+
export type ProxyServerType = 'Socks5' | 'Http';
|
|
26
|
+
export interface ProxyServer {
|
|
27
|
+
type: ProxyServerType;
|
|
28
|
+
ip: string;
|
|
29
|
+
port: number;
|
|
30
|
+
username?: string;
|
|
31
|
+
password?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const enum RelayType {
|
|
35
|
+
TurnUdp = 'TurnUdp',
|
|
36
|
+
TurnTcp = 'TurnTcp',
|
|
37
|
+
TurnTls = 'TurnTls',
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface IceServer {
|
|
41
|
+
hostname: string;
|
|
42
|
+
port: number;
|
|
43
|
+
username?: string;
|
|
44
|
+
password?: string;
|
|
45
|
+
relayType?: RelayType;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export type TransportPolicy = 'all' | 'relay';
|
|
49
|
+
|
|
50
|
+
export interface RtcConfig {
|
|
51
|
+
iceServers: (string | IceServer)[];
|
|
52
|
+
proxyServer?: ProxyServer;
|
|
53
|
+
bindAddress?: string;
|
|
54
|
+
enableIceTcp?: boolean;
|
|
55
|
+
enableIceUdpMux?: boolean;
|
|
56
|
+
disableAutoNegotiation?: boolean;
|
|
57
|
+
forceMediaTransport?: boolean;
|
|
58
|
+
portRangeBegin?: number;
|
|
59
|
+
portRangeEnd?: number;
|
|
60
|
+
maxMessageSize?: number;
|
|
61
|
+
mtu?: number;
|
|
62
|
+
iceTransportPolicy?: TransportPolicy;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Lowercase to match the description type string from libdatachannel
|
|
66
|
+
export const enum DescriptionType {
|
|
67
|
+
Unspec = 'unspec',
|
|
68
|
+
Offer = 'offer',
|
|
69
|
+
Answer = 'answer',
|
|
70
|
+
Pranswer = 'pranswer',
|
|
71
|
+
Rollback = 'rollback',
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const enum ReliabilityType {
|
|
75
|
+
Reliable = 0,
|
|
76
|
+
Rexmit = 1,
|
|
77
|
+
Timed = 2,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface DataChannelInitConfig {
|
|
81
|
+
protocol?: string;
|
|
82
|
+
negotiated?: boolean;
|
|
83
|
+
id?: number;
|
|
84
|
+
ordered?: boolean;
|
|
85
|
+
maxPacketLifeTime?: number;
|
|
86
|
+
maxRetransmits?: number;
|
|
87
|
+
|
|
88
|
+
// Deprecated, use ordered, maxPacketLifeTime, and maxRetransmits
|
|
89
|
+
reliability?: {
|
|
90
|
+
type?: ReliabilityType;
|
|
91
|
+
unordered?: boolean;
|
|
92
|
+
rexmit?: number;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface SelectedCandidateInfo {
|
|
97
|
+
address: string;
|
|
98
|
+
port: number;
|
|
99
|
+
type: string;
|
|
100
|
+
transportType: string;
|
|
101
|
+
candidate: string;
|
|
102
|
+
mid: string;
|
|
103
|
+
priority: number;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Must be same as rtc enum class Direction
|
|
107
|
+
export const enum Direction {
|
|
108
|
+
SendOnly = 'SendOnly',
|
|
109
|
+
RecvOnly = 'RecvOnly',
|
|
110
|
+
SendRecv = 'SendRecv',
|
|
111
|
+
Inactive = 'Inactive',
|
|
112
|
+
Unknown = 'Unknown',
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export class RtcpReceivingSession {
|
|
116
|
+
requestBitrate(bitRate: number): void;
|
|
117
|
+
requestKeyframe(): boolean;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export class Audio {
|
|
121
|
+
constructor(mid: string, dir: Direction);
|
|
122
|
+
addAudioCodec(payloadType: number, codec: string, profile?: string): void;
|
|
123
|
+
addOpusCodec(payloadType: number, profile?: string): string;
|
|
124
|
+
|
|
125
|
+
direction(): Direction;
|
|
126
|
+
generateSdp(eol: string, addr: string, port: number): string;
|
|
127
|
+
mid(): string;
|
|
128
|
+
setDirection(dir: Direction): void;
|
|
129
|
+
description(): string;
|
|
130
|
+
removeFormat(fmt: string): void;
|
|
131
|
+
addSSRC(ssrc: number, name?: string, msid?: string, trackID?: string): void;
|
|
132
|
+
removeSSRC(ssrc: number): void;
|
|
133
|
+
replaceSSRC(oldSsrc: number, ssrc: number, name?: string, msid?: string, trackID?: string): void;
|
|
134
|
+
hasSSRC(ssrc: number): boolean;
|
|
135
|
+
getSSRCs(): number[];
|
|
136
|
+
getCNameForSsrc(ssrc: number): string;
|
|
137
|
+
setBitrate(bitRate: number): void;
|
|
138
|
+
getBitrate(): number;
|
|
139
|
+
hasPayloadType(payloadType: number): boolean;
|
|
140
|
+
addRTXCodec(payloadType: number, originalPayloadType: number, clockRate: number): void;
|
|
141
|
+
addRTPMap(): void;
|
|
142
|
+
parseSdpLine(line: string): void;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export class Video {
|
|
146
|
+
constructor(mid: string, dir: Direction);
|
|
147
|
+
addVideoCodec(payloadType: number, codec: string, profile?: string): void;
|
|
148
|
+
addH264Codec(payloadType: number, profile?: string): void;
|
|
149
|
+
addVP8Codec(payloadType: number): void;
|
|
150
|
+
addVP9Codec(payloadType: number): void;
|
|
151
|
+
|
|
152
|
+
direction(): Direction;
|
|
153
|
+
generateSdp(eol: string, addr: string, port: number): string;
|
|
154
|
+
mid(): string;
|
|
155
|
+
setDirection(dir: Direction): void;
|
|
156
|
+
description(): string;
|
|
157
|
+
removeFormat(fmt: string): void;
|
|
158
|
+
addSSRC(ssrc: number, name?: string, msid?: string, trackID?: string): void;
|
|
159
|
+
removeSSRC(ssrc: number): void;
|
|
160
|
+
replaceSSRC(oldSsrc: number, ssrc: number, name?: string, msid?: string, trackID?: string): void;
|
|
161
|
+
hasSSRC(ssrc: number): boolean;
|
|
162
|
+
getSSRCs(): number[];
|
|
163
|
+
getCNameForSsrc(ssrc: number): string;
|
|
164
|
+
setBitrate(bitRate: number): void;
|
|
165
|
+
getBitrate(): number;
|
|
166
|
+
hasPayloadType(payloadType: number): boolean;
|
|
167
|
+
addRTXCodec(payloadType: number, originalPayloadType: number, clockRate: number): void;
|
|
168
|
+
addRTPMap(): void;
|
|
169
|
+
parseSdpLine(line: string): void;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export class Track {
|
|
173
|
+
direction(): Direction;
|
|
174
|
+
mid(): string;
|
|
175
|
+
type(): string;
|
|
176
|
+
close(): void;
|
|
177
|
+
sendMessage(msg: string): boolean;
|
|
178
|
+
sendMessageBinary(buffer: Buffer): boolean;
|
|
179
|
+
isOpen(): boolean;
|
|
180
|
+
isClosed(): boolean;
|
|
181
|
+
bufferedAmount(): number;
|
|
182
|
+
maxMessageSize(): number;
|
|
183
|
+
requestBitrate(bitRate: number): boolean;
|
|
184
|
+
setBufferedAmountLowThreshold(newSize: number): void;
|
|
185
|
+
requestKeyframe(): boolean;
|
|
186
|
+
setMediaHandler(handler: RtcpReceivingSession): void;
|
|
187
|
+
onOpen(cb: () => void): void;
|
|
188
|
+
onClosed(cb: () => void): void;
|
|
189
|
+
onError(cb: (err: string) => void): void;
|
|
190
|
+
onMessage(cb: (msg: Buffer) => void): void;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface Channel {
|
|
194
|
+
close(): void;
|
|
195
|
+
sendMessage(msg: string): boolean;
|
|
196
|
+
sendMessageBinary(buffer: Uint8Array): boolean;
|
|
197
|
+
isOpen(): boolean;
|
|
198
|
+
bufferedAmount(): number;
|
|
199
|
+
maxMessageSize(): number;
|
|
200
|
+
setBufferedAmountLowThreshold(newSize: number): void;
|
|
201
|
+
onOpen(cb: () => void): void;
|
|
202
|
+
onClosed(cb: () => void): void;
|
|
203
|
+
onError(cb: (err: string) => void): void;
|
|
204
|
+
onBufferedAmountLow(cb: () => void): void;
|
|
205
|
+
onMessage(cb: (msg: string | Buffer) => void): void;
|
|
206
|
+
}
|
|
207
|
+
export class DataChannel implements Channel {
|
|
208
|
+
getLabel(): string;
|
|
209
|
+
getId(): number;
|
|
210
|
+
getProtocol(): string;
|
|
211
|
+
|
|
212
|
+
// Channel implementation
|
|
213
|
+
close(): void;
|
|
214
|
+
sendMessage(msg: string): boolean;
|
|
215
|
+
sendMessageBinary(buffer: Uint8Array): boolean;
|
|
216
|
+
isOpen(): boolean;
|
|
217
|
+
bufferedAmount(): number;
|
|
218
|
+
maxMessageSize(): number;
|
|
219
|
+
setBufferedAmountLowThreshold(newSize: number): void;
|
|
220
|
+
onOpen(cb: () => void): void;
|
|
221
|
+
onClosed(cb: () => void): void;
|
|
222
|
+
onError(cb: (err: string) => void): void;
|
|
223
|
+
onBufferedAmountLow(cb: () => void): void;
|
|
224
|
+
onMessage(cb: (msg: string | Buffer) => void): void;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export interface WebSocketConfiguration {
|
|
228
|
+
disableTlsVerification?: boolean; // default = false, if true, don't verify the TLS certificate
|
|
229
|
+
proxyServer?: ProxyServer; // only non-authenticated http supported for now
|
|
230
|
+
protocols?: string[];
|
|
231
|
+
connectionTimeout?: number; // miliseconds, zero to disable
|
|
232
|
+
pingInterval?: number; // millisecondrs, zero to disable
|
|
233
|
+
maxOutstandingPings?: number;
|
|
234
|
+
caCertificatePemFile?: string;
|
|
235
|
+
certificatePemFile?: string;
|
|
236
|
+
keyPemFile?: string;
|
|
237
|
+
keyPemPass?: string;
|
|
238
|
+
maxMessageSize: number;
|
|
239
|
+
}
|
|
240
|
+
export class WebSocket implements Channel {
|
|
241
|
+
constructor(config?: WebSocketConfiguration);
|
|
242
|
+
open(url: string): void;
|
|
243
|
+
forceClose(): void;
|
|
244
|
+
remoteAddress(): string | undefined;
|
|
245
|
+
path(): string | undefined;
|
|
246
|
+
|
|
247
|
+
// Channel implementation
|
|
248
|
+
close(): void;
|
|
249
|
+
sendMessage(msg: string): boolean;
|
|
250
|
+
sendMessageBinary(buffer: Uint8Array): boolean;
|
|
251
|
+
isOpen(): boolean;
|
|
252
|
+
bufferedAmount(): number;
|
|
253
|
+
maxMessageSize(): number;
|
|
254
|
+
setBufferedAmountLowThreshold(newSize: number): void;
|
|
255
|
+
onOpen(cb: () => void): void;
|
|
256
|
+
onClosed(cb: () => void): void;
|
|
257
|
+
onError(cb: (err: string) => void): void;
|
|
258
|
+
onBufferedAmountLow(cb: () => void): void;
|
|
259
|
+
onMessage(cb: (msg: string | Buffer) => void): void;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export interface WebSocketServerConfiguration {
|
|
263
|
+
port?: number; // default 8080
|
|
264
|
+
enableTls?: boolean; // default = false;
|
|
265
|
+
certificatePemFile?: string;
|
|
266
|
+
keyPemFile?: string;
|
|
267
|
+
keyPemPass?: string;
|
|
268
|
+
bindAddress?: string;
|
|
269
|
+
connectionTimeout?: number; // milliseconds
|
|
270
|
+
maxMessageSize?: number;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export class WebSocketServer {
|
|
274
|
+
constructor(config?: WebSocketServerConfiguration);
|
|
275
|
+
port(): number;
|
|
276
|
+
stop(): void;
|
|
277
|
+
onClient(cb: (ws: WebSocket) => void): void;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export class PeerConnection {
|
|
281
|
+
constructor(peerName: string, config: RtcConfig);
|
|
282
|
+
close(): void;
|
|
283
|
+
setLocalDescription(type?: DescriptionType): void;
|
|
284
|
+
setRemoteDescription(sdp: string, type: DescriptionType): void;
|
|
285
|
+
localDescription(): { type: string; sdp: string } | null;
|
|
286
|
+
remoteDescription(): { type: string; sdp: string } | null;
|
|
287
|
+
addRemoteCandidate(candidate: string, mid: string): void;
|
|
288
|
+
createDataChannel(label: string, config?: DataChannelInitConfig): DataChannel;
|
|
289
|
+
addTrack(media: Video | Audio): Track;
|
|
290
|
+
hasMedia(): boolean;
|
|
291
|
+
state(): RTCPeerConnectionState;
|
|
292
|
+
iceState(): RTCIceConnectionState;
|
|
293
|
+
signalingState(): RTCSignalingState;
|
|
294
|
+
gatheringState(): RTCIceGatheringState;
|
|
295
|
+
onLocalDescription(cb: (sdp: string, type: DescriptionType) => void): void;
|
|
296
|
+
onLocalCandidate(cb: (candidate: string, mid: string) => void): void;
|
|
297
|
+
onStateChange(cb: (state: string) => void): void;
|
|
298
|
+
onIceStateChange(cb: (state: string) => void): void;
|
|
299
|
+
onSignalingStateChange(cb: (state: string) => void): void;
|
|
300
|
+
onGatheringStateChange(cb: (state: string) => void): void;
|
|
301
|
+
onDataChannel(cb: (dc: DataChannel) => void): void;
|
|
302
|
+
onTrack(cb: (track: Track) => void): void;
|
|
303
|
+
bytesSent(): number;
|
|
304
|
+
bytesReceived(): number;
|
|
305
|
+
rtt(): number;
|
|
306
|
+
getSelectedCandidatePair(): { local: SelectedCandidateInfo; remote: SelectedCandidateInfo } | null;
|
|
307
|
+
maxDataChannelId(): number;
|
|
308
|
+
maxMessageSize(): number;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export class DataChannelStream extends stream.Duplex {
|
|
312
|
+
constructor(rawChannel: DataChannel, options?: Omit<stream.DuplexOptions, 'objectMode'>);
|
|
313
|
+
get label(): string;
|
|
314
|
+
}
|
package/lib/index.d.ts
CHANGED
|
@@ -180,6 +180,7 @@ export class Track {
|
|
|
180
180
|
isClosed(): boolean;
|
|
181
181
|
bufferedAmount(): number;
|
|
182
182
|
maxMessageSize(): number;
|
|
183
|
+
requestBitrate(bitRate: number): boolean;
|
|
183
184
|
setBufferedAmountLowThreshold(newSize: number): void;
|
|
184
185
|
requestKeyframe(): boolean;
|
|
185
186
|
setMediaHandler(handler: RtcpReceivingSession): void;
|
|
@@ -238,6 +239,10 @@ export interface WebSocketConfiguration {
|
|
|
238
239
|
}
|
|
239
240
|
export class WebSocket implements Channel {
|
|
240
241
|
constructor(config?: WebSocketConfiguration);
|
|
242
|
+
open(url: string): void;
|
|
243
|
+
forceClose(): void;
|
|
244
|
+
remoteAddress(): string | undefined;
|
|
245
|
+
path(): string | undefined;
|
|
241
246
|
|
|
242
247
|
// Channel implementation
|
|
243
248
|
close(): void;
|
package/package.json
CHANGED
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-datachannel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "libdatachannel node bindings",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
7
7
|
".": {
|
|
8
|
-
"import":
|
|
9
|
-
|
|
8
|
+
"import": {
|
|
9
|
+
"default": "./lib/index.js",
|
|
10
|
+
"types": "./lib/index.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"require": {
|
|
13
|
+
"default": "./lib/index.cjs",
|
|
14
|
+
"types": "./lib/index.d.cts"
|
|
15
|
+
}
|
|
10
16
|
},
|
|
11
17
|
"./polyfill": {
|
|
12
|
-
"import":
|
|
13
|
-
|
|
18
|
+
"import": {
|
|
19
|
+
"default": "./polyfill/index.js",
|
|
20
|
+
"types": "./polyfill/index.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"require": {
|
|
23
|
+
"default": "./polyfill/index.cjs",
|
|
24
|
+
"types": "./polyfill/index.d.cts"
|
|
25
|
+
}
|
|
14
26
|
}
|
|
15
27
|
},
|
|
16
|
-
"typings": "lib/index.d.ts",
|
|
17
28
|
"engines": {
|
|
18
29
|
"node": ">=16.0.0"
|
|
19
30
|
},
|
|
@@ -34,7 +45,7 @@
|
|
|
34
45
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
35
46
|
"wpt-test": "node test/wpt.js",
|
|
36
47
|
"test-types": "tsc",
|
|
37
|
-
"prepublishOnly": "rollup lib/index.js --file lib/index.cjs --format cjs && rollup polyfill/index.js --file polyfill/
|
|
48
|
+
"prepublishOnly": "cp lib/index.d.ts lib/index.d.cts && cp polyfill/index.d.ts polyfill/index.d.cts && rollup lib/index.js --file lib/index.cjs --format cjs && rollup polyfill/index.js --file polyfill/index.cjs --format cjs"
|
|
38
49
|
},
|
|
39
50
|
"binary": {
|
|
40
51
|
"napi_versions": [
|
|
@@ -88,4 +99,4 @@
|
|
|
88
99
|
"prebuild-install": "^7.0.1",
|
|
89
100
|
"rollup": "^4.14.1"
|
|
90
101
|
}
|
|
91
|
-
}
|
|
102
|
+
}
|
|
@@ -547,7 +547,7 @@ class DataChannelStream extends stream.Duplex {
|
|
|
547
547
|
}
|
|
548
548
|
|
|
549
549
|
// createRequire is native in node version >= 12
|
|
550
|
-
const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('
|
|
550
|
+
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)));
|
|
551
551
|
|
|
552
552
|
const nodeDataChannel = require$1('../build/Release/node_datachannel.node');
|
|
553
553
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import RTCCertificate from './RTCCertificate.js';
|
|
2
|
+
import RTCDataChannel from './RTCDataChannel.js';
|
|
3
|
+
import RTCDtlsTransport from './RTCDtlsTransport.js';
|
|
4
|
+
import RTCIceCandidate from './RTCIceCandidate.js';
|
|
5
|
+
import RTCIceTransport from './RTCIceTransport.js';
|
|
6
|
+
import RTCPeerConnection from './RTCPeerConnection.js';
|
|
7
|
+
import RTCSctpTransport from './RTCSctpTransport.js';
|
|
8
|
+
import RTCSessionDescription from './RTCSessionDescription.js';
|
|
9
|
+
import { RTCDataChannelEvent, RTCPeerConnectionIceEvent } from './Events.js';
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
RTCCertificate,
|
|
13
|
+
RTCDataChannel,
|
|
14
|
+
RTCDtlsTransport,
|
|
15
|
+
RTCIceCandidate,
|
|
16
|
+
RTCIceTransport,
|
|
17
|
+
RTCPeerConnection,
|
|
18
|
+
RTCSctpTransport,
|
|
19
|
+
RTCSessionDescription,
|
|
20
|
+
RTCDataChannelEvent,
|
|
21
|
+
RTCPeerConnectionIceEvent,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
declare const _default: {
|
|
25
|
+
RTCCertificate: typeof RTCCertificate;
|
|
26
|
+
RTCDataChannel: typeof RTCDataChannel;
|
|
27
|
+
RTCDtlsTransport: typeof RTCDtlsTransport;
|
|
28
|
+
RTCIceCandidate: typeof RTCIceCandidate;
|
|
29
|
+
RTCIceTransport: typeof RTCIceTransport;
|
|
30
|
+
RTCPeerConnection: typeof RTCPeerConnection;
|
|
31
|
+
RTCSctpTransport: typeof RTCSctpTransport;
|
|
32
|
+
RTCSessionDescription: typeof RTCSessionDescription;
|
|
33
|
+
RTCDataChannelEvent: typeof RTCDataChannelEvent;
|
|
34
|
+
RTCPeerConnectionIceEvent: typeof RTCPeerConnectionIceEvent;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default _default;
|
|
@@ -58,6 +58,10 @@ DataChannelWrapper::DataChannelWrapper(const Napi::CallbackInfo &info) : Napi::O
|
|
|
58
58
|
PLOG_DEBUG << "Constructor called";
|
|
59
59
|
mDataChannelPtr = *(info[0].As<Napi::External<std::shared_ptr<rtc::DataChannel>>>().Data());
|
|
60
60
|
PLOG_DEBUG << "Data Channel created";
|
|
61
|
+
|
|
62
|
+
// Closed callback must be set to trigger cleanup
|
|
63
|
+
mOnClosedCallback = std::make_unique<ThreadSafeCallback>(Napi::Function::New(info.Env(), [](const Napi::CallbackInfo&){}));
|
|
64
|
+
|
|
61
65
|
instances.insert(this);
|
|
62
66
|
}
|
|
63
67
|
|
|
@@ -390,9 +390,8 @@ void AudioWrapper::setBitrate(const Napi::CallbackInfo &info)
|
|
|
390
390
|
return;
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
-
int
|
|
394
|
-
|
|
395
|
-
mAudioPtr->setBitrate(bitRate);
|
|
393
|
+
unsigned int bitrate = static_cast<uint32_t>(info[0].As<Napi::Number>().ToNumber());
|
|
394
|
+
mAudioPtr->setBitrate(bitrate);
|
|
396
395
|
}
|
|
397
396
|
|
|
398
397
|
Napi::Value AudioWrapper::getBitrate(const Napi::CallbackInfo &info)
|
|
@@ -428,9 +427,9 @@ void AudioWrapper::addRTXCodec(const Napi::CallbackInfo &info)
|
|
|
428
427
|
return;
|
|
429
428
|
}
|
|
430
429
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
unsigned int clockRate = static_cast<
|
|
430
|
+
int payloadType = static_cast<int32_t>(info[0].As<Napi::Number>().ToNumber());
|
|
431
|
+
int originalPayloadType = static_cast<int32_t>(info[1].As<Napi::Number>().ToNumber());
|
|
432
|
+
unsigned int clockRate = static_cast<uint32_t>(info[2].As<Napi::Number>().ToNumber());
|
|
434
433
|
|
|
435
434
|
mAudioPtr->addRtxCodec(payloadType, originalPayloadType, clockRate);
|
|
436
435
|
}
|
|
@@ -51,13 +51,12 @@ void RtcpReceivingSessionWrapper::requestBitrate(const Napi::CallbackInfo &info)
|
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
unsigned int
|
|
55
|
-
|
|
56
|
-
mSessionPtr->requestBitrate(bitRate);
|
|
54
|
+
unsigned int bitrate = static_cast<uint32_t>(info[0].As<Napi::Number>().ToNumber());
|
|
55
|
+
mSessionPtr->requestBitrate(bitrate);
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
Napi::Value RtcpReceivingSessionWrapper::requestKeyframe(const Napi::CallbackInfo &info)
|
|
60
59
|
{
|
|
61
60
|
Napi::Env env = info.Env();
|
|
62
61
|
return Napi::Boolean::New(env, mSessionPtr->requestKeyframe());
|
|
63
|
-
}
|
|
62
|
+
}
|
|
@@ -39,6 +39,7 @@ Napi::Object TrackWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
|
39
39
|
InstanceMethod("isOpen", &TrackWrapper::isOpen),
|
|
40
40
|
InstanceMethod("isClosed", &TrackWrapper::isClosed),
|
|
41
41
|
InstanceMethod("maxMessageSize", &TrackWrapper::maxMessageSize),
|
|
42
|
+
InstanceMethod("requestBitrate", &TrackWrapper::requestBitrate),
|
|
42
43
|
InstanceMethod("requestKeyframe", &TrackWrapper::requestKeyframe),
|
|
43
44
|
InstanceMethod("setMediaHandler", &TrackWrapper::setMediaHandler),
|
|
44
45
|
InstanceMethod("onOpen", &TrackWrapper::onOpen),
|
|
@@ -56,7 +57,12 @@ Napi::Object TrackWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
|
56
57
|
|
|
57
58
|
TrackWrapper::TrackWrapper(const Napi::CallbackInfo &info) : Napi::ObjectWrap<TrackWrapper>(info)
|
|
58
59
|
{
|
|
60
|
+
PLOG_DEBUG << "Constructor called";
|
|
59
61
|
mTrackPtr = *(info[0].As<Napi::External<std::shared_ptr<rtc::Track>>>().Data());
|
|
62
|
+
PLOG_DEBUG << "Track created";
|
|
63
|
+
|
|
64
|
+
// Closed callback must be set to trigger cleanup
|
|
65
|
+
mOnClosedCallback = std::make_unique<ThreadSafeCallback>(Napi::Function::New(info.Env(), [](const Napi::CallbackInfo&){}));
|
|
60
66
|
|
|
61
67
|
instances.insert(this);
|
|
62
68
|
}
|
|
@@ -237,6 +243,27 @@ Napi::Value TrackWrapper::maxMessageSize(const Napi::CallbackInfo &info)
|
|
|
237
243
|
}
|
|
238
244
|
}
|
|
239
245
|
|
|
246
|
+
Napi::Value TrackWrapper::requestBitrate(const Napi::CallbackInfo &info)
|
|
247
|
+
{
|
|
248
|
+
if (!mTrackPtr)
|
|
249
|
+
{
|
|
250
|
+
Napi::Error::New(info.Env(), "requestBitrate() called on destroyed track").ThrowAsJavaScriptException();
|
|
251
|
+
return info.Env().Null();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
Napi::Env env = info.Env();
|
|
255
|
+
int length = info.Length();
|
|
256
|
+
|
|
257
|
+
if (length < 1 || !info[0].IsNumber())
|
|
258
|
+
{
|
|
259
|
+
Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException();
|
|
260
|
+
return info.Env().Null();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
unsigned int bitrate = static_cast<uint32_t>(info[0].As<Napi::Number>());
|
|
264
|
+
return Napi::Boolean::New(env, mTrackPtr->requestBitrate(bitrate));
|
|
265
|
+
}
|
|
266
|
+
|
|
240
267
|
Napi::Value TrackWrapper::requestKeyframe(const Napi::CallbackInfo &info)
|
|
241
268
|
{
|
|
242
269
|
if (!mTrackPtr)
|
|
@@ -30,6 +30,7 @@ public:
|
|
|
30
30
|
Napi::Value isOpen(const Napi::CallbackInfo &info);
|
|
31
31
|
Napi::Value isClosed(const Napi::CallbackInfo &info);
|
|
32
32
|
Napi::Value maxMessageSize(const Napi::CallbackInfo &info);
|
|
33
|
+
Napi::Value requestBitrate(const Napi::CallbackInfo &info);
|
|
33
34
|
Napi::Value requestKeyframe(const Napi::CallbackInfo &info);
|
|
34
35
|
void setMediaHandler(const Napi::CallbackInfo &info);
|
|
35
36
|
|
|
@@ -423,14 +423,12 @@ void VideoWrapper::setBitrate(const Napi::CallbackInfo &info)
|
|
|
423
423
|
return;
|
|
424
424
|
}
|
|
425
425
|
|
|
426
|
-
int
|
|
427
|
-
|
|
428
|
-
mVideoPtr->setBitrate(bitRate);
|
|
426
|
+
unsigned int bitrate = info[0].As<Napi::Number>().ToNumber().Uint32Value();
|
|
427
|
+
mVideoPtr->setBitrate(bitrate);
|
|
429
428
|
}
|
|
430
429
|
|
|
431
430
|
Napi::Value VideoWrapper::getBitrate(const Napi::CallbackInfo &info)
|
|
432
431
|
{
|
|
433
|
-
|
|
434
432
|
return Napi::Number::New(info.Env(), mVideoPtr->bitrate());
|
|
435
433
|
}
|
|
436
434
|
|
|
@@ -445,7 +443,7 @@ Napi::Value VideoWrapper::hasPayloadType(const Napi::CallbackInfo &info)
|
|
|
445
443
|
return env.Null();
|
|
446
444
|
}
|
|
447
445
|
|
|
448
|
-
int payloadType = static_cast<
|
|
446
|
+
int payloadType = static_cast<int32_t>(info[0].As<Napi::Number>().ToNumber());
|
|
449
447
|
|
|
450
448
|
return Napi::Boolean::New(env, mVideoPtr->hasPayloadType(payloadType));
|
|
451
449
|
}
|
|
@@ -461,9 +459,9 @@ void VideoWrapper::addRTXCodec(const Napi::CallbackInfo &info)
|
|
|
461
459
|
return;
|
|
462
460
|
}
|
|
463
461
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
unsigned int clockRate = static_cast<
|
|
462
|
+
int payloadType = static_cast<int32_t>(info[0].As<Napi::Number>().ToNumber());
|
|
463
|
+
int originalPayloadType = static_cast<int32_t>(info[1].As<Napi::Number>().ToNumber());
|
|
464
|
+
unsigned int clockRate = static_cast<uint32_t>(info[2].As<Napi::Number>().ToNumber());
|
|
467
465
|
|
|
468
466
|
mVideoPtr->addRtxCodec(payloadType, originalPayloadType, clockRate);
|
|
469
467
|
}
|
|
@@ -237,7 +237,7 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
|
|
|
237
237
|
// Create peer-connection
|
|
238
238
|
try
|
|
239
239
|
{
|
|
240
|
-
PLOG_DEBUG << "Creating a new
|
|
240
|
+
PLOG_DEBUG << "Creating a new Peer Connection";
|
|
241
241
|
mRtcPeerConnPtr = std::make_unique<rtc::PeerConnection>(rtcConfig);
|
|
242
242
|
}
|
|
243
243
|
catch (std::exception &ex)
|
|
@@ -246,6 +246,11 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
|
|
|
246
246
|
return;
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
+
PLOG_DEBUG << "Peer Connection created";
|
|
250
|
+
|
|
251
|
+
// State change callback must be set to trigger cleanup on close
|
|
252
|
+
mOnStateChangeCallback = std::make_unique<ThreadSafeCallback>(Napi::Function::New(info.Env(), [](const Napi::CallbackInfo&){}));
|
|
253
|
+
|
|
249
254
|
instances.insert(this);
|
|
250
255
|
}
|
|
251
256
|
|
|
@@ -552,10 +557,10 @@ Napi::Value PeerConnectionWrapper::createDataChannel(const Napi::CallbackInfo &i
|
|
|
552
557
|
switch (reliability.Get("type").As<Napi::Number>().Uint32Value())
|
|
553
558
|
{
|
|
554
559
|
case 1:
|
|
555
|
-
init.reliability.rexmit =
|
|
560
|
+
init.reliability.rexmit = int(reliability.Get("rexmit").As<Napi::Number>().ToNumber().Uint32Value());
|
|
556
561
|
break;
|
|
557
562
|
case 2:
|
|
558
|
-
init.reliability.rexmit = std::chrono::milliseconds(reliability.Get("rexmit").As<Napi::Number>().
|
|
563
|
+
init.reliability.rexmit = std::chrono::milliseconds(reliability.Get("rexmit").As<Napi::Number>().Int32Value());
|
|
559
564
|
break;
|
|
560
565
|
}
|
|
561
566
|
}
|
|
@@ -572,25 +577,31 @@ Napi::Value PeerConnectionWrapper::createDataChannel(const Napi::CallbackInfo &i
|
|
|
572
577
|
init.reliability.unordered = !initConfig.Get("ordered").As<Napi::Boolean>();
|
|
573
578
|
}
|
|
574
579
|
|
|
575
|
-
|
|
580
|
+
|
|
581
|
+
if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull() &&
|
|
582
|
+
!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
|
|
576
583
|
{
|
|
577
584
|
Napi::TypeError::New(env, "Wrong DataChannel Init Config, maxPacketLifeTime and maxRetransmits are exclusive").ThrowAsJavaScriptException();
|
|
578
585
|
return info.Env().Null();
|
|
579
586
|
}
|
|
580
587
|
|
|
581
|
-
if (initConfig.Get("maxPacketLifeTime").
|
|
588
|
+
if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull())
|
|
582
589
|
{
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
init.reliability.
|
|
589
|
-
init.reliability.rexmit = int(initConfig.Get("maxRetransmits").As<Napi::Number>().Uint32Value());
|
|
590
|
+
if (!initConfig.Get("maxPacketLifeTime").IsNumber())
|
|
591
|
+
{
|
|
592
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config (maxPacketLifeTime)").ThrowAsJavaScriptException();
|
|
593
|
+
return info.Env().Null();
|
|
594
|
+
}
|
|
595
|
+
init.reliability.maxPacketLifeTime = std::chrono::milliseconds(initConfig.Get("maxPacketLifeTime").As<Napi::Number>().Uint32Value());
|
|
590
596
|
}
|
|
591
|
-
else
|
|
597
|
+
else if (!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
|
|
592
598
|
{
|
|
593
|
-
|
|
599
|
+
if (!initConfig.Get("maxRetransmits").IsNumber())
|
|
600
|
+
{
|
|
601
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config (maxRetransmits)").ThrowAsJavaScriptException();
|
|
602
|
+
return info.Env().Null();
|
|
603
|
+
}
|
|
604
|
+
init.reliability.maxRetransmits = int(initConfig.Get("maxRetransmits").As<Napi::Number>().Int32Value());
|
|
594
605
|
}
|
|
595
606
|
}
|
|
596
607
|
|
|
@@ -9,16 +9,16 @@ const char *ThreadSafeCallback::CancelException::what() const throw()
|
|
|
9
9
|
|
|
10
10
|
ThreadSafeCallback::ThreadSafeCallback(Napi::Function callback)
|
|
11
11
|
{
|
|
12
|
-
if (!callback.IsFunction())
|
|
13
|
-
throw Napi::Error::New(callback.Env(), "Callback must be a function");
|
|
14
|
-
|
|
15
12
|
Napi::Env env = callback.Env();
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
if (!callback.IsFunction())
|
|
15
|
+
throw Napi::Error::New(env, "Callback must be a function");
|
|
16
|
+
|
|
18
17
|
tsfn = tsfn_t::New(env,
|
|
19
18
|
std::move(callback),
|
|
20
19
|
"ThreadSafeCallback callback",
|
|
21
|
-
0,
|
|
20
|
+
0, // unlimited queue
|
|
21
|
+
1);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
ThreadSafeCallback::~ThreadSafeCallback()
|
|
@@ -38,10 +38,10 @@ void ThreadSafeCallback::call(arg_func_t argFunc, cleanup_func_t cleanupFunc)
|
|
|
38
38
|
|
|
39
39
|
void ThreadSafeCallback::callbackFunc(Napi::Env env,
|
|
40
40
|
Napi::Function callback,
|
|
41
|
-
|
|
41
|
+
ContextType *context,
|
|
42
42
|
CallbackData *data)
|
|
43
43
|
{
|
|
44
|
-
// if env is gone
|
|
44
|
+
// if env is gone, it could mean this cb was destroyed. See issue#176
|
|
45
45
|
if (!data || !env)
|
|
46
46
|
return;
|
|
47
47
|
|
|
@@ -59,9 +59,10 @@ void ThreadSafeCallback::callbackFunc(Napi::Env env,
|
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
if (
|
|
62
|
+
if (callback)
|
|
63
63
|
{
|
|
64
|
-
callback.Call(
|
|
65
|
-
cleanup();
|
|
64
|
+
callback.Call(args);
|
|
66
65
|
}
|
|
66
|
+
|
|
67
|
+
cleanup();
|
|
67
68
|
}
|
|
@@ -30,6 +30,7 @@ public:
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
private:
|
|
33
|
+
using ContextType = std::nullptr_t;
|
|
33
34
|
struct CallbackData
|
|
34
35
|
{
|
|
35
36
|
arg_func_t argFunc;
|
|
@@ -38,12 +39,10 @@ private:
|
|
|
38
39
|
|
|
39
40
|
static void callbackFunc(Napi::Env env,
|
|
40
41
|
Napi::Function callback,
|
|
41
|
-
|
|
42
|
+
ContextType *context,
|
|
42
43
|
CallbackData *data);
|
|
43
44
|
|
|
44
|
-
using tsfn_t = Napi::TypedThreadSafeFunction<
|
|
45
|
-
|
|
46
|
-
Napi::Reference<Napi::Value> receiver;
|
|
45
|
+
using tsfn_t = Napi::TypedThreadSafeFunction<ContextType, CallbackData, callbackFunc>;
|
|
47
46
|
tsfn_t tsfn;
|
|
48
47
|
};
|
|
49
48
|
|
|
@@ -31,6 +31,7 @@ Napi::Object WebSocketWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
|
31
31
|
{
|
|
32
32
|
InstanceMethod("open", &WebSocketWrapper::open),
|
|
33
33
|
InstanceMethod("close", &WebSocketWrapper::close),
|
|
34
|
+
InstanceMethod("forceClose", &WebSocketWrapper::forceClose),
|
|
34
35
|
InstanceMethod("sendMessage", &WebSocketWrapper::sendMessage),
|
|
35
36
|
InstanceMethod("sendMessageBinary", &WebSocketWrapper::sendMessageBinary),
|
|
36
37
|
InstanceMethod("isOpen", &WebSocketWrapper::isOpen),
|
|
@@ -42,6 +43,8 @@ Napi::Object WebSocketWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
|
42
43
|
InstanceMethod("onError", &WebSocketWrapper::onError),
|
|
43
44
|
InstanceMethod("onBufferedAmountLow", &WebSocketWrapper::onBufferedAmountLow),
|
|
44
45
|
InstanceMethod("onMessage", &WebSocketWrapper::onMessage),
|
|
46
|
+
InstanceMethod("remoteAddress", &WebSocketWrapper::remoteAddress),
|
|
47
|
+
InstanceMethod("path", &WebSocketWrapper::path),
|
|
45
48
|
});
|
|
46
49
|
|
|
47
50
|
constructor = Napi::Persistent(func);
|
|
@@ -235,6 +238,10 @@ WebSocketWrapper::WebSocketWrapper(const Napi::CallbackInfo &info) : Napi::Objec
|
|
|
235
238
|
}
|
|
236
239
|
|
|
237
240
|
PLOG_DEBUG << "WebSocket created";
|
|
241
|
+
|
|
242
|
+
// Closed callback must set to trigger cleanup
|
|
243
|
+
mOnClosedCallback = std::make_unique<ThreadSafeCallback>(Napi::Function::New(info.Env(), [](const Napi::CallbackInfo&){}));
|
|
244
|
+
|
|
238
245
|
instances.insert(this);
|
|
239
246
|
}
|
|
240
247
|
|
|
@@ -257,7 +264,31 @@ void WebSocketWrapper::doClose()
|
|
|
257
264
|
}
|
|
258
265
|
catch (std::exception &ex)
|
|
259
266
|
{
|
|
260
|
-
std::cerr << std::string("
|
|
267
|
+
std::cerr << std::string("libdatachannel error while closing WebSocket: ") + ex.what() << std::endl;
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
mOnOpenCallback.reset();
|
|
273
|
+
mOnErrorCallback.reset();
|
|
274
|
+
mOnBufferedAmountLowCallback.reset();
|
|
275
|
+
mOnMessageCallback.reset();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
void WebSocketWrapper::doForceClose()
|
|
279
|
+
{
|
|
280
|
+
PLOG_DEBUG << "doForceClose() called";
|
|
281
|
+
if (mWebSocketPtr)
|
|
282
|
+
{
|
|
283
|
+
PLOG_DEBUG << "Force closing...";
|
|
284
|
+
try
|
|
285
|
+
{
|
|
286
|
+
mWebSocketPtr->forceClose();
|
|
287
|
+
mWebSocketPtr.reset();
|
|
288
|
+
}
|
|
289
|
+
catch (std::exception &ex)
|
|
290
|
+
{
|
|
291
|
+
std::cerr << std::string("libdatachannel error while force closing WebSocket: ") + ex.what() << std::endl;
|
|
261
292
|
return;
|
|
262
293
|
}
|
|
263
294
|
}
|
|
@@ -297,7 +328,7 @@ void WebSocketWrapper::open(const Napi::CallbackInfo &info)
|
|
|
297
328
|
}
|
|
298
329
|
catch (std::exception &ex)
|
|
299
330
|
{
|
|
300
|
-
Napi::Error::New(env, std::string("
|
|
331
|
+
Napi::Error::New(env, std::string("libdatachannel error while opening WebSocket: ") + ex.what()).ThrowAsJavaScriptException();
|
|
301
332
|
return;
|
|
302
333
|
}
|
|
303
334
|
}
|
|
@@ -308,6 +339,12 @@ void WebSocketWrapper::close(const Napi::CallbackInfo &info)
|
|
|
308
339
|
doClose();
|
|
309
340
|
}
|
|
310
341
|
|
|
342
|
+
void WebSocketWrapper::forceClose(const Napi::CallbackInfo &info)
|
|
343
|
+
{
|
|
344
|
+
PLOG_DEBUG << "forceClose() called";
|
|
345
|
+
doForceClose();
|
|
346
|
+
}
|
|
347
|
+
|
|
311
348
|
Napi::Value WebSocketWrapper::sendMessage(const Napi::CallbackInfo &info)
|
|
312
349
|
{
|
|
313
350
|
PLOG_DEBUG << "sendMessage() called";
|
|
@@ -333,7 +370,7 @@ Napi::Value WebSocketWrapper::sendMessage(const Napi::CallbackInfo &info)
|
|
|
333
370
|
}
|
|
334
371
|
catch (std::exception &ex)
|
|
335
372
|
{
|
|
336
|
-
Napi::Error::New(env, std::string("
|
|
373
|
+
Napi::Error::New(env, std::string("libdatachannel error while sending data channel message: ") + ex.what()).ThrowAsJavaScriptException();
|
|
337
374
|
return Napi::Boolean::New(info.Env(), false);
|
|
338
375
|
}
|
|
339
376
|
}
|
|
@@ -363,7 +400,7 @@ Napi::Value WebSocketWrapper::sendMessageBinary(const Napi::CallbackInfo &info)
|
|
|
363
400
|
}
|
|
364
401
|
catch (std::exception &ex)
|
|
365
402
|
{
|
|
366
|
-
Napi::Error::New(env, std::string("
|
|
403
|
+
Napi::Error::New(env, std::string("libdatachannel error while sending data channel message: ") + ex.what()).ThrowAsJavaScriptException();
|
|
367
404
|
return Napi::Boolean::New(info.Env(), false);
|
|
368
405
|
}
|
|
369
406
|
}
|
|
@@ -384,7 +421,7 @@ Napi::Value WebSocketWrapper::isOpen(const Napi::CallbackInfo &info)
|
|
|
384
421
|
}
|
|
385
422
|
catch (std::exception &ex)
|
|
386
423
|
{
|
|
387
|
-
Napi::Error::New(env, std::string("
|
|
424
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
388
425
|
return Napi::Boolean::New(info.Env(), false);
|
|
389
426
|
}
|
|
390
427
|
}
|
|
@@ -405,7 +442,7 @@ Napi::Value WebSocketWrapper::bufferedAmount(const Napi::CallbackInfo &info)
|
|
|
405
442
|
}
|
|
406
443
|
catch (std::exception &ex)
|
|
407
444
|
{
|
|
408
|
-
Napi::Error::New(env, std::string("
|
|
445
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
409
446
|
return Napi::Number::New(info.Env(), 0);
|
|
410
447
|
}
|
|
411
448
|
}
|
|
@@ -426,11 +463,69 @@ Napi::Value WebSocketWrapper::maxMessageSize(const Napi::CallbackInfo &info)
|
|
|
426
463
|
}
|
|
427
464
|
catch (std::exception &ex)
|
|
428
465
|
{
|
|
429
|
-
Napi::Error::New(env, std::string("
|
|
466
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
430
467
|
return Napi::Number::New(info.Env(), 0);
|
|
431
468
|
}
|
|
432
469
|
}
|
|
433
470
|
|
|
471
|
+
Napi::Value WebSocketWrapper::remoteAddress(const Napi::CallbackInfo &info)
|
|
472
|
+
{
|
|
473
|
+
PLOG_DEBUG << "remoteAddress() called";
|
|
474
|
+
Napi::Env env = info.Env();
|
|
475
|
+
|
|
476
|
+
if (!mWebSocketPtr)
|
|
477
|
+
{
|
|
478
|
+
return env.Undefined();
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
try
|
|
482
|
+
{
|
|
483
|
+
auto address = mWebSocketPtr->remoteAddress();
|
|
484
|
+
if (address.has_value())
|
|
485
|
+
{
|
|
486
|
+
return Napi::String::New(info.Env(), address.value());
|
|
487
|
+
}
|
|
488
|
+
else
|
|
489
|
+
{
|
|
490
|
+
return env.Undefined();
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
catch (std::exception &ex)
|
|
494
|
+
{
|
|
495
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
496
|
+
return env.Undefined();
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
Napi::Value WebSocketWrapper::path(const Napi::CallbackInfo &info)
|
|
501
|
+
{
|
|
502
|
+
PLOG_DEBUG << "path() called";
|
|
503
|
+
Napi::Env env = info.Env();
|
|
504
|
+
|
|
505
|
+
if (!mWebSocketPtr)
|
|
506
|
+
{
|
|
507
|
+
return env.Undefined();
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
try
|
|
511
|
+
{
|
|
512
|
+
auto path = mWebSocketPtr->path();
|
|
513
|
+
if (path.has_value())
|
|
514
|
+
{
|
|
515
|
+
return Napi::String::New(info.Env(), path.value());
|
|
516
|
+
}
|
|
517
|
+
else
|
|
518
|
+
{
|
|
519
|
+
return env.Undefined();
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
catch (std::exception &ex)
|
|
523
|
+
{
|
|
524
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
525
|
+
return env.Undefined();
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
434
529
|
void WebSocketWrapper::setBufferedAmountLowThreshold(const Napi::CallbackInfo &info)
|
|
435
530
|
{
|
|
436
531
|
PLOG_DEBUG << "setBufferedAmountLowThreshold() called";
|
|
@@ -455,7 +550,7 @@ void WebSocketWrapper::setBufferedAmountLowThreshold(const Napi::CallbackInfo &i
|
|
|
455
550
|
}
|
|
456
551
|
catch (std::exception &ex)
|
|
457
552
|
{
|
|
458
|
-
Napi::Error::New(env, std::string("
|
|
553
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
459
554
|
return;
|
|
460
555
|
}
|
|
461
556
|
}
|
package/src/web-socket-wrapper.h
CHANGED
|
@@ -23,12 +23,15 @@ public:
|
|
|
23
23
|
// Functions
|
|
24
24
|
void open(const Napi::CallbackInfo &info);
|
|
25
25
|
void close(const Napi::CallbackInfo &info);
|
|
26
|
+
void forceClose(const Napi::CallbackInfo &info);
|
|
26
27
|
Napi::Value sendMessage(const Napi::CallbackInfo &info);
|
|
27
28
|
Napi::Value sendMessageBinary(const Napi::CallbackInfo &info);
|
|
28
29
|
Napi::Value isOpen(const Napi::CallbackInfo &info);
|
|
29
30
|
Napi::Value bufferedAmount(const Napi::CallbackInfo &info);
|
|
30
31
|
Napi::Value maxMessageSize(const Napi::CallbackInfo &info);
|
|
31
32
|
void setBufferedAmountLowThreshold(const Napi::CallbackInfo &info);
|
|
33
|
+
Napi::Value remoteAddress(const Napi::CallbackInfo &info);
|
|
34
|
+
Napi::Value path(const Napi::CallbackInfo &info);
|
|
32
35
|
|
|
33
36
|
// Callbacks
|
|
34
37
|
void onOpen(const Napi::CallbackInfo &info);
|
|
@@ -47,6 +50,7 @@ private:
|
|
|
47
50
|
static std::unordered_set<WebSocketWrapper *> instances;
|
|
48
51
|
|
|
49
52
|
void doClose();
|
|
53
|
+
void doForceClose();
|
|
50
54
|
void doCleanup();
|
|
51
55
|
|
|
52
56
|
std::shared_ptr<rtc::WebSocket> mWebSocketPtr = nullptr;
|
package/test/websockets.js
CHANGED
|
@@ -6,7 +6,9 @@ nodeDataChannel.preload();
|
|
|
6
6
|
const webSocketServer = new nodeDataChannel.WebSocketServer({ bindAddress: '127.0.0.1', port: 1987 });
|
|
7
7
|
|
|
8
8
|
webSocketServer.onClient((serverSocket) => {
|
|
9
|
-
console.log(
|
|
9
|
+
console.log(
|
|
10
|
+
'webSocketServer.onClient() remoteAddress: ' + serverSocket.remoteAddress() + ', path: ' + serverSocket.path(),
|
|
11
|
+
);
|
|
10
12
|
|
|
11
13
|
serverSocket.onOpen(() => {
|
|
12
14
|
console.log('serverSocket.onOpen()');
|
|
@@ -32,7 +34,7 @@ clientSocket.onOpen(() => {
|
|
|
32
34
|
|
|
33
35
|
clientSocket.onMessage((message) => {
|
|
34
36
|
console.log('clientSocket.onMessage():', message);
|
|
35
|
-
clientSocket.
|
|
37
|
+
clientSocket.forceClose();
|
|
36
38
|
webSocketServer.stop();
|
|
37
39
|
});
|
|
38
40
|
|