node-datachannel 0.2.4 → 0.3.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/.editorconfig +12 -0
- package/.eslintignore +2 -0
- package/.eslintrc.js +8 -0
- package/.github/FUNDING.yml +2 -0
- package/.github/workflows/build-linux.yml +3 -3
- package/.github/workflows/build-mac.yml +1 -1
- package/.github/workflows/build-win.yml +4 -4
- package/.prettierrc.js +7 -0
- package/CMakeLists.txt +7 -1
- package/README.md +4 -4
- package/lib/datachannel-stream.js +23 -12
- package/lib/index.d.ts +54 -57
- package/lib/index.js +3 -2
- package/node_modules/detect-libc/package.json +1 -0
- package/node_modules/lru-cache/package.json +3 -2
- package/node_modules/minimist/index.js +6 -2
- package/node_modules/minimist/package.json +10 -10
- package/node_modules/minimist/readme.markdown +4 -1
- package/node_modules/minimist/test/proto.js +16 -0
- package/node_modules/node-abi/package.json +1 -0
- package/package.json +12 -4
- package/src/data-channel-wrapper.cpp +56 -22
- package/src/data-channel-wrapper.h +3 -0
- package/src/media-audio-wrapper.cpp +5 -5
- package/src/media-track-wrapper.cpp +40 -21
- package/src/media-track-wrapper.h +2 -0
- package/src/media-video-wrapper.cpp +5 -5
- package/src/peer-connection-wrapper.cpp +48 -27
- package/src/peer-connection-wrapper.h +2 -0
- package/test/connectivity.js +6 -6
- package/test/test.js +4 -4
package/.editorconfig
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# EditorConfig helps developers define and maintain consistent
|
|
2
|
+
# coding styles between different editors and IDEs
|
|
3
|
+
# http://editorconfig.org
|
|
4
|
+
|
|
5
|
+
root = true
|
|
6
|
+
|
|
7
|
+
[*]
|
|
8
|
+
indent_style = space
|
|
9
|
+
end_of_line = lf
|
|
10
|
+
charset = utf-8
|
|
11
|
+
trim_trailing_whitespace = true
|
|
12
|
+
insert_final_newline = true
|
package/.eslintignore
ADDED
package/.eslintrc.js
ADDED
|
@@ -14,7 +14,7 @@ jobs:
|
|
|
14
14
|
runs-on: ubuntu-20.04
|
|
15
15
|
strategy:
|
|
16
16
|
matrix:
|
|
17
|
-
node-version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x]
|
|
17
|
+
node-version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x, 17.x]
|
|
18
18
|
|
|
19
19
|
steps:
|
|
20
20
|
- uses: actions/checkout@v2
|
|
@@ -40,7 +40,7 @@ jobs:
|
|
|
40
40
|
|
|
41
41
|
strategy:
|
|
42
42
|
matrix:
|
|
43
|
-
node-version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x]
|
|
43
|
+
node-version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x, 17.x]
|
|
44
44
|
steps:
|
|
45
45
|
- uses: actions/checkout@v2
|
|
46
46
|
- name: Prepare Cross Compile
|
|
@@ -68,7 +68,7 @@ jobs:
|
|
|
68
68
|
|
|
69
69
|
strategy:
|
|
70
70
|
matrix:
|
|
71
|
-
node-version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x]
|
|
71
|
+
node-version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x, 17.x]
|
|
72
72
|
steps:
|
|
73
73
|
- uses: actions/checkout@v2
|
|
74
74
|
- name: Prepare Cross Compile
|
|
@@ -11,10 +11,10 @@ env:
|
|
|
11
11
|
|
|
12
12
|
jobs:
|
|
13
13
|
build-windows-x64:
|
|
14
|
-
runs-on: windows-
|
|
14
|
+
runs-on: windows-2019
|
|
15
15
|
strategy:
|
|
16
16
|
matrix:
|
|
17
|
-
node-version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x]
|
|
17
|
+
node-version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x, 17.x]
|
|
18
18
|
|
|
19
19
|
steps:
|
|
20
20
|
- uses: actions/checkout@v2
|
|
@@ -39,10 +39,10 @@ jobs:
|
|
|
39
39
|
CI: true
|
|
40
40
|
|
|
41
41
|
build-windows-x86:
|
|
42
|
-
runs-on: windows-
|
|
42
|
+
runs-on: windows-2019
|
|
43
43
|
strategy:
|
|
44
44
|
matrix:
|
|
45
|
-
node_version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x]
|
|
45
|
+
node_version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x, 17.x]
|
|
46
46
|
node_arch:
|
|
47
47
|
- x86
|
|
48
48
|
steps:
|
package/.prettierrc.js
ADDED
package/CMakeLists.txt
CHANGED
|
@@ -2,6 +2,12 @@ cmake_minimum_required(VERSION 3.15)
|
|
|
2
2
|
cmake_policy(SET CMP0091 NEW)
|
|
3
3
|
project(node_datachannel VERSION 0.2.4)
|
|
4
4
|
|
|
5
|
+
# Workaround for https://github.com/murat-dogan/node-datachannel/issues/65
|
|
6
|
+
if( NODE_RUNTIMEVERSION VERSION_GREATER_EQUAL "17.0.0")
|
|
7
|
+
add_compile_definitions(OPENSSL_API_COMPAT=0x10100001L)
|
|
8
|
+
add_compile_definitions(OPENSSL_CONFIGURED_API=0x30000000L)
|
|
9
|
+
endif()
|
|
10
|
+
|
|
5
11
|
include_directories(${CMAKE_JS_INC})
|
|
6
12
|
|
|
7
13
|
set(CMAKE_BUILD_TYPE Release)
|
|
@@ -27,7 +33,7 @@ include(FetchContent)
|
|
|
27
33
|
FetchContent_Declare(
|
|
28
34
|
libdatachannel
|
|
29
35
|
GIT_REPOSITORY https://github.com/paullouisageneau/libdatachannel.git
|
|
30
|
-
GIT_TAG "v0.
|
|
36
|
+
GIT_TAG "v0.17.0"
|
|
31
37
|
)
|
|
32
38
|
|
|
33
39
|
option(NO_MEDIA "Disable media transport support in libdatachannel" OFF)
|
package/README.md
CHANGED
|
@@ -118,7 +118,7 @@ export const enum RelayType {
|
|
|
118
118
|
|
|
119
119
|
export interface IceServer {
|
|
120
120
|
hostname: string;
|
|
121
|
-
port:
|
|
121
|
+
port: number;
|
|
122
122
|
username?: string;
|
|
123
123
|
password?: string;
|
|
124
124
|
relayType?: RelayType;
|
|
@@ -271,15 +271,15 @@ Send Message as binary
|
|
|
271
271
|
|
|
272
272
|
Query data-channel
|
|
273
273
|
|
|
274
|
-
**bufferedAmount: () =>
|
|
274
|
+
**bufferedAmount: () => number**
|
|
275
275
|
|
|
276
276
|
Get current buffered amount level
|
|
277
277
|
|
|
278
|
-
**maxMessageSize: () =>
|
|
278
|
+
**maxMessageSize: () => number**
|
|
279
279
|
|
|
280
280
|
Get max message size of the data-channel, that could be sent
|
|
281
281
|
|
|
282
|
-
**setBufferedAmountLowThreshold: (newSize:
|
|
282
|
+
**setBufferedAmountLowThreshold: (newSize: number) => void**
|
|
283
283
|
|
|
284
284
|
Set buffer level of the `onBufferedAmountLow` callback
|
|
285
285
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
1
2
|
const stream = require('stream');
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -9,12 +10,11 @@ const stream = require('stream');
|
|
|
9
10
|
* the protocol level, and is preserved here throughout.
|
|
10
11
|
*/
|
|
11
12
|
module.exports = class DataChannelStream extends stream.Duplex {
|
|
12
|
-
|
|
13
13
|
constructor(rawChannel, streamOptions) {
|
|
14
14
|
super({
|
|
15
15
|
allowHalfOpen: false, // Default to autoclose on end().
|
|
16
16
|
...streamOptions,
|
|
17
|
-
objectMode: true // Preserve the string/buffer distinction (WebRTC treats them differently)
|
|
17
|
+
objectMode: true, // Preserve the string/buffer distinction (WebRTC treats them differently)
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
this._rawChannel = rawChannel;
|
|
@@ -51,20 +51,24 @@ module.exports = class DataChannelStream extends stream.Duplex {
|
|
|
51
51
|
|
|
52
52
|
_write(chunk, encoding, callback) {
|
|
53
53
|
let sentOk;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
if (Buffer.isBuffer(chunk)) {
|
|
57
|
+
sentOk = this._rawChannel.sendMessageBinary(chunk);
|
|
58
|
+
} else if (typeof chunk === 'string') {
|
|
59
|
+
sentOk = this._rawChannel.sendMessage(chunk);
|
|
60
|
+
} else {
|
|
61
|
+
const typeName = chunk.constructor.name || typeof chunk;
|
|
62
|
+
throw new Error(`Cannot write ${typeName} to DataChannel stream`);
|
|
63
|
+
}
|
|
64
|
+
} catch (err) {
|
|
65
|
+
return callback(err);
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
if (sentOk) {
|
|
65
69
|
callback(null);
|
|
66
70
|
} else {
|
|
67
|
-
callback(new Error(
|
|
71
|
+
callback(new Error('Failed to write to DataChannel'));
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
74
|
|
|
@@ -83,4 +87,11 @@ module.exports = class DataChannelStream extends stream.Duplex {
|
|
|
83
87
|
return this._rawChannel.getLabel();
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
|
|
90
|
+
get id() {
|
|
91
|
+
return this._rawChannel.getId();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
get protocol() {
|
|
95
|
+
return this._rawChannel.getProtocol();
|
|
96
|
+
}
|
|
97
|
+
};
|
package/lib/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as stream from 'stream';
|
|
|
3
3
|
export as namespace NodeDataChannel;
|
|
4
4
|
|
|
5
5
|
// Enum in d.ts is tricky
|
|
6
|
-
export type LogLevel =
|
|
6
|
+
export type LogLevel = 'Verbose' | 'Debug' | 'Info' | 'Warning' | 'Error' | 'Fatal';
|
|
7
7
|
|
|
8
8
|
// SCTP Settings
|
|
9
9
|
export interface SctpSettings {
|
|
@@ -26,7 +26,7 @@ export type ProxyServerType = 'None' | 'Socks5' | 'Http';
|
|
|
26
26
|
export interface ProxyServer {
|
|
27
27
|
type: ProxyServerType;
|
|
28
28
|
ip: string;
|
|
29
|
-
port:
|
|
29
|
+
port: number;
|
|
30
30
|
username?: string;
|
|
31
31
|
password?: string;
|
|
32
32
|
}
|
|
@@ -34,12 +34,12 @@ export interface ProxyServer {
|
|
|
34
34
|
export const enum RelayType {
|
|
35
35
|
TurnUdp = 'TurnUdp',
|
|
36
36
|
TurnTcp = 'TurnTcp',
|
|
37
|
-
TurnTls = 'TurnTls'
|
|
37
|
+
TurnTls = 'TurnTls',
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export interface IceServer {
|
|
41
41
|
hostname: string;
|
|
42
|
-
port:
|
|
42
|
+
port: number;
|
|
43
43
|
username?: string;
|
|
44
44
|
password?: string;
|
|
45
45
|
relayType?: RelayType;
|
|
@@ -61,11 +61,13 @@ export const enum DescriptionType {
|
|
|
61
61
|
Offer = 'Offer',
|
|
62
62
|
Answer = 'Answer',
|
|
63
63
|
Pranswer = 'Pranswer',
|
|
64
|
-
Rollback = 'Rollback'
|
|
64
|
+
Rollback = 'Rollback',
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
export const enum ReliabilityType {
|
|
68
|
-
Reliable = 0,
|
|
68
|
+
Reliable = 0,
|
|
69
|
+
Rexmit = 1,
|
|
70
|
+
Timed = 2,
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
export interface DataChannelInitConfig {
|
|
@@ -81,7 +83,7 @@ export interface DataChannelInitConfig {
|
|
|
81
83
|
type?: ReliabilityType;
|
|
82
84
|
unordered?: boolean;
|
|
83
85
|
rexmit?: number;
|
|
84
|
-
}
|
|
86
|
+
};
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
export interface SelectedCandidateInfo {
|
|
@@ -97,18 +99,18 @@ export const enum Direction {
|
|
|
97
99
|
RecvOnly = 'RecvOnly',
|
|
98
100
|
SendRecv = 'SendRecv',
|
|
99
101
|
Inactive = 'Inactive',
|
|
100
|
-
Unknown = 'Unknown'
|
|
102
|
+
Unknown = 'Unknown',
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
export class RtcpReceivingSession {
|
|
104
|
-
requestBitrate: (bitRate:
|
|
106
|
+
requestBitrate: (bitRate: number) => void;
|
|
105
107
|
requestKeyframe: () => boolean;
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
export class Audio {
|
|
109
111
|
constructor(mid: string, dir: Direction);
|
|
110
|
-
addAudioCodec: (payloadType:
|
|
111
|
-
addOpusCodec: (payloadType:
|
|
112
|
+
addAudioCodec: (payloadType: number, codec: string, profile?: string) => void;
|
|
113
|
+
addOpusCodec: (payloadType: number, profile?: string) => string;
|
|
112
114
|
|
|
113
115
|
direction: () => Direction;
|
|
114
116
|
generateSdp: (eol: string, addr: string, port: string) => string;
|
|
@@ -116,26 +118,26 @@ export class Audio {
|
|
|
116
118
|
setDirection: (dir: Direction) => void;
|
|
117
119
|
description: () => string;
|
|
118
120
|
removeFormat: (fmt: string) => void;
|
|
119
|
-
addSSRC: (ssrc:
|
|
120
|
-
removeSSRC: (ssrc:
|
|
121
|
-
replaceSSRC: (oldSsrc:
|
|
122
|
-
hasSSRC: (ssrc:
|
|
123
|
-
getSSRCs: () =>
|
|
124
|
-
getCNameForSsrc: (ssrc:
|
|
125
|
-
setBitrate: (bitRate:
|
|
126
|
-
getBitrate: () =>
|
|
127
|
-
hasPayloadType: (payloadType:
|
|
128
|
-
addRTXCodec: (payloadType:
|
|
121
|
+
addSSRC: (ssrc: number, name?: string, msid?: string, trackID?: string) => void;
|
|
122
|
+
removeSSRC: (ssrc: number) => void;
|
|
123
|
+
replaceSSRC: (oldSsrc: number, ssrc: number, name?: string, msid?: string, trackID?: string) => void;
|
|
124
|
+
hasSSRC: (ssrc: number) => boolean;
|
|
125
|
+
getSSRCs: () => number[];
|
|
126
|
+
getCNameForSsrc: (ssrc: number) => string;
|
|
127
|
+
setBitrate: (bitRate: number) => void;
|
|
128
|
+
getBitrate: () => number;
|
|
129
|
+
hasPayloadType: (payloadType: number) => boolean;
|
|
130
|
+
addRTXCodec: (payloadType: number, originalPayloadType: number, clockRate: number) => void;
|
|
129
131
|
addRTPMap: () => void;
|
|
130
132
|
parseSdpLine: (line: string) => void;
|
|
131
133
|
}
|
|
132
134
|
|
|
133
135
|
export class Video {
|
|
134
136
|
constructor(mid: string, dir: Direction);
|
|
135
|
-
addVideoCodec: (payloadType:
|
|
136
|
-
addH264Codec: (payloadType:
|
|
137
|
-
addVP8Codec: (payloadType:
|
|
138
|
-
addVP9Codec: (payloadType:
|
|
137
|
+
addVideoCodec: (payloadType: number, codec: string, profile?: string) => void;
|
|
138
|
+
addH264Codec: (payloadType: number, profile?: string) => void;
|
|
139
|
+
addVP8Codec: (payloadType: number) => void;
|
|
140
|
+
addVP9Codec: (payloadType: number) => void;
|
|
139
141
|
|
|
140
142
|
direction: () => Direction;
|
|
141
143
|
generateSdp: (eol: string, addr: string, port: string) => string;
|
|
@@ -143,16 +145,16 @@ export class Video {
|
|
|
143
145
|
setDirection: (dir: Direction) => void;
|
|
144
146
|
description: () => string;
|
|
145
147
|
removeFormat: (fmt: string) => void;
|
|
146
|
-
addSSRC: (ssrc:
|
|
147
|
-
removeSSRC: (ssrc:
|
|
148
|
-
replaceSSRC: (oldSsrc:
|
|
149
|
-
hasSSRC: (ssrc:
|
|
150
|
-
getSSRCs: () =>
|
|
151
|
-
getCNameForSsrc: (ssrc:
|
|
152
|
-
setBitrate: (bitRate:
|
|
153
|
-
getBitrate: () =>
|
|
154
|
-
hasPayloadType: (payloadType:
|
|
155
|
-
addRTXCodec: (payloadType:
|
|
148
|
+
addSSRC: (ssrc: number, name?: string, msid?: string, trackID?: string) => void;
|
|
149
|
+
removeSSRC: (ssrc: number) => void;
|
|
150
|
+
replaceSSRC: (oldSsrc: number, ssrc: number, name?: string, msid?: string, trackID?: string) => void;
|
|
151
|
+
hasSSRC: (ssrc: number) => boolean;
|
|
152
|
+
getSSRCs: () => number[];
|
|
153
|
+
getCNameForSsrc: (ssrc: number) => string;
|
|
154
|
+
setBitrate: (bitRate: number) => void;
|
|
155
|
+
getBitrate: () => number;
|
|
156
|
+
hasPayloadType: (payloadType: number) => boolean;
|
|
157
|
+
addRTXCodec: (payloadType: number, originalPayloadType: number, clockRate: number) => void;
|
|
156
158
|
addRTPMap: () => void;
|
|
157
159
|
parseSdpLine: (line: string) => void;
|
|
158
160
|
}
|
|
@@ -160,39 +162,37 @@ export class Video {
|
|
|
160
162
|
export class Track {
|
|
161
163
|
direction: () => Direction;
|
|
162
164
|
mid: () => string;
|
|
165
|
+
type: () => string;
|
|
163
166
|
close: () => void;
|
|
164
167
|
sendMessage: (msg: string) => boolean;
|
|
165
168
|
sendMessageBinary: (buffer: Buffer) => boolean;
|
|
166
169
|
isOpen: () => boolean;
|
|
167
170
|
isClosed: () => boolean;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
setBufferedAmountLowThreshold: (newSize: Number) => void;
|
|
171
|
+
bufferedAmount: () => number;
|
|
172
|
+
maxMessageSize: () => number;
|
|
173
|
+
setBufferedAmountLowThreshold: (newSize: number) => void;
|
|
172
174
|
requestKeyframe: () => boolean;
|
|
173
|
-
setMediaHandler: (handler: RtcpReceivingSession) => void
|
|
175
|
+
setMediaHandler: (handler: RtcpReceivingSession) => void;
|
|
174
176
|
onOpen: (cb: () => void) => void;
|
|
175
177
|
onClosed: (cb: () => void) => void;
|
|
176
178
|
onError: (cb: (err: string) => void) => void;
|
|
177
|
-
|
|
178
|
-
onBufferedAmountLow: (cb: () => void) => void;
|
|
179
|
-
onMessage: (cb: (msg: string | Buffer) => void) => void;
|
|
179
|
+
onMessage: (cb: (msg: Buffer) => void) => void;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
182
|
export class DataChannel {
|
|
183
183
|
close: () => void;
|
|
184
184
|
getLabel: () => string;
|
|
185
|
+
getId: () => number;
|
|
186
|
+
getProtocol: () => string;
|
|
185
187
|
sendMessage: (msg: string) => boolean;
|
|
186
188
|
sendMessageBinary: (buffer: Buffer) => boolean;
|
|
187
189
|
isOpen: () => boolean;
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
setBufferedAmountLowThreshold: (newSize: Number) => void;
|
|
190
|
+
bufferedAmount: () => number;
|
|
191
|
+
maxMessageSize: () => number;
|
|
192
|
+
setBufferedAmountLowThreshold: (newSize: number) => void;
|
|
192
193
|
onOpen: (cb: () => void) => void;
|
|
193
194
|
onClosed: (cb: () => void) => void;
|
|
194
195
|
onError: (cb: (err: string) => void) => void;
|
|
195
|
-
onAvailable: (cb: () => void) => void;
|
|
196
196
|
onBufferedAmountLow: (cb: () => void) => void;
|
|
197
197
|
onMessage: (cb: (msg: string | Buffer) => void) => void;
|
|
198
198
|
}
|
|
@@ -200,9 +200,9 @@ export class DataChannel {
|
|
|
200
200
|
export class PeerConnection {
|
|
201
201
|
constructor(peerName: string, config: RtcConfig);
|
|
202
202
|
close: () => void;
|
|
203
|
-
setLocalDescription: (type
|
|
203
|
+
setLocalDescription: (type?: DescriptionType) => void;
|
|
204
204
|
setRemoteDescription: (sdp: string, type: DescriptionType) => void;
|
|
205
|
-
localDescription: () => { type: string
|
|
205
|
+
localDescription: () => { type: string; sdp: string };
|
|
206
206
|
addRemoteCandidate: (candidate: string, mid: string) => void;
|
|
207
207
|
createDataChannel: (label: string, config?: DataChannelInitConfig) => DataChannel;
|
|
208
208
|
addTrack: (media: Video | Audio) => Track;
|
|
@@ -216,17 +216,14 @@ export class PeerConnection {
|
|
|
216
216
|
onSignalingStateChange: (state: (sdp: string) => void) => void;
|
|
217
217
|
onGatheringStateChange: (state: (sdp: string) => void) => void;
|
|
218
218
|
onDataChannel: (cb: (dc: DataChannel) => void) => void;
|
|
219
|
-
onTrack: () =>
|
|
219
|
+
onTrack: (cb: (track: Track) => void) => void;
|
|
220
220
|
bytesSent: () => number;
|
|
221
221
|
bytesReceived: () => number;
|
|
222
222
|
rtt: () => number;
|
|
223
|
-
getSelectedCandidatePair: () => { local: SelectedCandidateInfo
|
|
223
|
+
getSelectedCandidatePair: () => { local: SelectedCandidateInfo; remote: SelectedCandidateInfo } | null;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
export class DataChannelStream extends stream.Duplex {
|
|
227
|
-
constructor(
|
|
228
|
-
rawChannel: DataChannel,
|
|
229
|
-
options?: Omit<stream.DuplexOptions, 'objectMode'>
|
|
230
|
-
);
|
|
227
|
+
constructor(rawChannel: DataChannel, options?: Omit<stream.DuplexOptions, 'objectMode'>);
|
|
231
228
|
get label(): string;
|
|
232
|
-
}
|
|
229
|
+
}
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
2
|
+
const nodeDataChannel = require('../build/Release/node_datachannel.node');
|
|
2
3
|
module.exports = nodeDataChannel;
|
|
3
4
|
|
|
4
|
-
module.exports.DataChannelStream = require('./datachannel-stream');
|
|
5
|
+
module.exports.DataChannelStream = require('./datachannel-stream');
|
|
@@ -22,9 +22,10 @@
|
|
|
22
22
|
"fetchSpec": "6.0.0"
|
|
23
23
|
},
|
|
24
24
|
"_requiredBy": [
|
|
25
|
+
"/@typescript-eslint/eslint-plugin/semver",
|
|
26
|
+
"/@typescript-eslint/typescript-estree/semver",
|
|
25
27
|
"/jest-snapshot/semver",
|
|
26
|
-
"/node-abi/semver"
|
|
27
|
-
"/prebuild/node-abi/semver"
|
|
28
|
+
"/node-abi/semver"
|
|
28
29
|
],
|
|
29
30
|
"_resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
|
30
31
|
"_spec": "6.0.0",
|
|
@@ -70,7 +70,7 @@ module.exports = function (args, opts) {
|
|
|
70
70
|
var o = obj;
|
|
71
71
|
for (var i = 0; i < keys.length-1; i++) {
|
|
72
72
|
var key = keys[i];
|
|
73
|
-
if (key
|
|
73
|
+
if (isConstructorOrProto(o, key)) return;
|
|
74
74
|
if (o[key] === undefined) o[key] = {};
|
|
75
75
|
if (o[key] === Object.prototype || o[key] === Number.prototype
|
|
76
76
|
|| o[key] === String.prototype) o[key] = {};
|
|
@@ -79,7 +79,7 @@ module.exports = function (args, opts) {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
var key = keys[keys.length - 1];
|
|
82
|
-
if (key
|
|
82
|
+
if (isConstructorOrProto(o, key)) return;
|
|
83
83
|
if (o === Object.prototype || o === Number.prototype
|
|
84
84
|
|| o === String.prototype) o = {};
|
|
85
85
|
if (o === Array.prototype) o = [];
|
|
@@ -243,3 +243,7 @@ function isNumber (x) {
|
|
|
243
243
|
return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x);
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
|
|
247
|
+
function isConstructorOrProto (obj, key) {
|
|
248
|
+
return key === 'constructor' && typeof obj[key] === 'function' || key === '__proto__';
|
|
249
|
+
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_args": [
|
|
3
3
|
[
|
|
4
|
-
"minimist@1.2.
|
|
4
|
+
"minimist@1.2.6",
|
|
5
5
|
"/home/runner/work/node-datachannel/node-datachannel"
|
|
6
6
|
]
|
|
7
7
|
],
|
|
8
|
-
"_from": "minimist@1.2.
|
|
9
|
-
"_id": "minimist@1.2.
|
|
8
|
+
"_from": "minimist@1.2.6",
|
|
9
|
+
"_id": "minimist@1.2.6",
|
|
10
10
|
"_inBundle": false,
|
|
11
|
-
"_integrity": "sha512-
|
|
11
|
+
"_integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
|
12
12
|
"_location": "/minimist",
|
|
13
13
|
"_phantomChildren": {},
|
|
14
14
|
"_requested": {
|
|
15
15
|
"type": "version",
|
|
16
16
|
"registry": true,
|
|
17
|
-
"raw": "minimist@1.2.
|
|
17
|
+
"raw": "minimist@1.2.6",
|
|
18
18
|
"name": "minimist",
|
|
19
19
|
"escapedName": "minimist",
|
|
20
|
-
"rawSpec": "1.2.
|
|
20
|
+
"rawSpec": "1.2.6",
|
|
21
21
|
"saveSpec": null,
|
|
22
|
-
"fetchSpec": "1.2.
|
|
22
|
+
"fetchSpec": "1.2.6"
|
|
23
23
|
},
|
|
24
24
|
"_requiredBy": [
|
|
25
25
|
"/json5",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"/prebuild-install",
|
|
29
29
|
"/rc"
|
|
30
30
|
],
|
|
31
|
-
"_resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.
|
|
32
|
-
"_spec": "1.2.
|
|
31
|
+
"_resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
|
32
|
+
"_spec": "1.2.6",
|
|
33
33
|
"_where": "/home/runner/work/node-datachannel/node-datachannel",
|
|
34
34
|
"author": {
|
|
35
35
|
"name": "James Halliday",
|
|
@@ -76,5 +76,5 @@
|
|
|
76
76
|
"opera/12"
|
|
77
77
|
]
|
|
78
78
|
},
|
|
79
|
-
"version": "1.2.
|
|
79
|
+
"version": "1.2.6"
|
|
80
80
|
}
|
|
@@ -34,7 +34,10 @@ $ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz
|
|
|
34
34
|
Previous versions had a prototype pollution bug that could cause privilege
|
|
35
35
|
escalation in some circumstances when handling untrusted user input.
|
|
36
36
|
|
|
37
|
-
Please use version 1.2.
|
|
37
|
+
Please use version 1.2.6 or later:
|
|
38
|
+
|
|
39
|
+
* https://security.snyk.io/vuln/SNYK-JS-MINIMIST-2429795 (version <=1.2.5)
|
|
40
|
+
* https://snyk.io/vuln/SNYK-JS-MINIMIST-559764 (version <=1.2.3)
|
|
38
41
|
|
|
39
42
|
# methods
|
|
40
43
|
|
|
@@ -42,3 +42,19 @@ test('proto pollution (constructor)', function (t) {
|
|
|
42
42
|
t.equal(argv.y, undefined);
|
|
43
43
|
t.end();
|
|
44
44
|
});
|
|
45
|
+
|
|
46
|
+
test('proto pollution (constructor function)', function (t) {
|
|
47
|
+
var argv = parse(['--_.concat.constructor.prototype.y', '123']);
|
|
48
|
+
function fnToBeTested() {}
|
|
49
|
+
t.equal(fnToBeTested.y, undefined);
|
|
50
|
+
t.equal(argv.y, undefined);
|
|
51
|
+
t.end();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// powered by snyk - https://github.com/backstage/backstage/issues/10343
|
|
55
|
+
test('proto pollution (constructor function) snyk', function (t) {
|
|
56
|
+
var argv = parse('--_.constructor.constructor.prototype.foo bar'.split(' '));
|
|
57
|
+
t.equal((function(){}).foo, undefined);
|
|
58
|
+
t.equal(argv.y, undefined);
|
|
59
|
+
t.end();
|
|
60
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-datachannel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "libdatachannel node bindings",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"build": "cmake-js build",
|
|
16
16
|
"_prebuild": "prebuild --backend cmake-js",
|
|
17
17
|
"clean": "cmake-js clean",
|
|
18
|
+
"lint": "eslint lib/**/*",
|
|
18
19
|
"test": "jest"
|
|
19
20
|
},
|
|
20
21
|
"repository": {
|
|
@@ -46,18 +47,25 @@
|
|
|
46
47
|
},
|
|
47
48
|
"homepage": "https://github.com/murat-dogan/node-datachannel#readme",
|
|
48
49
|
"devDependencies": {
|
|
50
|
+
"@types/node": "^17.0.23",
|
|
51
|
+
"@typescript-eslint/eslint-plugin": "^5.18.0",
|
|
52
|
+
"@typescript-eslint/parser": "^5.18.0",
|
|
49
53
|
"cmake-js": "^6.3.0",
|
|
54
|
+
"eslint": "^8.12.0",
|
|
55
|
+
"eslint-config-prettier": "^8.5.0",
|
|
56
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
50
57
|
"jest": "^27.5.1",
|
|
51
58
|
"nan": "^2.15.0",
|
|
52
59
|
"napi-thread-safe-callback-cancellable": "^0.0.7",
|
|
53
|
-
"node-addon-api": "^4.
|
|
54
|
-
"prebuild": "^11.0.3"
|
|
60
|
+
"node-addon-api": "^4.3.0",
|
|
61
|
+
"prebuild": "^11.0.3",
|
|
62
|
+
"prettier": "^2.6.2",
|
|
63
|
+
"typescript": "^4.6.3"
|
|
55
64
|
},
|
|
56
65
|
"bundledDependencies": [
|
|
57
66
|
"prebuild-install"
|
|
58
67
|
],
|
|
59
68
|
"dependencies": {
|
|
60
|
-
"@types/node": "^17.0.21",
|
|
61
69
|
"prebuild-install": "^7.0.1"
|
|
62
70
|
}
|
|
63
71
|
}
|
|
@@ -20,6 +20,8 @@ Napi::Object DataChannelWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
|
20
20
|
{
|
|
21
21
|
InstanceMethod("close", &DataChannelWrapper::close),
|
|
22
22
|
InstanceMethod("getLabel", &DataChannelWrapper::getLabel),
|
|
23
|
+
InstanceMethod("getId", &DataChannelWrapper::getId),
|
|
24
|
+
InstanceMethod("getProtocol", &DataChannelWrapper::getProtocol),
|
|
23
25
|
InstanceMethod("sendMessage", &DataChannelWrapper::sendMessage),
|
|
24
26
|
InstanceMethod("sendMessageBinary", &DataChannelWrapper::sendMessageBinary),
|
|
25
27
|
InstanceMethod("isOpen", &DataChannelWrapper::isOpen),
|
|
@@ -42,8 +44,26 @@ Napi::Object DataChannelWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
|
42
44
|
|
|
43
45
|
DataChannelWrapper::DataChannelWrapper(const Napi::CallbackInfo &info) : Napi::ObjectWrap<DataChannelWrapper>(info)
|
|
44
46
|
{
|
|
45
|
-
mDataChannelPtr = *(info[0].As<Napi::External<std::shared_ptr<rtc::DataChannel>>>().Data());
|
|
47
|
+
mDataChannelPtr = *(info[0].As<Napi::External<std::shared_ptr<rtc::DataChannel>>>().Data());
|
|
46
48
|
|
|
49
|
+
mDataChannelPtr->onClosed([&]()
|
|
50
|
+
{
|
|
51
|
+
if (mOnClosedCallback)
|
|
52
|
+
mOnClosedCallback->call([this](Napi::Env env, std::vector<napi_value> &args) {
|
|
53
|
+
// Check the peer connection is not closed
|
|
54
|
+
if(instances.find(this) == instances.end())
|
|
55
|
+
throw ThreadSafeCallback::CancelException();
|
|
56
|
+
|
|
57
|
+
cleanCbsAndEraseInstance();
|
|
58
|
+
|
|
59
|
+
// This will run in main thread and needs to construct the
|
|
60
|
+
// arguments for the call
|
|
61
|
+
args = {};
|
|
62
|
+
});
|
|
63
|
+
else {
|
|
64
|
+
cleanCbsAndEraseInstance();
|
|
65
|
+
} });
|
|
66
|
+
|
|
47
67
|
instances.insert(this);
|
|
48
68
|
}
|
|
49
69
|
|
|
@@ -54,20 +74,11 @@ DataChannelWrapper::~DataChannelWrapper()
|
|
|
54
74
|
|
|
55
75
|
void DataChannelWrapper::doClose()
|
|
56
76
|
{
|
|
57
|
-
instances.erase(this);
|
|
58
|
-
|
|
59
77
|
if (mDataChannelPtr)
|
|
60
78
|
{
|
|
61
79
|
try
|
|
62
80
|
{
|
|
63
|
-
mOnOpenCallback.reset();
|
|
64
|
-
mOnClosedCallback.reset();
|
|
65
|
-
mOnErrorCallback.reset();
|
|
66
|
-
mOnBufferedAmountLowCallback.reset();
|
|
67
|
-
mOnMessageCallback.reset();
|
|
68
|
-
|
|
69
81
|
mDataChannelPtr->close();
|
|
70
|
-
mDataChannelPtr.reset();
|
|
71
82
|
}
|
|
72
83
|
catch (std::exception &ex)
|
|
73
84
|
{
|
|
@@ -77,6 +88,18 @@ void DataChannelWrapper::doClose()
|
|
|
77
88
|
}
|
|
78
89
|
}
|
|
79
90
|
|
|
91
|
+
void DataChannelWrapper::cleanCbsAndEraseInstance()
|
|
92
|
+
{
|
|
93
|
+
mOnOpenCallback.reset();
|
|
94
|
+
mOnClosedCallback.reset();
|
|
95
|
+
mOnErrorCallback.reset();
|
|
96
|
+
mOnBufferedAmountLowCallback.reset();
|
|
97
|
+
mOnMessageCallback.reset();
|
|
98
|
+
|
|
99
|
+
instances.erase(this);
|
|
100
|
+
mDataChannelPtr.reset();
|
|
101
|
+
}
|
|
102
|
+
|
|
80
103
|
void DataChannelWrapper::close(const Napi::CallbackInfo &info)
|
|
81
104
|
{
|
|
82
105
|
doClose();
|
|
@@ -93,6 +116,28 @@ Napi::Value DataChannelWrapper::getLabel(const Napi::CallbackInfo &info)
|
|
|
93
116
|
return Napi::String::New(info.Env(), mDataChannelPtr->label());
|
|
94
117
|
}
|
|
95
118
|
|
|
119
|
+
Napi::Value DataChannelWrapper::getId(const Napi::CallbackInfo &info)
|
|
120
|
+
{
|
|
121
|
+
if (!mDataChannelPtr)
|
|
122
|
+
{
|
|
123
|
+
Napi::Error::New(info.Env(), "It seems data-channel is destroyed!").ThrowAsJavaScriptException();
|
|
124
|
+
return info.Env().Null();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return Napi::Number::New(info.Env(), mDataChannelPtr->id());
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
Napi::Value DataChannelWrapper::getProtocol(const Napi::CallbackInfo &info)
|
|
131
|
+
{
|
|
132
|
+
if (!mDataChannelPtr)
|
|
133
|
+
{
|
|
134
|
+
Napi::Error::New(info.Env(), "It seems data-channel is destroyed!").ThrowAsJavaScriptException();
|
|
135
|
+
return info.Env().Null();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return Napi::String::New(info.Env(), mDataChannelPtr->protocol());
|
|
139
|
+
}
|
|
140
|
+
|
|
96
141
|
Napi::Value DataChannelWrapper::sendMessage(const Napi::CallbackInfo &info)
|
|
97
142
|
{
|
|
98
143
|
if (!mDataChannelPtr)
|
|
@@ -278,18 +323,7 @@ void DataChannelWrapper::onClosed(const Napi::CallbackInfo &info)
|
|
|
278
323
|
// Callback
|
|
279
324
|
mOnClosedCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
280
325
|
|
|
281
|
-
|
|
282
|
-
{
|
|
283
|
-
if (mOnClosedCallback)
|
|
284
|
-
mOnClosedCallback->call([this](Napi::Env env, std::vector<napi_value> &args) {
|
|
285
|
-
// Check the peer connection is not closed
|
|
286
|
-
if(instances.find(this) == instances.end())
|
|
287
|
-
throw ThreadSafeCallback::CancelException();
|
|
288
|
-
|
|
289
|
-
// This will run in main thread and needs to construct the
|
|
290
|
-
// arguments for the call
|
|
291
|
-
args = {};
|
|
292
|
-
}); });
|
|
326
|
+
// Object cb call moved to the constructor
|
|
293
327
|
}
|
|
294
328
|
|
|
295
329
|
void DataChannelWrapper::onError(const Napi::CallbackInfo &info)
|
|
@@ -23,6 +23,8 @@ public:
|
|
|
23
23
|
// Functions
|
|
24
24
|
void close(const Napi::CallbackInfo &info);
|
|
25
25
|
Napi::Value getLabel(const Napi::CallbackInfo &info);
|
|
26
|
+
Napi::Value getId(const Napi::CallbackInfo &info);
|
|
27
|
+
Napi::Value getProtocol(const Napi::CallbackInfo &info);
|
|
26
28
|
Napi::Value sendMessage(const Napi::CallbackInfo &info);
|
|
27
29
|
Napi::Value sendMessageBinary(const Napi::CallbackInfo &info);
|
|
28
30
|
Napi::Value isOpen(const Napi::CallbackInfo &info);
|
|
@@ -44,6 +46,7 @@ private:
|
|
|
44
46
|
static std::unordered_set<DataChannelWrapper*> instances;
|
|
45
47
|
|
|
46
48
|
void doClose();
|
|
49
|
+
void cleanCbsAndEraseInstance();
|
|
47
50
|
|
|
48
51
|
std::string mLabel;
|
|
49
52
|
std::shared_ptr<rtc::DataChannel> mDataChannelPtr = nullptr;
|
|
@@ -157,15 +157,15 @@ Napi::Value AudioWrapper::generateSdp(const Napi::CallbackInfo &info)
|
|
|
157
157
|
Napi::Env env = info.Env();
|
|
158
158
|
int length = info.Length();
|
|
159
159
|
|
|
160
|
-
if (length < 3 || !info[0].IsString() || !info[1].IsString() || !info[2].
|
|
160
|
+
if (length < 3 || !info[0].IsString() || !info[1].IsString() || !info[2].IsNumber())
|
|
161
161
|
{
|
|
162
|
-
Napi::TypeError::New(env, "We expect (String, String,
|
|
162
|
+
Napi::TypeError::New(env, "We expect (String, String, Number) as param").ThrowAsJavaScriptException();
|
|
163
163
|
return Napi::String::New(env, "");
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
std::string eol = info[0].As<Napi::String>().ToString();
|
|
167
167
|
std::string addr = info[1].As<Napi::String>().ToString();
|
|
168
|
-
|
|
168
|
+
uint16_t port = info[2].As<Napi::Number>().Uint32Value();
|
|
169
169
|
|
|
170
170
|
return Napi::String::New(env, mAudioPtr->generateSdp(eol, addr, port));
|
|
171
171
|
}
|
|
@@ -398,7 +398,7 @@ void AudioWrapper::setBitrate(const Napi::CallbackInfo &info)
|
|
|
398
398
|
Napi::Value AudioWrapper::getBitrate(const Napi::CallbackInfo &info)
|
|
399
399
|
{
|
|
400
400
|
|
|
401
|
-
return Napi::Number::New(info.Env(), mAudioPtr->
|
|
401
|
+
return Napi::Number::New(info.Env(), mAudioPtr->bitrate());
|
|
402
402
|
}
|
|
403
403
|
|
|
404
404
|
Napi::Value AudioWrapper::hasPayloadType(const Napi::CallbackInfo &info)
|
|
@@ -432,7 +432,7 @@ void AudioWrapper::addRTXCodec(const Napi::CallbackInfo &info)
|
|
|
432
432
|
unsigned int originalPayloadType = static_cast<unsigned int>(info[1].As<Napi::Number>().ToNumber());
|
|
433
433
|
unsigned int clockRate = static_cast<unsigned int>(info[2].As<Napi::Number>().ToNumber());
|
|
434
434
|
|
|
435
|
-
mAudioPtr->
|
|
435
|
+
mAudioPtr->addRtxCodec(payloadType, originalPayloadType, clockRate);
|
|
436
436
|
}
|
|
437
437
|
|
|
438
438
|
void AudioWrapper::addRTPMap(const Napi::CallbackInfo &info)
|
|
@@ -22,6 +22,7 @@ Napi::Object TrackWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
|
22
22
|
{
|
|
23
23
|
InstanceMethod("direction", &TrackWrapper::direction),
|
|
24
24
|
InstanceMethod("mid", &TrackWrapper::mid),
|
|
25
|
+
InstanceMethod("type", &TrackWrapper::type),
|
|
25
26
|
InstanceMethod("close", &TrackWrapper::close),
|
|
26
27
|
InstanceMethod("sendMessage", &TrackWrapper::sendMessage),
|
|
27
28
|
InstanceMethod("sendMessageBinary", &TrackWrapper::sendMessageBinary),
|
|
@@ -45,8 +46,26 @@ Napi::Object TrackWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
|
45
46
|
|
|
46
47
|
TrackWrapper::TrackWrapper(const Napi::CallbackInfo &info) : Napi::ObjectWrap<TrackWrapper>(info)
|
|
47
48
|
{
|
|
48
|
-
mTrackPtr = *(info[0].As<Napi::External<std::shared_ptr<rtc::Track>>>().Data());
|
|
49
|
+
mTrackPtr = *(info[0].As<Napi::External<std::shared_ptr<rtc::Track>>>().Data());
|
|
49
50
|
|
|
51
|
+
mTrackPtr->onClosed([&]()
|
|
52
|
+
{
|
|
53
|
+
if (mOnClosedCallback)
|
|
54
|
+
mOnClosedCallback->call([this](Napi::Env env, std::vector<napi_value> &args) {
|
|
55
|
+
// Check the peer connection is not closed
|
|
56
|
+
if(instances.find(this) == instances.end())
|
|
57
|
+
throw ThreadSafeCallback::CancelException();
|
|
58
|
+
|
|
59
|
+
cleanCbsAndEraseInstance();
|
|
60
|
+
|
|
61
|
+
// This will run in main thread and needs to construct the
|
|
62
|
+
// arguments for the call
|
|
63
|
+
args = {};
|
|
64
|
+
});
|
|
65
|
+
else {
|
|
66
|
+
cleanCbsAndEraseInstance();
|
|
67
|
+
} });
|
|
68
|
+
|
|
50
69
|
instances.insert(this);
|
|
51
70
|
}
|
|
52
71
|
|
|
@@ -57,19 +76,11 @@ TrackWrapper::~TrackWrapper()
|
|
|
57
76
|
|
|
58
77
|
void TrackWrapper::doClose()
|
|
59
78
|
{
|
|
60
|
-
instances.erase(this);
|
|
61
|
-
|
|
62
79
|
if (mTrackPtr)
|
|
63
80
|
{
|
|
64
81
|
try
|
|
65
82
|
{
|
|
66
|
-
mOnOpenCallback.reset();
|
|
67
|
-
mOnClosedCallback.reset();
|
|
68
|
-
mOnErrorCallback.reset();
|
|
69
|
-
mOnMessageCallback.reset();
|
|
70
|
-
|
|
71
83
|
mTrackPtr->close();
|
|
72
|
-
mTrackPtr.reset();
|
|
73
84
|
}
|
|
74
85
|
catch (std::exception &ex)
|
|
75
86
|
{
|
|
@@ -79,6 +90,17 @@ void TrackWrapper::doClose()
|
|
|
79
90
|
}
|
|
80
91
|
}
|
|
81
92
|
|
|
93
|
+
void TrackWrapper::cleanCbsAndEraseInstance()
|
|
94
|
+
{
|
|
95
|
+
mOnOpenCallback.reset();
|
|
96
|
+
mOnClosedCallback.reset();
|
|
97
|
+
mOnErrorCallback.reset();
|
|
98
|
+
mOnMessageCallback.reset();
|
|
99
|
+
|
|
100
|
+
instances.erase(this);
|
|
101
|
+
mTrackPtr.reset();
|
|
102
|
+
}
|
|
103
|
+
|
|
82
104
|
void TrackWrapper::close(const Napi::CallbackInfo &info)
|
|
83
105
|
{
|
|
84
106
|
doClose();
|
|
@@ -96,6 +118,12 @@ Napi::Value TrackWrapper::mid(const Napi::CallbackInfo &info)
|
|
|
96
118
|
return Napi::String::New(env, mTrackPtr->mid());
|
|
97
119
|
}
|
|
98
120
|
|
|
121
|
+
Napi::Value TrackWrapper::type(const Napi::CallbackInfo &info)
|
|
122
|
+
{
|
|
123
|
+
Napi::Env env = info.Env();
|
|
124
|
+
return Napi::String::New(env, mTrackPtr->description().type());
|
|
125
|
+
}
|
|
126
|
+
|
|
99
127
|
Napi::Value TrackWrapper::sendMessage(const Napi::CallbackInfo &info)
|
|
100
128
|
{
|
|
101
129
|
if (!mTrackPtr)
|
|
@@ -254,18 +282,7 @@ void TrackWrapper::onClosed(const Napi::CallbackInfo &info)
|
|
|
254
282
|
// Callback
|
|
255
283
|
mOnClosedCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
256
284
|
|
|
257
|
-
|
|
258
|
-
{
|
|
259
|
-
if (mOnClosedCallback)
|
|
260
|
-
mOnClosedCallback->call([this](Napi::Env env, std::vector<napi_value> &args) {
|
|
261
|
-
// Check the peer connection is not closed
|
|
262
|
-
if(instances.find(this) == instances.end())
|
|
263
|
-
throw ThreadSafeCallback::CancelException();
|
|
264
|
-
|
|
265
|
-
// This will run in main thread and needs to construct the
|
|
266
|
-
// arguments for the call
|
|
267
|
-
args = {};
|
|
268
|
-
}); });
|
|
285
|
+
// Object cb call moved to the constructor
|
|
269
286
|
}
|
|
270
287
|
|
|
271
288
|
void TrackWrapper::onError(const Napi::CallbackInfo &info)
|
|
@@ -323,6 +340,8 @@ void TrackWrapper::onMessage(const Napi::CallbackInfo &info)
|
|
|
323
340
|
Napi::Object payload = Napi::Object::New(env);
|
|
324
341
|
if (std::holds_alternative<std::string>(message))
|
|
325
342
|
{
|
|
343
|
+
// Track will always send message as binary
|
|
344
|
+
// So this code is not needed actually
|
|
326
345
|
args = {Napi::String::New(env, std::get<std::string>(message))};
|
|
327
346
|
}
|
|
328
347
|
else
|
|
@@ -23,6 +23,7 @@ public:
|
|
|
23
23
|
// Functions
|
|
24
24
|
Napi::Value direction(const Napi::CallbackInfo &info);
|
|
25
25
|
Napi::Value mid(const Napi::CallbackInfo &info);
|
|
26
|
+
Napi::Value type(const Napi::CallbackInfo &info);
|
|
26
27
|
void close(const Napi::CallbackInfo &info);
|
|
27
28
|
Napi::Value sendMessage(const Napi::CallbackInfo &info);
|
|
28
29
|
Napi::Value sendMessageBinary(const Napi::CallbackInfo &info);
|
|
@@ -45,6 +46,7 @@ private:
|
|
|
45
46
|
static std::unordered_set<TrackWrapper *> instances;
|
|
46
47
|
|
|
47
48
|
void doClose();
|
|
49
|
+
void cleanCbsAndEraseInstance();
|
|
48
50
|
|
|
49
51
|
std::shared_ptr<rtc::Track> mTrackPtr = nullptr;
|
|
50
52
|
|
|
@@ -190,15 +190,15 @@ Napi::Value VideoWrapper::generateSdp(const Napi::CallbackInfo &info)
|
|
|
190
190
|
Napi::Env env = info.Env();
|
|
191
191
|
int length = info.Length();
|
|
192
192
|
|
|
193
|
-
if (length < 3 || !info[0].IsString() || !info[1].IsString() || !info[2].
|
|
193
|
+
if (length < 3 || !info[0].IsString() || !info[1].IsString() || !info[2].IsNumber())
|
|
194
194
|
{
|
|
195
|
-
Napi::TypeError::New(env, "We expect (String, String,
|
|
195
|
+
Napi::TypeError::New(env, "We expect (String, String, Number) as param").ThrowAsJavaScriptException();
|
|
196
196
|
return Napi::String::New(env, "");
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
std::string eol = info[0].As<Napi::String>().ToString();
|
|
200
200
|
std::string addr = info[1].As<Napi::String>().ToString();
|
|
201
|
-
|
|
201
|
+
uint16_t port = info[2].As<Napi::Number>().Uint32Value();
|
|
202
202
|
|
|
203
203
|
return Napi::String::New(env, mVideoPtr->generateSdp(eol, addr, port));
|
|
204
204
|
}
|
|
@@ -431,7 +431,7 @@ void VideoWrapper::setBitrate(const Napi::CallbackInfo &info)
|
|
|
431
431
|
Napi::Value VideoWrapper::getBitrate(const Napi::CallbackInfo &info)
|
|
432
432
|
{
|
|
433
433
|
|
|
434
|
-
return Napi::Number::New(info.Env(), mVideoPtr->
|
|
434
|
+
return Napi::Number::New(info.Env(), mVideoPtr->bitrate());
|
|
435
435
|
}
|
|
436
436
|
|
|
437
437
|
Napi::Value VideoWrapper::hasPayloadType(const Napi::CallbackInfo &info)
|
|
@@ -465,7 +465,7 @@ void VideoWrapper::addRTXCodec(const Napi::CallbackInfo &info)
|
|
|
465
465
|
unsigned int originalPayloadType = static_cast<unsigned int>(info[1].As<Napi::Number>().ToNumber());
|
|
466
466
|
unsigned int clockRate = static_cast<unsigned int>(info[2].As<Napi::Number>().ToNumber());
|
|
467
467
|
|
|
468
|
-
mVideoPtr->
|
|
468
|
+
mVideoPtr->addRtxCodec(payloadType, originalPayloadType, clockRate);
|
|
469
469
|
}
|
|
470
470
|
|
|
471
471
|
void VideoWrapper::addRTPMap(const Napi::CallbackInfo &info)
|
|
@@ -147,10 +147,6 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
|
|
|
147
147
|
std::string strType = proxyServer.Get("type").As<Napi::String>().ToString();
|
|
148
148
|
rtc::ProxyServer::Type type = rtc::ProxyServer::Type::Http;
|
|
149
149
|
|
|
150
|
-
if (strType == "None")
|
|
151
|
-
type = rtc::ProxyServer::Type::None;
|
|
152
|
-
if (strType == "Http")
|
|
153
|
-
type = rtc::ProxyServer::Type::Http;
|
|
154
150
|
if (strType == "Socks5")
|
|
155
151
|
type = rtc::ProxyServer::Type::Socks5;
|
|
156
152
|
|
|
@@ -176,6 +172,14 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
|
|
|
176
172
|
if (config.Get("enableIceTcp").IsBoolean())
|
|
177
173
|
rtcConfig.enableIceTcp = config.Get("enableIceTcp").As<Napi::Boolean>();
|
|
178
174
|
|
|
175
|
+
// enableIceUdpMux option
|
|
176
|
+
if (config.Get("enableIceUdpMux").IsBoolean())
|
|
177
|
+
rtcConfig.enableIceUdpMux = config.Get("enableIceUdpMux").As<Napi::Boolean>();
|
|
178
|
+
|
|
179
|
+
// disableAutoNegotiation option
|
|
180
|
+
if (config.Get("disableAutoNegotiation").IsBoolean())
|
|
181
|
+
rtcConfig.disableAutoNegotiation = config.Get("disableAutoNegotiation").As<Napi::Boolean>();
|
|
182
|
+
|
|
179
183
|
// Max Message Size
|
|
180
184
|
if (config.Get("maxMessageSize").IsNumber())
|
|
181
185
|
rtcConfig.maxMessageSize = config.Get("maxMessageSize").As<Napi::Number>().Uint32Value();
|
|
@@ -211,6 +215,27 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
|
|
|
211
215
|
return;
|
|
212
216
|
}
|
|
213
217
|
|
|
218
|
+
mRtcPeerConnPtr->onStateChange([&](rtc::PeerConnection::State state) {
|
|
219
|
+
if (mOnStateChangeCallback)
|
|
220
|
+
mOnStateChangeCallback->call([this, state](Napi::Env env, std::vector<napi_value> &args) {
|
|
221
|
+
// Check the peer connection is not closed
|
|
222
|
+
if(instances.find(this) == instances.end())
|
|
223
|
+
throw ThreadSafeCallback::CancelException();
|
|
224
|
+
|
|
225
|
+
if(mDoCloseFlag && state == rtc::PeerConnection::State::Closed)
|
|
226
|
+
cleanCbsAndEraseInstance();
|
|
227
|
+
|
|
228
|
+
// This will run in main thread and needs to construct the
|
|
229
|
+
// arguments for the call
|
|
230
|
+
std::ostringstream stream;
|
|
231
|
+
stream << state;
|
|
232
|
+
args = {Napi::String::New(env, stream.str())};
|
|
233
|
+
});
|
|
234
|
+
else {
|
|
235
|
+
if(mDoCloseFlag && state == rtc::PeerConnection::State::Closed)
|
|
236
|
+
cleanCbsAndEraseInstance();
|
|
237
|
+
} });
|
|
238
|
+
|
|
214
239
|
instances.insert(this);
|
|
215
240
|
}
|
|
216
241
|
|
|
@@ -221,20 +246,14 @@ PeerConnectionWrapper::~PeerConnectionWrapper()
|
|
|
221
246
|
|
|
222
247
|
void PeerConnectionWrapper::doClose()
|
|
223
248
|
{
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (mRtcPeerConnPtr)
|
|
249
|
+
if (mRtcPeerConnPtr && !mDoCloseFlag)
|
|
227
250
|
{
|
|
228
251
|
try
|
|
229
252
|
{
|
|
230
|
-
|
|
231
|
-
mOnLocalCandidateCallback.reset();
|
|
232
|
-
mOnStateChangeCallback.reset();
|
|
233
|
-
mOnGatheringStateChangeCallback.reset();
|
|
234
|
-
mOnDataChannelCallback.reset();
|
|
235
|
-
mOnTrackCallback.reset();
|
|
236
|
-
|
|
253
|
+
mDoCloseFlag = true;
|
|
237
254
|
mRtcPeerConnPtr->close();
|
|
255
|
+
|
|
256
|
+
// Resetting in cleanCbsAndEraseInstance causes a deadlock
|
|
238
257
|
mRtcPeerConnPtr.reset();
|
|
239
258
|
}
|
|
240
259
|
catch (std::exception &ex)
|
|
@@ -245,6 +264,20 @@ void PeerConnectionWrapper::doClose()
|
|
|
245
264
|
}
|
|
246
265
|
}
|
|
247
266
|
|
|
267
|
+
void PeerConnectionWrapper::cleanCbsAndEraseInstance()
|
|
268
|
+
{
|
|
269
|
+
mOnLocalDescriptionCallback.reset();
|
|
270
|
+
mOnLocalCandidateCallback.reset();
|
|
271
|
+
mOnStateChangeCallback.reset();
|
|
272
|
+
mOnGatheringStateChangeCallback.reset();
|
|
273
|
+
mOnDataChannelCallback.reset();
|
|
274
|
+
mOnTrackCallback.reset();
|
|
275
|
+
|
|
276
|
+
instances.erase(this);
|
|
277
|
+
|
|
278
|
+
mDoCloseFlag = false;
|
|
279
|
+
}
|
|
280
|
+
|
|
248
281
|
void PeerConnectionWrapper::close(const Napi::CallbackInfo &info)
|
|
249
282
|
{
|
|
250
283
|
doClose();
|
|
@@ -598,19 +631,7 @@ void PeerConnectionWrapper::onStateChange(const Napi::CallbackInfo &info)
|
|
|
598
631
|
// Callback
|
|
599
632
|
mOnStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
600
633
|
|
|
601
|
-
|
|
602
|
-
if (mOnStateChangeCallback)
|
|
603
|
-
mOnStateChangeCallback->call([this, state](Napi::Env env, std::vector<napi_value> &args) {
|
|
604
|
-
// Check the peer connection is not closed
|
|
605
|
-
if(instances.find(this) == instances.end())
|
|
606
|
-
throw ThreadSafeCallback::CancelException();
|
|
607
|
-
|
|
608
|
-
// This will run in main thread and needs to construct the
|
|
609
|
-
// arguments for the call
|
|
610
|
-
std::ostringstream stream;
|
|
611
|
-
stream << state;
|
|
612
|
-
args = {Napi::String::New(env, stream.str())};
|
|
613
|
-
}); });
|
|
634
|
+
// onState cb will be called from constructor
|
|
614
635
|
}
|
|
615
636
|
|
|
616
637
|
void PeerConnectionWrapper::onSignalingStateChange(const Napi::CallbackInfo &info)
|
package/test/connectivity.js
CHANGED
|
@@ -66,6 +66,9 @@ peer2.onDataChannel((dc) => {
|
|
|
66
66
|
console.log('Peer2 Received Msg:', msg);
|
|
67
67
|
});
|
|
68
68
|
dc2.sendMessage("Hello From Peer2");
|
|
69
|
+
dc2.onClosed(() => {
|
|
70
|
+
console.log('dc2 closed');
|
|
71
|
+
});
|
|
69
72
|
});
|
|
70
73
|
|
|
71
74
|
// DataChannel Options
|
|
@@ -85,17 +88,14 @@ dc1.onOpen(() => {
|
|
|
85
88
|
dc1.onMessage((msg) => {
|
|
86
89
|
console.log('Peer1 Received Msg:', msg);
|
|
87
90
|
});
|
|
91
|
+
dc1.onClosed(() => {
|
|
92
|
+
console.log('dc1 closed');
|
|
93
|
+
});
|
|
88
94
|
|
|
89
95
|
setTimeout(() => {
|
|
90
96
|
dc1.close();
|
|
91
97
|
dc2.close();
|
|
92
98
|
peer1.close();
|
|
93
99
|
peer2.close();
|
|
94
|
-
dc1 = null;
|
|
95
|
-
dc2 = null;
|
|
96
|
-
peer1 = null;
|
|
97
|
-
peer2 = null;
|
|
98
100
|
nodeDataChannel.cleanup();
|
|
99
|
-
// No need for this (>= V0.1.14)
|
|
100
|
-
// process.exit();
|
|
101
101
|
}, 5 * 1000);
|
package/test/test.js
CHANGED
|
@@ -24,8 +24,11 @@ describe('PeerConnection Classes', () => {
|
|
|
24
24
|
|
|
25
25
|
test('Create Data Channel', () => {
|
|
26
26
|
let peer = new nodeDataChannel.PeerConnection("Peer", { iceServers: ["stun:stun.l.google.com:19302"] });
|
|
27
|
-
let dc = peer.createDataChannel('test');
|
|
27
|
+
let dc = peer.createDataChannel('test', { protocol: 'test-protocol' });
|
|
28
28
|
expect(dc).toBeDefined();
|
|
29
|
+
expect(dc.getId()).toBeDefined();
|
|
30
|
+
expect(dc.getProtocol()).toBe('test-protocol');
|
|
31
|
+
expect(dc.getLabel()).toBe('test');
|
|
29
32
|
expect(dc.onOpen).toBeDefined();
|
|
30
33
|
expect(dc.onMessage).toBeDefined();
|
|
31
34
|
|
|
@@ -184,9 +187,6 @@ describe('DataChannel streams', () => {
|
|
|
184
187
|
|
|
185
188
|
expect(await clientResponsePromise).toBe("test message");
|
|
186
189
|
|
|
187
|
-
clientChannel.close();
|
|
188
|
-
await new Promise((resolve) => echoStream.on('end', resolve));
|
|
189
|
-
|
|
190
190
|
clientPeer.close();
|
|
191
191
|
echoPeer.close();
|
|
192
192
|
});
|