node-datachannel 0.1.14 → 0.2.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.
@@ -1,15 +1,18 @@
1
1
  #include "peer-connection-wrapper.h"
2
2
  #include "data-channel-wrapper.h"
3
+ #include "media-track-wrapper.h"
4
+ #include "media-video-wrapper.h"
5
+ #include "media-audio-wrapper.h"
3
6
 
4
7
  #include <sstream>
5
8
 
6
9
  Napi::FunctionReference PeerConnectionWrapper::constructor;
7
- std::unordered_set<PeerConnectionWrapper*> PeerConnectionWrapper::instances;
10
+ std::unordered_set<PeerConnectionWrapper *> PeerConnectionWrapper::instances;
8
11
 
9
12
  void PeerConnectionWrapper::CloseAll()
10
13
  {
11
14
  auto copy(instances);
12
- for(auto inst : copy)
15
+ for (auto inst : copy)
13
16
  inst->doClose();
14
17
  }
15
18
 
@@ -20,19 +23,26 @@ Napi::Object PeerConnectionWrapper::Init(Napi::Env env, Napi::Object exports)
20
23
  Napi::Function func = DefineClass(
21
24
  env,
22
25
  "PeerConnection",
23
- {InstanceMethod("close", &PeerConnectionWrapper::close),
24
- InstanceMethod("setRemoteDescription", &PeerConnectionWrapper::setRemoteDescription),
25
- InstanceMethod("addRemoteCandidate", &PeerConnectionWrapper::addRemoteCandidate),
26
- InstanceMethod("createDataChannel", &PeerConnectionWrapper::createDataChannel),
27
- InstanceMethod("onLocalDescription", &PeerConnectionWrapper::onLocalDescription),
28
- InstanceMethod("onLocalCandidate", &PeerConnectionWrapper::onLocalCandidate),
29
- InstanceMethod("onStateChange", &PeerConnectionWrapper::onStateChange),
30
- InstanceMethod("onGatheringStateChange", &PeerConnectionWrapper::onGatheringStateChange),
31
- InstanceMethod("onDataChannel", &PeerConnectionWrapper::onDataChannel),
32
- InstanceMethod("bytesSent", &PeerConnectionWrapper::bytesSent),
33
- InstanceMethod("bytesReceived", &PeerConnectionWrapper::bytesReceived),
34
- InstanceMethod("rtt", &PeerConnectionWrapper::rtt),
35
- InstanceMethod("getSelectedCandidatePair", &PeerConnectionWrapper::getSelectedCandidatePair)});
26
+ {
27
+ InstanceMethod("close", &PeerConnectionWrapper::close),
28
+ InstanceMethod("setLocalDescription", &PeerConnectionWrapper::setLocalDescription),
29
+ InstanceMethod("setRemoteDescription", &PeerConnectionWrapper::setRemoteDescription),
30
+ InstanceMethod("localDescription", &PeerConnectionWrapper::localDescription),
31
+ InstanceMethod("addRemoteCandidate", &PeerConnectionWrapper::addRemoteCandidate),
32
+ InstanceMethod("createDataChannel", &PeerConnectionWrapper::createDataChannel),
33
+ InstanceMethod("addTrack", &PeerConnectionWrapper::addTrack),
34
+ InstanceMethod("hasMedia", &PeerConnectionWrapper::hasMedia),
35
+ InstanceMethod("onLocalDescription", &PeerConnectionWrapper::onLocalDescription),
36
+ InstanceMethod("onLocalCandidate", &PeerConnectionWrapper::onLocalCandidate),
37
+ InstanceMethod("onStateChange", &PeerConnectionWrapper::onStateChange),
38
+ InstanceMethod("onGatheringStateChange", &PeerConnectionWrapper::onGatheringStateChange),
39
+ InstanceMethod("onDataChannel", &PeerConnectionWrapper::onDataChannel),
40
+ InstanceMethod("onTrack", &PeerConnectionWrapper::onTrack),
41
+ InstanceMethod("bytesSent", &PeerConnectionWrapper::bytesSent),
42
+ InstanceMethod("bytesReceived", &PeerConnectionWrapper::bytesReceived),
43
+ InstanceMethod("rtt", &PeerConnectionWrapper::rtt),
44
+ InstanceMethod("getSelectedCandidatePair", &PeerConnectionWrapper::getSelectedCandidatePair),
45
+ });
36
46
 
