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.
Files changed (61) hide show
  1. package/.clang-format +17 -0
  2. package/CMakeLists.txt +16 -2
  3. package/dist/cjs/lib/index.cjs +21 -0
  4. package/dist/cjs/lib/index.cjs.map +1 -1
  5. package/dist/cjs/polyfill/RTCPeerConnection.cjs +6 -1
  6. package/dist/cjs/polyfill/RTCPeerConnection.cjs.map +1 -1
  7. package/dist/esm/lib/index.mjs +15 -1
  8. package/dist/esm/lib/index.mjs.map +1 -1
  9. package/dist/esm/polyfill/RTCPeerConnection.mjs +6 -1
  10. package/dist/esm/polyfill/RTCPeerConnection.mjs.map +1 -1
  11. package/dist/types/lib/index.d.ts +58 -4
  12. package/dist/types/lib/types.d.ts +3 -1
  13. package/package.json +3 -2
  14. package/rollup.config.mjs +1 -1
  15. package/src/cpp/data-channel-wrapper.cpp +432 -411
  16. package/src/cpp/data-channel-wrapper.h +0 -2
  17. package/src/cpp/ice-udp-mux-listener-wrapper.cpp +104 -97
  18. package/src/cpp/main.cpp +25 -11
  19. package/src/cpp/media-audio-wrapper.cpp +291 -294
  20. package/src/cpp/media-audio-wrapper.h +1 -3
  21. package/src/cpp/media-av1packetization.cpp +24 -0
  22. package/src/cpp/media-av1packetization.h +11 -0
  23. package/src/cpp/media-av1rtppacketizer-wrapper.cpp +126 -0
  24. package/src/cpp/media-av1rtppacketizer-wrapper.h +29 -0
  25. package/src/cpp/media-direction.cpp +32 -32
  26. package/src/cpp/media-direction.h +1 -1
  27. package/src/cpp/media-h264rtppacketizer-wrapper.cpp +126 -0
  28. package/src/cpp/media-h264rtppacketizer-wrapper.h +30 -0
  29. package/src/cpp/media-h265rtppacketizer-wrapper.cpp +126 -0
  30. package/src/cpp/media-h265rtppacketizer-wrapper.h +30 -0
  31. package/src/cpp/media-h26xseparator.cpp +32 -0
  32. package/src/cpp/media-h26xseparator.h +11 -0
  33. package/src/cpp/media-mediahandler-helper.cpp +28 -0
  34. package/src/cpp/media-mediahandler-helper.h +11 -0
  35. package/src/cpp/media-rtcpnackresponder-wrapper.cpp +68 -0
  36. package/src/cpp/media-rtcpnackresponder-wrapper.h +28 -0
  37. package/src/cpp/media-rtcpreceivingsession-wrapper.cpp +38 -25
  38. package/src/cpp/media-rtcpreceivingsession-wrapper.h +1 -6
  39. package/src/cpp/media-rtcpsrreporter-wrapper.cpp +93 -0
  40. package/src/cpp/media-rtcpsrreporter-wrapper.h +30 -0
  41. package/src/cpp/media-rtppacketizationconfig-wrapper.cpp +167 -0
  42. package/src/cpp/media-rtppacketizationconfig-wrapper.h +35 -0
  43. package/src/cpp/media-rtppacketizer-wrapper.cpp +95 -0
  44. package/src/cpp/media-rtppacketizer-wrapper.h +30 -0
  45. package/src/cpp/media-track-wrapper.cpp +356 -340
  46. package/src/cpp/media-track-wrapper.h +0 -3
  47. package/src/cpp/media-video-wrapper.cpp +347 -313
  48. package/src/cpp/media-video-wrapper.h +3 -3
  49. package/src/cpp/peer-connection-wrapper.cpp +1094 -1047
  50. package/src/cpp/peer-connection-wrapper.h +0 -2
  51. package/src/cpp/rtc-wrapper.cpp +142 -138
  52. package/src/cpp/rtc-wrapper.h +8 -10
  53. package/src/cpp/thread-safe-callback.cpp +39 -50
  54. package/src/cpp/thread-safe-callback.h +26 -28
  55. package/src/cpp/web-socket-server-wrapper.cpp +205 -199
  56. package/src/cpp/web-socket-server-wrapper.h +0 -4
  57. package/src/cpp/web-socket-wrapper.cpp +625 -598
  58. package/src/cpp/web-socket-wrapper.h +0 -3
  59. package/src/lib/index.ts +69 -2
  60. package/src/lib/types.ts +6 -0
  61. 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
