node-datachannel 0.1.14-dev → 0.2.2

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,30 @@ 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("state", &PeerConnectionWrapper::state),
36
+ InstanceMethod("signalingState", &PeerConnectionWrapper::signalingState),
37
+ InstanceMethod("gatheringState", &PeerConnectionWrapper::gatheringState),
38
+ InstanceMethod("onLocalDescription", &PeerConnectionWrapper::onLocalDescription),
39
+ InstanceMethod("onLocalCandidate", &PeerConnectionWrapper::onLocalCandidate),
40
+ InstanceMethod("onStateChange", &PeerConnectionWrapper::onStateChange),
41
+ InstanceMethod("onSignalingStateChange", &PeerConnectionWrapper::onSignalingStateChange),
42
+ InstanceMethod("onGatheringStateChange", &PeerConnectionWrapper::onGatheringStateChange),
43
+ InstanceMethod("onDataChannel", &PeerConnectionWrapper::onDataChannel),
44
+ InstanceMethod("onTrack", &PeerConnectionWrapper::onTrack),
45
+ InstanceMethod("bytesSent", &PeerConnectionWrapper::bytesSent),
46
+ InstanceMethod("bytesReceived", &PeerConnectionWrapper::bytesReceived),
47
+ InstanceMethod("rtt", &PeerConnectionWrapper::rtt),
48
+ InstanceMethod("getSelectedCandidatePair", &PeerConnectionWrapper::getSelectedCandidatePair),
49
+ });
36
50
 
37
51
  constructor = Napi::Persistent(func);
38
52
  constructor.SuppressDestruct();
@@ -175,9 +189,9 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
175
189
  return;
176
190
  }
177
191
  std::string strPolicy = config.Get("iceTransportPolicy").As<Napi::String>().ToString();
178
- if(strPolicy == "all")
192
+ if (strPolicy == "all")
179
193
  rtcConfig.iceTransportPolicy = rtc::TransportPolicy::All;
180
- else if(strPolicy == "relay")
194
+ else if (strPolicy == "relay")
181
195
  rtcConfig.iceTransportPolicy = rtc::TransportPolicy::Relay;
182
196
  else
183
197
  {
@@ -218,6 +232,7 @@ void PeerConnectionWrapper::doClose()
218
232
  mOnStateChangeCallback.reset();
219
233
  mOnGatheringStateChangeCallback.reset();
220
234
  mOnDataChannelCallback.reset();
235
+ mOnTrackCallback.reset();
221
236
 
222
237
  mRtcPeerConnPtr->close();
223
238
  mRtcPeerConnPtr.reset();
@@ -235,6 +250,42 @@ void PeerConnectionWrapper::close(const Napi::CallbackInfo &info)
235
250
  doClose();
236
251
  }
237
252
 
253
+ void PeerConnectionWrapper::setLocalDescription(const Napi::CallbackInfo &info)
254
+ {
255
+ Napi::Env env = info.Env();
256
+ if (!mRtcPeerConnPtr)
257
+ {
258
+ Napi::Error::New(info.Env(), "It seems peer-connection is closed").ThrowAsJavaScriptException();
259
+ return;
260
+ }
261
+
262
+ int length = info.Length();
263
+
264
+ rtc::Description::Type type = rtc::Description::Type::Unspec;
265
+
266
+ // optional
267
+ if (length > 0)
268
+ {
269
+ if (!info[0].IsString())
270
+ {
271
+ Napi::TypeError::New(env, "type (String) expected").ThrowAsJavaScriptException();
272
+ return;
273
+ }
274
+ std::string typeStr = info[0].As<Napi::String>().ToString();
275
+
276
+ if (typeStr == "Answer")
277
+ type = rtc::Description::Type::Answer;
278
+ if (typeStr == "Offer")
279
+ type = rtc::Description::Type::Offer;
280
+ if (typeStr == "Pranswer")
281
+ type = rtc::Description::Type::Pranswer;
282
+ if (typeStr == "Rollback")
283
+ type = rtc::Description::Type::Rollback;
284
+ }
285
+
286
+ mRtcPeerConnPtr->setLocalDescription(type);
287
+ }
288
+
238
289
  void PeerConnectionWrapper::setRemoteDescription(const Napi::CallbackInfo &info)
