node-datachannel 0.29.0 → 0.31.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/CMakeLists.txt +16 -2
- package/dist/cjs/lib/index.cjs +21 -0
- package/dist/cjs/lib/index.cjs.map +1 -1
- package/dist/cjs/polyfill/RTCPeerConnection.cjs +6 -1
- package/dist/cjs/polyfill/RTCPeerConnection.cjs.map +1 -1
- package/dist/esm/lib/index.mjs +15 -1
- package/dist/esm/lib/index.mjs.map +1 -1
- package/dist/esm/polyfill/RTCPeerConnection.mjs +6 -1
- package/dist/esm/polyfill/RTCPeerConnection.mjs.map +1 -1
- package/dist/types/lib/index.d.ts +58 -4
- package/dist/types/lib/types.d.ts +3 -1
- package/package.json +3 -2
- package/rollup.config.mjs +1 -1
- 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 +104 -97
- package/src/cpp/main.cpp +25 -11
- package/src/cpp/media-audio-wrapper.cpp +291 -294
- package/src/cpp/media-audio-wrapper.h +1 -3
- package/src/cpp/media-av1packetization.cpp +24 -0
- package/src/cpp/media-av1packetization.h +11 -0
- package/src/cpp/media-av1rtppacketizer-wrapper.cpp +126 -0
- package/src/cpp/media-av1rtppacketizer-wrapper.h +29 -0
- package/src/cpp/media-direction.cpp +32 -32
- package/src/cpp/media-direction.h +1 -1
- package/src/cpp/media-h264rtppacketizer-wrapper.cpp +126 -0
- package/src/cpp/media-h264rtppacketizer-wrapper.h +30 -0
- package/src/cpp/media-h265rtppacketizer-wrapper.cpp +126 -0
- package/src/cpp/media-h265rtppacketizer-wrapper.h +30 -0
- package/src/cpp/media-h26xseparator.cpp +32 -0
- package/src/cpp/media-h26xseparator.h +11 -0
- package/src/cpp/media-mediahandler-helper.cpp +28 -0
- package/src/cpp/media-mediahandler-helper.h +11 -0
- package/src/cpp/media-rtcpnackresponder-wrapper.cpp +68 -0
- package/src/cpp/media-rtcpnackresponder-wrapper.h +28 -0
- package/src/cpp/media-rtcpreceivingsession-wrapper.cpp +38 -25
- package/src/cpp/media-rtcpreceivingsession-wrapper.h +1 -6
- package/src/cpp/media-rtcpsrreporter-wrapper.cpp +93 -0
- package/src/cpp/media-rtcpsrreporter-wrapper.h +30 -0
- package/src/cpp/media-rtppacketizationconfig-wrapper.cpp +167 -0
- package/src/cpp/media-rtppacketizationconfig-wrapper.h +35 -0
- package/src/cpp/media-rtppacketizer-wrapper.cpp +95 -0
- package/src/cpp/media-rtppacketizer-wrapper.h +30 -0
- package/src/cpp/media-track-wrapper.cpp +356 -340
- package/src/cpp/media-track-wrapper.h +0 -3
- package/src/cpp/media-video-wrapper.cpp +347 -313
- package/src/cpp/media-video-wrapper.h +3 -3
- package/src/cpp/peer-connection-wrapper.cpp +1094 -1047
- package/src/cpp/peer-connection-wrapper.h +0 -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 +69 -2
- package/src/lib/types.ts +6 -0
- package/src/polyfill/RTCPeerConnection.ts +8 -2
|
@@ -17,1235 +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("remoteFingerprint", &PeerConnectionWrapper::remoteFingerprint),
|
|
48
|
-
InstanceMethod("addRemoteCandidate", &PeerConnectionWrapper::addRemoteCandidate),
|
|
49
|
-
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),
|
|
50
47
|
|
|
51
48
|
#if RTC_ENABLE_MEDIA == 1
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
InstanceMethod("addTrack", &PeerConnectionWrapper::addTrack),
|
|
50
|
+
InstanceMethod("onTrack", &PeerConnectionWrapper::onTrack),
|
|
54
51
|
#endif
|
|
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
|
-
|
|
83
|
-
|
|
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;
|
|
84
81
|
}
|
|
85
82
|
|
|
86
|
-
PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info)
|
|
83
|
+
PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info)
|
|
84
|
+
: Napi::ObjectWrap<PeerConnectionWrapper>(info)
|
|
87
85
|
{
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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();
|
|
96
122
|
return;
|
|
123
|
+
}
|
|
97
124
|
}
|
|
98
|
-
|
|
99
|
-
// Peer Name
|
|
100
|
-
mPeerName = info[0].As<Napi::String>().ToString();
|
|
101
|
-
|
|
102
|
-
// Peer Config
|
|
103
|
-
rtc::Configuration rtcConfig;
|
|
104
|
-
Napi::Object config = info[1].As<Napi::Object>();
|
|
105
|
-
if (!config.Get("iceServers").IsArray())
|
|
125
|
+
else
|
|
106
126
|
{
|
|
107
|
-
|
|
127
|
+
if (!iceServers.Get(i).IsObject())
|
|
128
|
+
{
|
|
129
|
+
Napi::TypeError::New(env, "IceServer config should be a string Or an object").ThrowAsJavaScriptException();
|
|
108
130
|
return;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
Napi::Array iceServers = config.Get("iceServers").As<Napi::Array>();
|
|
112
|
-
for (uint32_t i = 0; i < iceServers.Length(); i++)
|
|
113
|
-
{
|
|
114
|
-
if (iceServers.Get(i).IsString()){
|
|
115
|
-
try
|
|
116
|
-
{
|
|
117
|
-
rtcConfig.iceServers.emplace_back(iceServers.Get(i).As<Napi::String>().ToString());
|
|
118
|
-
}
|
|
119
|
-
catch(std::exception &ex)
|
|
120
|
-
{
|
|
121
|
-
Napi::TypeError::New(env, "SyntaxError: IceServer config error: " + std::string(ex.what())).ThrowAsJavaScriptException();
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
else
|
|
126
|
-
{
|
|
127
|
-
if (!iceServers.Get(i).IsObject())
|
|
128
|
-
{
|
|
129
|
-
Napi::TypeError::New(env, "IceServer config should be a string Or an object").ThrowAsJavaScriptException();
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
|
|
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)").ThrowAsJavaScriptException();
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (iceServer.Get("relayType").IsString() &&
|
|
140
|
-
(!iceServer.Get("username").IsString() || !iceServer.Get("password").IsString()))
|
|
141
|
-
{
|
|
142
|
-
Napi::TypeError::New(env, "IceServer config error (username AND password is needed)").ThrowAsJavaScriptException();
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (iceServer.Get("relayType").IsString())
|
|
147
|
-
{
|
|
148
|
-
std::string relayTypeStr = iceServer.Get("relayType").As<Napi::String>();
|
|
149
|
-
rtc::IceServer::RelayType relayType = rtc::IceServer::RelayType::TurnUdp;
|
|
150
|
-
if (relayTypeStr.compare("TurnTcp") == 0)
|
|
151
|
-
relayType = rtc::IceServer::RelayType::TurnTcp;
|
|
152
|
-
if (relayTypeStr.compare("TurnTls") == 0)
|
|
153
|
-
relayType = rtc::IceServer::RelayType::TurnTls;
|
|
154
|
-
|
|
155
|
-
rtcConfig.iceServers.emplace_back(
|
|
156
|
-
rtc::IceServer(iceServer.Get("hostname").As<Napi::String>(),
|
|
157
|
-
uint16_t(iceServer.Get("port").As<Napi::Number>().Uint32Value()),
|
|
158
|
-
iceServer.Get("username").As<Napi::String>(),
|
|
159
|
-
iceServer.Get("password").As<Napi::String>(),
|
|
160
|
-
relayType));
|
|
161
|
-
}
|
|
162
|
-
else
|
|
163
|
-
{
|
|
164
|
-
rtcConfig.iceServers.emplace_back(
|
|
165
|
-
rtc::IceServer(
|
|
166
|
-
iceServer.Get("hostname").As<Napi::String>(),
|
|
167
|
-
uint16_t(iceServer.Get("port").As<Napi::Number>().Uint32Value())));
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Proxy Server
|
|
173
|
-
if (config.Get("proxyServer").IsObject())
|
|
174
|
-
{
|
|
175
|
-
Napi::Object proxyServer = config.Get("proxyServer").As<Napi::Object>();
|
|
176
|
-
|
|
177
|
-
// IP
|
|
178
|
-
std::string ip = proxyServer.Get("ip").As<Napi::String>();
|
|
179
|
-
|
|
180
|
-
// Port
|
|
181
|
-
uint16_t port = proxyServer.Get("port").As<Napi::Number>().Uint32Value();
|
|
182
|
-
|
|
183
|
-
// Type
|
|
184
|
-
std::string strType = proxyServer.Get("type").As<Napi::String>().ToString();
|
|
185
|
-
rtc::ProxyServer::Type type = rtc::ProxyServer::Type::Http;
|
|
186
|
-
|
|
187
|
-
if (strType == "Socks5")
|
|
188
|
-
type = rtc::ProxyServer::Type::Socks5;
|
|
189
|
-
|
|
190
|
-
// Username & Password
|
|
191
|
-
std::string username = "";
|
|
192
|
-
std::string password = "";
|
|
193
|
-
|
|
194
|
-
if (proxyServer.Get("username").IsString())
|
|
195
|
-
username = proxyServer.Get("username").As<Napi::String>().ToString();
|
|
196
|
-
if (proxyServer.Get("password").IsString())
|
|
197
|
-
username = proxyServer.Get("password").As<Napi::String>().ToString();
|
|
198
|
-
|
|
199
|
-
rtcConfig.proxyServer = rtc::ProxyServer(type, ip, port, username, password);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// bind address, libjuice only
|
|
203
|
-
if (config.Get("bindAddress").IsString())
|
|
204
|
-
rtcConfig.bindAddress = config.Get("bindAddress").As<Napi::String>().ToString();
|
|
205
|
-
|
|
206
|
-
// Port Ranges
|
|
207
|
-
if (config.Get("portRangeBegin").IsNumber())
|
|
208
|
-
rtcConfig.portRangeBegin = config.Get("portRangeBegin").As<Napi::Number>().Uint32Value();
|
|
209
|
-
if (config.Get("portRangeEnd").IsNumber())
|
|
210
|
-
rtcConfig.portRangeEnd = config.Get("portRangeEnd").As<Napi::Number>().Uint32Value();
|
|
211
|
-
|
|
212
|
-
// enableIceTcp option
|
|
213
|
-
if (config.Get("enableIceTcp").IsBoolean())
|
|
214
|
-
rtcConfig.enableIceTcp = config.Get("enableIceTcp").As<Napi::Boolean>();
|
|
215
|
-
|
|
216
|
-
// enableIceUdpMux option
|
|
217
|
-
if (config.Get("enableIceUdpMux").IsBoolean())
|
|
218
|
-
rtcConfig.enableIceUdpMux = config.Get("enableIceUdpMux").As<Napi::Boolean>();
|
|
219
|
-
|
|
220
|
-
// disableAutoNegotiation option
|
|
221
|
-
if (config.Get("disableAutoNegotiation").IsBoolean())
|
|
222
|
-
rtcConfig.disableAutoNegotiation = config.Get("disableAutoNegotiation").As<Napi::Boolean>();
|
|
223
|
-
|
|
224
|
-
// disableAutoGathering option
|
|
225
|
-
if (config.Get("disableAutoGathering").IsBoolean())
|
|
226
|
-
rtcConfig.disableAutoGathering = config.Get("disableAutoGathering").As<Napi::Boolean>();
|
|
227
|
-
|
|
228
|
-
// forceMediaTransport option
|
|
229
|
-
if (config.Get("forceMediaTransport").IsBoolean())
|
|
230
|
-
rtcConfig.forceMediaTransport = config.Get("forceMediaTransport").As<Napi::Boolean>();
|
|
231
|
-
|
|
232
|
-
// Max Message Size
|
|
233
|
-
if (config.Get("maxMessageSize").IsNumber())
|
|
234
|
-
rtcConfig.maxMessageSize = config.Get("maxMessageSize").As<Napi::Number>().Int32Value();
|
|
235
|
-
|
|
236
|
-
// MTU
|
|
237
|
-
if (config.Get("mtu").IsNumber())
|
|
238
|
-
rtcConfig.mtu = config.Get("mtu").As<Napi::Number>().Int32Value();
|
|
239
|
-
|
|
240
|
-
// ICE transport policy
|
|
241
|
-
if (!config.Get("iceTransportPolicy").IsUndefined())
|
|
242
|
-
{
|
|
243
|
-
if (!config.Get("iceTransportPolicy").IsString())
|
|
244
|
-
{
|
|
245
|
-
Napi::TypeError::New(env, "Invalid ICE transport policy, expected string").ThrowAsJavaScriptException();
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
std::string strPolicy = config.Get("iceTransportPolicy").As<Napi::String>().ToString();
|
|
249
|
-
if (strPolicy == "all")
|
|
250
|
-
rtcConfig.iceTransportPolicy = rtc::TransportPolicy::All;
|
|
251
|
-
else if (strPolicy == "relay")
|
|
252
|
-
rtcConfig.iceTransportPolicy = rtc::TransportPolicy::Relay;
|
|
253
|
-
else
|
|
254
|
-
{
|
|
255
|
-
Napi::TypeError::New(env, "Unknown ICE transport policy").ThrowAsJavaScriptException();
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Allow skipping fingerprint validation
|
|
261
|
-
if (config.Get("disableFingerprintVerification").IsBoolean()) {
|
|
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
|
-
rtcConfig.certificatePemFile = config.Get("certificatePemFile").As<Napi::String>().ToString();
|
|
268
|
-
}
|
|
269
|
-
if (config.Get("keyPemFile").IsString()) {
|
|
270
|
-
rtcConfig.keyPemFile = config.Get("keyPemFile").As<Napi::String>().ToString();
|
|
271
|
-
}
|
|
272
|
-
if (config.Get("keyPemPass").IsString()) {
|
|
273
|
-
rtcConfig.keyPemPass = config.Get("keyPemPass").As<Napi::String>().ToString();
|
|
274
|
-
}
|
|
131
|
+
}
|
|
275
132
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
catch (std::exception &ex)
|
|
283
|
-
{
|
|
284
|
-
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();
|
|
285
138
|
return;
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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);
|
|
294
299
|
}
|
|
295
300
|
|
|
296
301
|
PeerConnectionWrapper::~PeerConnectionWrapper()
|
|
297
302
|
{
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
303
|
+
PLOG_DEBUG << "Destructor called";
|
|
304
|
+
doCleanup();
|
|
305
|
+
doClose();
|
|
301
306
|
}
|
|
302
307
|
|
|
303
308
|
void PeerConnectionWrapper::doClose()
|
|
304
309
|
{
|
|
305
|
-
|
|
306
|
-
|
|
310
|
+
PLOG_DEBUG << "doClose() called";
|
|
311
|
+
if (mRtcPeerConnPtr)
|
|
312
|
+
{
|
|
313
|
+
PLOG_DEBUG << "Closing...";
|
|
314
|
+
try
|
|
307
315
|
{
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
{
|
|
316
|
-
std::cerr << std::string("libdatachannel error while closing peer connection: ") + ex.what() << std::endl;
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
316
|
+
mRtcPeerConnPtr->close();
|
|
317
|
+
mRtcPeerConnPtr.reset();
|
|
318
|
+
}
|
|
319
|
+
catch (std::exception &ex)
|
|
320
|
+
{
|
|
321
|
+
std::cerr << std::string("libdatachannel error while closing peer connection: ") + ex.what() << std::endl;
|
|
322
|
+
return;
|
|
319
323
|
}
|
|
324
|
+
}
|
|
320
325
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
326
|
+
mOnLocalDescriptionCallback.reset();
|
|
327
|
+
mOnLocalCandidateCallback.reset();
|
|
328
|
+
mOnIceStateChangeCallback.reset();
|
|
329
|
+
mOnSignalingStateChangeCallback.reset();
|
|
330
|
+
mOnGatheringStateChangeCallback.reset();
|
|
331
|
+
mOnDataChannelCallback.reset();
|
|
332
|
+
mOnTrackCallback.reset();
|
|
328
333
|
}
|
|
329
334
|
|
|
330
335
|
void PeerConnectionWrapper::close(const Napi::CallbackInfo &info)
|
|
331
336
|
{
|
|
332
|
-
|
|
333
|
-
|
|
337
|
+
PLOG_DEBUG << "close() called";
|
|
338
|
+
doClose();
|
|
334
339
|
}
|
|
335
340
|
|
|
336
341
|
void PeerConnectionWrapper::doCleanup()
|
|
337
342
|
{
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
343
|
+
PLOG_DEBUG << "doCleanup() called";
|
|
344
|
+
mOnStateChangeCallback.reset();
|
|
345
|
+
instances.erase(this);
|
|
341
346
|
}
|
|
342
347
|
|
|
343
348
|
void PeerConnectionWrapper::setLocalDescription(const Napi::CallbackInfo &info)
|
|
344
349
|
{
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
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);
|
|
405
412
|
}
|
|
406
413
|
|
|
407
414
|
void PeerConnectionWrapper::setRemoteDescription(const Napi::CallbackInfo &info)
|
|
408
415
|
{
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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
|
+
}
|
|
438
446
|
}
|
|
439
447
|
|
|
440
448
|
Napi::Value PeerConnectionWrapper::localDescription(const Napi::CallbackInfo &info)
|
|
441
449
|
{
|
|
442
|
-
|
|
443
|
-
|
|
450
|
+
PLOG_DEBUG << "localDescription() called";
|
|
451
|
+
Napi::Env env = info.Env();
|
|
444
452
|
|
|
445
|
-
|
|
453
|
+
std::optional<rtc::Description> desc = mRtcPeerConnPtr ? mRtcPeerConnPtr->localDescription() : std::nullopt;
|
|
446
454
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
455
|
+
// Return JS null if no description
|
|
456
|
+
if (!desc.has_value())
|
|
457
|
+
{
|
|
458
|
+
return env.Null();
|
|
459
|
+
}
|
|
452
460
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
461
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
462
|
+
obj.Set("type", desc->typeString());
|
|
463
|
+
obj.Set("sdp", desc.value());
|
|
464
|
+
return obj;
|
|
457
465
|
}
|
|
458
466
|
|
|
459
467
|
Napi::Value PeerConnectionWrapper::remoteDescription(const Napi::CallbackInfo &info)
|
|
460
468
|
{
|
|
461
|
-
|
|
469
|
+
Napi::Env env = info.Env();
|
|
462
470
|
|
|
463
|
-
|
|
471
|
+
std::optional<rtc::Description> desc = mRtcPeerConnPtr ? mRtcPeerConnPtr->remoteDescription() : std::nullopt;
|
|
464
472
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
473
|
+
// Return JS null if no description
|
|
474
|
+
if (!desc.has_value())
|
|
475
|
+
{
|
|
476
|
+
return env.Null();
|
|
477
|
+
}
|
|
470
478
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
479
|
+
Napi::Object obj = Napi::Object::New(env);
|
|
480
|
+
obj.Set("type", desc->typeString());
|
|
481
|
+
obj.Set("sdp", desc.value());
|
|
482
|
+
return obj;
|
|
475
483
|
}
|
|
476
484
|
|
|
477
485
|
void PeerConnectionWrapper::addRemoteCandidate(const Napi::CallbackInfo &info)
|
|
478
486
|
{
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
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
|
+
}
|
|
482
516
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
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();
|
|
488
522
|
|
|
489
|
-
|
|
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())
|
|
490
540
|
{
|
|
491
|
-
|
|
492
|
-
|
|
541
|
+
Napi::TypeError::New(env, "Data Channel Init Config expected(As Object)").ThrowAsJavaScriptException();
|
|
542
|
+
return info.Env().Null();
|
|
493
543
|
}
|
|
494
544
|
|
|
495
|
-
|
|
545
|
+
Napi::Object initConfig = info[1].As<Napi::Object>();
|
|
546
|
+
|
|
547
|
+
if (!initConfig.Get("protocol").IsUndefined())
|
|
496
548
|
{
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
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>();
|
|
500
555
|
}
|
|
501
|
-
|
|
556
|
+
|
|
557
|
+
if (!initConfig.Get("negotiated").IsUndefined())
|
|
502
558
|
{
|
|
503
|
-
|
|
504
|
-
|
|
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>();
|
|
505
565
|
}
|
|
506
|
-
}
|
|
507
566
|
|
|
508
|
-
|
|
509
|
-
{
|
|
510
|
-
PLOG_DEBUG << "createDataChannel() called";
|
|
511
|
-
Napi::Env env = info.Env();
|
|
512
|
-
int length = info.Length();
|
|
513
|
-
|
|
514
|
-
if (!mRtcPeerConnPtr)
|
|
567
|
+
if (!initConfig.Get("id").IsUndefined())
|
|
515
568
|
{
|
|
516
|
-
|
|
569
|
+
if (!initConfig.Get("id").IsNumber())
|
|
570
|
+
{
|
|
571
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config (id)").ThrowAsJavaScriptException();
|
|
517
572
|
return info.Env().Null();
|
|
573
|
+
}
|
|
574
|
+
init.id = uint16_t(initConfig.Get("id").As<Napi::Number>().Uint32Value());
|
|
518
575
|
}
|
|
519
576
|
|
|
520
|
-
|
|
577
|
+
// Reliability.unordered parameter
|
|
578
|
+
if (!initConfig.Get("unordered").IsUndefined())
|
|
521
579
|
{
|
|
522
|
-
|
|
580
|
+
if (!initConfig.Get("unordered").IsBoolean())
|
|
581
|
+
{
|
|
582
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config (unordered)").ThrowAsJavaScriptException();
|
|
523
583
|
return info.Env().Null();
|
|
584
|
+
}
|
|
585
|
+
init.reliability.unordered = initConfig.Get("unordered").As<Napi::Boolean>();
|
|
524
586
|
}
|
|
525
587
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
if (length > 1)
|
|
588
|
+
if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull() &&
|
|
589
|
+
!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
|
|
529
590
|
{
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
return info.Env().Null();
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
Napi::Object initConfig = info[1].As<Napi::Object>();
|
|
537
|
-
|
|
538
|
-
if (!initConfig.Get("protocol").IsUndefined())
|
|
539
|
-
{
|
|
540
|
-
if (!initConfig.Get("protocol").IsString())
|
|
541
|
-
{
|
|
542
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (protocol)").ThrowAsJavaScriptException();
|
|
543
|
-
return info.Env().Null();
|
|
544
|
-
}
|
|
545
|
-
init.protocol = initConfig.Get("protocol").As<Napi::String>();
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
if (!initConfig.Get("negotiated").IsUndefined())
|
|
549
|
-
{
|
|
550
|
-
if (!initConfig.Get("negotiated").IsBoolean())
|
|
551
|
-
{
|
|
552
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (negotiated)").ThrowAsJavaScriptException();
|
|
553
|
-
return info.Env().Null();
|
|
554
|
-
}
|
|
555
|
-
init.negotiated = initConfig.Get("negotiated").As<Napi::Boolean>();
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
if (!initConfig.Get("id").IsUndefined())
|
|
559
|
-
{
|
|
560
|
-
if (!initConfig.Get("id").IsNumber())
|
|
561
|
-
{
|
|
562
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (id)").ThrowAsJavaScriptException();
|
|
563
|
-
return info.Env().Null();
|
|
564
|
-
}
|
|
565
|
-
init.id = uint16_t(initConfig.Get("id").As<Napi::Number>().Uint32Value());
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
// Reliability.unordered parameter
|
|
569
|
-
if (!initConfig.Get("unordered").IsUndefined())
|
|
570
|
-
{
|
|
571
|
-
if (!initConfig.Get("unordered").IsBoolean())
|
|
572
|
-
{
|
|
573
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (unordered)").ThrowAsJavaScriptException();
|
|
574
|
-
return info.Env().Null();
|
|
575
|
-
}
|
|
576
|
-
init.reliability.unordered = !initConfig.Get("unordered").As<Napi::Boolean>();
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull() &&
|
|
580
|
-
!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
|
|
581
|
-
{
|
|
582
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config, maxPacketLifeTime and maxRetransmits are exclusive").ThrowAsJavaScriptException();
|
|
583
|
-
return info.Env().Null();
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull())
|
|
587
|
-
{
|
|
588
|
-
if (!initConfig.Get("maxPacketLifeTime").IsNumber())
|
|
589
|
-
{
|
|
590
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (maxPacketLifeTime)").ThrowAsJavaScriptException();
|
|
591
|
-
return info.Env().Null();
|
|
592
|
-
}
|
|
593
|
-
init.reliability.maxPacketLifeTime = std::chrono::milliseconds(initConfig.Get("maxPacketLifeTime").As<Napi::Number>().Uint32Value());
|
|
594
|
-
}
|
|
595
|
-
else if (!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
|
|
596
|
-
{
|
|
597
|
-
if (!initConfig.Get("maxRetransmits").IsNumber())
|
|
598
|
-
{
|
|
599
|
-
Napi::TypeError::New(env, "Wrong DataChannel Init Config (maxRetransmits)").ThrowAsJavaScriptException();
|
|
600
|
-
return info.Env().Null();
|
|
601
|
-
}
|
|
602
|
-
init.reliability.maxRetransmits = int(initConfig.Get("maxRetransmits").As<Napi::Number>().Int32Value());
|
|
603
|
-
}
|
|
591
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config, maxPacketLifeTime and maxRetransmits are exclusive")
|
|
592
|
+
.ThrowAsJavaScriptException();
|
|
593
|
+
return info.Env().Null();
|
|
604
594
|
}
|
|
605
595
|
|
|
606
|
-
|
|
596
|
+
if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull())
|
|
607
597
|
{
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
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());
|
|
613
605
|
}
|
|
614
|
-
|
|
606
|
+
else if (!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
|
|
615
607
|
{
|
|
616
|
-
|
|
608
|
+
if (!initConfig.Get("maxRetransmits").IsNumber())
|
|
609
|
+
{
|
|
610
|
+
Napi::TypeError::New(env, "Wrong DataChannel Init Config (maxRetransmits)").ThrowAsJavaScriptException();
|
|
617
611
|
return info.Env().Null();
|
|
618
|
-
|
|
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
|
+
}
|
|
619
632
|
}
|
|
620
633
|
|
|
621
634
|
void PeerConnectionWrapper::onLocalDescription(const Napi::CallbackInfo &info)
|
|
622
635
|
{
|
|
623
|
-
|
|
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
|
-
|
|
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
|
+
});
|
|
659
674
|
}
|
|
660
675
|
|
|
661
676
|
void PeerConnectionWrapper::onLocalCandidate(const Napi::CallbackInfo &info)
|
|
662
677
|
{
|
|
663
|
-
|
|
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
|
-
|
|
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
|
+
});
|
|
699
716
|
}
|
|
700
717
|
|
|
701
718
|
void PeerConnectionWrapper::onStateChange(const Napi::CallbackInfo &info)
|
|
702
719
|
{
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
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
|
-
|
|
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
|
+
});
|
|
745
768
|
}
|
|
746
769
|
|
|
747
770
|
void PeerConnectionWrapper::onIceStateChange(const Napi::CallbackInfo &info)
|
|
748
771
|
{
|
|
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
|
-
|
|
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
|
+
});
|
|
784
811
|
}
|
|
785
812
|
|
|
786
813
|
void PeerConnectionWrapper::onSignalingStateChange(const Napi::CallbackInfo &info)
|
|
787
814
|
{
|
|
788
|
-
|
|
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
|
-
|
|
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
|
+
});
|
|
824
855
|
}
|
|
825
856
|
|
|
826
857
|
void PeerConnectionWrapper::onGatheringStateChange(const Napi::CallbackInfo &info)
|
|
827
858
|
{
|
|
828
|
-
|
|
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
|
-
|
|
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
|
+
});
|
|
864
899
|
}
|
|
865
900
|
|
|
866
901
|
void PeerConnectionWrapper::onDataChannel(const Napi::CallbackInfo &info)
|
|
867
902
|
{
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
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
|
+
});
|
|
904
944
|
}
|
|
905
945
|
|
|
906
946
|
Napi::Value PeerConnectionWrapper::bytesSent(const Napi::CallbackInfo &info)
|
|
907
947
|
{
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
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
|
+
}
|
|
925
965
|
}
|
|
926
966
|
|
|
927
967
|
Napi::Value PeerConnectionWrapper::bytesReceived(const Napi::CallbackInfo &info)
|
|
928
968
|
{
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
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
|
+
}
|
|
946
986
|
}
|
|
947
987
|
|
|
948
988
|
Napi::Value PeerConnectionWrapper::rtt(const Napi::CallbackInfo &info)
|
|
949
989
|
{
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
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
|
+
}
|
|
967
1007
|
}
|
|
968
1008
|
|
|
969
1009
|
Napi::Value PeerConnectionWrapper::getSelectedCandidatePair(const Napi::CallbackInfo &info)
|
|
970
1010
|
{
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
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
|
+
}
|
|
1015
1055
|
}
|
|
1016
1056
|
|
|
1017
1057
|
Napi::Value PeerConnectionWrapper::maxDataChannelId(const Napi::CallbackInfo &info)
|
|
1018
1058
|
{
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
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
|
+
}
|
|
1036
1076
|
}
|
|
1037
1077
|
|
|
1038
1078
|
Napi::Value PeerConnectionWrapper::maxMessageSize(const Napi::CallbackInfo &info)
|
|
1039
1079
|
{
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
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
|
+
}
|
|
1057
1097
|
}
|
|
1058
1098
|
|
|
1059
1099
|
Napi::Value PeerConnectionWrapper::remoteFingerprint(const Napi::CallbackInfo &info)
|
|
1060
1100
|
{
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
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
|
+
}
|
|
1084
1124
|
}
|
|
1085
1125
|
|
|
1086
1126
|
std::string PeerConnectionWrapper::candidateTypeToString(const rtc::Candidate::Type &type)
|
|
1087
1127
|
{
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
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
|
+
}
|
|
1102
1142
|
}
|
|
1103
1143
|
|
|
1104
1144
|
std::string PeerConnectionWrapper::candidateTransportTypeToString(const rtc::Candidate::TransportType &transportType)
|
|
1105
1145
|
{
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
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
|
+
}
|
|
1122
1162
|
}
|
|
1123
1163
|
|
|
1124
1164
|
#if RTC_ENABLE_MEDIA == 1
|
|
1125
1165
|
Napi::Value PeerConnectionWrapper::addTrack(const Napi::CallbackInfo &info)
|
|
1126
1166
|
{
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
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
|
+
}
|
|
1170
1212
|
}
|
|
1171
1213
|
|
|
1172
1214
|
void PeerConnectionWrapper::onTrack(const Napi::CallbackInfo &info)
|
|
1173
1215
|
{
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
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
|
+
});
|
|
1207
1254
|
}
|
|
1208
1255
|
#endif
|
|
1209
1256
|
|
|
1210
1257
|
Napi::Value PeerConnectionWrapper::hasMedia(const Napi::CallbackInfo &info)
|
|
1211
1258
|
{
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1259
|
+
PLOG_DEBUG << "hasMedia() called";
|
|
1260
|
+
Napi::Env env = info.Env();
|
|
1261
|
+
return Napi::Boolean::New(env, mRtcPeerConnPtr ? mRtcPeerConnPtr->hasMedia() : false);
|
|
1215
1262
|
}
|
|
1216
1263
|
|
|
1217
1264
|
Napi::Value PeerConnectionWrapper::state(const Napi::CallbackInfo &info)
|
|
1218
1265
|
{
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
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());
|
|
1224
1271
|
}
|
|
1225
1272
|
|
|
1226
1273
|
Napi::Value PeerConnectionWrapper::iceState(const Napi::CallbackInfo &info)
|
|
1227
1274
|
{
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
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());
|
|
1233
1280
|
}
|
|
1234
1281
|
|
|
1235
1282
|
Napi::Value PeerConnectionWrapper::signalingState(const Napi::CallbackInfo &info)
|
|
1236
1283
|
{
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
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());
|
|
1242
1289
|
}
|
|
1243
1290
|
|
|
1244
1291
|
Napi::Value PeerConnectionWrapper::gatheringState(const Napi::CallbackInfo &info)
|
|
1245
1292
|
{
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
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());
|
|
1251
1298
|
}
|