node-datachannel 0.3.0 → 0.3.3

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 (54) hide show
  1. package/.github/workflows/build-linux.yml +1 -1
  2. package/.github/workflows/build-mac.yml +1 -1
  3. package/.github/workflows/build-win.yml +1 -1
  4. package/.github/workflows/lint.yml +19 -0
  5. package/CMakeLists.txt +3 -3
  6. package/README.md +2 -0
  7. package/examples/client-server/client-benchmark.js +43 -32
  8. package/examples/client-server/client-periodic.js +30 -14
  9. package/examples/client-server/client.js +6 -5
  10. package/examples/client-server/package-lock.json +183 -44
  11. package/examples/client-server/signaling-server.js +3 -5
  12. package/examples/media/media.js +9 -9
  13. package/lib/index.d.ts +102 -101
  14. package/node_modules/lru-cache/package.json +2 -4
  15. package/node_modules/minimist/package.json +0 -1
  16. package/node_modules/node-abi/node_modules/semver/README.md +3 -1
  17. package/node_modules/node-abi/node_modules/semver/bin/semver.js +19 -9
  18. package/node_modules/node-abi/node_modules/semver/classes/comparator.js +3 -2
  19. package/node_modules/node-abi/node_modules/semver/classes/index.js +1 -1
  20. package/node_modules/node-abi/node_modules/semver/classes/range.js +31 -22
  21. package/node_modules/node-abi/node_modules/semver/classes/semver.js +1 -1
  22. package/node_modules/node-abi/node_modules/semver/functions/cmp.js +8 -4
  23. package/node_modules/node-abi/node_modules/semver/functions/coerce.js +3 -2
  24. package/node_modules/node-abi/node_modules/semver/functions/inc.js +4 -1
  25. package/node_modules/node-abi/node_modules/semver/functions/parse.js +1 -1
  26. package/node_modules/node-abi/node_modules/semver/internal/constants.js +2 -2
  27. package/node_modules/node-abi/node_modules/semver/internal/identifiers.js +1 -1
  28. package/node_modules/node-abi/node_modules/semver/internal/parse-options.js +3 -3
  29. package/node_modules/node-abi/node_modules/semver/internal/re.js +3 -3
  30. package/node_modules/node-abi/node_modules/semver/package.json +51 -18
  31. package/node_modules/node-abi/node_modules/semver/ranges/min-version.js +2 -1
  32. package/node_modules/node-abi/node_modules/semver/ranges/outside.js +1 -1
  33. package/node_modules/node-abi/node_modules/semver/ranges/simplify.js +15 -12
  34. package/node_modules/node-abi/node_modules/semver/ranges/subset.js +53 -31
  35. package/node_modules/npmlog/node_modules/are-we-there-yet/package.json +10 -10
  36. package/node_modules/npmlog/package.json +1 -1
  37. package/node_modules/tar-stream/node_modules/bl/.travis.yml +4 -3
  38. package/node_modules/tar-stream/node_modules/bl/BufferList.js +1 -1
  39. package/node_modules/tar-stream/node_modules/bl/package.json +10 -10
  40. package/node_modules/tar-stream/node_modules/bl/test/test.js +20 -2
  41. package/node_modules/wide-align/LICENSE +0 -0
  42. package/node_modules/wide-align/README.md +0 -0
  43. package/node_modules/wide-align/align.js +0 -0
  44. package/node_modules/wide-align/package.json +14 -14
  45. package/package.json +2 -2
  46. package/src/data-channel-wrapper.cpp +69 -53
  47. package/src/data-channel-wrapper.h +0 -1
  48. package/src/media-track-wrapper.cpp +91 -52
  49. package/src/media-track-wrapper.h +0 -1
  50. package/src/peer-connection-wrapper.cpp +111 -71
  51. package/src/peer-connection-wrapper.h +0 -2
  52. package/test/connectivity.js +18 -17
  53. package/test/test.js +22 -30
  54. package/node_modules/node-abi/node_modules/semver/CHANGELOG.md +0 -111
@@ -63,7 +63,7 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
63
63
  // We expect (String, Object, Function) as param
64
64
  if (length < 2 || !info[0].IsString() || !info[1].IsObject())
65
65
  {
66
- Napi::TypeError::New(env, "Peer Name (String) & Configuration (Object) expected").ThrowAsJavaScriptException();
66
+ Napi::TypeError::New(env, "Peer Name (String) and Configuration (Object) expected").ThrowAsJavaScriptException();
67
67
  return;
68
68
  }