239
290
  {
240
291
  Napi::Env env = info.Env();
@@ -266,6 +317,17 @@ void PeerConnectionWrapper::setRemoteDescription(const Napi::CallbackInfo &info)
266
317
  }
267
318
  }
268
319
 
320
+ Napi::Value PeerConnectionWrapper::localDescription(const Napi::CallbackInfo &info)
321
+ {
322
+ Napi::Env env = info.Env();
323
+ std::optional<rtc::Description> desc = mRtcPeerConnPtr->localDescription();
324
+
325
+ Napi::Object obj = Napi::Object::New(env);
326
+ obj.Set("type", desc->typeString());
327
+ obj.Set("sdp", desc.value());
328
+ return obj;
329
+ }
330
+
269
331
  void PeerConnectionWrapper::addRemoteCandidate(const Napi::CallbackInfo &info)
270
332
  {
271
333
  Napi::Env env = info.Env();
@@ -428,7 +490,7 @@ Napi::Value PeerConnectionWrapper::createDataChannel(const Napi::CallbackInfo &i
428
490
  init.reliability.unordered = !initConfig.Get("ordered").As<Napi::Boolean>();
429
491
  }
430
492
 
431
- if(initConfig.Get("maxPacketLifeTime").IsNumber() && initConfig.Get("maxRetransmits").IsNumber())
493
+ if (initConfig.Get("maxPacketLifeTime").IsNumber() && initConfig.Get("maxRetransmits").IsNumber())
432
494
  {
433
495
  Napi::TypeError::New(env, "Wrong DataChannel Init Config, maxPacketLifeTime and maxRetransmits are exclusive").ThrowAsJavaScriptException();
434
496
  return info.Env().Null();
@@ -490,8 +552,7 @@ void PeerConnectionWrapper::onLocalDescription(const Napi::CallbackInfo &info)
490
552
  args = {
491
553
  Napi::String::New(env, std::string(sdp)),
492
554
  Napi::String::New(env, sdp.typeString())};
493
- });
494
- });
555
+ }); });
495
556
  }
496
557
 
497
558
  void PeerConnectionWrapper::onLocalCandidate(const Napi::CallbackInfo &info)
@@ -520,8 +581,7 @@ void PeerConnectionWrapper::onLocalCandidate(const Napi::CallbackInfo &info)
520
581
  args = {
521
582
  Napi::String::New(env, std::string(candidate)),
522
583
  Napi::String::New(env, candidate.mid())};
523
- });
524
- });
584
+ }); });
525
585
  }
526
586
 
527
587
  void PeerConnectionWrapper::onStateChange(const Napi::CallbackInfo &info)
@@ -550,8 +610,36 @@ void PeerConnectionWrapper::onStateChange(const Napi::CallbackInfo &info)
550
610
  std::ostringstream stream;
551
611
  stream << state;
552
612
  args = {Napi::String::New(env, stream.str())};
553
- });
554
- });
613
+ }); });
614
+ }
615
+
616
+ void PeerConnectionWrapper::onSignalingStateChange(const Napi::CallbackInfo &info)
617
+ {
618
+ Napi::Env env = info.Env();
619
+ int length = info.Length();
620
+
621
+ if (length < 1 || !info[0].IsFunction())
622
+ {
623
+ Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
624
+ return;
625
+ }
626
+
627
+ // Callback
628
+ mOnSignalingStateChangeCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
629
+
630
+ mRtcPeerConnPtr->onSignalingStateChange([&](rtc::PeerConnection::SignalingState state) {
631
+ if (mOnSignalingStateChangeCallback)
632
+ mOnSignalingStateChangeCallback->call([this, state](Napi::Env env, std::vector<napi_value> &args) {
633
+ // Check the peer connection is not closed
634
+ if(instances.find(this) == instances.end())
635
+ throw ThreadSafeCallback::CancelException();
636
+
637
+ // This will run in main thread and needs to construct the
638
+ // arguments for the call
639
+ std::ostringstream stream;
640
+ stream << state;
641
+ args = {Napi::String::New(env, stream.str())};
642
+ }); });
555
643
  }
556
644
 
557
645
  void PeerConnectionWrapper::onGatheringStateChange(const Napi::CallbackInfo &info)
