node-datachannel 0.28.0 → 0.30.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/.clang-format +17 -0
- package/.prettierignore +3 -0
- package/API.md +30 -0
- package/BULDING.md +2 -1
- package/CMakeLists.txt +7 -2
- package/dist/cjs/lib/index.cjs +4 -1
- package/dist/cjs/lib/index.cjs.map +1 -1
- package/dist/cjs/polyfill/Events.cjs.map +1 -1
- package/dist/cjs/polyfill/RTCDataChannel.cjs +18 -5
- package/dist/cjs/polyfill/RTCDataChannel.cjs.map +1 -1
- package/dist/cjs/polyfill/RTCDtlsTransport.cjs.map +1 -1
- package/dist/cjs/polyfill/RTCPeerConnection.cjs +6 -1
- package/dist/cjs/polyfill/RTCPeerConnection.cjs.map +1 -1
- package/dist/cjs/polyfill/RTCSctpTransport.cjs.map +1 -1
- package/dist/esm/lib/index.mjs +4 -2
- package/dist/esm/lib/index.mjs.map +1 -1
- package/dist/esm/polyfill/Events.mjs.map +1 -1
- package/dist/esm/polyfill/RTCDataChannel.mjs +18 -5
- package/dist/esm/polyfill/RTCDataChannel.mjs.map +1 -1
- package/dist/esm/polyfill/RTCDtlsTransport.mjs.map +1 -1
- package/dist/esm/polyfill/RTCPeerConnection.mjs +6 -1
- package/dist/esm/polyfill/RTCPeerConnection.mjs.map +1 -1
- package/dist/esm/polyfill/RTCSctpTransport.mjs.map +1 -1
- package/dist/types/lib/index.d.ts +14 -3
- package/dist/types/lib/types.d.ts +24 -1
- package/dist/types/polyfill/RTCPeerConnection.d.ts +1 -2
- package/package.json +4 -2
- package/src/cpp/data-channel-wrapper.cpp +432 -411
- package/src/cpp/data-channel-wrapper.h +0 -2
- package/src/cpp/ice-udp-mux-listener-wrapper.cpp +157 -0
- package/src/cpp/ice-udp-mux-listener-wrapper.h +43 -0
- package/src/cpp/main.cpp +12 -10
- package/src/cpp/media-audio-wrapper.cpp +291 -294
- package/src/cpp/media-audio-wrapper.h +1 -3
- package/src/cpp/media-direction.cpp +32 -32
- package/src/cpp/media-direction.h +1 -1
- package/src/cpp/media-rtcpreceivingsession-wrapper.cpp +24 -28
- package/src/cpp/media-rtcpreceivingsession-wrapper.h +0 -5
- package/src/cpp/media-track-wrapper.cpp +350 -339
- package/src/cpp/media-track-wrapper.h +0 -3
- package/src/cpp/media-video-wrapper.cpp +312 -313
- package/src/cpp/media-video-wrapper.h +1 -3
- package/src/cpp/peer-connection-wrapper.cpp +1097 -984
- package/src/cpp/peer-connection-wrapper.h +1 -2
- package/src/cpp/rtc-wrapper.cpp +142 -138
- package/src/cpp/rtc-wrapper.h +8 -10
- package/src/cpp/thread-safe-callback.cpp +39 -50
- package/src/cpp/thread-safe-callback.h +26 -28
- package/src/cpp/web-socket-server-wrapper.cpp +205 -199
- package/src/cpp/web-socket-server-wrapper.h +0 -4
- package/src/cpp/web-socket-wrapper.cpp +625 -598
- package/src/cpp/web-socket-wrapper.h +0 -3
- package/src/lib/index.ts +14 -1
- package/src/lib/types.ts +26 -0
- package/src/polyfill/Events.ts +4 -1
- package/src/polyfill/RTCDataChannel.ts +24 -5
- package/src/polyfill/RTCDtlsTransport.ts +1 -1
- package/src/polyfill/RTCPeerConnection.ts +9 -3
- package/src/polyfill/RTCSctpTransport.ts +2 -2
|
@@ -17,1169 +17,1282 @@ std::unordered_set<PeerConnectionWrapper *> PeerConnectionWrapper::instances;
|
|
|
17
17
|
|
|
18
18
|
void PeerConnectionWrapper::CloseAll()
|
|
19
19
|
{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
PLOG_DEBUG << "CloseAll() called";
|
|
21
|
+
auto copy(instances);
|
|
22
|
+
for (auto inst : copy)
|
|
23
|
+
inst->doClose();
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
void PeerConnectionWrapper::CleanupAll()
|
|
27
27
|
{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
PLOG_DEBUG << "CleanupAll() called";
|
|
29
|
+
auto copy(instances);
|
|
30
|
+
for (auto inst : copy)
|
|
31
|
+
inst->doCleanup();
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
Napi::Object PeerConnectionWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
35
35
|
{
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
InstanceMethod("addRemoteCandidate", &PeerConnectionWrapper::addRemoteCandidate),
|
|
48
|
-
InstanceMethod("createDataChannel", &PeerConnectionWrapper::createDataChannel),
|
|
36
|
+
Napi::HandleScope scope(env);
|
|
37
|
+
|
|
38
|
+
Napi::Function func = DefineClass(env, "PeerConnection", {
|
|
39
|
+
InstanceMethod("close", &PeerConnectionWrapper::close),
|
|
40
|
+
InstanceMethod("setLocalDescription", &PeerConnectionWrapper::setLocalDescription),
|
|
41
|
+
InstanceMethod("setRemoteDescription", &PeerConnectionWrapper::setRemoteDescription),
|
|
42
|
+
InstanceMethod("localDescription", &PeerConnectionWrapper::localDescription),
|
|
43
|
+
InstanceMethod("remoteDescription", &PeerConnectionWrapper::remoteDescription),
|
|
44
|
+
InstanceMethod("remoteFingerprint", &PeerConnectionWrapper::remoteFingerprint),
|
|
45
|
+
InstanceMethod("addRemoteCandidate", &PeerConnectionWrapper::addRemoteCandidate),
|
|
46
|
+
InstanceMethod("createDataChannel", &PeerConnectionWrapper::createDataChannel),
|
|
49
47
|
|
|
50
48
|
#if RTC_ENABLE_MEDIA == 1
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
InstanceMethod("addTrack", &PeerConnectionWrapper::addTrack),
|
|
50
|
+
InstanceMethod("onTrack", &PeerConnectionWrapper::onTrack),
|
|
53
51
|
#endif
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
52
|
+
InstanceMethod("hasMedia", &PeerConnectionWrapper::hasMedia),
|
|
53
|
+
InstanceMethod("state", &PeerConnectionWrapper::state),
|
|
54
|
+
InstanceMethod("iceState", &PeerConnectionWrapper::iceState),
|
|
55
|
+
InstanceMethod("signalingState", &PeerConnectionWrapper::signalingState),
|
|
56
|
+
InstanceMethod("gatheringState", &PeerConnectionWrapper::gatheringState),
|
|
57
|
+
InstanceMethod("onLocalDescription", &PeerConnectionWrapper::onLocalDescription),
|
|
58
|
+
InstanceMethod("onLocalCandidate", &PeerConnectionWrapper::onLocalCandidate),
|
|
59
|
+
InstanceMethod("onStateChange", &PeerConnectionWrapper::onStateChange),
|
|
60
|
+
InstanceMethod("onIceStateChange", &PeerConnectionWrapper::onIceStateChange),
|
|
61
|
+
InstanceMethod("onSignalingStateChange", &PeerConnectionWrapper::onSignalingStateChange),
|
|
62
|
+
InstanceMethod("onGatheringStateChange", &PeerConnectionWrapper::onGatheringStateChange),
|
|
63
|
+
InstanceMethod("onDataChannel", &PeerConnectionWrapper::onDataChannel),
|
|
64
|
+
InstanceMethod("bytesSent", &PeerConnectionWrapper::bytesSent),
|
|
65
|
+
InstanceMethod("bytesReceived", &PeerConnectionWrapper::bytesReceived),
|
|
66
|
+
InstanceMethod("rtt", &PeerConnectionWrapper::rtt),
|
|
67
|
+
InstanceMethod("getSelectedCandidatePair", &PeerConnectionWrapper::getSelectedCandidatePair),
|
|
68
|
+
InstanceMethod("maxDataChannelId", &PeerConnectionWrapper::maxDataChannelId),
|
|
69
|
+
InstanceMethod("maxMessageSize", &PeerConnectionWrapper::maxMessageSize),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// If this is not the first call, we don't want to reassign the constructor (hot-reload problem)
|
|
73
|
+
if (constructor.IsEmpty())
|
|
74
|
+
{
|
|
75
|
+
constructor = Napi::Persistent(func);
|
|
76
|
+
constructor.SuppressDestruct();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
exports.Set("PeerConnection", func);
|
|
80
|
+
return exports;
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info)
|
|
83
|
+
PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info)
|
|
84
|
+
: Napi::ObjectWrap<PeerConnectionWrapper>(info)
|
|
86
85
|
{
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
86
|
+
PLOG_DEBUG << "Constructor called";
|
|
87
|
+
Napi::Env env = info.Env();
|
|
88
|
+
int length = info.Length();
|
|
89
|
+
|
|
90
|
+
// We expect (String, Object, Function) as param
|
|
91
|
+
if (length < 2 || !info[0].IsString() || !info[1].IsObject())
|
|
92
|
+
{
|
|
93
|
+
Napi::TypeError::New(env, "Peer Name (String) and Configuration (Object) expected").ThrowAsJavaScriptException();
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Peer Name
|
|
98
|
+
mPeerName = info[0].As<Napi::String>().ToString();
|
|
99
|
+
|
|
100
|
+
// Peer Config
|
|
101
|
+
rtc::Configuration rtcConfig;
|
|
102
|
+
Napi::Object config = info[1].As<Napi::Object>();
|
|
103
|
+
if (!config.Get("iceServers").IsArray())
|
|
104
|
+
{
|
|
105
|
+
Napi::TypeError::New(env, "iceServers(Array) expected").ThrowAsJavaScriptException();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
Napi::Array iceServers = config.Get("iceServers").As<Napi::Array>();
|
|
110
|
+
for (uint32_t i = 0; i < iceServers.Length(); i++)
|
|
111
|
+
{
|
|
112
|
+
if (iceServers.Get(i).IsString())
|
|
113
|
+
{
|
|
114
|
+
try
|
|
115
|
+
{
|
|
116
|
+
rtcConfig.iceServers.emplace_back(iceServers.Get(i).As<Napi::String>().ToString());
|
|
117
|
+
}
|
|
118
|
+
catch (std::exception &ex)
|
|
119
|
+
{
|
|
120
|
+
Napi::TypeError::New(env, "SyntaxError: IceServer config error: " + std::string(ex.what()))
|
|
121
|
+
.ThrowAsJavaScriptException();
|
|
95
122
|
return;
|
|
123
|
+
}
|
|
96
124
|
}
|
|
97
|
-
|
|
98
|
-
// Peer Name
|
|
99
|
-
mPeerName = info[0].As<Napi::String>().ToString();
|
|
100
|
-
|
|
101
|
-
// Peer Config
|
|
102
|
-
rtc::Configuration rtcConfig;
|
|
103
|
-
Napi::Object config = info[1].As<Napi::Object>();
|
|
104
|
-
if (!config.Get("iceServers").IsArray())
|
|
125
|
+
else
|
|
105
126
|
{
|
|
106
|
-
|
|
127
|
+
if (!iceServers.Get(i).IsObject())
|
|
128
|
+
{
|
|
129
|
+
Napi::TypeError::New(env, "IceServer config should be a string Or an object").ThrowAsJavaScriptException();
|
|
107
130
|
return;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Napi::Array iceServers = config.Get("iceServers").As<Napi::Array>();
|
|
111
|
-
for (uint32_t i = 0; i < iceServers.Length(); i++)
|
|
112
|
-
{
|
|
113
|
-
if (iceServers.Get(i).IsString()){
|
|
114
|
-
try
|
|
115
|
-
{
|
|
116
|
-
rtcConfig.iceServers.emplace_back(iceServers.Get(i).As<Napi::String>().ToString());
|
|
117
|
-
}
|
|
118
|
-
catch(std::exception &ex)
|
|
119
|
-
{
|
|
120
|
-
Napi::TypeError::New(env, "SyntaxError: IceServer config error: " + std::string(ex.what())).ThrowAsJavaScriptException();
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
else
|
|
125
|
-
{
|
|
126
|
-
if (!iceServers.Get(i).IsObject())
|
|
127
|
-
{
|
|
128
|
-
Napi::TypeError::New(env, "IceServer config should be a string Or an object").ThrowAsJavaScriptException();
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
Napi::Object iceServer = iceServers.Get(i).As<Napi::Object>();
|
|
133
|
-
if (!iceServer.Get("hostname").IsString() || !iceServer.Get("port").IsNumber())
|
|
134
|
-
{
|
|
135
|
-
Napi::TypeError::New(env, "IceServer config error (hostname OR/AND port is not suitable)").ThrowAsJavaScriptException();
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
if (iceServer.Get("relayType").IsString() &&
|
|
139
|
-
(!iceServer.Get("username").IsString() || !iceServer.Get("password").IsString()))
|
|
140
|
-
{
|
|
141
|
-
Napi::TypeError::New(env, "IceServer config error (username AND password is needed)").ThrowAsJavaScriptException();
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (iceServer.Get("relayType").IsString())
|
|
146
|
-
{
|
|
147
|
-
std::string relayTypeStr = iceServer.Get("relayType").As<Napi::String>();
|
|
148
|
-
rtc::IceServer::RelayType relayType = rtc::IceServer::RelayType::TurnUdp;
|
|
149
|
-
if (relayTypeStr.compare("TurnTcp") == 0)
|
|
150
|
-
relayType = rtc::IceServer::RelayType::TurnTcp;
|
|
151
|
-
if (relayTypeStr.compare("TurnTls") == 0)
|
|
152
|
-
relayType = rtc::IceServer::RelayType::TurnTls;
|
|
153
|
-
|
|
154
|
-
rtcConfig.iceServers.emplace_back(
|
|
155
|
-
rtc::IceServer(iceServer.Get("hostname").As<Napi::String>(),
|
|
156
|
-
uint16_t(iceServer.Get("port").As<Napi::Number>().Uint32Value()),
|
|
157
|
-
iceServer.Get("username").As<Napi::String>(),
|
|
158
|
-
iceServer.Get("password").As<Napi::String>(),
|
|
159
|
-
relayType));
|
|
160
|
-
}
|
|
161
|
-
else
|
|
162
|
-
{
|
|
163
|
-
rtcConfig.iceServers.emplace_back(
|
|
164
|
-
rtc::IceServer(
|
|
165
|
-
iceServer.Get("hostname").As<Napi::String>(),
|
|
166
|
-
uint16_t(iceServer.Get("port").As<Napi::Number>().Uint32Value())));
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// Proxy Server
|
|
172
|
-
if (config.Get("proxyServer").IsObject())
|
|
173
|
-
{
|
|
174
|
-
Napi::Object proxyServer = config.Get("proxyServer").As<Napi::Object>();
|
|
175
|
-
|
|
176
|
-
// IP
|
|
177
|
-
std::string ip = proxyServer.Get("ip").As<Napi::String>();
|
|
131
|
+
}
|
|
178
132
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
rtc::ProxyServer::Type type = rtc::ProxyServer::Type::Http;
|
|
185
|
-
|
|
186
|
-
if (strType == "Socks5")
|
|
187
|
-
type = rtc::ProxyServer::Type::Socks5;
|
|
188
|
-
|
|
189
|
-
// Username & Password
|
|
190
|
-
std::string username = "";
|
|
191
|
-
std::string password = "";
|
|
192
|
-
|
|
193
|
-
if (proxyServer.Get("username").IsString())
|
|
194
|
-
username = proxyServer.Get("username").As<Napi::String>().ToString();
|
|
195
|
-
if (proxyServer.Get("password").IsString())
|
|
196
|
-
username = proxyServer.Get("password").As<Napi::String>().ToString();
|
|
197
|
-
|
|
198
|
-
rtcConfig.proxyServer = rtc::ProxyServer(type, ip, port, username, password);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// bind address, libjuice only
|
|
202
|
-
if (config.Get("bindAddress").IsString())
|
|
203
|
-
rtcConfig.bindAddress = config.Get("bindAddress").As<Napi::String>().ToString();
|
|
204
|
-
|
|
205
|
-
// Port Ranges
|
|
206
|
-
if (config.Get("portRangeBegin").IsNumber())
|
|
207
|
-
rtcConfig.portRangeBegin = config.Get("portRangeBegin").As<Napi::Number>().Uint32Value();
|
|
208
|
-
if (config.Get("portRangeEnd").IsNumber())
|
|
209
|
-
rtcConfig.portRangeEnd = config.Get("portRangeEnd").As<Napi::Number>().Uint32Value();
|
|
210
|
-
|
|
211
|
-
// enableIceTcp option
|
|
212
|
-
if (config.Get("enableIceTcp").IsBoolean())
|
|
213
|
-
rtcConfig.enableIceTcp = config.Get("enableIceTcp").As<Napi::Boolean>();
|
|
214
|
-
|
|
215
|
-
// enableIceUdpMux option
|
|
216
|
-
if (config.Get("enableIceUdpMux").IsBoolean())
|
|
217
|
-
rtcConfig.enableIceUdpMux = config.Get("enableIceUdpMux").As<Napi::Boolean>();
|
|
218
|
-
|
|
219
|
-
// disableAutoNegotiation option
|
|
220
|
-
if (config.Get("disableAutoNegotiation").IsBoolean())
|
|
221
|
-
rtcConfig.disableAutoNegotiation = config.Get("disableAutoNegotiation").As<Napi::Boolean>();
|
|
222
|
-
|
|
223
|
-
// forceMediaTransport option
|
|
224
|
-
if (config.Get("forceMediaTransport").IsBoolean())
|
|
225
|
-
rtcConfig.forceMediaTransport = config.Get("forceMediaTransport").As<Napi::Boolean>();
|
|
226
|
-
|
|
227
|
-
// Max Message Size
|
|
228
|
-
if (config.Get("maxMessageSize").IsNumber())
|
|
229
|
-
rtcConfig.maxMessageSize = config.Get("maxMessageSize").As<Napi::Number>().Int32Value();
|
|
230
|
-
|
|
231
|
-
// MTU
|
|
232
|
-
if (config.Get("mtu").IsNumber())
|
|
233
|
-
rtcConfig.mtu = config.Get("mtu").As<Napi::Number>().Int32Value();
|
|
234
|
-
|
|
235
|
-
// ICE transport policy
|
|
236
|
-
if (!config.Get("iceTransportPolicy").IsUndefined())
|
|
237
|
-
{
|
|
238
|
-
if (!config.Get("iceTransportPolicy").IsString())
|
|
239
|
-
{
|
|
240
|
-
Napi::TypeError::New(env, "Invalid ICE transport policy, expected string").ThrowAsJavaScriptException();
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
std::string strPolicy = config.Get("iceTransportPolicy").As<Napi::String>().ToString();
|
|
244
|
-
if (strPolicy == "all")
|
|
245
|
-
rtcConfig.iceTransportPolicy = rtc::TransportPolicy::All;
|
|
246
|
-
else if (strPolicy == "relay")
|
|
247
|
-
rtcConfig.iceTransportPolicy = rtc::TransportPolicy::Relay;
|
|
248
|
-
else
|
|
249
|
-
{
|
|
250
|
-
Napi::TypeError::New(env, "Unknown ICE transport policy").ThrowAsJavaScriptException();
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// Allow skipping fingerprint validation
|
|
256
|
-
if (config.Get("disableFingerprintVerification").IsBoolean()) {
|
|
257
|
-
rtcConfig.disableFingerprintVerification = config.Get("disableFingerprintVerification").As<Napi::Boolean>();
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Create peer-connection
|
|
261
|
-
try
|
|
262
|
-
{
|
|
263
|
-
PLOG_DEBUG << "Creating a new Peer Connection";
|
|
264
|
-
mRtcPeerConnPtr = std::make_unique<rtc::PeerConnection>(rtcConfig);
|
|
265
|
-
}
|
|
266
|
-
catch (std::exception &ex)
|
|
267
|
-
{
|
|
268
|
-
Napi::Error::New(env, std::string("libdatachannel error while creating peer connection: ") + ex.what()).ThrowAsJavaScriptException();
|
|
133
|
+
Napi::Object iceServer = iceServers.Get(i).As<Napi::Object>();
|
|
134
|
+
if (!iceServer.Get("hostname").IsString() || !iceServer.Get("port").IsNumber())
|
|
135
|
+
{
|
|
136
|
+
Napi::TypeError::New(env, "IceServer config error (hostname OR/AND port is not suitable)")
|
|
137
|
+
.ThrowAsJavaScriptException();
|
|
269
138
|
return;
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
139
|
+
}
|
|
140
|
+
if (iceServer.Get("relayType").IsString() &&
|
|
141
|
+
(!iceServer.Get("username").IsString() || !iceServer.Get("password").IsString()))
|
|
142
|
+
{
|
|
143
|
+
Napi::TypeError::New(env, "IceServer config error (username AND password is needed)")
|
|
144
|
+
.ThrowAsJavaScriptException();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (iceServer.Get("relayType").IsString())
|
|
149
|
+
{
|
|
150
|
+
std::string relayTypeStr = iceServer.Get("relayType").As<Napi::String>();
|
|
151
|
+
rtc::IceServer::RelayType relayType = rtc::IceServer::RelayType::TurnUdp;
|
|
152
|
+
if (relayTypeStr.compare("TurnTcp") == 0)
|
|
153
|
+
relayType = rtc::IceServer::RelayType::TurnTcp;
|
|
154
|
+
if (relayTypeStr.compare("TurnTls") == 0)
|
|
155
|
+
relayType = rtc::IceServer::RelayType::TurnTls;
|
|
156
|
+
|
|
157
|
+
rtcConfig.iceServers.emplace_back(rtc::IceServer(
|
|
158
|
+
iceServer.Get("hostname").As<Napi::String>(),
|
|
159
|
+
uint16_t(iceServer.Get("port").As<Napi::Number>().Uint32Value()),
|
|
160
|
+
iceServer.Get("username").As<Napi::String>(), iceServer.Get("password").As<Napi::String>(), relayType));
|
|
161
|
+
}
|
|
162
|
+
else
|
|
163
|
+
{
|
|
164
|
+
rtcConfig.iceServers.emplace_back(
|
|
165
|
+
rtc::IceServer(iceServer.Get("hostname").As<Napi::String>(),
|
|
166
|
+
uint16_t(iceServer.Get("port").As<Napi::Number>().Uint32Value())));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Proxy Server
|
|
172
|
+
if (config.Get("proxyServer").IsObject())
|
|
173
|
+
{
|
|
174
|
+
Napi::Object proxyServer = config.Get("proxyServer").As<Napi::Object>();
|
|
175
|
+
|
|
176
|
+
// IP
|
|
177
|
+
std::string ip = proxyServer.Get("ip").As<Napi::String>();
|
|
178
|
+
|
|
179
|
+
// Port
|
|
180
|
+
uint16_t port = proxyServer.Get("port").As<Napi::Number>().Uint32Value();
|
|
181
|
+
|
|
182
|
+
// Type
|
|
183
|
+
std::string strType = proxyServer.Get("type").As<Napi::String>().ToString();
|
|
184
|
+
rtc::ProxyServer::Type type = rtc::ProxyServer::Type::Http;
|
|
185
|
+
|
|
186
|
+
if (strType == "Socks5")
|
|
187
|
+
type = rtc::ProxyServer::Type::Socks5;
|
|
188
|
+
|
|
189
|
+
// Username & Password
|
|
190
|
+
std::string username = "";
|
|
191
|
+
std::string password = "";
|
|
192
|
+
|
|
193
|
+
if (proxyServer.Get("username").IsString())
|
|
194
|
+
username = proxyServer.Get("username").As<Napi::String>().ToString();
|
|
195
|
+
if (proxyServer.Get("password").IsString())
|
|
196
|
+
password = proxyServer.Get("password").As<Napi::String>().ToString();
|
|
197
|
+
|
|
198
|
+
rtcConfig.proxyServer = rtc::ProxyServer(type, ip, port, username, password);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// bind address, libjuice only
|
|
202
|
+
if (config.Get("bindAddress").IsString())
|
|
203
|
+
rtcConfig.bindAddress = config.Get("bindAddress").As<Napi::String>().ToString();
|
|
204
|
+
|
|
205
|
+
// Port Ranges
|
|
206
|
+
if (config.Get("portRangeBegin").IsNumber())
|
|
207
|
+
rtcConfig.portRangeBegin = config.Get("portRangeBegin").As<Napi::Number>().Uint32Value();
|
|
208
|
+
if (config.Get("portRangeEnd").IsNumber())
|
|
209
|
+
rtcConfig.portRangeEnd = config.Get("portRangeEnd").As<Napi::Number>().Uint32Value();
|
|
210
|
+
|
|
211
|
+
// enableIceTcp option
|
|
212
|
+
if (config.Get("enableIceTcp").IsBoolean())
|
|
213
|
+
rtcConfig.enableIceTcp = config.Get("enableIceTcp").As<Napi::Boolean>();
|
|
214
|
+
|
|
215
|
+
// enableIceUdpMux option
|
|
216
|
+
if (config.Get("enableIceUdpMux").IsBoolean())
|
|
217
|
+
rtcConfig.enableIceUdpMux = config.Get("enableIceUdpMux").As<Napi::Boolean>();
|
|
218
|
+
|
|
219
|
+
// disableAutoNegotiation option
|
|
220
|
+
if (config.Get("disableAutoNegotiation").IsBoolean())
|
|
221
|
+
rtcConfig.disableAutoNegotiation = config.Get("disableAutoNegotiation").As<Napi::Boolean>();
|
|
222
|
+
|
|
223
|
+
// disableAutoGathering option
|
|
224
|
+
if (config.Get("disableAutoGathering").IsBoolean())
|
|
225
|
+
rtcConfig.disableAutoGathering = config.Get("disableAutoGathering").As<Napi::Boolean>();
|
|
226
|
+
|
|
227
|
+
// forceMediaTransport option
|
|
228
|
+
if (config.Get("forceMediaTransport").IsBoolean())
|
|
229
|
+
rtcConfig.forceMediaTransport = config.Get("forceMediaTransport").As<Napi::Boolean>();
|
|
230
|
+
|
|
231
|
+
// Max Message Size
|
|
232
|
+
if (config.Get("maxMessageSize").IsNumber())
|
|
233
|
+
rtcConfig.maxMessageSize = config.Get("maxMessageSize").As<Napi::Number>().Int32Value();
|
|
234
|
+
|
|
235
|
+
// MTU
|
|
236
|
+
if (config.Get("mtu").IsNumber())
|
|
237
|
+
rtcConfig.mtu = config.Get("mtu").As<Napi::Number>().Int32Value();
|
|
238
|
+
|
|
239
|
+
// ICE transport policy
|
|
240
|
+
if (!config.Get("iceTransportPolicy").IsUndefined())
|
|
241
|
+
{
|
|
242
|
+
if (!config.Get("iceTransportPolicy").IsString())
|
|
243
|
+
{
|
|
244
|
+
Napi::TypeError::New(env, "Invalid ICE transport policy, expected string").ThrowAsJavaScriptException();
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
std::string strPolicy = config.Get("iceTransportPolicy").As<Napi::String>().ToString();
|
|
248
|
+
if (strPolicy == "all")
|
|
249
|
+
rtcConfig.iceTransportPolicy = rtc::TransportPolicy::All;
|
|
250
|
+
else if (strPolicy == "relay")
|
|
251
|
+
rtcConfig.iceTransportPolicy = rtc::TransportPolicy::Relay;
|
|
252
|
+
else
|
|
253
|
+
{
|
|
254
|
+
Napi::TypeError::New(env, "Unknown ICE transport policy").ThrowAsJavaScriptException();
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Allow skipping fingerprint validation
|
|
260
|
+
if (config.Get("disableFingerprintVerification").IsBoolean())
|
|
261
|
+
{
|
|
262
|
+
rtcConfig.disableFingerprintVerification = config.Get("disableFingerprintVerification").As<Napi::Boolean>();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Specify certificate to use if set
|
|
266
|
+
if (config.Get("certificatePemFile").IsString())
|
|
267
|
+
{
|
|
268
|
+
rtcConfig.certificatePemFile = config.Get("certificatePemFile").As<Napi::String>().ToString();
|
|
269
|
+
}
|
|
270
|
+
if (config.Get("keyPemFile").IsString())
|
|
271
|
+
{
|
|
272
|
+
rtcConfig.keyPemFile = config.Get("keyPemFile").As<Napi::String>().ToString();
|
|
273
|
+
}
|
|
274
|
+
if (config.Get("keyPemPass").IsString())
|
|
275
|
+
{
|
|
276
|
+
rtcConfig.keyPemPass = config.Get("keyPemPass").As<Napi::String>().ToString();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Create peer-connection
|
|
280
|
+
try
|
|
281
|
+
{
|
|
282
|
+
PLOG_DEBUG << "Creating a new Peer Connection";
|
|
283
|
+
mRtcPeerConnPtr = std::make_unique<rtc::PeerConnection>(rtcConfig);
|
|
284
|
+
}
|
|
285
|
+
catch (std::exception &ex)
|
|
286
|
+
{
|
|
287
|
+
Napi::Error::New(env, std::string("libdatachannel error while creating peer connection: ") + ex.what())
|
|
288
|
+
.ThrowAsJavaScriptException();
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
PLOG_DEBUG << "Peer Connection created";
|
|
293
|
+
|
|
294
|
+
// State change callback must be set to trigger cleanup on close
|
|
295
|
+
mOnStateChangeCallback =
|
|
296
|
+
std::make_unique<ThreadSafeCallback>(Napi::Function::New(info.Env(), [](const Napi::CallbackInfo &) {}));
|
|
297
|
+
|
|
298
|
+
instances.insert(this);
|
|
278
299
|
}
|
|
279
300
|
|
|
280
301
|
PeerConnectionWrapper::~PeerConnectionWrapper()
|
|
281
302
|
{
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
303
|
+
PLOG_DEBUG << "Destructor called";
|
|
304
|
+
doCleanup();
|
|
305
|
+
doClose();
|
|
285
306
|
}
|
|
286
307
|
|
|
287
308
|
void PeerConnectionWrapper::doClose()
|
|
288
309
|
{
|
|
289
|
-
|
|
290
|
-
|
|
310
|
+
PLOG_DEBUG << "doClose() called";
|
|
311
|
+
if (mRtcPeerConnPtr)
|
|
312
|
+
{
|
|
313
|
+
PLOG_DEBUG << "Closing...";
|
|
314
|
+
try
|
|
291
315
|
{
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
{
|
|
295
|
-
mRtcPeerConnPtr->close();
|
|
296
|
-
mRtcPeerConnPtr.reset();
|
|
297
|
-
}
|
|
298
|
-
catch (std::exception &ex)
|
|
299
|
-
{
|
|
300
|
-
std::cerr << std::string("libdatachannel error while closing peer connection: ") + ex.what() << std::endl;
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
316
|
+
mRtcPeerConnPtr->close();
|
|
317
|
+
mRtcPeerConnPtr.reset();
|
|
303
318
|
}
|
|
319
|
+
catch (std::exception &ex)
|
|
320
|
+
{
|
|
321
|
+
std::cerr << std::string("libdatachannel error while closing peer connection: ") + ex.what() << std::endl;
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
304
325
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
326
|
+
mOnLocalDescriptionCallback.reset();
|
|
327
|
+
mOnLocalCandidateCallback.reset();
|
|
328
|
+
mOnIceStateChangeCallback.reset();
|
|
329
|
+
mOnSignalingStateChangeCallback.reset();
|
|
330
|
+
mOnGatheringStateChangeCallback.reset();
|
|
331
|
+
mOnDataChannelCallback.reset();
|
|
332
|
+
mOnTrackCallback.reset();
|
|
312
333
|
}
|
|
313
334
|
|
|
314
335
|
void PeerConnectionWrapper::close(const Napi::CallbackInfo &info)
|
|
315
336
|
{
|
|
316
|
-
|
|
317
|
-
|
|
337
|
+
PLOG_DEBUG << "close() called";
|
|
338
|
+
doClose();
|
|
318
339
|
}
|
|
319
340
|
|
|
320
341
|
void PeerConnectionWrapper::doCleanup()
|
|
321
342
|
{
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
343
|
+
PLOG_DEBUG << "doCleanup() called";
|
|
344
|
+
mOnStateChangeCallback.reset();
|
|
345
|
+
instances.erase(this);
|
|
325
346
|
}
|
|
326
347
|
|
|
327
348
|
void PeerConnectionWrapper::setLocalDescription(const Napi::CallbackInfo &info)
|
|
328
349
|
{
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
350
|
+
PLOG_DEBUG << "setLocalDescription() called";
|
|
351
|
+
Napi::Env env = info.Env();
|
|
352
|
+
int length = info.Length();
|
|
353
|
+
|
|
354
|
+
if (!mRtcPeerConnPtr)
|
|
355
|
+
{
|
|
356
|
+
Napi::Error::New(env, "setLocalDescription() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
rtc::Description::Type type = rtc::Description::Type::Unspec;
|
|
361
|
+
rtc::LocalDescriptionInit init;
|
|
362
|
+
|
|
363
|
+
// optional
|
|
364
|
+
if (length > 0)
|
|
365
|
+
{
|
|
366
|
+
if (!info[0].IsString())
|
|
367
|
+
{
|
|
368
|
+
Napi::TypeError::New(env, "type (String) expected").ThrowAsJavaScriptException();
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
std::string typeStr = info[0].As<Napi::String>().ToString();
|
|
372
|
+
|
|
373
|
+
// Accept uppercase first letter for backward compatibility
|
|
374
|
+
if (typeStr.size() > 0)
|
|
375
|
+
typeStr[0] = std::tolower(typeStr[0]);
|
|
376
|
+
|
|
377
|
+
if (typeStr == "answer")
|
|
378
|
+
type = rtc::Description::Type::Answer;
|
|
379
|
+
else if (typeStr == "offer")
|
|
380
|
+
type = rtc::Description::Type::Offer;
|
|
381
|
+
else if (typeStr == "pranswer")
|
|
382
|
+
type = rtc::Description::Type::Pranswer;
|
|
383
|
+
else if (typeStr == "rollback")
|
|
384
|
+
type = rtc::Description::Type::Rollback;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// optional
|
|
388
|
+
if (length > 1)
|
|
389
|
+
{
|
|
390
|
+
PLOG_DEBUG << "setLocalDescription() called with LocalDescriptionInit";
|
|
391
|
+
|
|
392
|
+
if (info[1].IsObject())
|
|
393
|
+
{
|
|
394
|
+
PLOG_DEBUG << "setLocalDescription() called with LocalDescriptionInit as object";
|
|
395
|
+
Napi::Object obj = info[1].As<Napi::Object>();
|
|
396
|
+
|
|
397
|
+
if (obj.Get("iceUfrag").IsString())
|
|
398
|
+
{
|
|
399
|
+
PLOG_DEBUG << "setLocalDescription() has ufrag";
|
|
400
|
+
init.iceUfrag = obj.Get("iceUfrag").As<Napi::String>();
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (obj.Get("icePwd").IsString())
|
|
404
|
+
{
|
|
405
|
+
PLOG_DEBUG << "setLocalDescription() has password";
|
|
406
|
+
init.icePwd = obj.Get("icePwd").As<Napi::String>();
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
mRtcPeerConnPtr->setLocalDescription(type, init);
|
|
366
412
|
}
|
|
367
413
|
|
|
368
414
|
void PeerConnectionWrapper::setRemoteDescription(const Napi::CallbackInfo &info)
|
|
369
415
|
{
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
416
|
+
PLOG_DEBUG << "setRemoteDescription() called";
|
|
417
|
+
Napi::Env env = info.Env();
|
|
418
|
+
int length = info.Length();
|
|
419
|
+
|
|
420
|
+
if (!mRtcPeerConnPtr)
|
|
421
|
+
{
|
|
422
|
+
Napi::Error::New(env, "setRemoteDescription() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
if (length < 2 || !info[0].IsString() || !info[1].IsString())
|
|
427
|
+
{
|
|
428
|
+
Napi::TypeError::New(info.Env(), "String,String expected").ThrowAsJavaScriptException();
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
std::string sdp = info[0].As<Napi::String>().ToString();
|
|
433
|
+
std::string type = info[1].As<Napi::String>().ToString();
|
|
434
|
+
|
|
435
|
+
try
|
|
436
|
+
{
|
|
437
|
+
rtc::Description desc(sdp, type);
|
|
438
|
+
mRtcPeerConnPtr->setRemoteDescription(desc);
|
|
439
|
+
}
|
|
440
|
+
catch (std::exception &ex)
|
|
441
|
+
{
|
|
442
|
+
Napi::Error::New(env, std::string("libdatachannel error while adding remote description: ") + ex.what())
|
|
443
|
+
.ThrowAsJavaScriptException();
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
399
446
|
}
|
|
400
447
|
|
|
401
448
|
Napi::Value PeerConnectionWrapper::localDescription(const Napi::CallbackInfo &info)
|
|
402
449
|
{
|
|
403
|
-
|
|
404
|
-
|
|
450
|
+
PLOG_DEBUG << "localDescription() called";
|
|
451
|
+
Napi::Env env = info.Env();
|
|
405
452
|
|
|
406
|
-
|
|
453
|
+
std::optional<rtc::Description> desc = mRtcPeerConnPtr ? mRtcPeerConnPtr->localDescription() : std::nullopt;
|
|
407
454
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
455
|
+
// Return JS null if no description
|
|
456
|
+
if (!desc.has_value())
|
|
457
|
+
{
|
|
458
|
+
return env.Null();
|
|
459
|
+
}
|
|
413
460
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
461
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
462
|
+
obj.Set("type", desc->typeString());
|
|
463
|
+
obj.Set("sdp", desc.value());
|
|
464
|
+
return obj;
|
|
418
465
|
}
|
|
419
466
|
|
|
420
467
|
Napi::Value PeerConnectionWrapper::remoteDescription(const Napi::CallbackInfo &info)
|
|
421
468
|
{
|
|
422
|
-
|
|
469
|
+
Napi::Env env = info.Env();
|
|
423
470
|
|
|
424
|
-
|
|
471
|
+
std::optional<rtc::Description> desc = mRtcPeerConnPtr ? mRtcPeerConnPtr->remoteDescription() : std::nullopt;
|
|
425
472
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
473
|
+
// Return JS null if no description
|
|
474
|
+
if (!desc.has_value())
|
|
475
|
+
{
|
|
476
|
+
return env.Null();
|
|
477
|
+
}
|
|
431
478
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
479
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
480
|
+
obj.Set("type", desc->typeString());
|
|
481
|
+
obj.Set("sdp", desc.value());
|
|
482
|
+
return obj;
|
|
436
483
|
}
|
|
437
484
|
|
|
438
485
|
void PeerConnectionWrapper::addRemoteCandidate(const Napi::CallbackInfo &info)
|
|
439
486
|
{
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
487
|
+
PLOG_DEBUG << "addRemoteCandidate() called";
|
|
488
|
+
Napi::Env env = info.Env();
|
|
489
|
+
int length = info.Length();
|
|
490
|
+
|
|
491
|
+
if (!mRtcPeerConnPtr)
|
|
492
|
+
{
|
|
493
|
+
Napi::Error::New(env, "addRemoteCandidate() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (length < 2 || !info[0].IsString() || !info[1].IsString())
|
|
498
|
+
{
|
|
499
|
+
Napi::TypeError::New(info.Env(), "String, String expected").ThrowAsJavaScriptException();
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
try
|
|
504
|
+
{
|
|
505
|
+
std::string candidate = info[0].As<Napi::String>().ToString();
|
|
506
|
+
std::string mid = info[1].As<Napi::String>().ToString();
|
|
507
|
+
mRtcPeerConnPtr->addRemoteCandidate(rtc::Candidate(candidate, mid));
|
|
508
|
+
}
|
|
509
|
+
catch (std::exception &ex)
|
|
510
|
+
{
|
|
511
|
+
Napi::Error::New(env, std::string("libdatachannel error while adding remote candidate: ") + ex.what())
|
|
512
|
+
.ThrowAsJavaScriptException();
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
443
516
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
517
|
+
Napi::Value PeerConnectionWrapper::createDataChannel(const Napi::CallbackInfo &info)
|
|
518
|
+
{
|
|
519
|
+
PLOG_DEBUG << "createDataChannel() called";
|
|
520
|
+
Napi::Env env = info.Env();
|
|
521
|
+
int length = info.Length();
|
|
449
522
|
|
|
450
|
-
|
|
523
|
+
if (!mRtcPeerConnPtr)
|
|
524
|
+
{
|
|
525
|
+
Napi::Error::New(env, "createDataChannel() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
526
|
+
return info.Env().Null();
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (length < 1 || !info[0].IsString())
|
|
530
|
+
{
|
|
531
|
+
Napi::TypeError::New(env, "Data Channel Label expected").ThrowAsJavaScriptException();
|
|
532
|
+
return info.Env().Null();
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// Optional Params
|
|
536
|
+
rtc::DataChannelInit init;
|
|
537
|
+
if (length > 1)
|
|
538
|
+
{
|
|
539
|
+
if (!info[1].IsObject())
|
|
451
540
|
{
|
|
452
|
-
|
|
453
|
-
|
|
541
|
+
Napi::TypeError::New(env, "Data Channel Init Config expected(As Object)").ThrowAsJavaScriptException();
|
|
542
|
+
return info.Env().Null();
|
|
454
543
|
}
|
|
455
544
|
|
|
456
|
-
|
|
545
|
+
Napi::Object initConfig = info[1].As<Napi::Object>();
|
|
546
|
+
|
|
547
|
+
if (!initConfig.Get("protocol").IsUndefined())
|
|
457
548
|
{
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
549
|
+
if (!initConfig.Get("protocol").IsString())
|
|
550
|
+
{
|
|
551
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config (protocol)").ThrowAsJavaScriptException();
|
|
552
|
+
return info.Env().Null();
|
|
553
|
+
}
|
|
554
|
+
init.protocol = initConfig.Get("protocol").As<Napi::String>();
|
|
461
555
|
}
|
|
462
|
-
|
|
556
|
+
|
|
557
|
+
if (!initConfig.Get("negotiated").IsUndefined())
|
|
463
558
|
{
|
|
464
|
-
|
|
465
|
-
|
|
559
|
+
if (!initConfig.Get("negotiated").IsBoolean())
|
|
560
|
+
{
|
|
561
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config (negotiated)").ThrowAsJavaScriptException();
|
|
562
|
+
return info.Env().Null();
|
|
563
|
+
}
|
|
564
|
+
init.negotiated = initConfig.Get("negotiated").As<Napi::Boolean>();
|
|
466
565
|
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
Napi::Value PeerConnectionWrapper::createDataChannel(const Napi::CallbackInfo &info)
|
|
470
|
-
{
|
|
471
|
-
PLOG_DEBUG << "createDataChannel() called";
|
|
472
|
-
Napi::Env env = info.Env();
|
|
473
|
-
int length = info.Length();
|
|
474
566
|
|
|
475
|
-
if (!
|
|
567
|
+
if (!initConfig.Get("id").IsUndefined())
|
|
476
568
|
{
|
|
477
|
-
|
|
569
|
+
if (!initConfig.Get("id").IsNumber())
|
|
570
|
+
{
|
|
571
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config (id)").ThrowAsJavaScriptException();
|
|
478
572
|
return info.Env().Null();
|
|
573
|
+
}
|
|
574
|
+
init.id = uint16_t(initConfig.Get("id").As<Napi::Number>().Uint32Value());
|
|
479
575
|
}
|
|
480
576
|
|
|
481
|
-
|
|
577
|
+
// Reliability.unordered parameter
|
|
578
|
+
if (!initConfig.Get("unordered").IsUndefined())
|
|
482
579
|
{
|
|
483
|
-
|
|
580
|
+
if (!initConfig.Get("unordered").IsBoolean())
|
|
581
|
+
{
|
|
582
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config (unordered)").ThrowAsJavaScriptException();
|
|
484
583
|
return info.Env().Null();
|
|
584
|
+
}
|
|
585
|
+
init.reliability.unordered = initConfig.Get("unordered").As<Napi::Boolean>();
|
|
485
586
|
}
|
|
486
587
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
if (length > 1)
|
|
588
|
+
if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull() &&
|
|
589
|
+
!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
|
|
490
590
|
{
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
return info.Env().Null();
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
Napi::Object initConfig = info[1].As<Napi::Object>();
|
|
498
|
-
|
|
499
|
-
if (!initConfig.Get("protocol").IsUndefined())
|
|
500
|
-
{
|
|
501
|
-
if (!initConfig.Get("protocol").IsString())
|
|
502
|
-
{
|
|
503
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (protocol)").ThrowAsJavaScriptException();
|
|
504
|
-
return info.Env().Null();
|
|
505
|
-
}
|
|
506
|
-
init.protocol = initConfig.Get("protocol").As<Napi::String>();
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
if (!initConfig.Get("negotiated").IsUndefined())
|
|
510
|
-
{
|
|
511
|
-
if (!initConfig.Get("negotiated").IsBoolean())
|
|
512
|
-
{
|
|
513
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (negotiated)").ThrowAsJavaScriptException();
|
|
514
|
-
return info.Env().Null();
|
|
515
|
-
}
|
|
516
|
-
init.negotiated = initConfig.Get("negotiated").As<Napi::Boolean>();
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
if (!initConfig.Get("id").IsUndefined())
|
|
520
|
-
{
|
|
521
|
-
if (!initConfig.Get("id").IsNumber())
|
|
522
|
-
{
|
|
523
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (id)").ThrowAsJavaScriptException();
|
|
524
|
-
return info.Env().Null();
|
|
525
|
-
}
|
|
526
|
-
init.id = uint16_t(initConfig.Get("id").As<Napi::Number>().Uint32Value());
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
// Reliability.unordered parameter
|
|
530
|
-
if (!initConfig.Get("unordered").IsUndefined())
|
|
531
|
-
{
|
|
532
|
-
if (!initConfig.Get("unordered").IsBoolean())
|
|
533
|
-
{
|
|
534
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (unordered)").ThrowAsJavaScriptException();
|
|
535
|
-
return info.Env().Null();
|
|
536
|
-
}
|
|
537
|
-
init.reliability.unordered = !initConfig.Get("unordered").As<Napi::Boolean>();
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull() &&
|
|
541
|
-
!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
|
|
542
|
-
{
|
|
543
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config, maxPacketLifeTime and maxRetransmits are exclusive").ThrowAsJavaScriptException();
|
|
544
|
-
return info.Env().Null();
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull())
|
|
548
|
-
{
|
|
549
|
-
if (!initConfig.Get("maxPacketLifeTime").IsNumber())
|
|
550
|
-
{
|
|
551
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (maxPacketLifeTime)").ThrowAsJavaScriptException();
|
|
552
|
-
return info.Env().Null();
|
|
553
|
-
}
|
|
554
|
-
init.reliability.maxPacketLifeTime = std::chrono::milliseconds(initConfig.Get("maxPacketLifeTime").As<Napi::Number>().Uint32Value());
|
|
555
|
-
}
|
|
556
|
-
else if (!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
|
|
557
|
-
{
|
|
558
|
-
if (!initConfig.Get("maxRetransmits").IsNumber())
|
|
559
|
-
{
|
|
560
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (maxRetransmits)").ThrowAsJavaScriptException();
|
|
561
|
-
return info.Env().Null();
|
|
562
|
-
}
|
|
563
|
-
init.reliability.maxRetransmits = int(initConfig.Get("maxRetransmits").As<Napi::Number>().Int32Value());
|
|
564
|
-
}
|
|
591
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config, maxPacketLifeTime and maxRetransmits are exclusive")
|
|
592
|
+
.ThrowAsJavaScriptException();
|
|
593
|
+
return info.Env().Null();
|
|
565
594
|
}
|
|
566
595
|
|
|
567
|
-
|
|
596
|
+
if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull())
|
|
568
597
|
{
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
598
|
+
if (!initConfig.Get("maxPacketLifeTime").IsNumber())
|
|
599
|
+
{
|
|
600
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config (maxPacketLifeTime)").ThrowAsJavaScriptException();
|
|
601
|
+
return info.Env().Null();
|
|
602
|
+
}
|
|
603
|
+
init.reliability.maxPacketLifeTime =
|
|
604
|
+
std::chrono::milliseconds(initConfig.Get("maxPacketLifeTime").As<Napi::Number>().Uint32Value());
|
|
574
605
|
}
|
|
575
|
-
|
|
606
|
+
else if (!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
|
|
576
607
|
{
|
|
577
|
-
|
|
608
|
+
if (!initConfig.Get("maxRetransmits").IsNumber())
|
|
609
|
+
{
|
|
610
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config (maxRetransmits)").ThrowAsJavaScriptException();
|
|
578
611
|
return info.Env().Null();
|
|
579
|
-
|
|
612
|
+
}
|
|
613
|
+
init.reliability.maxRetransmits = int(initConfig.Get("maxRetransmits").As<Napi::Number>().Int32Value());
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
try
|
|
618
|
+
{
|
|
619
|
+
std::string label = info[0].As<Napi::String>().ToString();
|
|
620
|
+
std::shared_ptr<rtc::DataChannel> dataChannel = mRtcPeerConnPtr->createDataChannel(label, std::move(init));
|
|
621
|
+
auto instance = DataChannelWrapper::constructor.New(
|
|
622
|
+
{Napi::External<std::shared_ptr<rtc::DataChannel>>::New(info.Env(), &dataChannel)});
|
|
623
|
+
PLOG_DEBUG << "Data Channel created. Label: " << label;
|
|
624
|
+
return instance;
|
|
625
|
+
}
|
|
626
|
+
catch (std::exception &ex)
|
|
627
|
+
{
|
|
628
|
+
Napi::Error::New(env, std::string("libdatachannel error while creating datachannel: ") + ex.what())
|
|
629
|
+
.ThrowAsJavaScriptException();
|
|
630
|
+
return info.Env().Null();
|
|
631
|
+
}
|
|
580
632
|
}
|
|
581
633
|
|
|
582
634
|
void PeerConnectionWrapper::onLocalDescription(const Napi::CallbackInfo &info)
|
|
583
635
|
{
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
636
|
+
PLOG_DEBUG << "onLocalDescription() called";
|
|
637
|
+
Napi::Env env = info.Env();
|
|
638
|
+
int length = info.Length();
|
|
639
|
+
|
|
640
|
+
if (!mRtcPeerConnPtr)
|
|
641
|
+
{
|
|
642
|
+
Napi::Error::New(env, "onLocalDescription() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (length < 1 || !info[0].IsFunction())
|
|
647
|
+
{
|
|
648
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Callback
|
|
653
|
+
mOnLocalDescriptionCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
654
|
+
|
|
655
|
+
mRtcPeerConnPtr->onLocalDescription(
|
|
656
|
+
[&](rtc::Description sdp)
|
|
657
|
+
{
|
|
658
|
+
PLOG_DEBUG << "onLocalDescription cb received from rtc";
|
|
659
|
+
if (mOnLocalDescriptionCallback)
|
|
660
|
+
mOnLocalDescriptionCallback->call(
|
|
661
|
+
[this, sdp = std::move(sdp)](Napi::Env env, std::vector<napi_value> &args)
|
|
662
|
+
{
|
|
663
|
+
PLOG_DEBUG << "mOnLocalDescriptionCallback call(1)";
|
|
664
|
+
// Check the peer connection is not closed
|
|
665
|
+
if (instances.find(this) == instances.end())
|
|
666
|
+
throw ThreadSafeCallback::CancelException();
|
|
667
|
+
|
|
668
|
+
// This will run in main thread and needs to construct the
|
|
669
|
+
// arguments for the call
|
|
670
|
+
args = {Napi::String::New(env, std::string(sdp)), Napi::String::New(env, sdp.typeString())};
|
|
671
|
+
PLOG_DEBUG << "mOnLocalDescriptionCallback call(2)";
|
|
672
|
+
});
|
|
673
|
+
});
|
|
620
674
|
}
|
|
621
675
|
|
|
622
676
|
void PeerConnectionWrapper::onLocalCandidate(const Napi::CallbackInfo &info)
|
|
623
677
|
{
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
678
|
+
PLOG_DEBUG << "onLocalCandidate() called";
|
|
679
|
+
Napi::Env env = info.Env();
|
|
680
|
+
int length = info.Length();
|
|
681
|
+
|
|
682
|
+
if (!mRtcPeerConnPtr)
|
|
683
|
+
{
|
|
684
|
+
Napi::Error::New(env, "onLocalCandidate() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (length < 1 || !info[0].IsFunction())
|
|
689
|
+
{
|
|
690
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// Callback
|
|
695
|
+
mOnLocalCandidateCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
696
|
+
|
|
697
|
+
mRtcPeerConnPtr->onLocalCandidate(
|
|
698
|
+
[&](rtc::Candidate cand)
|
|
699
|
+
{
|
|
700
|
+
PLOG_DEBUG << "onLocalCandidate cb received from rtc";
|
|
701
|
+
if (mOnLocalCandidateCallback)
|
|
702
|
+
mOnLocalCandidateCallback->call(
|
|
703
|
+
[this, cand = std::move(cand)](Napi::Env env, std::vector<napi_value> &args)
|
|
704
|
+
{
|
|
705
|
+
PLOG_DEBUG << "mOnLocalCandidateCallback call(1)";
|
|
706
|
+
// Check the peer connection is not closed
|
|
707
|
+
if (instances.find(this) == instances.end())
|
|
708
|
+
throw ThreadSafeCallback::CancelException();
|
|
709
|
+
|
|
710
|
+
// This will run in main thread and needs to construct the
|
|
711
|
+
// arguments for the call
|
|
712
|
+
args = {Napi::String::New(env, std::string(cand)), Napi::String::New(env, cand.mid())};
|
|
713
|
+
PLOG_DEBUG << "mOnLocalCandidateCallback call(2)";
|
|
714
|
+
});
|
|
715
|
+
});
|
|
660
716
|
}
|
|
661
717
|
|
|
662
718
|
void PeerConnectionWrapper::onStateChange(const Napi::CallbackInfo &info)
|
|
663
719
|
{
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
720
|
+
PLOG_DEBUG << "onStateChange() called";
|
|
721
|
+
Napi::Env env = info.Env();
|
|
722
|
+
int length = info.Length();
|
|
723
|
+
|
|
724
|
+
if (!mRtcPeerConnPtr)
|
|
725
|
+
{
|
|
726
|
+
Napi::Error::New(env, "onStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
if (length < 1 || !info[0].IsFunction())
|
|
731
|
+
{
|
|
732
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// Callback
|
|
737
|
+
mOnStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
738
|
+
|
|
739
|
+
mRtcPeerConnPtr->onStateChange(
|
|
740
|
+
[&](rtc::PeerConnection::State state)
|
|
741
|
+
{
|
|
742
|
+
PLOG_DEBUG << "onStateChange cb received from rtc";
|
|
743
|
+
if (mOnStateChangeCallback)
|
|
744
|
+
mOnStateChangeCallback->call(
|
|
745
|
+
[this, state](Napi::Env env, std::vector<napi_value> &args)
|
|
746
|
+
{
|
|
747
|
+
PLOG_DEBUG << "mOnStateChangeCallback call(1)";
|
|
748
|
+
if (instances.find(this) == instances.end())
|
|
749
|
+
throw ThreadSafeCallback::CancelException();
|
|
750
|
+
|
|
751
|
+
// This will run in main thread and needs to construct the
|
|
752
|
+
// arguments for the call
|
|
753
|
+
std::ostringstream stream;
|
|
754
|
+
stream << state;
|
|
755
|
+
args = {Napi::String::New(env, stream.str())};
|
|
756
|
+
PLOG_DEBUG << "mOnStateChangeCallback call(2)";
|
|
757
|
+
},
|
|
758
|
+
[this, state]()
|
|
759
|
+
{
|
|
760
|
+
PLOG_DEBUG << "mOnStateChangeCallback cleanup";
|
|
761
|
+
// Special case for closed state, we need to reset all callbacks
|
|
762
|
+
if (state == rtc::PeerConnection::State::Closed)
|
|
763
|
+
{
|
|
764
|
+
doCleanup();
|
|
765
|
+
}
|
|
766
|
+
});
|
|
767
|
+
});
|
|
706
768
|
}
|
|
707
769
|
|
|
708
770
|
void PeerConnectionWrapper::onIceStateChange(const Napi::CallbackInfo &info)
|
|
709
771
|
{
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
772
|
+
PLOG_DEBUG << "onIceStateChange() called";
|
|
773
|
+
Napi::Env env = info.Env();
|
|
774
|
+
int length = info.Length();
|
|
775
|
+
|
|
776
|
+
if (!mRtcPeerConnPtr)
|
|
777
|
+
{
|
|
778
|
+
Napi::Error::New(env, "onIceStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
if (length < 1 || !info[0].IsFunction())
|
|
783
|
+
{
|
|
784
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Callback
|
|
789
|
+
mOnIceStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
790
|
+
|
|
791
|
+
mRtcPeerConnPtr->onIceStateChange(
|
|
792
|
+
[&](rtc::PeerConnection::IceState state)
|
|
793
|
+
{
|
|
794
|
+
PLOG_DEBUG << "onIceStateChange cb received from rtc";
|
|
795
|
+
if (mOnIceStateChangeCallback)
|
|
796
|
+
mOnIceStateChangeCallback->call(
|
|
797
|
+
[this, state](Napi::Env env, std::vector<napi_value> &args)
|
|
798
|
+
{
|
|
799
|
+
PLOG_DEBUG << "mOnIceStateChangeCallback call(1)";
|
|
800
|
+
if (instances.find(this) == instances.end())
|
|
801
|
+
throw ThreadSafeCallback::CancelException();
|
|
802
|
+
|
|
803
|
+
// This will run in main thread and needs to construct the
|
|
804
|
+
// arguments for the call
|
|
805
|
+
std::ostringstream stream;
|
|
806
|
+
stream << state;
|
|
807
|
+
args = {Napi::String::New(env, stream.str())};
|
|
808
|
+
PLOG_DEBUG << "mOnIceStateChangeCallback call(2)";
|
|
809
|
+
});
|
|
810
|
+
});
|
|
745
811
|
}
|
|
746
812
|
|
|
747
813
|
void PeerConnectionWrapper::onSignalingStateChange(const Napi::CallbackInfo &info)
|
|
748
814
|
{
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
815
|
+
PLOG_DEBUG << "onSignalingStateChange() called";
|
|
816
|
+
Napi::Env env = info.Env();
|
|
817
|
+
int length = info.Length();
|
|
818
|
+
|
|
819
|
+
if (!mRtcPeerConnPtr)
|
|
820
|
+
{
|
|
821
|
+
Napi::Error::New(env, "onSignalingStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
if (length < 1 || !info[0].IsFunction())
|
|
826
|
+
{
|
|
827
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
828
|
+
return;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// Callback
|
|
832
|
+
mOnSignalingStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
833
|
+
|
|
834
|
+
mRtcPeerConnPtr->onSignalingStateChange(
|
|
835
|
+
[&](rtc::PeerConnection::SignalingState state)
|
|
836
|
+
{
|
|
837
|
+
PLOG_DEBUG << "onSignalingStateChange cb received from rtc";
|
|
838
|
+
if (mOnSignalingStateChangeCallback)
|
|
839
|
+
mOnSignalingStateChangeCallback->call(
|
|
840
|
+
[this, state](Napi::Env env, std::vector<napi_value> &args)
|
|
841
|
+
{
|
|
842
|
+
PLOG_DEBUG << "mOnSignalingStateChangeCallback call(1)";
|
|
843
|
+
// Check the peer connection is not closed
|
|
844
|
+
if (instances.find(this) == instances.end())
|
|
845
|
+
throw ThreadSafeCallback::CancelException();
|
|
846
|
+
|
|
847
|
+
// This will run in main thread and needs to construct the
|
|
848
|
+
// arguments for the call
|
|
849
|
+
std::ostringstream stream;
|
|
850
|
+
stream << state;
|
|
851
|
+
args = {Napi::String::New(env, stream.str())};
|
|
852
|
+
PLOG_DEBUG << "mOnSignalingStateChangeCallback call(2)";
|
|
853
|
+
});
|
|
854
|
+
});
|
|
785
855
|
}
|
|
786
856
|
|
|
787
857
|
void PeerConnectionWrapper::onGatheringStateChange(const Napi::CallbackInfo &info)
|
|
788
858
|
{
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
859
|
+
PLOG_DEBUG << "onGatheringStateChange() called";
|
|
860
|
+
Napi::Env env = info.Env();
|
|
861
|
+
int length = info.Length();
|
|
862
|
+
|
|
863
|
+
if (!mRtcPeerConnPtr)
|
|
864
|
+
{
|
|
865
|
+
Napi::Error::New(env, "onGatheringStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (length < 1 || !info[0].IsFunction())
|
|
870
|
+
{
|
|
871
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// Callback
|
|
876
|
+
mOnGatheringStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
877
|
+
|
|
878
|
+
mRtcPeerConnPtr->onGatheringStateChange(
|
|
879
|
+
[&](rtc::PeerConnection::GatheringState state)
|
|
880
|
+
{
|
|
881
|
+
PLOG_DEBUG << "onGatheringStateChange cb received from rtc";
|
|
882
|
+
if (mOnGatheringStateChangeCallback)
|
|
883
|
+
mOnGatheringStateChangeCallback->call(
|
|
884
|
+
[this, state](Napi::Env env, std::vector<napi_value> &args)
|
|
885
|
+
{
|
|
886
|
+
PLOG_DEBUG << "mOnGatheringStateChangeCallback call(1)";
|
|
887
|
+
// Check the peer connection is not closed
|
|
888
|
+
if (instances.find(this) == instances.end())
|
|
889
|
+
throw ThreadSafeCallback::CancelException();
|
|
890
|
+
|
|
891
|
+
// This will run in main thread and needs to construct the
|
|
892
|
+
// arguments for the call
|
|
893
|
+
std::ostringstream stream;
|
|
894
|
+
stream << state;
|
|
895
|
+
args = {Napi::String::New(env, stream.str())};
|
|
896
|
+
PLOG_DEBUG << "mOnGatheringStateChangeCallback call(2)";
|
|
897
|
+
});
|
|
898
|
+
});
|
|
825
899
|
}
|
|
826
900
|
|
|
827
901
|
void PeerConnectionWrapper::onDataChannel(const Napi::CallbackInfo &info)
|
|
828
902
|
{
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
903
|
+
PLOG_DEBUG << "onDataChannel() called";
|
|
904
|
+
Napi::Env env = info.Env();
|
|
905
|
+
int length = info.Length();
|
|
906
|
+
|
|
907
|
+
if (!mRtcPeerConnPtr)
|
|
908
|
+
{
|
|
909
|
+
Napi::Error::New(env, "onDataChannel() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
910
|
+
return;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
if (length < 1 || !info[0].IsFunction())
|
|
914
|
+
{
|
|
915
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// Callback
|
|
920
|
+
mOnDataChannelCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
921
|
+
|
|
922
|
+
mRtcPeerConnPtr->onDataChannel(
|
|
923
|
+
[&](std::shared_ptr<rtc::DataChannel> dc)
|
|
924
|
+
{
|
|
925
|
+
PLOG_DEBUG << "onDataChannel cb received from rtc";
|
|
926
|
+
if (mOnDataChannelCallback)
|
|
927
|
+
mOnDataChannelCallback->call(
|
|
928
|
+
[this, dc](Napi::Env env, std::vector<napi_value> &args)
|
|
929
|
+
{
|
|
930
|
+
PLOG_DEBUG << "mOnDataChannelCallback call(1)";
|
|
931
|
+
// Check the peer connection is not closed
|
|
932
|
+
if (instances.find(this) == instances.end())
|
|
933
|
+
throw ThreadSafeCallback::CancelException();
|
|
934
|
+
|
|
935
|
+
// This will run in main thread and needs to construct the
|
|
936
|
+
// arguments for the call
|
|
937
|
+
std::shared_ptr<rtc::DataChannel> dataChannel = dc;
|
|
938
|
+
auto instance = DataChannelWrapper::constructor.New(
|
|
939
|
+
{Napi::External<std::shared_ptr<rtc::DataChannel>>::New(env, &dataChannel)});
|
|
940
|
+
args = {instance};
|
|
941
|
+
PLOG_DEBUG << "mOnDataChannelCallback call(2)";
|
|
942
|
+
});
|
|
943
|
+
});
|
|
865
944
|
}
|
|
866
945
|
|
|
867
946
|
Napi::Value PeerConnectionWrapper::bytesSent(const Napi::CallbackInfo &info)
|
|
868
947
|
{
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
948
|
+
PLOG_DEBUG << "bytesSent() called";
|
|
949
|
+
Napi::Env env = info.Env();
|
|
950
|
+
|
|
951
|
+
if (!mRtcPeerConnPtr)
|
|
952
|
+
{
|
|
953
|
+
return Napi::Number::New(info.Env(), 0);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
try
|
|
957
|
+
{
|
|
958
|
+
return Napi::Number::New(env, mRtcPeerConnPtr->bytesSent());
|
|
959
|
+
}
|
|
960
|
+
catch (std::exception &ex)
|
|
961
|
+
{
|
|
962
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
963
|
+
return Napi::Number::New(info.Env(), 0);
|
|
964
|
+
}
|
|
886
965
|
}
|
|
887
966
|
|
|
888
967
|
Napi::Value PeerConnectionWrapper::bytesReceived(const Napi::CallbackInfo &info)
|
|
889
968
|
{
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
969
|
+
PLOG_DEBUG << "bytesReceived() called";
|
|
970
|
+
Napi::Env env = info.Env();
|
|
971
|
+
|
|
972
|
+
if (!mRtcPeerConnPtr)
|
|
973
|
+
{
|
|
974
|
+
return Napi::Number::New(info.Env(), 0);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
try
|
|
978
|
+
{
|
|
979
|
+
return Napi::Number::New(env, mRtcPeerConnPtr->bytesReceived());
|
|
980
|
+
}
|
|
981
|
+
catch (std::exception &ex)
|
|
982
|
+
{
|
|
983
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
984
|
+
return Napi::Number::New(info.Env(), 0);
|
|
985
|
+
}
|
|
907
986
|
}
|
|
908
987
|
|
|
909
988
|
Napi::Value PeerConnectionWrapper::rtt(const Napi::CallbackInfo &info)
|
|
910
989
|
{
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
990
|
+
PLOG_DEBUG << "rtt() called";
|
|
991
|
+
Napi::Env env = info.Env();
|
|
992
|
+
|
|
993
|
+
if (!mRtcPeerConnPtr)
|
|
994
|
+
{
|
|
995
|
+
return Napi::Number::New(info.Env(), 0);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
try
|
|
999
|
+
{
|
|
1000
|
+
return Napi::Number::New(env, mRtcPeerConnPtr->rtt().value_or(std::chrono::milliseconds(-1)).count());
|
|
1001
|
+
}
|
|
1002
|
+
catch (std::exception &ex)
|
|
1003
|
+
{
|
|
1004
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
1005
|
+
return Napi::Number::New(info.Env(), -1);
|
|
1006
|
+
}
|
|
928
1007
|
}
|
|
929
1008
|
|
|
930
1009
|
Napi::Value PeerConnectionWrapper::getSelectedCandidatePair(const Napi::CallbackInfo &info)
|
|
931
1010
|
{
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1011
|
+
PLOG_DEBUG << "getSelectedCandidatePair() called";
|
|
1012
|
+
Napi::Env env = info.Env();
|
|
1013
|
+
|
|
1014
|
+
if (!mRtcPeerConnPtr)
|
|
1015
|
+
{
|
|
1016
|
+
return env.Null();
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
try
|
|
1020
|
+
{
|
|
1021
|
+
rtc::Candidate local, remote;
|
|
1022
|
+
if (!mRtcPeerConnPtr->getSelectedCandidatePair(&local, &remote))
|
|
1023
|
+
return env.Null();
|
|
1024
|
+
|
|
1025
|
+
Napi::Object retvalue = Napi::Object::New(env);
|
|
1026
|
+
Napi::Object localObj = Napi::Object::New(env);
|
|
1027
|
+
Napi::Object remoteObj = Napi::Object::New(env);
|
|
1028
|
+
|
|
1029
|
+
localObj.Set("address", local.address().value_or("?"));
|
|
1030
|
+
localObj.Set("port", local.port().value_or(0));
|
|
1031
|
+
localObj.Set("type", candidateTypeToString(local.type()));
|
|
1032
|
+
localObj.Set("transportType", candidateTransportTypeToString(local.transportType()));
|
|
1033
|
+
localObj.Set("candidate", local.candidate());
|
|
1034
|
+
localObj.Set("mid", local.mid());
|
|
1035
|
+
localObj.Set("priority", local.priority());
|
|
1036
|
+
|
|
1037
|
+
remoteObj.Set("address", remote.address().value_or("?"));
|
|
1038
|
+
remoteObj.Set("port", remote.port().value_or(0));
|
|
1039
|
+
remoteObj.Set("type", candidateTypeToString(remote.type()));
|
|
1040
|
+
remoteObj.Set("transportType", candidateTransportTypeToString(remote.transportType()));
|
|
1041
|
+
remoteObj.Set("candidate", remote.candidate());
|
|
1042
|
+
remoteObj.Set("mid", remote.mid());
|
|
1043
|
+
remoteObj.Set("priority", remote.priority());
|
|
1044
|
+
|
|
1045
|
+
retvalue.Set("local", localObj);
|
|
1046
|
+
retvalue.Set("remote", remoteObj);
|
|
1047
|
+
|
|
1048
|
+
return retvalue;
|
|
1049
|
+
}
|
|
1050
|
+
catch (std::exception &ex)
|
|
1051
|
+
{
|
|
1052
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
1053
|
+
return Napi::Number::New(info.Env(), -1);
|
|
1054
|
+
}
|
|
976
1055
|
}
|
|
977
1056
|
|
|
978
1057
|
Napi::Value PeerConnectionWrapper::maxDataChannelId(const Napi::CallbackInfo &info)
|
|
979
1058
|
{
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1059
|
+
PLOG_DEBUG << "maxDataChannelId() called";
|
|
1060
|
+
Napi::Env env = info.Env();
|
|
1061
|
+
|
|
1062
|
+
if (!mRtcPeerConnPtr)
|
|
1063
|
+
{
|
|
1064
|
+
return Napi::Number::New(info.Env(), 0);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
try
|
|
1068
|
+
{
|
|
1069
|
+
return Napi::Number::New(env, mRtcPeerConnPtr->maxDataChannelId());
|
|
1070
|
+
}
|
|
1071
|
+
catch (std::exception &ex)
|
|
1072
|
+
{
|
|
1073
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
1074
|
+
return Napi::Number::New(info.Env(), 0);
|
|
1075
|
+
}
|
|
997
1076
|
}
|
|
998
1077
|
|
|
999
1078
|
Napi::Value PeerConnectionWrapper::maxMessageSize(const Napi::CallbackInfo &info)
|
|
1000
1079
|
{
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1080
|
+
PLOG_DEBUG << "maxMessageSize() called";
|
|
1081
|
+
Napi::Env env = info.Env();
|
|
1082
|
+
|
|
1083
|
+
if (!mRtcPeerConnPtr)
|
|
1084
|
+
{
|
|
1085
|
+
return Napi::Number::New(info.Env(), 0);
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
try
|
|
1089
|
+
{
|
|
1090
|
+
return Napi::Number::New(env, mRtcPeerConnPtr->remoteMaxMessageSize());
|
|
1091
|
+
}
|
|
1092
|
+
catch (std::exception &ex)
|
|
1093
|
+
{
|
|
1094
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
1095
|
+
return Napi::Number::New(info.Env(), 0);
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1008
1098
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1099
|
+
Napi::Value PeerConnectionWrapper::remoteFingerprint(const Napi::CallbackInfo &info)
|
|
1100
|
+
{
|
|
1101
|
+
PLOG_DEBUG << "remoteFingerprints() called";
|
|
1102
|
+
Napi::Env env = info.Env();
|
|
1103
|
+
|
|
1104
|
+
if (!mRtcPeerConnPtr)
|
|
1105
|
+
{
|
|
1106
|
+
return Napi::Number::New(info.Env(), 0);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
try
|
|
1110
|
+
{
|
|
1111
|
+
auto fingerprint = mRtcPeerConnPtr->remoteFingerprint();
|
|
1112
|
+
|
|
1113
|
+
Napi::Object fingerprintObject = Napi::Object::New(env);
|
|
1114
|
+
fingerprintObject.Set("value", fingerprint.value);
|
|
1115
|
+
fingerprintObject.Set("algorithm", rtc::CertificateFingerprint::AlgorithmIdentifier(fingerprint.algorithm));
|
|
1116
|
+
|
|
1117
|
+
return fingerprintObject;
|
|
1118
|
+
}
|
|
1119
|
+
catch (std::exception &ex)
|
|
1120
|
+
{
|
|
1121
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
1122
|
+
return Napi::Number::New(info.Env(), 0);
|
|
1123
|
+
}
|
|
1018
1124
|
}
|
|
1019
1125
|
|
|
1020
1126
|
std::string PeerConnectionWrapper::candidateTypeToString(const rtc::Candidate::Type &type)
|
|
1021
1127
|
{
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1128
|
+
PLOG_DEBUG << "candidateTypeToString() called";
|
|
1129
|
+
switch (type)
|
|
1130
|
+
{
|
|
1131
|
+
case rtc::Candidate::Type::Host:
|
|
1132
|
+
return "host";
|
|
1133
|
+
case rtc::Candidate::Type::PeerReflexive:
|
|
1134
|
+
return "prflx";
|
|
1135
|
+
case rtc::Candidate::Type::ServerReflexive:
|
|
1136
|
+
return "srflx";
|
|
1137
|
+
case rtc::Candidate::Type::Relayed:
|
|
1138
|
+
return "relay";
|
|
1139
|
+
default:
|
|
1140
|
+
return "unknown";
|
|
1141
|
+
}
|
|
1036
1142
|
}
|
|
1037
1143
|
|
|
1038
1144
|
std::string PeerConnectionWrapper::candidateTransportTypeToString(const rtc::Candidate::TransportType &transportType)
|
|
1039
1145
|
{
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1146
|
+
PLOG_DEBUG << "candidateTransportTypeToString() called";
|
|
1147
|
+
switch (transportType)
|
|
1148
|
+
{
|
|
1149
|
+
case rtc::Candidate::TransportType::Udp:
|
|
1150
|
+
return "UDP";
|
|
1151
|
+
case rtc::Candidate::TransportType::TcpActive:
|
|
1152
|
+
return "TCP_active";
|
|
1153
|
+
case rtc::Candidate::TransportType::TcpPassive:
|
|
1154
|
+
return "TCP_passive";
|
|
1155
|
+
case rtc::Candidate::TransportType::TcpSo:
|
|
1156
|
+
return "TCP_so";
|
|
1157
|
+
case rtc::Candidate::TransportType::TcpUnknown:
|
|
1158
|
+
return "TCP_unknown";
|
|
1159
|
+
default:
|
|
1160
|
+
return "unknown";
|
|
1161
|
+
}
|
|
1056
1162
|
}
|
|
1057
1163
|
|
|
1058
1164
|
#if RTC_ENABLE_MEDIA == 1
|
|
1059
1165
|
Napi::Value PeerConnectionWrapper::addTrack(const Napi::CallbackInfo &info)
|
|
1060
1166
|
{
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1167
|
+
PLOG_DEBUG << "addTrack() called";
|
|
1168
|
+
Napi::Env env = info.Env();
|
|
1169
|
+
int length = info.Length();
|
|
1170
|
+
|
|
1171
|
+
if (!mRtcPeerConnPtr)
|
|
1172
|
+
{
|
|
1173
|
+
Napi::Error::New(env, "addTrack() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
1174
|
+
return env.Null();
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
if (length < 1 || !info[0].IsObject())
|
|
1178
|
+
{
|
|
1179
|
+
Napi::TypeError::New(env, "Media class instance expected").ThrowAsJavaScriptException();
|
|
1180
|
+
return env.Null();
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
try
|
|
1184
|
+
{
|
|
1185
|
+
Napi::Object obj = info[0].As<Napi::Object>();
|
|
1186
|
+
if (obj.Get("media-type-video").IsBoolean())
|
|
1187
|
+
{
|
|
1188
|
+
VideoWrapper *videoPtr = Napi::ObjectWrap<VideoWrapper>::Unwrap(obj);
|
|
1189
|
+
std::shared_ptr<rtc::Track> track = mRtcPeerConnPtr->addTrack(videoPtr->getVideoInstance());
|
|
1190
|
+
auto instance =
|
|
1191
|
+
TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(info.Env(), &track)});
|
|
1192
|
+
return instance;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
if (obj.Get("media-type-audio").IsBoolean())
|
|
1196
|
+
{
|
|
1197
|
+
AudioWrapper *audioPtr = Napi::ObjectWrap<AudioWrapper>::Unwrap(obj);
|
|
1198
|
+
std::shared_ptr<rtc::Track> track = mRtcPeerConnPtr->addTrack(audioPtr->getAudioInstance());
|
|
1199
|
+
auto instance =
|
|
1200
|
+
TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(info.Env(), &track)});
|
|
1201
|
+
return instance;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
Napi::Error::New(env, std::string("Unknown media type")).ThrowAsJavaScriptException();
|
|
1205
|
+
return env.Null();
|
|
1206
|
+
}
|
|
1207
|
+
catch (std::exception &ex)
|
|
1208
|
+
{
|
|
1209
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
1210
|
+
return env.Null();
|
|
1211
|
+
}
|
|
1104
1212
|
}
|
|
1105
1213
|
|
|
1106
1214
|
void PeerConnectionWrapper::onTrack(const Napi::CallbackInfo &info)
|
|
1107
1215
|
{
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1216
|
+
PLOG_DEBUG << "onTrack() called";
|
|
1217
|
+
Napi::Env env = info.Env();
|
|
1218
|
+
int length = info.Length();
|
|
1219
|
+
|
|
1220
|
+
if (!mRtcPeerConnPtr)
|
|
1221
|
+
{
|
|
1222
|
+
Napi::Error::New(env, "onGatheringStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
if (length < 1 || !info[0].IsFunction())
|
|
1227
|
+
{
|
|
1228
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
// Callback
|
|
1233
|
+
mOnTrackCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
1234
|
+
|
|
1235
|
+
mRtcPeerConnPtr->onTrack(
|
|
1236
|
+
[&](std::shared_ptr<rtc::Track> track)
|
|
1237
|
+
{
|
|
1238
|
+
if (mOnTrackCallback)
|
|
1239
|
+
mOnTrackCallback->call(
|
|
1240
|
+
[this, track](Napi::Env env, std::vector<napi_value> &args)
|
|
1241
|
+
{
|
|
1242
|
+
// Check the peer connection is not closed
|
|
1243
|
+
if (instances.find(this) == instances.end())
|
|
1244
|
+
throw ThreadSafeCallback::CancelException();
|
|
1245
|
+
|
|
1246
|
+
// This will run in main thread and needs to construct the
|
|
1247
|
+
// arguments for the call
|
|
1248
|
+
std::shared_ptr<rtc::Track> newTrack = track;
|
|
1249
|
+
auto instance =
|
|
1250
|
+
TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(env, &newTrack)});
|
|
1251
|
+
args = {instance};
|
|
1252
|
+
});
|
|
1253
|
+
});
|
|
1141
1254
|
}
|
|
1142
1255
|
#endif
|
|
1143
1256
|
|
|
1144
1257
|
Napi::Value PeerConnectionWrapper::hasMedia(const Napi::CallbackInfo &info)
|
|
1145
1258
|
{
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1259
|
+
PLOG_DEBUG << "hasMedia() called";
|
|
1260
|
+
Napi::Env env = info.Env();
|
|
1261
|
+
return Napi::Boolean::New(env, mRtcPeerConnPtr ? mRtcPeerConnPtr->hasMedia() : false);
|
|
1149
1262
|
}
|
|
1150
1263
|
|
|
1151
1264
|
Napi::Value PeerConnectionWrapper::state(const Napi::CallbackInfo &info)
|
|
1152
1265
|
{
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1266
|
+
PLOG_DEBUG << "state() called";
|
|
1267
|
+
Napi::Env env = info.Env();
|
|
1268
|
+
std::ostringstream stream;
|
|
1269
|
+
stream << (mRtcPeerConnPtr ? mRtcPeerConnPtr->state() : rtc::PeerConnection::State::Closed);
|
|
1270
|
+
return Napi::String::New(env, stream.str());
|
|
1158
1271
|
}
|
|
1159
1272
|
|
|
1160
1273
|
Napi::Value PeerConnectionWrapper::iceState(const Napi::CallbackInfo &info)
|
|
1161
1274
|
{
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1275
|
+
PLOG_DEBUG << "iceState() called";
|
|
1276
|
+
Napi::Env env = info.Env();
|
|
1277
|
+
std::ostringstream stream;
|
|
1278
|
+
stream << (mRtcPeerConnPtr ? mRtcPeerConnPtr->iceState() : rtc::PeerConnection::IceState::Closed);
|
|
1279
|
+
return Napi::String::New(env, stream.str());
|
|
1167
1280
|
}
|
|
1168
1281
|
|
|
1169
1282
|
Napi::Value PeerConnectionWrapper::signalingState(const Napi::CallbackInfo &info)
|
|
1170
1283
|
{
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1284
|
+
PLOG_DEBUG << "signalingState() called";
|
|
1285
|
+
Napi::Env env = info.Env();
|
|
1286
|
+
std::ostringstream stream;
|
|
1287
|
+
stream << (mRtcPeerConnPtr ? mRtcPeerConnPtr->signalingState() : rtc::PeerConnection::SignalingState::Stable);
|
|
1288
|
+
return Napi::String::New(env, stream.str());
|
|
1176
1289
|
}
|
|
1177
1290
|
|
|
1178
1291
|
Napi::Value PeerConnectionWrapper::gatheringState(const Napi::CallbackInfo &info)
|
|
1179
1292
|
{
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1293
|
+
PLOG_DEBUG << "gatheringState() called";
|
|
1294
|
+
Napi::Env env = info.Env();
|
|
1295
|
+
std::ostringstream stream;
|
|
1296
|
+
stream << (mRtcPeerConnPtr ? mRtcPeerConnPtr->gatheringState() : rtc::PeerConnection::GatheringState::Complete);
|
|
1297
|
+
return Napi::String::New(env, stream.str());
|
|
1185
1298
|
}
|