node-datachannel 0.28.0 → 0.30.0

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