@@ -580,8 +668,7 @@ void PeerConnectionWrapper::onGatheringStateChange(const Napi::CallbackInfo &inf
580
668
  std::ostringstream stream;
581
669
  stream << state;
582
670
  args = {Napi::String::New(env, stream.str())};
583
- });
584
- });
671
+ }); });
585
672
  }
586
673
 
587
674
  void PeerConnectionWrapper::onDataChannel(const Napi::CallbackInfo &info)
@@ -598,7 +685,8 @@ void PeerConnectionWrapper::onDataChannel(const Napi::CallbackInfo &info)
598
685
  // Callback
599
686
  mOnDataChannelCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
600
687
 
601
- mRtcPeerConnPtr->onDataChannel([&](std::shared_ptr<rtc::DataChannel> dc) {
688
+ mRtcPeerConnPtr->onDataChannel([&](std::shared_ptr<rtc::DataChannel> dc)
689
+ {
602
690
  if (mOnDataChannelCallback)
603
691
  mOnDataChannelCallback->call([this, dc](Napi::Env env, std::vector<napi_value> &args) {
604
692
  // Check the peer connection is not closed
@@ -610,8 +698,7 @@ void PeerConnectionWrapper::onDataChannel(const Napi::CallbackInfo &info)
610
698
  std::shared_ptr<rtc::DataChannel> dataChannel = dc;
611
699
  auto instance = DataChannelWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::DataChannel>>::New(env, &dataChannel)});
612
700
  args = {instance};
613
- });
614
- });
701
+ }); });
615
702
  }
616
703
 
617
704
  Napi::Value PeerConnectionWrapper::bytesSent(const Napi::CallbackInfo &info)
@@ -746,3 +833,109 @@ std::string PeerConnectionWrapper::candidateTransportTypeToString(const rtc::Can
746
833
  return "unknown";
747
834
  }
748
835
  }
836
+
837
+ Napi::Value PeerConnectionWrapper::addTrack(const Napi::CallbackInfo &info)
838
+ {
839
+ Napi::Env env = info.Env();
840
+ int length = info.Length();
841
+
842
+ if (!mRtcPeerConnPtr)
843
+ {
844
+ Napi::Error::New(info.Env(), "It seems peer-connection is closed").ThrowAsJavaScriptException();
845
+ return env.Null();
846
+ }
847
+
848
+ if (length < 1 || !info[0].IsObject())
849
+ {
850
+ Napi::TypeError::New(env, "Media class instance expected").ThrowAsJavaScriptException();
851
+ return env.Null();
852
+ }
853
+
854
+ try
855
+ {
856
+ Napi::Object obj = info[0].As<Napi::Object>();
857
+ if (obj.Get("media-type-video").IsBoolean())
858
+ {
859
+ VideoWrapper *videoPtr = Napi::ObjectWrap<VideoWrapper>::Unwrap(obj);
860
+ std::shared_ptr<rtc::Track> track = mRtcPeerConnPtr->addTrack(videoPtr->getVideoInstance());
861
+ auto instance = TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(info.Env(), &track)});
862
+ return instance;
863
+ }
864
+
865
+ if (obj.Get("media-type-audio").IsBoolean())
866
+ {
867
+ AudioWrapper *audioPtr = Napi::ObjectWrap<AudioWrapper>::Unwrap(obj);
868
+ std::shared_ptr<rtc::Track> track = mRtcPeerConnPtr->addTrack(audioPtr->getAudioInstance());
869
+ auto instance = TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(info.Env(), &track)});
870
+ return instance;
871
+ }
872
+
873
+ Napi::Error::New(env, std::string("Unknown media type")).ThrowAsJavaScriptException();
874
+ return env.Null();
875
+ }
876
+ catch (std::exception &ex)
877
+ {
878
+ Napi::Error::New(env, std::string("libdatachannel error# ") + ex.what()).ThrowAsJavaScriptException();
879
+ return env.Null();
880
+ }
881
+ }
882
+
883
+ void PeerConnectionWrapper::onTrack(const Napi::CallbackInfo &info)
884
+ {
885
+ Napi::Env env = info.Env();
886
+ int length = info.Length();
887
+
888
+ if (length < 1 || !info[0].IsFunction())
889
+ {
890
+ Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
891
+ return;
892
+ }
893
+
894
+ // Callback
895
+ mOnTrackCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
896
+
897
+ mRtcPeerConnPtr->onTrack([&](std::shared_ptr<rtc::Track> track)
898
+ {
899
+ if (mOnTrackCallback)
900
+ mOnTrackCallback->call([this, track](Napi::Env env, std::vector<napi_value> &args) {
901
+ // Check the peer connection is not closed
902
+ if(instances.find(this) == instances.end())
903
+ throw ThreadSafeCallback::CancelException();
904
+
905
+ // This will run in main thread and needs to construct the
906
+ // arguments for the call
907
+ std::shared_ptr<rtc::Track> newTrack = track;
908
+ auto instance = TrackWrapper::constructor.New({Napi::External<std::shared_ptr<rtc::Track>>::New(env, &newTrack)});
909
+ args = {instance};
910
+ }); });
911
+ }
912
+
913
+ Napi::Value PeerConnectionWrapper::hasMedia(const Napi::CallbackInfo &info)
914
+ {
915
+ Napi::Env env = info.Env();
916
+ return Napi::Boolean::New(env, mRtcPeerConnPtr->hasMedia());
917
+ }
918
+
919
+ Napi::Value PeerConnectionWrapper::state(const Napi::CallbackInfo &info)
920
+ {
921
+ Napi::Env env = info.Env();
922
+ std::ostringstream stream;
923
+ stream << mRtcPeerConnPtr->state();
924
+ return Napi::String::New(env, stream.str());
925
+ }
926
+
927
+ Napi::Value PeerConnectionWrapper::signalingState(const Napi::CallbackInfo &info)
928
+ {
929
+ Napi::Env env = info.Env();
930
+ std::ostringstream stream;
931
+ stream << mRtcPeerConnPtr->signalingState();
932
+ return Napi::String::New(env, stream.str());
933
+ }
934
+
935
+ Napi::Value PeerConnectionWrapper::gatheringState(const Napi::CallbackInfo &info)
936
+ {
937
+ Napi::Env env = info.Env();
938
+ std::ostringstream stream;
939
+ stream << mRtcPeerConnPtr->gatheringState();
940
+ return Napi::String::New(env, stream.str());
941
+ }
@@ -21,16 +21,25 @@ 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);
31
+ Napi::Value state(const Napi::CallbackInfo &info);
32
+ Napi::Value signalingState(const Napi::CallbackInfo &info);
33
+ Napi::Value gatheringState(const Napi::CallbackInfo &info);
27
34
 