69
69
 
@@ -182,7 +182,11 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
182
182
 
183
183
  // Max Message Size
184
184
  if (config.Get("maxMessageSize").IsNumber())
185
- rtcConfig.maxMessageSize = config.Get("maxMessageSize").As<Napi::Number>().Uint32Value();
185
+ rtcConfig.maxMessageSize = config.Get("maxMessageSize").As<Napi::Number>().Int32Value();
186
+
187
+ // MTU
188
+ if (config.Get("mtu").IsNumber())
189
+ rtcConfig.mtu = config.Get("mtu").As<Napi::Number>().Int32Value();
186
190
 
187
191
  // ICE transport policy
188
192
  if (!config.Get("iceTransportPolicy").IsUndefined())
@@ -211,31 +215,10 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
211
215
  }
212
216
  catch (std::exception &ex)
213
217
  {
214
- Napi::Error::New(env, std::string("libdatachannel error while creating peerConnection# ") + ex.what()).ThrowAsJavaScriptException();
218
+ Napi::Error::New(env, std::string("libdatachannel error while creating peer connection: ") + ex.what()).ThrowAsJavaScriptException();
215
219
  return;
216
220
  }
217
221
 
218
- mRtcPeerConnPtr->onStateChange([&](rtc::PeerConnection::State state) {
219
- if (mOnStateChangeCallback)
220
- mOnStateChangeCallback->call([this, state](Napi::Env env, std::vector<napi_value> &args) {
221
- // Check the peer connection is not closed
222
- if(instances.find(this) == instances.end())
223
- throw ThreadSafeCallback::CancelException();
224
-
225
- if(mDoCloseFlag && state == rtc::PeerConnection::State::Closed)
226
- cleanCbsAndEraseInstance();
227
-
228
- // This will run in main thread and needs to construct the
229
- // arguments for the call
230
- std::ostringstream stream;
231
- stream << state;
232
- args = {Napi::String::New(env, stream.str())};
233
- });
234
- else {
235
- if(mDoCloseFlag && state == rtc::PeerConnection::State::Closed)
236
- cleanCbsAndEraseInstance();
237
- } });
238
-
239
222
  instances.insert(this);
240
223
  }
241
224
 
@@ -246,26 +229,20 @@ PeerConnectionWrapper::~PeerConnectionWrapper()
246
229
 
247
230
  void PeerConnectionWrapper::doClose()
248
231
  {
249
- if (mRtcPeerConnPtr && !mDoCloseFlag)
232
+ if (mRtcPeerConnPtr)
250
233
  {
251
234
  try
252
235
  {
253
- mDoCloseFlag = true;
254
236
  mRtcPeerConnPtr->close();
255
-
256
- // Resetting in cleanCbsAndEraseInstance causes a deadlock
257
237
  mRtcPeerConnPtr.reset();
258
238
  }
259
239
  catch (std::exception &ex)
260
240
  {
261
- std::cout << std::string("libdatachannel error while closing peerConnection# ") + ex.what() << std::endl;
241
+ std::cerr << std::string("libdatachannel error while closing peer connection: ") + ex.what() << std::endl;
262
242
  return;
263
243
  }
264
244
  }
265
- }
266
245
 
267
- void PeerConnectionWrapper::cleanCbsAndEraseInstance()
268
- {
269
246
  mOnLocalDescriptionCallback.reset();
270
247
  mOnLocalCandidateCallback.reset();
271
248
  mOnStateChangeCallback.reset();
@@ -274,8 +251,6 @@ void PeerConnectionWrapper::cleanCbsAndEraseInstance()
274
251
  mOnTrackCallback.reset();
275
252
 
276
253
  instances.erase(this);
277
-
278
- mDoCloseFlag = false;
279
254
  }
280
255
 
281
256
  void PeerConnectionWrapper::close(const Napi::CallbackInfo &info)
@@ -286,14 +261,14 @@ void PeerConnectionWrapper::close(const Napi::CallbackInfo &info)
286
261
  void PeerConnectionWrapper::setLocalDescription(const Napi::CallbackInfo &info)