- PLOG_DEBUG << "CloseAll() called";
21
- auto copy(instances);
22
- for (auto inst : copy)
23
- inst->doClose();
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
- PLOG_DEBUG << "CleanupAll() called";
29
- auto copy(instances);
30
- for (auto inst : copy)
31
- inst->doCleanup();
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
- Napi::HandleScope scope(env);
37
-
38
- Napi::Function func = DefineClass(
39
- env,
40
- "PeerConnection",
41
- {
42
- InstanceMethod("close", &PeerConnectionWrapper::close),
43
- InstanceMethod("setLocalDescription", &PeerConnectionWrapper::setLocalDescription),
44
- InstanceMethod("setRemoteDescription", &PeerConnectionWrapper::setRemoteDescription),
45
- InstanceMethod("localDescription", &PeerConnectionWrapper::localDescription),
46
- InstanceMethod("remoteDescription", &PeerConnectionWrapper::remoteDescription),
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
- InstanceMethod("addTrack", &PeerConnectionWrapper::addTrack),
53
- InstanceMethod("onTrack", &PeerConnectionWrapper::onTrack),
49
+ InstanceMethod("addTrack", &PeerConnectionWrapper::addTrack),
50
+ InstanceMethod("onTrack", &PeerConnectionWrapper::onTrack),
54
51
  #endif
55
- InstanceMethod("hasMedia", &PeerConnectionWrapper::hasMedia),
56
- InstanceMethod("state", &PeerConnectionWrapper::state),
57
- InstanceMethod("iceState", &PeerConnectionWrapper::iceState),
58
- InstanceMethod("signalingState", &PeerConnectionWrapper::signalingState),
59
- InstanceMethod("gatheringState", &PeerConnectionWrapper::gatheringState),
60
- InstanceMethod("onLocalDescription", &PeerConnectionWrapper::onLocalDescription),
61
- InstanceMethod("onLocalCandidate", &PeerConnectionWrapper::onLocalCandidate),
62
- InstanceMethod("onStateChange", &PeerConnectionWrapper::onStateChange),
63
- InstanceMethod("onIceStateChange", &PeerConnectionWrapper::onIceStateChange),
64
- InstanceMethod("onSignalingStateChange", &PeerConnectionWrapper::onSignalingStateChange),
65
- InstanceMethod("onGatheringStateChange", &PeerConnectionWrapper::onGatheringStateChange),
66
- InstanceMethod("onDataChannel", &PeerConnectionWrapper::onDataChannel),
67
- InstanceMethod("bytesSent", &PeerConnectionWrapper::bytesSent),
68
- InstanceMethod("bytesReceived", &PeerConnectionWrapper::bytesReceived),
69
- InstanceMethod("rtt", &PeerConnectionWrapper::rtt),
70
- InstanceMethod("getSelectedCandidatePair", &PeerConnectionWrapper::getSelectedCandidatePair),
71
- InstanceMethod("maxDataChannelId", &PeerConnectionWrapper::maxDataChannelId),
72
- InstanceMethod("maxMessageSize", &PeerConnectionWrapper::maxMessageSize),
73
- });
74
-
75
- // If this is not the first call, we don't want to reassign the constructor (hot-reload problem)
76
- if(constructor.IsEmpty())
77
- {
78
- constructor = Napi::Persistent(func);
79
- constructor.SuppressDestruct();
80
- }
81
-
82
- exports.Set("PeerConnection", func);
83
- return exports;
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) : Napi::ObjectWrap<PeerConnectionWrapper>(info)
83
+ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info)
84
+ : Napi::ObjectWrap<PeerConnectionWrapper>(info)
87
85
  {
88
- PLOG_DEBUG << "Constructor called";
89
- Napi::Env env = info.Env();
90
- int length = info.Length();
91
-
92
- // We expect (String, Object, Function) as param
93
- if (length < 2 || !info[0].IsString() || !info[1].IsObject())
94
- {
95
- Napi::TypeError::New(env, "Peer Name (String) and Configuration (Object) expected").ThrowAsJavaScriptException();
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
- Napi::TypeError::New(env, "iceServers(Array) expected").ThrowAsJavaScriptException();
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
- // Create peer-connection
277
- try
278
- {
279
- PLOG_DEBUG << "Creating a new Peer Connection";
280
- mRtcPeerConnPtr = std::make_unique<rtc::PeerConnection>(rtcConfig);
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
- PLOG_DEBUG << "Peer Connection created";
289
-
290
- // State change callback must be set to trigger cleanup on close
291
- mOnStateChangeCallback = std::make_unique<ThreadSafeCallback>(Napi::Function::New(info.Env(), [](const Napi::CallbackInfo &) {}));
292
-
293
- instances.insert(this);
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
- PLOG_DEBUG << "Destructor called";
299
- doCleanup();
300
- doClose();
303
+ PLOG_DEBUG << "Destructor called";
304
+ doCleanup();
305
+ doClose();
301
306
  }
302
307
 
303
308
  void PeerConnectionWrapper::doClose()
304
309
  {
305
- PLOG_DEBUG << "doClose() called";
306
- if (mRtcPeerConnPtr)
310
+ PLOG_DEBUG << "doClose() called";
311
+ if (mRtcPeerConnPtr)
312
+ {
313
+ PLOG_DEBUG << "Closing...";
314
+ try
307
315
  {
308
- PLOG_DEBUG << "Closing...";
309
- try
310
- {
311
- mRtcPeerConnPtr->close();
312
- mRtcPeerConnPtr.reset();
313
- }
314
- catch (std::exception &ex)
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
- mOnLocalDescriptionCallback.reset();
322
- mOnLocalCandidateCallback.reset();
323
- mOnIceStateChangeCallback.reset();
324
- mOnSignalingStateChangeCallback.reset();
325
- mOnGatheringStateChangeCallback.reset();
326
- mOnDataChannelCallback.reset();
327
- mOnTrackCallback.reset();
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
- PLOG_DEBUG << "close() called";
333
- doClose();
337
+ PLOG_DEBUG << "close() called";
338
+ doClose();
334
339
  }
335
340
 
336
341
  void PeerConnectionWrapper::doCleanup()
337
342
  {
338
- PLOG_DEBUG << "doCleanup() called";
339
- mOnStateChangeCallback.reset();
340
- instances.erase(this);
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
- PLOG_DEBUG << "setLocalDescription() called";
346
- Napi::Env env = info.Env();
347
- int length = info.Length();
348
-
349
- if (!mRtcPeerConnPtr)
350
- {
351
- Napi::Error::New(env, "setLocalDescription() called on destroyed peer connection").ThrowAsJavaScriptException();
352
- return;
353
- }
354
-
355
- rtc::Description::Type type = rtc::Description::Type::Unspec;
356
- rtc::LocalDescriptionInit init;
357
-
358
- // optional
359
- if (length > 0)
360
- {
361
- if (!info[0].IsString())
362
- {
363
- Napi::TypeError::New(env, "type (String) expected").ThrowAsJavaScriptException();
364
- return;
365
- }
366
- std::string typeStr = info[0].As<Napi::String>().ToString();
367
-
368
- // Accept uppercase first letter for backward compatibility
369
- if (typeStr.size() > 0)
370
- typeStr[0] = std::tolower(typeStr[0]);
371
-
372
- if (typeStr == "answer")
373
- type = rtc::Description::Type::Answer;
374
- else if (typeStr == "offer")
375
- type = rtc::Description::Type::Offer;
376
- else if (typeStr == "pranswer")
377
- type = rtc::Description::Type::Pranswer;
378
- else if (typeStr == "rollback")
379
- type = rtc::Description::Type::Rollback;
380
- }
381
-
382
- // optional
383
- if (length > 1)
384
- {
385
- PLOG_DEBUG << "setLocalDescription() called with LocalDescriptionInit";
386
-
387
- if (info[1].IsObject())
388
- {
389
- PLOG_DEBUG << "setLocalDescription() called with LocalDescriptionInit as object";
390
- Napi::Object obj = info[1].As<Napi::Object>();
391
-
392
- if (obj.Get("iceUfrag").IsString()) {
393
- PLOG_DEBUG << "setLocalDescription() has ufrag";
394
- init.iceUfrag = obj.Get("iceUfrag").As<Napi::String>();
395
- }
396
-
397
- if (obj.Get("icePwd").IsString()) {
398
- PLOG_DEBUG << "setLocalDescription() has password";
399
- init.icePwd = obj.Get("icePwd").As<Napi::String>();
400
- }
401
- }
402
- }
403
-
404
- mRtcPeerConnPtr->setLocalDescription(type, init);
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
- PLOG_DEBUG << "setRemoteDescription() called";
410
- Napi::Env env = info.Env();
411
- int length = info.Length();
412
-
413
- if (!mRtcPeerConnPtr)
414
- {
415
- Napi::Error::New(env, "setRemoteDescription() called on destroyed peer connection").ThrowAsJavaScriptException();
416
- return;
417
- }
418
-
419
- if (length < 2 || !info[0].IsString() || !info[1].IsString())
420
- {
421
- Napi::TypeError::New(info.Env(), "String,String expected").ThrowAsJavaScriptException();
422
- return;
423
- }
424
-
425
- std::string sdp = info[0].As<Napi::String>().ToString();
426
- std::string type = info[1].As<Napi::String>().ToString();
427
-
428
- try
429
- {
430
- rtc::Description desc(sdp, type);
431
- mRtcPeerConnPtr->setRemoteDescription(desc);
432
- }
433
- catch (std::exception &ex)
434
- {
435
- Napi::Error::New(env, std::string("libdatachannel error while adding remote description: ") + ex.what()).ThrowAsJavaScriptException();
436
- return;
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
- PLOG_DEBUG << "localDescription() called";
443
- Napi::Env env = info.Env();
450
+ PLOG_DEBUG << "localDescription() called";
451
+ Napi::Env env = info.Env();
444
452
 
445
- std::optional<rtc::Description> desc = mRtcPeerConnPtr ? mRtcPeerConnPtr->localDescription() : std::nullopt;
453
+ std::optional<rtc::Description> desc = mRtcPeerConnPtr ? mRtcPeerConnPtr->localDescription() : std::nullopt;
446
454
 
447
- // Return JS null if no description
448
- if (!desc.has_value())
449
- {
450
- return env.Null();
451
- }
455
+ // Return JS null if no description
456
+ if (!desc.has_value())
457
+ {
458
+ return env.Null();
459
+ }
452
460
 
453
- Napi::Object obj = Napi::Object::New(env);
454
- obj.Set("type", desc->typeString());
455
- obj.Set("sdp", desc.value());
456
- return obj;
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
- Napi::Env env = info.Env();
469
+ Napi::Env env = info.Env();
462
470
 
463
- std::optional<rtc::Description> desc = mRtcPeerConnPtr ? mRtcPeerConnPtr->remoteDescription() : std::nullopt;
471
+ std::optional<rtc::Description> desc = mRtcPeerConnPtr ? mRtcPeerConnPtr->remoteDescription() : std::nullopt;
464
472
 
465
- // Return JS null if no description
466
- if (!desc.has_value())
467
- {
468
- return env.Null();
469
- }
473
+ // Return JS null if no description
474
+ if (!desc.has_value())
475
+ {
476
+ return env.Null();
477
+ }
470
478
 
471
- Napi::Object obj = Napi::Object::New(env);
472
- obj.Set("type", desc->typeString());
473
- obj.Set("sdp", desc.value());
474
- return obj;
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
- PLOG_DEBUG << "addRemoteCandidate() called";
480
- Napi::Env env = info.Env();
481
- int length = info.Length();
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
- if (!mRtcPeerConnPtr)
484
- {
485
- Napi::Error::New(env, "addRemoteCandidate() called on destroyed peer connection").ThrowAsJavaScriptException();
486
- return;
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
- if (length < 2 || !info[0].IsString() || !info[1].IsString())
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
- Napi::TypeError::New(info.Env(), "String, String expected").ThrowAsJavaScriptException();
492
- return;
541
+ Napi::TypeError::New(env, "Data Channel Init Config expected(As Object)").ThrowAsJavaScriptException();
542
+ return info.Env().Null();
493
543
  }
494
544
 
495
- try
545
+ Napi::Object initConfig = info[1].As<Napi::Object>();
546
+
547
+ if (!initConfig.Get("protocol").IsUndefined())
496
548
  {
497
- std::string candidate = info[0].As<Napi::String>().ToString();
498
- std::string mid = info[0].As<Napi::String>().ToString();
499
- mRtcPeerConnPtr->addRemoteCandidate(rtc::Candidate(candidate, mid));
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
- catch (std::exception &ex)
556
+
557
+ if (!initConfig.Get("negotiated").IsUndefined())
502
558
  {
503
- Napi::Error::New(env, std::string("libdatachannel error while adding remote candidate: ") + ex.what()).ThrowAsJavaScriptException();
504
- return;
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
- Napi::Value PeerConnectionWrapper::createDataChannel(const Napi::CallbackInfo &info)
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
- Napi::Error::New(env, "createDataChannel() called on destroyed peer connection").ThrowAsJavaScriptException();
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
- if (length < 1 || !info[0].IsString())
577
+ // Reliability.unordered parameter
578
+ if (!initConfig.Get("unordered").IsUndefined())
521
579
  {
522
- Napi::TypeError::New(env, "Data Channel Label expected").ThrowAsJavaScriptException();
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
- // Optional Params
527
- rtc::DataChannelInit init;
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
- if (!info[1].IsObject())
531
- {
532
- Napi::TypeError::New(env, "Data Channel Init Config expected(As Object)").ThrowAsJavaScriptException();
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
- try
596
+ if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull())
607
597
  {
608
- std::string label = info[0].As<Napi::String>().ToString();
609
- std::shared_ptr<rtc::DataChannel> dataChannel = mRtcPeerConnPtr->createDataChannel(label, std::move(init));
610
- auto instance = DataChannelWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::DataChannel>>::New(info.Env(), &dataChannel)});
611
- PLOG_DEBUG << "Data Channel created. Label: " << label;
612
- return instance;
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
- catch (std::exception &ex)
606
+ else if (!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
615
607
  {
616
- Napi::Error::New(env, std::string("libdatachannel error while creating datachannel: ") + ex.what()).ThrowAsJavaScriptException();
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
- PLOG_DEBUG << "onLocalDescription() called";
624
- Napi::Env env = info.Env();
625
- int length = info.Length();
626
-
627
- if (!mRtcPeerConnPtr)
628
- {
629
- Napi::Error::New(env, "onLocalDescription() called on destroyed peer connection").ThrowAsJavaScriptException();
630
- return;
631
- }
632
-
633
- if (length < 1 || !info[0].IsFunction())
634
- {
635
- Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
636
- return;
637
- }
638
-
639
- // Callback
640
- mOnLocalDescriptionCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
641
-
642
- mRtcPeerConnPtr->onLocalDescription([&](rtc::Description sdp)
643
- {
644
- PLOG_DEBUG << "onLocalDescription cb received from rtc";
645
- if (mOnLocalDescriptionCallback)
646
- mOnLocalDescriptionCallback->call([this, sdp = std::move(sdp)](Napi::Env env, std::vector<napi_value> &args) {
647
- PLOG_DEBUG << "mOnLocalDescriptionCallback call(1)";
648
- // Check the peer connection is not closed
649
- if(instances.find(this) == instances.end())
650
- throw ThreadSafeCallback::CancelException();
651
-
652
- // This will run in main thread and needs to construct the
653
- // arguments for the call
654
- args = {
655
- Napi::String::New(env, std::string(sdp)),
656
- Napi::String::New(env, sdp.typeString())};
657
- PLOG_DEBUG << "mOnLocalDescriptionCallback call(2)";
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
- PLOG_DEBUG << "onLocalCandidate() called";
664
- Napi::Env env = info.Env();
665
- int length = info.Length();
666
-
667
- if (!mRtcPeerConnPtr)
668
- {
669
- Napi::Error::New(env, "onLocalCandidate() called on destroyed peer connection").ThrowAsJavaScriptException();
670
- return;
671
- }
672
-
673
- if (length < 1 || !info[0].IsFunction())
674
- {
675
- Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
676
- return;
677
- }
678
-
679
- // Callback
680
- mOnLocalCandidateCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
681
-
682
- mRtcPeerConnPtr->onLocalCandidate([&](rtc::Candidate cand)
683
- {
684
- PLOG_DEBUG << "onLocalCandidate cb received from rtc";
685
- if (mOnLocalCandidateCallback)
686
- mOnLocalCandidateCallback->call([this, cand = std::move(cand)](Napi::Env env, std::vector<napi_value> &args) {
687
- PLOG_DEBUG << "mOnLocalCandidateCallback call(1)";
688
- // Check the peer connection is not closed
689
- if(instances.find(this) == instances.end())
690
- throw ThreadSafeCallback::CancelException();
691
-
692
- // This will run in main thread and needs to construct the
693
- // arguments for the call
694
- args = {
695
- Napi::String::New(env, std::string(cand)),
696
- Napi::String::New(env, cand.mid())};
697
- PLOG_DEBUG << "mOnLocalCandidateCallback call(2)";
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
- PLOG_DEBUG << "onStateChange() called";
704
- Napi::Env env = info.Env();
705
- int length = info.Length();
706
-
707
- if (!mRtcPeerConnPtr)
708
- {
709
- Napi::Error::New(env, "onStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
710
- return;
711
- }
712
-
713
- if (length < 1 || !info[0].IsFunction())
714
- {
715
- Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
716
- return;
717
- }
718
-
719
- // Callback
720
- mOnStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
721
-
722
- mRtcPeerConnPtr->onStateChange([&](rtc::PeerConnection::State state)
723
- {
724
- PLOG_DEBUG << "onStateChange cb received from rtc";
725
- if (mOnStateChangeCallback)
726
- mOnStateChangeCallback->call([this, state](Napi::Env env, std::vector<napi_value> &args) {
727
- PLOG_DEBUG << "mOnStateChangeCallback call(1)";
728
- if(instances.find(this) == instances.end())
729
- throw ThreadSafeCallback::CancelException();
730
-
731
- // This will run in main thread and needs to construct the
732
- // arguments for the call
733
- std::ostringstream stream;
734
- stream << state;
735
- args = {Napi::String::New(env, stream.str())};
736
- PLOG_DEBUG << "mOnStateChangeCallback call(2)";
737
- },[this,state](){
738
- PLOG_DEBUG << "mOnStateChangeCallback cleanup";
739
- // Special case for closed state, we need to reset all callbacks
740
- if(state == rtc::PeerConnection::State::Closed)
741
- {
742
- doCleanup();
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
- PLOG_DEBUG << "onIceStateChange() called";
750
- Napi::Env env = info.Env();
751
- int length = info.Length();
752
-
753
- if (!mRtcPeerConnPtr)
754
- {
755
- Napi::Error::New(env, "onIceStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
756
- return;
757
- }
758
-
759
- if (length < 1 || !info[0].IsFunction())
760
- {
761
- Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
762
- return;
763
- }
764
-
765
- // Callback
766
- mOnIceStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
767
-
768
- mRtcPeerConnPtr->onIceStateChange([&](rtc::PeerConnection::IceState state)
769
- {
770
- PLOG_DEBUG << "onIceStateChange cb received from rtc";
771
- if (mOnIceStateChangeCallback)
772
- mOnIceStateChangeCallback->call([this, state](Napi::Env env, std::vector<napi_value> &args) {
773
- PLOG_DEBUG << "mOnIceStateChangeCallback call(1)";
774
- if(instances.find(this) == instances.end())
775
- throw ThreadSafeCallback::CancelException();
776
-
777
- // This will run in main thread and needs to construct the
778
- // arguments for the call
779
- std::ostringstream stream;
780
- stream << state;
781
- args = {Napi::String::New(env, stream.str())};
782
- PLOG_DEBUG << "mOnIceStateChangeCallback call(2)";
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
- PLOG_DEBUG << "onSignalingStateChange() called";
789
- Napi::Env env = info.Env();
790
- int length = info.Length();
791
-
792
- if (!mRtcPeerConnPtr)
793
- {
794
- Napi::Error::New(env, "onSignalingStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
795
- return;
796
- }
797
-
798
- if (length < 1 || !info[0].IsFunction())
799
- {
800
- Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
801
- return;
802
- }
803
-
804
- // Callback
805
- mOnSignalingStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
806
-
807
- mRtcPeerConnPtr->onSignalingStateChange([&](rtc::PeerConnection::SignalingState state)
808
- {
809
- PLOG_DEBUG << "onSignalingStateChange cb received from rtc";
810
- if (mOnSignalingStateChangeCallback)
811
- mOnSignalingStateChangeCallback->call([this, state](Napi::Env env, std::vector<napi_value> &args) {
812
- PLOG_DEBUG << "mOnSignalingStateChangeCallback call(1)";
813
- // Check the peer connection is not closed
814
- if(instances.find(this) == instances.end())
815
- throw ThreadSafeCallback::CancelException();
816
-
817
- // This will run in main thread and needs to construct the
818
- // arguments for the call
819
- std::ostringstream stream;
820
- stream << state;
821
- args = {Napi::String::New(env, stream.str())};
822
- PLOG_DEBUG << "mOnSignalingStateChangeCallback call(2)";
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
- PLOG_DEBUG << "onGatheringStateChange() called";
829
- Napi::Env env = info.Env();
830
- int length = info.Length();
831
-
832
- if (!mRtcPeerConnPtr)
833
- {
834
- Napi::Error::New(env, "onGatheringStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
835
- return;
836
- }
837
-
838
- if (length < 1 || !info[0].IsFunction())
839
- {
840
- Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
841
- return;
842
- }
843
-
844
- // Callback
845
- mOnGatheringStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
846
-
847
- mRtcPeerConnPtr->onGatheringStateChange([&](rtc::PeerConnection::GatheringState state)
848
- {
849
- PLOG_DEBUG << "onGatheringStateChange cb received from rtc";
850
- if (mOnGatheringStateChangeCallback)
851
- mOnGatheringStateChangeCallback->call([this, state](Napi::Env env, std::vector<napi_value> &args) {
852
- PLOG_DEBUG << "mOnGatheringStateChangeCallback call(1)";
853
- // Check the peer connection is not closed
854
- if(instances.find(this) == instances.end())
855
- throw ThreadSafeCallback::CancelException();
856
-
857
- // This will run in main thread and needs to construct the
858
- // arguments for the call
859
- std::ostringstream stream;
860
- stream << state;
861
- args = {Napi::String::New(env, stream.str())};
862
- PLOG_DEBUG << "mOnGatheringStateChangeCallback call(2)";
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
- PLOG_DEBUG << "onDataChannel() called";
869
- Napi::Env env = info.Env();
870
- int length = info.Length();
871
-
872
- if (!mRtcPeerConnPtr)
873
- {
874
- Napi::Error::New(env, "onDataChannel() called on destroyed peer connection").ThrowAsJavaScriptException();
875
- return;
876
- }
877
-
878
- if (length < 1 || !info[0].IsFunction())
879
- {
880
- Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
881
- return;
882
- }
883
-
884
- // Callback
885
- mOnDataChannelCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
886
-
887
- mRtcPeerConnPtr->onDataChannel([&](std::shared_ptr<rtc::DataChannel> dc)
888
- {
889
- PLOG_DEBUG << "onDataChannel cb received from rtc";
890
- if (mOnDataChannelCallback)
891
- mOnDataChannelCallback->call([this, dc](Napi::Env env, std::vector<napi_value> &args) {
892
- PLOG_DEBUG << "mOnDataChannelCallback call(1)";
893
- // Check the peer connection is not closed
894
- if(instances.find(this) == instances.end())
895
- throw ThreadSafeCallback::CancelException();
896
-
897
- // This will run in main thread and needs to construct the
898
- // arguments for the call
899
- std::shared_ptr<rtc::DataChannel> dataChannel = dc;
900
- auto instance = DataChannelWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::DataChannel>>::New(env, &dataChannel)});
901
- args = {instance};
902
- PLOG_DEBUG << "mOnDataChannelCallback call(2)";
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
- PLOG_DEBUG << "bytesSent() called";
909
- Napi::Env env = info.Env();
910
-
911
- if (!mRtcPeerConnPtr)
912
- {
913
- return Napi::Number::New(info.Env(), 0);
914
- }
915
-
916
- try
917
- {
918
- return Napi::Number::New(env, mRtcPeerConnPtr->bytesSent());
919
- }
920
- catch (std::exception &ex)
921
- {
922
- Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
923
- return Napi::Number::New(info.Env(), 0);
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
- PLOG_DEBUG << "bytesReceived() called";
930
- Napi::Env env = info.Env();
931
-
932
- if (!mRtcPeerConnPtr)
933
- {
934
- return Napi::Number::New(info.Env(), 0);
935
- }
936
-
937
- try
938
- {
939
- return Napi::Number::New(env, mRtcPeerConnPtr->bytesReceived());
940
- }
941
- catch (std::exception &ex)
942
- {
943
- Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
944
- return Napi::Number::New(info.Env(), 0);
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
- PLOG_DEBUG << "rtt() called";
951
- Napi::Env env = info.Env();
952
-
953
- if (!mRtcPeerConnPtr)
954
- {
955
- return Napi::Number::New(info.Env(), 0);
956
- }
957
-
958
- try
959
- {
960
- return Napi::Number::New(env, mRtcPeerConnPtr->rtt().value_or(std::chrono::milliseconds(-1)).count());
961
- }
962
- catch (std::exception &ex)
963
- {
964
- Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
965
- return Napi::Number::New(info.Env(), -1);
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
- PLOG_DEBUG << "getSelectedCandidatePair() called";
972
- Napi::Env env = info.Env();
973
-
974
- if (!mRtcPeerConnPtr)
975
- {
976
- return env.Null();
977
- }
978
-
979
- try
980
- {
981
- rtc::Candidate local, remote;
982
- if (!mRtcPeerConnPtr->getSelectedCandidatePair(&local, &remote))
983
- return env.Null();
984
-
985
- Napi::Object retvalue = Napi::Object::New(env);
986
- Napi::Object localObj = Napi::Object::New(env);
987
- Napi::Object remoteObj = Napi::Object::New(env);
988
-
989
- localObj.Set("address", local.address().value_or("?"));
990
- localObj.Set("port", local.port().value_or(0));
991
- localObj.Set("type", candidateTypeToString(local.type()));
992
- localObj.Set("transportType", candidateTransportTypeToString(local.transportType()));
993
- localObj.Set("candidate", local.candidate());
994
- localObj.Set("mid", local.mid());
995
- localObj.Set("priority", local.priority());
996
-
997
- remoteObj.Set("address", remote.address().value_or("?"));
998
- remoteObj.Set("port", remote.port().value_or(0));
999
- remoteObj.Set("type", candidateTypeToString(remote.type()));
1000
- remoteObj.Set("transportType", candidateTransportTypeToString(remote.transportType()));
1001
- remoteObj.Set("candidate", remote.candidate());
1002
- remoteObj.Set("mid", remote.mid());
1003
- remoteObj.Set("priority", remote.priority());
1004
-
1005
- retvalue.Set("local", localObj);
1006
- retvalue.Set("remote", remoteObj);
1007
-
1008
- return retvalue;
1009
- }
1010
- catch (std::exception &ex)
1011
- {
1012
- Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
1013
- return Napi::Number::New(info.Env(), -1);
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
- PLOG_DEBUG << "maxDataChannelId() called";
1020
- Napi::Env env = info.Env();
1021
-
1022
- if (!mRtcPeerConnPtr)
1023
- {
1024
- return Napi::Number::New(info.Env(), 0);
1025
- }
1026
-
1027
- try
1028
- {
1029
- return Napi::Number::New(env, mRtcPeerConnPtr->maxDataChannelId());
1030
- }
1031
- catch (std::exception &ex)
1032
- {
1033
- Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
1034
- return Napi::Number::New(info.Env(), 0);
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
- PLOG_DEBUG << "maxMessageSize() called";
1041
- Napi::Env env = info.Env();
1042
-
1043
- if (!mRtcPeerConnPtr)
1044
- {
1045
- return Napi::Number::New(info.Env(), 0);
1046
- }
1047
-
1048
- try
1049
- {
1050
- return Napi::Array::New(env, mRtcPeerConnPtr->remoteMaxMessageSize());
1051
- }
1052
- catch (std::exception &ex)
1053
- {
1054
- Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
1055
- return Napi::Number::New(info.Env(), 0);
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
- PLOG_DEBUG << "remoteFingerprints() called";
1062
- Napi::Env env = info.Env();
1063
-
1064
- if (!mRtcPeerConnPtr)
1065
- {
1066
- return Napi::Number::New(info.Env(), 0);
1067
- }
1068
-
1069
- try
1070
- {
1071
- auto fingerprint = mRtcPeerConnPtr->remoteFingerprint();
1072
-
1073
- Napi::Object fingerprintObject = Napi::Object::New(env);
1074
- fingerprintObject.Set("value", fingerprint.value);
1075
- fingerprintObject.Set("algorithm", rtc::CertificateFingerprint::AlgorithmIdentifier(fingerprint.algorithm));
1076
-
1077
- return fingerprintObject;
1078
- }
1079
- catch (std::exception &ex)
1080
- {
1081
- Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
1082
- return Napi::Number::New(info.Env(), 0);
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
- PLOG_DEBUG << "candidateTypeToString() called";
1089
- switch (type)
1090
- {
1091
- case rtc::Candidate::Type::Host:
1092
- return "host";
1093
- case rtc::Candidate::Type::PeerReflexive:
1094
- return "prflx";
1095
- case rtc::Candidate::Type::ServerReflexive:
1096
- return "srflx";
1097
- case rtc::Candidate::Type::Relayed:
1098
- return "relay";
1099
- default:
1100
- return "unknown";
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
- PLOG_DEBUG << "candidateTransportTypeToString() called";
1107
- switch (transportType)
1108
- {
1109
- case rtc::Candidate::TransportType::Udp:
1110
- return "UDP";
1111
- case rtc::Candidate::TransportType::TcpActive:
1112
- return "TCP_active";
1113
- case rtc::Candidate::TransportType::TcpPassive:
1114
- return "TCP_passive";
1115
- case rtc::Candidate::TransportType::TcpSo:
1116
- return "TCP_so";
1117
- case rtc::Candidate::TransportType::TcpUnknown:
1118
- return "TCP_unknown";
1119
- default:
1120
- return "unknown";
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
- PLOG_DEBUG << "addTrack() called";
1128
- Napi::Env env = info.Env();
1129
- int length = info.Length();
1130
-
1131
- if (!mRtcPeerConnPtr)
1132
- {
1133
- Napi::Error::New(env, "addTrack() called on destroyed peer connection").ThrowAsJavaScriptException();
1134
- return env.Null();
1135
- }
1136
-
1137
- if (length < 1 || !info[0].IsObject())
1138
- {
1139
- Napi::TypeError::New(env, "Media class instance expected").ThrowAsJavaScriptException();
1140
- return env.Null();
1141
- }
1142
-
1143
- try
1144
- {
1145
- Napi::Object obj = info[0].As<Napi::Object>();
1146
- if (obj.Get("media-type-video").IsBoolean())
1147
- {
1148
- VideoWrapper *videoPtr = Napi::ObjectWrap<VideoWrapper>::Unwrap(obj);
1149
- std::shared_ptr<rtc::Track> track = mRtcPeerConnPtr->addTrack(videoPtr->getVideoInstance());
1150
- auto instance = TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(info.Env(), &track)});
1151
- return instance;
1152
- }
1153
-
1154
- if (obj.Get("media-type-audio").IsBoolean())
1155
- {
1156
- AudioWrapper *audioPtr = Napi::ObjectWrap<AudioWrapper>::Unwrap(obj);
1157
- std::shared_ptr<rtc::Track> track = mRtcPeerConnPtr->addTrack(audioPtr->getAudioInstance());
1158
- auto instance = TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(info.Env(), &track)});
1159
- return instance;
1160
- }
1161
-
1162
- Napi::Error::New(env, std::string("Unknown media type")).ThrowAsJavaScriptException();
1163
- return env.Null();
1164
- }
1165
- catch (std::exception &ex)
1166
- {
1167
- Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
1168
- return env.Null();
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
- PLOG_DEBUG << "onTrack() called";
1175
- Napi::Env env = info.Env();
1176
- int length = info.Length();
1177
-
1178
- if (!mRtcPeerConnPtr)
1179
- {
1180
- Napi::Error::New(env, "onGatheringStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
1181
- return;
1182
- }
1183
-
1184
- if (length < 1 || !info[0].IsFunction())
1185
- {
1186
- Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
1187
- return;
1188
- }
1189
-
1190
- // Callback
1191
- mOnTrackCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
1192
-
1193
- mRtcPeerConnPtr->onTrack([&](std::shared_ptr<rtc::Track> track)
1194
- {
1195
- if (mOnTrackCallback)
1196
- mOnTrackCallback->call([this, track](Napi::Env env, std::vector<napi_value> &args) {
1197
- // Check the peer connection is not closed
1198
- if(instances.find(this) == instances.end())
1199
- throw ThreadSafeCallback::CancelException();
1200
-
1201
- // This will run in main thread and needs to construct the
1202
- // arguments for the call
1203
- std::shared_ptr<rtc::Track> newTrack = track;
1204
- auto instance = TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(env, &newTrack)});
1205
- args = {instance};
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
- PLOG_DEBUG << "hasMedia() called";
1213
- Napi::Env env = info.Env();
1214
- return Napi::Boolean::New(env, mRtcPeerConnPtr ? mRtcPeerConnPtr->hasMedia() : false);
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
- PLOG_DEBUG << "state() called";
1220
- Napi::Env env = info.Env();
1221
- std::ostringstream stream;
1222
- stream << (mRtcPeerConnPtr ? mRtcPeerConnPtr->state() : rtc::PeerConnection::State::Closed);
1223
- return Napi::String::New(env, stream.str());
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
- PLOG_DEBUG << "iceState() called";
1229
- Napi::Env env = info.Env();
1230
- std::ostringstream stream;
1231
- stream << (mRtcPeerConnPtr ? mRtcPeerConnPtr->iceState() : rtc::PeerConnection::IceState::Closed);
1232
- return Napi::String::New(env, stream.str());
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
- PLOG_DEBUG << "signalingState() called";
1238
- Napi::Env env = info.Env();
1239
- std::ostringstream stream;
1240
- stream << (mRtcPeerConnPtr ? mRtcPeerConnPtr->signalingState() : rtc::PeerConnection::SignalingState::Stable);
1241
- return Napi::String::New(env, stream.str());
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
- PLOG_DEBUG << "gatheringState() called";
1247
- Napi::Env env = info.Env();
1248
- std::ostringstream stream;
1249
- stream << (mRtcPeerConnPtr ? mRtcPeerConnPtr->gatheringState() : rtc::PeerConnection::GatheringState::Complete);
1250
- return Napi::String::New(env, stream.str());
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
  }