28
35
  // Callbacks
29
36
  void onLocalDescription(const Napi::CallbackInfo &info);
30
37
  void onLocalCandidate(const Napi::CallbackInfo &info);
31
38
  void onStateChange(const Napi::CallbackInfo &info);
39
+ void onSignalingStateChange(const Napi::CallbackInfo &info);
32
40
  void onGatheringStateChange(const Napi::CallbackInfo &info);
33
41
  void onDataChannel(const Napi::CallbackInfo &info);
42
+ void onTrack(const Napi::CallbackInfo &info);
34
43
 
35
44
  // Stats
36
45
  Napi::Value bytesSent(const Napi::CallbackInfo &info);
@@ -43,7 +52,7 @@ public:
43
52
 
44
53
  private:
45
54
  static Napi::FunctionReference constructor;
46
- static std::unordered_set<PeerConnectionWrapper*> instances;
55
+ static std::unordered_set<PeerConnectionWrapper *> instances;
47
56
 
48
57
  void doClose();
49
58
 
@@ -54,8 +63,10 @@ private:
54
63
  std::unique_ptr<ThreadSafeCallback> mOnLocalDescriptionCallback = nullptr;
55
64
  std::unique_ptr<ThreadSafeCallback> mOnLocalCandidateCallback = nullptr;
56
65
  std::unique_ptr<ThreadSafeCallback> mOnStateChangeCallback = nullptr;
66
+ std::unique_ptr<ThreadSafeCallback> mOnSignalingStateChangeCallback = nullptr;
57
67
  std::unique_ptr<ThreadSafeCallback> mOnGatheringStateChangeCallback = nullptr;
58
68
  std::unique_ptr<ThreadSafeCallback> mOnDataChannelCallback = nullptr;
69
+ std::unique_ptr<ThreadSafeCallback> mOnTrackCallback = nullptr;
59
70
 
60
71
  // Helpers
61
72
  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)