287
262
  {
288
263
  Napi::Env env = info.Env();
264
+ int length = info.Length();
265
+
289
266
  if (!mRtcPeerConnPtr)
290
267
  {
291
- Napi::Error::New(info.Env(), "It seems peer-connection is closed").ThrowAsJavaScriptException();
268
+ Napi::Error::New(env, "setLocalDescription() called on destroyed peer connection").ThrowAsJavaScriptException();
292
269
  return;
293
270
  }
294
271
 
295
- int length = info.Length();
296
-
297
272
  rtc::Description::Type type = rtc::Description::Type::Unspec;
298
273
 
299
274
  // optional
@@ -322,13 +297,14 @@ void PeerConnectionWrapper::setLocalDescription(const Napi::CallbackInfo &info)
322
297
  void PeerConnectionWrapper::setRemoteDescription(const Napi::CallbackInfo &info)
323
298
  {
324
299
  Napi::Env env = info.Env();
300
+ int length = info.Length();
301
+
325
302
  if (!mRtcPeerConnPtr)
326
303
  {
327
- Napi::Error::New(info.Env(), "It seems peer-connection is closed").ThrowAsJavaScriptException();
304
+ Napi::Error::New(env, "setRemoteDescription() called on destroyed peer connection").ThrowAsJavaScriptException();
328
305
  return;
329
306
  }
330
307
 
331
- int length = info.Length();
332
308
  if (length < 2 || !info[0].IsString() || !info[1].IsString())
333
309
  {
334
310
  Napi::TypeError::New(info.Env(), "String,String expected").ThrowAsJavaScriptException();
@@ -345,7 +321,7 @@ void PeerConnectionWrapper::setRemoteDescription(const Napi::CallbackInfo &info)
345
321
  }
346
322
  catch (std::exception &ex)
347
323
  {
348
- Napi::Error::New(env, std::string("libdatachannel error while adding remote decsription # ") + ex.what()).ThrowAsJavaScriptException();
324
+ Napi::Error::New(env, std::string("libdatachannel error while adding remote description: ") + ex.what()).ThrowAsJavaScriptException();
349
325
  return;
350
326
  }
351
327
  }
@@ -353,7 +329,13 @@ void PeerConnectionWrapper::setRemoteDescription(const Napi::CallbackInfo &info)
353
329
  Napi::Value PeerConnectionWrapper::localDescription(const Napi::CallbackInfo &info)
354
330
  {
355
331
  Napi::Env env = info.Env();
356
- std::optional<rtc::Description> desc = mRtcPeerConnPtr->localDescription();
332
+
333
+ std::optional<rtc::Description> desc = mRtcPeerConnPtr ? mRtcPeerConnPtr->localDescription() : std::nullopt;
334
+
335
+ // Return JS null if no description
336
+ if (!desc.has_value()) {
337
+ return env.Null();
338
+ }
357
339
 
358
340
  Napi::Object obj = Napi::Object::New(env);
359
341
  obj.Set("type", desc->typeString());
@@ -364,16 +346,17 @@ Napi::Value PeerConnectionWrapper::localDescription(const Napi::CallbackInfo &in
364
346
  void PeerConnectionWrapper::addRemoteCandidate(const Napi::CallbackInfo &info)
365
347
  {
366
348
  Napi::Env env = info.Env();
349
+ int length = info.Length();
350
+
367
351
  if (!mRtcPeerConnPtr)
368
352
  {
369
- Napi::Error::New(info.Env(), "It seems peer-connection is closed").ThrowAsJavaScriptException();
353
+ Napi::Error::New(env, "addRemoteCandidate() called on destroyed peer connection").ThrowAsJavaScriptException();
370
354
  return;
371
355
  }
372
356
 
373
- int length = info.Length();
374
357
  if (length < 2 || !info[0].IsString() || !info[1].IsString())
375
358
  {
376
- Napi::TypeError::New(info.Env(), "String,String expected").ThrowAsJavaScriptException();
359
+ Napi::TypeError::New(info.Env(), "String, String expected").ThrowAsJavaScriptException();
377
360
  return;
378
361
  }
379
362
 
@@ -385,22 +368,22 @@ void PeerConnectionWrapper::addRemoteCandidate(const Napi::CallbackInfo &info)
385
368
  }
386
369
  catch (std::exception &ex)
387
370
  {
388
- Napi::Error::New(env, std::string("libdatachannel error while adding remote candidate# ") + ex.what()).ThrowAsJavaScriptException();
371
+ Napi::Error::New(env, std::string("libdatachannel error while adding remote candidate: ") + ex.what()).ThrowAsJavaScriptException();
389
372
  return;
390
373
  }
391
374
  }
392
375
 
393
376
  Napi::Value PeerConnectionWrapper::createDataChannel(const Napi::CallbackInfo &info)
394
377
  {
378
+ Napi::Env env = info.Env();
379
+ int length = info.Length();
380
+
395
381
  if (!mRtcPeerConnPtr)
396
382
  {
397
- Napi::Error::New(info.Env(), "It seems peer-connection is closed").ThrowAsJavaScriptException();
383
+ Napi::Error::New(env, "createDataChannel() called on destroyed peer connection").ThrowAsJavaScriptException();
398
384
  return info.Env().Null();
399
385
  }
400
386
 
401
- Napi::Env env = info.Env();
402
- int length = info.Length();
403
-
404
387
  if (length < 1 || !info[0].IsString())
405
388
  {
406
389
  Napi::TypeError::New(env, "Data Channel Label expected").ThrowAsJavaScriptException();
@@ -554,7 +537,7 @@ Napi::Value PeerConnectionWrapper::createDataChannel(const Napi::CallbackInfo &i
554
537
  }
555
538
  catch (std::exception &ex)
556
539
  {
557
- Napi::Error::New(env, std::string("libdatachannel error while creating datachannel# ") + ex.what()).ThrowAsJavaScriptException();
540
+ Napi::Error::New(env, std::string("libdatachannel error while creating datachannel: ") + ex.what()).ThrowAsJavaScriptException();
558
541
  return info.Env().Null();
559
542
  }
560
543
  }
@@ -564,6 +547,12 @@ void PeerConnectionWrapper::onLocalDescription(const Napi::CallbackInfo &info)
564
547
  Napi::Env env = info.Env();
565
548
  int length = info.Length();
566
549
 
550
+ if (!mRtcPeerConnPtr)
551
+ {
552
+ Napi::Error::New(env, "onLocalDescription() called on destroyed peer connection").ThrowAsJavaScriptException();
553
+ return;
554
+ }
555
+
567
556
  if (length < 1 || !info[0].IsFunction())
568
557
  {
569
558
  Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
@@ -573,9 +562,9 @@ void PeerConnectionWrapper::onLocalDescription(const Napi::CallbackInfo &info)
573
562
  // Callback
574
563
  mOnLocalDescriptionCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
575
564
 
576
- mRtcPeerConnPtr->onLocalDescription([&](const rtc::Description &sdp) {
565
+ mRtcPeerConnPtr->onLocalDescription([&](rtc::Description sdp) {
577
566
  if (mOnLocalDescriptionCallback)
578
- mOnLocalDescriptionCallback->call([this, sdp](Napi::Env env, std::vector<napi_value> &args) {
567
+ mOnLocalDescriptionCallback->call([this, sdp = std::move(sdp)](Napi::Env env, std::vector<napi_value> &args) {
579
568
  // Check the peer connection is not closed
580
569
  if(instances.find(this) == instances.end())
581
570
  throw ThreadSafeCallback::CancelException();
@@ -593,6 +582,12 @@ void PeerConnectionWrapper::onLocalCandidate(const Napi::CallbackInfo &info)
593
582
  Napi::Env env = info.Env();
594
583
  int length = info.Length();
595
584
 
585
+ if (!mRtcPeerConnPtr)
586
+ {
587
+ Napi::Error::New(env, "onLocalCandidate() called on destroyed peer connection").ThrowAsJavaScriptException();
588
+ return;
589
+ }
590
+
596
591
  if (length < 1 || !info[0].IsFunction())
597
592
  {
598
593
  Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
@@ -602,9 +597,9 @@ void PeerConnectionWrapper::onLocalCandidate(const Napi::CallbackInfo &info)
602
597
  // Callback
603
598
  mOnLocalCandidateCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
604
599
 
605
- mRtcPeerConnPtr->onLocalCandidate([&](const rtc::Candidate &candidate) {
600
+ mRtcPeerConnPtr->onLocalCandidate([&](rtc::Candidate cand) {
606
601
  if (mOnLocalCandidateCallback)
607
- mOnLocalCandidateCallback->call([this, candidate](Napi::Env env, std::vector<napi_value> &args) {
602
+ mOnLocalCandidateCallback->call([this, cand = std::move(cand)](Napi::Env env, std::vector<napi_value> &args) {
608
603
  // Check the peer connection is not closed
609
604
  if(instances.find(this) == instances.end())
610
605
  throw ThreadSafeCallback::CancelException();
@@ -612,8 +607,8 @@ void PeerConnectionWrapper::onLocalCandidate(const Napi::CallbackInfo &info)
612
607
  // This will run in main thread and needs to construct the
613
608
  // arguments for the call
614
609
  args = {
615
- Napi::String::New(env, std::string(candidate)),
616
- Napi::String::New(env, candidate.mid())};
610
+ Napi::String::New(env, std::string(cand)),
611
+ Napi::String::New(env, cand.mid())};
617
612
  }); });
618
613
  }
619
614
 
@@ -622,6 +617,12 @@ void PeerConnectionWrapper::onStateChange(const Napi::CallbackInfo &info)
622
617
  Napi::Env env = info.Env();
623
618
  int length = info.Length();
624
619
 
620
+ if (!mRtcPeerConnPtr)
621
+ {
622
+ Napi::Error::New(env, "onStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
623
+ return;
624
+ }
625
+
625
626
  if (length < 1 || !info[0].IsFunction())
626
627
  {
627
628
  Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
@@ -631,7 +632,19 @@ void PeerConnectionWrapper::onStateChange(const Napi::CallbackInfo &info)
631
632
  // Callback
632
633
  mOnStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
633
634
 
634
- // onState cb will be called from constructor
635
+ mRtcPeerConnPtr->onStateChange([&](rtc::PeerConnection::State state) {
636
+ if (mOnStateChangeCallback)
637
+ mOnStateChangeCallback->call([this, state](Napi::Env env, std::vector<napi_value> &args) {
638
+ // Check the peer connection is not closed but still allow a call for State::Closed
639
+ if(state != rtc::PeerConnection::State::Closed && instances.find(this) == instances.end())
640
+ throw ThreadSafeCallback::CancelException();
641
+
642
+ // This will run in main thread and needs to construct the
643
+ // arguments for the call
644
+ std::ostringstream stream;
645
+ stream << state;
646
+ args = {Napi::String::New(env, stream.str())};
647
+ }); });
635
648
  }
636
649
 
637
650
  void PeerConnectionWrapper::onSignalingStateChange(const Napi::CallbackInfo &info)
@@ -639,6 +652,12 @@ void PeerConnectionWrapper::onSignalingStateChange(const Napi::CallbackInfo &inf
639
652
  Napi::Env env = info.Env();
640
653
  int length = info.Length();
641
654
 
655
+ if (!mRtcPeerConnPtr)
656
+ {
657
+ Napi::Error::New(env, "onSignalingStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
658
+ return;
659
+ }
660
+
642
661
  if (length < 1 || !info[0].IsFunction())
643
662
  {
644
663
  Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
@@ -668,6 +687,12 @@ void PeerConnectionWrapper::onGatheringStateChange(const Napi::CallbackInfo &inf
668
687
  Napi::Env env = info.Env();
669
688
  int length = info.Length();
670
689
 
690
+ if (!mRtcPeerConnPtr)
691
+ {
692
+ Napi::Error::New(env, "onGatheringStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
693
+ return;
694
+ }
695
+
671
696
  if (length < 1 || !info[0].IsFunction())
672
697
  {
673
698
  Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
@@ -697,6 +722,12 @@ void PeerConnectionWrapper::onDataChannel(const Napi::CallbackInfo &info)
697
722
  Napi::Env env = info.Env();
698
723
  int length = info.Length();
699
724
 
725
+ if (!mRtcPeerConnPtr)
726
+ {
727
+ Napi::Error::New(env, "onDataChannel() called on destroyed peer connection").ThrowAsJavaScriptException();
728
+ return;
729
+ }
730
+
700
731
  if (length < 1 || !info[0].IsFunction())
701
732
  {
702
733
  Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
@@ -725,6 +756,7 @@ void PeerConnectionWrapper::onDataChannel(const Napi::CallbackInfo &info)
725
756
  Napi::Value PeerConnectionWrapper::bytesSent(const Napi::CallbackInfo &info)
726
757
  {
727
758
  Napi::Env env = info.Env();
759
+
728
760
  if (!mRtcPeerConnPtr)
729
761
  {
730
762
  return Napi::Number::New(info.Env(), 0);
@@ -736,7 +768,7 @@ Napi::Value PeerConnectionWrapper::bytesSent(const Napi::CallbackInfo &info)
736
768
  }
737
769
  catch (std::exception &ex)
738
770
  {
739
- Napi::Error::New(env, std::string("libdatachannel error# ") + ex.what()).ThrowAsJavaScriptException();
771
+ Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
740
772
  return Napi::Number::New(info.Env(), 0);
741
773
  }
742
774
  }
@@ -744,6 +776,7 @@ Napi::Value PeerConnectionWrapper::bytesSent(const Napi::CallbackInfo &info)
744
776
  Napi::Value PeerConnectionWrapper::bytesReceived(const Napi::CallbackInfo &info)
745
777
  {
746
778
  Napi::Env env = info.Env();
779
+
747
780
  if (!mRtcPeerConnPtr)
748
781
  {
749
782
  return Napi::Number::New(info.Env(), 0);
@@ -755,7 +788,7 @@ Napi::Value PeerConnectionWrapper::bytesReceived(const Napi::CallbackInfo &info)
755
788
  }
756
789
  catch (std::exception &ex)
757
790
  {
758
- Napi::Error::New(env, std::string("libdatachannel error# ") + ex.what()).ThrowAsJavaScriptException();
791
+ Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
759
792
  return Napi::Number::New(info.Env(), 0);
760
793
  }
761
794
  }
@@ -763,6 +796,7 @@ Napi::Value PeerConnectionWrapper::bytesReceived(const Napi::CallbackInfo &info)
763
796
  Napi::Value PeerConnectionWrapper::rtt(const Napi::CallbackInfo &info)
764
797
  {
765
798
  Napi::Env env = info.Env();
799
+
766
800
  if (!mRtcPeerConnPtr)
767
801
  {
768
802
  return Napi::Number::New(info.Env(), 0);
@@ -774,7 +808,7 @@ Napi::Value PeerConnectionWrapper::rtt(const Napi::CallbackInfo &info)
774
808
  }
775
809
  catch (std::exception &ex)
776
810
  {
777
- Napi::Error::New(env, std::string("libdatachannel error# ") + ex.what()).ThrowAsJavaScriptException();
811
+ Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
778
812
  return Napi::Number::New(info.Env(), -1);
779
813
  }
780
814
  }
@@ -782,16 +816,17 @@ Napi::Value PeerConnectionWrapper::rtt(const Napi::CallbackInfo &info)
782
816
  Napi::Value PeerConnectionWrapper::getSelectedCandidatePair(const Napi::CallbackInfo &info)
783
817
  {
784
818
  Napi::Env env = info.Env();
819
+
785
820
  if (!mRtcPeerConnPtr)
786
821
  {
787
- return Napi::Number::New(info.Env(), 0);
822
+ return env.Null();
788
823
  }
789
824
 
790
825
  try
791
826
  {
792
827
  rtc::Candidate local, remote;
793
828
  if (!mRtcPeerConnPtr->getSelectedCandidatePair(&local, &remote))
794
- return info.Env().Null();
829
+ return env.Null();
795
830
 
796
831
  Napi::Object retvalue = Napi::Object::New(env);
797
832
  Napi::Object localObj = Napi::Object::New(env);
@@ -814,7 +849,7 @@ Napi::Value PeerConnectionWrapper::getSelectedCandidatePair(const Napi::Callback
814
849
  }
815
850
  catch (std::exception &ex)
816
851
  {
817
- Napi::Error::New(env, std::string("libdatachannel error# ") + ex.what()).ThrowAsJavaScriptException();
852
+ Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
818
853
  return Napi::Number::New(info.Env(), -1);
819
854
  }
820
855
  }
@@ -862,7 +897,7 @@ Napi::Value PeerConnectionWrapper::addTrack(const Napi::CallbackInfo &info)
862
897
 
863
898
  if (!mRtcPeerConnPtr)
864
899
  {
865
- Napi::Error::New(info.Env(), "It seems peer-connection is closed").ThrowAsJavaScriptException();
900
+ Napi::Error::New(env, "addTrack() called on destroyed peer connection").ThrowAsJavaScriptException();
866
901
  return env.Null();
867
902
  }
868
903
 
@@ -896,7 +931,7 @@ Napi::Value PeerConnectionWrapper::addTrack(const Napi::CallbackInfo &info)
896
931
  }
897
932
  catch (std::exception &ex)
898
933
  {
899
- Napi::Error::New(env, std::string("libdatachannel error# ") + ex.what()).ThrowAsJavaScriptException();
934
+ Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
900
935
  return env.Null();
901
936
  }
902
937
  }
@@ -906,6 +941,12 @@ void PeerConnectionWrapper::onTrack(const Napi::CallbackInfo &info)
906
941
  Napi::Env env = info.Env();
907
942
  int length = info.Length();
908
943
 
944
+ if (!mRtcPeerConnPtr)
945
+ {
946
+ Napi::Error::New(env, "onGatheringStateChange() called on destroyed peer connection").ThrowAsJavaScriptException();
947
+ return;
948
+ }
949
+
909
950
  if (length < 1 || !info[0].IsFunction())
910
951
  {
911
952
  Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
@@ -915,8 +956,7 @@ void PeerConnectionWrapper::onTrack(const Napi::CallbackInfo &info)
915
956
  // Callback
916
957
  mOnTrackCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
917
958
 
918
- mRtcPeerConnPtr->onTrack([&](std::shared_ptr<rtc::Track> track)
919
- {
959
+ mRtcPeerConnPtr->onTrack([&](std::shared_ptr<rtc::Track> track) {
920
960
  if (mOnTrackCallback)
921
961
  mOnTrackCallback->call([this, track](Napi::Env env, std::vector<napi_value> &args) {
922
962
  // Check the peer connection is not closed
@@ -934,14 +974,14 @@ void PeerConnectionWrapper::onTrack(const Napi::CallbackInfo &info)
934
974
  Napi::Value PeerConnectionWrapper::hasMedia(const Napi::CallbackInfo &info)
935
975
  {
936
976
  Napi::Env env = info.Env();
937
- return Napi::Boolean::New(env, mRtcPeerConnPtr->hasMedia());
977
+ return Napi::Boolean::New(env, mRtcPeerConnPtr ? mRtcPeerConnPtr->hasMedia() : false);
938
978
  }
939
979
 
940
980
  Napi::Value PeerConnectionWrapper::state(const Napi::CallbackInfo &info)
941
981
  {
942
982
  Napi::Env env = info.Env();
943
983
  std::ostringstream stream;
944
- stream << mRtcPeerConnPtr->state();
984
+ stream << (mRtcPeerConnPtr ? mRtcPeerConnPtr->state() : rtc::PeerConnection::State::Closed);
945
985
  return Napi::String::New(env, stream.str());
946
986
  }
947
987
 
@@ -949,7 +989,7 @@ Napi::Value PeerConnectionWrapper::signalingState(const Napi::CallbackInfo &info
949
989
  {
950
990
  Napi::Env env = info.Env();
951
991
  std::ostringstream stream;
952
- stream << mRtcPeerConnPtr->signalingState();
992
+ stream << (mRtcPeerConnPtr ? mRtcPeerConnPtr->signalingState() : rtc::PeerConnection::SignalingState::Stable);
953
993
  return Napi::String::New(env, stream.str());
954
994
  }
955
995
 
@@ -957,6 +997,6 @@ Napi::Value PeerConnectionWrapper::gatheringState(const Napi::CallbackInfo &info
957
997
  {
958
998
  Napi::Env env = info.Env();
959
999
  std::ostringstream stream;
960
- stream << mRtcPeerConnPtr->gatheringState();
1000
+ stream << (mRtcPeerConnPtr ? mRtcPeerConnPtr->gatheringState() : rtc::PeerConnection::GatheringState::Complete);
961
1001
  return Napi::String::New(env, stream.str());
962
1002
  }
@@ -55,8 +55,6 @@ private:
55
55
  static std::unordered_set<PeerConnectionWrapper *> instances;
56
56
 
57
57
  void doClose();
58
- void cleanCbsAndEraseInstance();
59
- bool mDoCloseFlag = false;
60
58
 
61
59
  std::string mPeerName;
62
60
  std::unique_ptr<rtc::PeerConnection> mRtcPeerConnPtr = nullptr;
@@ -1,6 +1,7 @@
1
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
1
2
  const nodeDataChannel = require('../lib/index');
2
3
 
3
- nodeDataChannel.initLogger("Debug");
4
+ nodeDataChannel.initLogger('Debug');
4
5
  nodeDataChannel.preload();
5
6
 
6
7
  let dc1 = null;
@@ -24,51 +25,51 @@ let dc2 = null;
24
25
  // TURN Server Example (TCP) : turn:USERNAME:PASSWORD@TURN_IP_OR_ADDRESS:PORT?transport=tcp
25
26
  // TURN Server Example (TLS) : turns:USERNAME:PASSWORD@TURN_IP_OR_ADDRESS:PORT
26
27
 
27
- let peer1 = new nodeDataChannel.PeerConnection("Peer1", { iceServers: ["stun:stun.l.google.com:19302"] });
28
+ let peer1 = new nodeDataChannel.PeerConnection('Peer1', { iceServers: ['stun:stun.l.google.com:19302'] });
28
29
 
29
30
  // Set Callbacks
30
31
  peer1.onStateChange((state) => {
31
- console.log("Peer1 State:", state);
32
+ console.log('Peer1 State:', state);
32
33
  });
33
34
  peer1.onGatheringStateChange((state) => {
34
- console.log("Peer1 GatheringState:", state);
35
+ console.log('Peer1 GatheringState:', state);
35
36
  });
36
37
  peer1.onLocalDescription((sdp, type) => {
37
- console.log("Peer1 SDP:", sdp, " Type:", type);
38
+ console.log('Peer1 SDP:', sdp, ' Type:', type);
38
39
  peer2.setRemoteDescription(sdp, type);
39
40
  });
40
41
  peer1.onLocalCandidate((candidate, mid) => {
41
- console.log("Peer1 Candidate:", candidate);
42
+ console.log('Peer1 Candidate:', candidate);
42
43
  peer2.addRemoteCandidate(candidate, mid);
43
44
  });
44
45
 
45
- let peer2 = new nodeDataChannel.PeerConnection("Peer2", { iceServers: ["stun:stun.l.google.com:19302"] });
46
+ let peer2 = new nodeDataChannel.PeerConnection('Peer2', { iceServers: ['stun:stun.l.google.com:19302'] });
46
47
 
47
48
  // Set Callbacks
48
49
  peer2.onStateChange((state) => {
49
- console.log("Peer2 State:", state);
50
+ console.log('Peer2 State:', state);
50
51
  });
51
52
  peer2.onGatheringStateChange((state) => {
52
- console.log("Peer2 GatheringState:", state);
53
+ console.log('Peer2 GatheringState:', state);
53
54
  });
54
55
  peer2.onLocalDescription((sdp, type) => {
55
- console.log("Peer2 SDP:", sdp, " Type:", type);
56
+ console.log('Peer2 SDP:', sdp, ' Type:', type);
56
57
  peer1.setRemoteDescription(sdp, type);
57
58
  });
58
59
  peer2.onLocalCandidate((candidate, mid) => {
59
- console.log("Peer2 Candidate:", candidate);
60
+ console.log('Peer2 Candidate:', candidate);
60
61
  peer1.addRemoteCandidate(candidate, mid);
61
62
  });
62
63
  peer2.onDataChannel((dc) => {
63
- console.log("Peer2 Got DataChannel: ", dc.getLabel());
64
+ console.log('Peer2 Got DataChannel: ', dc.getLabel());
64
65
  dc2 = dc;
65
66
  dc2.onMessage((msg) => {
66
67
  console.log('Peer2 Received Msg:', msg);
67
68
  });
68
- dc2.sendMessage("Hello From Peer2");
69
+ dc2.sendMessage('Hello From Peer2');
69
70
  dc2.onClosed(() => {
70
71
  console.log('dc2 closed');
71
- });
72
+ });
72
73
  });
73
74
 
74
75
  // DataChannel Options
@@ -80,16 +81,16 @@ peer2.onDataChannel((dc) => {
80
81
  // maxPacketLifeTime?: number;
81
82
  // maxRetransmits?: number;
82
83
  // }
83
- dc1 = peer1.createDataChannel("test");
84
+ dc1 = peer1.createDataChannel('test');
84
85
  dc1.onOpen(() => {
85
- dc1.sendMessage("Hello from Peer1");
86
+ dc1.sendMessage('Hello from Peer1');
86
87
  // Binary message: Use sendMessageBinary(Buffer)
87
88
  });
88
89
  dc1.onMessage((msg) => {
89
90
  console.log('Peer1 Received Msg:', msg);
90
91
  });
91
92
  dc1.onClosed(() => {
92
- console.log('dc1 closed');
93
+ console.log('dc1 closed');
93
94
  });
94
95
 
95
96
  setTimeout(() => {