37
47
  constructor = Napi::Persistent(func);
38
48
  constructor.SuppressDestruct();
@@ -175,9 +185,9 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
175
185
  return;
176
186
  }
177
187
  std::string strPolicy = config.Get("iceTransportPolicy").As<Napi::String>().ToString();
178
- if(strPolicy == "all")
188
+ if (strPolicy == "all")
179
189
  rtcConfig.iceTransportPolicy = rtc::TransportPolicy::All;
180
- else if(strPolicy == "relay")
190
+ else if (strPolicy == "relay")
181
191
  rtcConfig.iceTransportPolicy = rtc::TransportPolicy::Relay;
182
192
  else
183
193
  {
@@ -218,6 +228,7 @@ void PeerConnectionWrapper::doClose()
218
228
  mOnStateChangeCallback.reset();
219
229
  mOnGatheringStateChangeCallback.reset();
220
230
  mOnDataChannelCallback.reset();
231
+ mOnTrackCallback.reset();
221
232
 
222
233
  mRtcPeerConnPtr->close();
223
234
  mRtcPeerConnPtr.reset();
@@ -235,6 +246,42 @@ void PeerConnectionWrapper::close(const Napi::CallbackInfo &info)
235
246
  doClose();
236
247
  }
237
248
 
249
+ void PeerConnectionWrapper::setLocalDescription(const Napi::CallbackInfo &info)
250
+ {
251
+ Napi::Env env = info.Env();
252
+ if (!mRtcPeerConnPtr)
253
+ {
254
+ Napi::Error::New(info.Env(), "It seems peer-connection is closed").ThrowAsJavaScriptException();
255
+ return;
256
+ }
257
+
258
+ int length = info.Length();
259
+
260
+ rtc::Description::Type type = rtc::Description::Type::Unspec;
261
+
262
+ // optional
263
+ if (length > 0)
264
+ {
265
+ if (!info[0].IsString())
266
+ {
267
+ Napi::TypeError::New(env, "type (String) expected").ThrowAsJavaScriptException();
268
+ return;
269
+ }
270
+ std::string typeStr = info[0].As<Napi::String>().ToString();
271
+
272
+ if (typeStr == "Answer")
273
+ type = rtc::Description::Type::Answer;
274
+ if (typeStr == "Offer")
275
+ type = rtc::Description::Type::Offer;
276
+ if (typeStr == "Pranswer")
277
+ type = rtc::Description::Type::Pranswer;
278
+ if (typeStr == "Rollback")
279
+ type = rtc::Description::Type::Rollback;
280
+ }
281
+
282
+ mRtcPeerConnPtr->setLocalDescription(type);
283
+ }
284
+
238
285
  void PeerConnectionWrapper::setRemoteDescription(const Napi::CallbackInfo &info)
239
286
  {
240
287
  Napi::Env env = info.Env();
@@ -266,6 +313,17 @@ void PeerConnectionWrapper::setRemoteDescription(const Napi::CallbackInfo &info)
266
313
  }
267
314
  }
268
315
 
316
+ Napi::Value PeerConnectionWrapper::localDescription(const Napi::CallbackInfo &info)
317
+ {
318
+ Napi::Env env = info.Env();
319
+ std::optional<rtc::Description> desc = mRtcPeerConnPtr->localDescription();
320
+
321
+ Napi::Object obj = Napi::Object::New(env);
322
+ obj.Set("type", desc->typeString());
323
+ obj.Set("sdp", desc.value());
324
+ return obj;
325
+ }
326
+
269
327
  void PeerConnectionWrapper::addRemoteCandidate(const Napi::CallbackInfo &info)
270
328
  {
271
329
  Napi::Env env = info.Env();
@@ -428,7 +486,7 @@ Napi::Value PeerConnectionWrapper::createDataChannel(const Napi::CallbackInfo &i
428
486
  init.reliability.unordered = !initConfig.Get("ordered").As<Napi::Boolean>();
429
487
  }
430
488
 
431
- if(initConfig.Get("maxPacketLifeTime").IsNumber() && initConfig.Get("maxRetransmits").IsNumber())
489
+ if (initConfig.Get("maxPacketLifeTime").IsNumber() && initConfig.Get("maxRetransmits").IsNumber())
432
490
  {
433
491
  Napi::TypeError::New(env, "Wrong DataChannel Init Config, maxPacketLifeTime and maxRetransmits are exclusive").ThrowAsJavaScriptException();
434
492
  return info.Env().Null();
@@ -478,7 +536,8 @@ void PeerConnectionWrapper::onLocalDescription(const Napi::CallbackInfo &info)
478
536
  // Callback
479
537
  mOnLocalDescriptionCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
480
538
 
481
- mRtcPeerConnPtr->onLocalDescription([&](const rtc::Description &sdp) {
539
+ mRtcPeerConnPtr->onLocalDescription([&](const rtc::Description &sdp)
540
+ {
482
541
  if (mOnLocalDescriptionCallback)
483
542
  mOnLocalDescriptionCallback->call([this, sdp](Napi::Env env, std::vector<napi_value> &args) {
484
543
  // Check the peer connection is not closed
@@ -490,8 +549,7 @@ void PeerConnectionWrapper::onLocalDescription(const Napi::CallbackInfo &info)
490
549
  args = {
491
550
  Napi::String::New(env, std::string(sdp)),
492
551
  Napi::String::New(env, sdp.typeString())};
493
- });
494
- });
552
+ }); });
495
553
  }
496
554
 
497
555
  void PeerConnectionWrapper::onLocalCandidate(const Napi::CallbackInfo &info)
@@ -508,7 +566,8 @@ void PeerConnectionWrapper::onLocalCandidate(const Napi::CallbackInfo &info)
508
566
  // Callback
509
567
  mOnLocalCandidateCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
510
568
 
511
- mRtcPeerConnPtr->onLocalCandidate([&](const rtc::Candidate &candidate) {
569
+ mRtcPeerConnPtr->onLocalCandidate([&](const rtc::Candidate &candidate)
570
+ {
512
571
  if (mOnLocalCandidateCallback)
513
572
  mOnLocalCandidateCallback->call([this, candidate](Napi::Env env, std::vector<napi_value> &args) {
514
573
  // Check the peer connection is not closed
@@ -520,8 +579,7 @@ void PeerConnectionWrapper::onLocalCandidate(const Napi::CallbackInfo &info)
520
579
  args = {
521
580
  Napi::String::New(env, std::string(candidate)),
522
581
  Napi::String::New(env, candidate.mid())};
523
- });
524
- });
582
+ }); });
525
583
  }
526
584
 
527
585
  void PeerConnectionWrapper::onStateChange(const Napi::CallbackInfo &info)
@@ -538,7 +596,8 @@ void PeerConnectionWrapper::onStateChange(const Napi::CallbackInfo &info)
538
596
  // Callback
539
597
  mOnStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
540
598
 
541
- mRtcPeerConnPtr->onStateChange([&](rtc::PeerConnection::State state) {
599
+ mRtcPeerConnPtr->onStateChange([&](rtc::PeerConnection::State state)
600
+ {
542
601
  if (mOnStateChangeCallback)
543
602
  mOnStateChangeCallback->call([this, state](Napi::Env env, std::vector<napi_value> &args) {
544
603
  // Check the peer connection is not closed
@@ -550,8 +609,7 @@ void PeerConnectionWrapper::onStateChange(const Napi::CallbackInfo &info)
550
609
  std::ostringstream stream;
551
610
  stream << state;
552
611
  args = {Napi::String::New(env, stream.str())};
553
- });
554
- });
612
+ }); });
555
613
  }
556
614
 
557
615
  void PeerConnectionWrapper::onGatheringStateChange(const Napi::CallbackInfo &info)
@@ -568,7 +626,8 @@ void PeerConnectionWrapper::onGatheringStateChange(const Napi::CallbackInfo &inf
568
626
  // Callback
569
627
  mOnGatheringStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
570
628
 
571
- mRtcPeerConnPtr->onGatheringStateChange([&](rtc::PeerConnection::GatheringState state) {
629
+ mRtcPeerConnPtr->onGatheringStateChange([&](rtc::PeerConnection::GatheringState state)
630
+ {
572
631
  if (mOnGatheringStateChangeCallback)
573
632
  mOnGatheringStateChangeCallback->call([this, state](Napi::Env env, std::vector<napi_value> &args) {
574
633
  // Check the peer connection is not closed
@@ -580,8 +639,7 @@ void PeerConnectionWrapper::onGatheringStateChange(const Napi::CallbackInfo &inf
580
639
  std::ostringstream stream;
581
640
  stream << state;
582
641
  args = {Napi::String::New(env, stream.str())};
583
- });
584
- });
642
+ }); });
585
643
  }
586
644
 
587
645
  void PeerConnectionWrapper::onDataChannel(const Napi::CallbackInfo &info)
@@ -598,7 +656,8 @@ void PeerConnectionWrapper::onDataChannel(const Napi::CallbackInfo &info)
598
656
  // Callback
599
657
  mOnDataChannelCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
600
658
 
601
- mRtcPeerConnPtr->onDataChannel([&](std::shared_ptr<rtc::DataChannel> dc) {
659
+ mRtcPeerConnPtr->onDataChannel([&](std::shared_ptr<rtc::DataChannel> dc)
660
+ {
602
661
  if (mOnDataChannelCallback)
603
662
  mOnDataChannelCallback->call([this, dc](Napi::Env env, std::vector<napi_value> &args) {
604
663
  // Check the peer connection is not closed
@@ -610,8 +669,7 @@ void PeerConnectionWrapper::onDataChannel(const Napi::CallbackInfo &info)
610
669
  std::shared_ptr<rtc::DataChannel> dataChannel = dc;
611
670
  auto instance = DataChannelWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::DataChannel>>::New(env, &dataChannel)});
612
671
  args = {instance};
613
- });
614
- });
672
+ }); });
615
673
  }
616
674
 
617
675
  Napi::Value PeerConnectionWrapper::bytesSent(const Napi::CallbackInfo &info)
@@ -746,3 +804,85 @@ std::string PeerConnectionWrapper::candidateTransportTypeToString(const rtc::Can
746
804
  return "unknown";
747
805
  }
748
806
  }
807
+
808
+ Napi::Value PeerConnectionWrapper::addTrack(const Napi::CallbackInfo &info)
809
+ {
810
+ Napi::Env env = info.Env();
811
+ int length = info.Length();
812
+
813
+ if (!mRtcPeerConnPtr)
814
+ {
815
+ Napi::Error::New(info.Env(), "It seems peer-connection is closed").ThrowAsJavaScriptException();
816
+ return env.Null();
817
+ }
818
+
819
+ if (length < 1 || !info[0].IsObject())
820
+ {
821
+ Napi::TypeError::New(env, "Media class instance expected").ThrowAsJavaScriptException();
822
+ return env.Null();
823
+ }
824
+
825
+ try
826
+ {
827
+ Napi::Object obj = info[0].As<Napi::Object>();
828
+ if (obj.Get("media-type-video").IsBoolean())
829
+ {
830
+ VideoWrapper *videoPtr = Napi::ObjectWrap<VideoWrapper>::Unwrap(obj);
831
+ std::shared_ptr<rtc::Track> track = mRtcPeerConnPtr->addTrack(videoPtr->getVideoInstance());
832
+ auto instance = TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(info.Env(), &track)});
833
+ return instance;
834
+ }
835
+
836
+ if (obj.Get("media-type-audio").IsBoolean())
837
+ {
838
+ AudioWrapper *audioPtr = Napi::ObjectWrap<AudioWrapper>::Unwrap(obj);
839
+ std::shared_ptr<rtc::Track> track = mRtcPeerConnPtr->addTrack(audioPtr->getAudioInstance());
840
+ auto instance = TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(info.Env(), &track)});
841
+ return instance;
842
+ }
843
+
844
+ Napi::Error::New(env, std::string("Unknown media type")).ThrowAsJavaScriptException();
845
+ return env.Null();
846
+ }
847
+ catch (std::exception &ex)
848
+ {
849
+ Napi::Error::New(env, std::string("libdatachannel error# ") + ex.what()).ThrowAsJavaScriptException();
850
+ return env.Null();
851
+ }
852
+ }
853
+
854
+ void PeerConnectionWrapper::onTrack(const Napi::CallbackInfo &info)
855
+ {
856
+ Napi::Env env = info.Env();
857
+ int length = info.Length();
858
+
859
+ if (length < 1 || !info[0].IsFunction())
860
+ {
861
+ Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
862
+ return;
863
+ }
864
+
865
+ // Callback
866
+ mOnTrackCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
867
+
868
+ mRtcPeerConnPtr->onTrack([&](std::shared_ptr<rtc::Track> track)
869
+ {
870
+ if (mOnTrackCallback)
871
+ mOnTrackCallback->call([this, track](Napi::Env env, std::vector<napi_value> &args) {
872
+ // Check the peer connection is not closed
873
+ if(instances.find(this) == instances.end())
874
+ throw ThreadSafeCallback::CancelException();
875
+
876
+ // This will run in main thread and needs to construct the
877
+ // arguments for the call
878
+ std::shared_ptr<rtc::Track> newTrack = track;
879
+ auto instance = TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(env, &newTrack)});
880
+ args = {instance};
881
+ }); });
882
+ }
883
+
884
+ Napi::Value PeerConnectionWrapper::hasMedia(const Napi::CallbackInfo &info)
885
+ {
886
+ Napi::Env env = info.Env();
887
+ return Napi::Boolean::New(env, mRtcPeerConnPtr->hasMedia());
888
+ }
@@ -21,9 +21,13 @@ public:
21
21
 
22
22
  // Functions
23
23
  void close(const Napi::CallbackInfo &info);
24
+ void setLocalDescription(const Napi::CallbackInfo &info);
24
25
  void setRemoteDescription(const Napi::CallbackInfo &info);
26
+ Napi::Value localDescription(const Napi::CallbackInfo &info);
25
27
  void addRemoteCandidate(const Napi::CallbackInfo &info);
26
28
  Napi::Value createDataChannel(const Napi::CallbackInfo &info);
29
+ Napi::Value addTrack(const Napi::CallbackInfo &info);
30
+ Napi::Value hasMedia(const Napi::CallbackInfo &info);
27
31
 
28
32
  // Callbacks
29
33
  void onLocalDescription(const Napi::CallbackInfo &info);
@@ -31,6 +35,7 @@ public:
31
35
  void onStateChange(const Napi::CallbackInfo &info);
32
36
  void onGatheringStateChange(const Napi::CallbackInfo &info);
33
37
  void onDataChannel(const Napi::CallbackInfo &info);
38
+ void onTrack(const Napi::CallbackInfo &info);
34
39
 
35
40
  // Stats
36
41
  Napi::Value bytesSent(const Napi::CallbackInfo &info);
@@ -43,7 +48,7 @@ public:
43
48
 
44
49
  private:
45
50
  static Napi::FunctionReference constructor;
46
- static std::unordered_set<PeerConnectionWrapper*> instances;
51
+ static std::unordered_set<PeerConnectionWrapper *> instances;
47
52
 
48
53
  void doClose();
49
54
 
@@ -56,6 +61,7 @@ private:
56
61
  std::unique_ptr<ThreadSafeCallback> mOnStateChangeCallback = nullptr;
57
62
  std::unique_ptr<ThreadSafeCallback> mOnGatheringStateChangeCallback = nullptr;
58
63
  std::unique_ptr<ThreadSafeCallback> mOnDataChannelCallback = nullptr;
64
+ std::unique_ptr<ThreadSafeCallback> mOnTrackCallback = nullptr;
59
65
 
60
66
  // Helpers
61
67
  std::string candidateTypeToString(const rtc::Candidate::Type &type);
@@ -1,6 +1,7 @@
1
1
  #include "rtc-wrapper.h"
2
2
  #include "peer-connection-wrapper.h"
3
3
  #include "data-channel-wrapper.h"
4
+ #include "media-track-wrapper.h"
4
5
 
5
6
  #include <chrono>
6
7
  #include <future>
@@ -76,6 +77,7 @@ void RtcWrapper::cleanup(const Napi::CallbackInfo &info)
76
77
  {
77
78
  PeerConnectionWrapper::CloseAll();
78
79
  DataChannelWrapper::CloseAll();
80
+ TrackWrapper::CloseAll();
79
81
 
80
82
  const auto timeout = std::chrono::seconds(10);
81
83
  if(rtc::Cleanup().wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout)