node-datachannel 0.8.0 → 0.9.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.
@@ -13,7 +13,7 @@ jobs:
13
13
  - name: Set up Node.js
14
14
  uses: actions/setup-node@v1
15
15
  with:
16
- node-version: 16.x
16
+ node-version: 20.x
17
17
  registry-url: "https://registry.npmjs.org"
18
18
  - name: Publish
19
19
  run: |
package/CMakeLists.txt CHANGED
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.15)
2
2
  cmake_policy(SET CMP0091 NEW)
3
3
  cmake_policy(SET CMP0042 NEW)
4
4
 
5
- project(node_datachannel VERSION 0.8.0)
5
+ project(node_datachannel VERSION 0.9.0)
6
6
 
7
7
  # -Dnapi_build_version=8
8
8
  add_definitions(-DNAPI_VERSION=8)
@@ -29,7 +29,7 @@ include(FetchContent)
29
29
  FetchContent_Declare(
30
30
  libdatachannel
31
31
  GIT_REPOSITORY https://github.com/paullouisageneau/libdatachannel.git
32
- GIT_TAG "v0.20.3"
32
+ GIT_TAG "v0.21.0"
33
33
  )
34
34
 
35
35
  option(NO_MEDIA "Disable media transport support in libdatachannel" OFF)
package/lib/index.d.cts CHANGED
@@ -180,6 +180,7 @@ export class Track {
180
180
  isClosed(): boolean;
181
181
  bufferedAmount(): number;
182
182
  maxMessageSize(): number;
183
+ requestBitrate(bitRate: number): boolean;
183
184
  setBufferedAmountLowThreshold(newSize: number): void;
184
185
  requestKeyframe(): boolean;
185
186
  setMediaHandler(handler: RtcpReceivingSession): void;
package/lib/index.d.ts CHANGED
@@ -180,6 +180,7 @@ export class Track {
180
180
  isClosed(): boolean;
181
181
  bufferedAmount(): number;
182
182
  maxMessageSize(): number;
183
+ requestBitrate(bitRate: number): boolean;
183
184
  setBufferedAmountLowThreshold(newSize: number): void;
184
185
  requestKeyframe(): boolean;
185
186
  setMediaHandler(handler: RtcpReceivingSession): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-datachannel",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "libdatachannel node bindings",
5
5
  "type": "module",
6
6
  "exports": {
@@ -99,4 +99,4 @@
99
99
  "prebuild-install": "^7.0.1",
100
100
  "rollup": "^4.14.1"
101
101
  }
102
- }
102
+ }
@@ -58,6 +58,10 @@ DataChannelWrapper::DataChannelWrapper(const Napi::CallbackInfo &info) : Napi::O
58
58
  PLOG_DEBUG << "Constructor called";
59
59
  mDataChannelPtr = *(info[0].As<Napi::External<std::shared_ptr<rtc::DataChannel>>>().Data());
60
60
  PLOG_DEBUG << "Data Channel created";
61
+
62
+ // Closed callback must be set to trigger cleanup
63
+ mOnClosedCallback = std::make_unique<ThreadSafeCallback>(Napi::Function::New(info.Env(), [](const Napi::CallbackInfo&){}));
64
+
61
65
  instances.insert(this);
62
66
  }
63
67
 
@@ -390,9 +390,8 @@ void AudioWrapper::setBitrate(const Napi::CallbackInfo &info)
390
390
  return;
391
391
  }
392
392
 
393
- int bitRate = static_cast<int>(info[0].As<Napi::Number>().ToNumber());
394
-
395
- mAudioPtr->setBitrate(bitRate);
393
+ unsigned int bitrate = static_cast<uint32_t>(info[0].As<Napi::Number>().ToNumber());
394
+ mAudioPtr->setBitrate(bitrate);
396
395
  }
397
396
 
398
397
  Napi::Value AudioWrapper::getBitrate(const Napi::CallbackInfo &info)
@@ -428,9 +427,9 @@ void AudioWrapper::addRTXCodec(const Napi::CallbackInfo &info)
428
427
  return;
429
428
  }
430
429
 
431
- unsigned int payloadType = static_cast<unsigned int>(info[0].As<Napi::Number>().ToNumber());
432
- unsigned int originalPayloadType = static_cast<unsigned int>(info[1].As<Napi::Number>().ToNumber());
433
- unsigned int clockRate = static_cast<unsigned int>(info[2].As<Napi::Number>().ToNumber());
430
+ int payloadType = static_cast<int32_t>(info[0].As<Napi::Number>().ToNumber());
431
+ int originalPayloadType = static_cast<int32_t>(info[1].As<Napi::Number>().ToNumber());
432
+ unsigned int clockRate = static_cast<uint32_t>(info[2].As<Napi::Number>().ToNumber());
434
433
 
435
434
  mAudioPtr->addRtxCodec(payloadType, originalPayloadType, clockRate);
436
435
  }
@@ -51,13 +51,12 @@ void RtcpReceivingSessionWrapper::requestBitrate(const Napi::CallbackInfo &info)
51
51
  return;
52
52
  }
53
53
 
54
- unsigned int bitRate = static_cast<unsigned int>(info[0].As<Napi::Number>().ToNumber());
55
-
56
- mSessionPtr->requestBitrate(bitRate);
54
+ unsigned int bitrate = static_cast<uint32_t>(info[0].As<Napi::Number>().ToNumber());
55
+ mSessionPtr->requestBitrate(bitrate);
57
56
  }
58
57
 
59
58
  Napi::Value RtcpReceivingSessionWrapper::requestKeyframe(const Napi::CallbackInfo &info)
60
59
  {
61
60
  Napi::Env env = info.Env();
62
61
  return Napi::Boolean::New(env, mSessionPtr->requestKeyframe());
63
- }
62
+ }
@@ -39,6 +39,7 @@ Napi::Object TrackWrapper::Init(Napi::Env env, Napi::Object exports)
39
39
  InstanceMethod("isOpen", &TrackWrapper::isOpen),
40
40
  InstanceMethod("isClosed", &TrackWrapper::isClosed),
41
41
  InstanceMethod("maxMessageSize", &TrackWrapper::maxMessageSize),
42
+ InstanceMethod("requestBitrate", &TrackWrapper::requestBitrate),
42
43
  InstanceMethod("requestKeyframe", &TrackWrapper::requestKeyframe),
43
44
  InstanceMethod("setMediaHandler", &TrackWrapper::setMediaHandler),
44
45
  InstanceMethod("onOpen", &TrackWrapper::onOpen),
@@ -56,7 +57,12 @@ Napi::Object TrackWrapper::Init(Napi::Env env, Napi::Object exports)
56
57
 
57
58
  TrackWrapper::TrackWrapper(const Napi::CallbackInfo &info) : Napi::ObjectWrap<TrackWrapper>(info)
58
59
  {
60
+ PLOG_DEBUG << "Constructor called";
59
61
  mTrackPtr = *(info[0].As<Napi::External<std::shared_ptr<rtc::Track>>>().Data());
62
+ PLOG_DEBUG << "Track created";
63
+
64
+ // Closed callback must be set to trigger cleanup
65
+ mOnClosedCallback = std::make_unique<ThreadSafeCallback>(Napi::Function::New(info.Env(), [](const Napi::CallbackInfo&){}));
60
66
 
61
67
  instances.insert(this);
62
68
  }
@@ -237,6 +243,27 @@ Napi::Value TrackWrapper::maxMessageSize(const Napi::CallbackInfo &info)
237
243
  }
238
244
  }
239
245
 
246
+ Napi::Value TrackWrapper::requestBitrate(const Napi::CallbackInfo &info)
247
+ {
248
+ if (!mTrackPtr)
249
+ {
250
+ Napi::Error::New(info.Env(), "requestBitrate() called on destroyed track").ThrowAsJavaScriptException();
251
+ return info.Env().Null();
252
+ }
253
+
254
+ Napi::Env env = info.Env();
255
+ int length = info.Length();
256
+
257
+ if (length < 1 || !info[0].IsNumber())
258
+ {
259
+ Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException();
260
+ return info.Env().Null();
261
+ }
262
+
263
+ unsigned int bitrate = static_cast<uint32_t>(info[0].As<Napi::Number>());
264
+ return Napi::Boolean::New(env, mTrackPtr->requestBitrate(bitrate));
265
+ }
266
+
240
267
  Napi::Value TrackWrapper::requestKeyframe(const Napi::CallbackInfo &info)
241
268
  {
242
269
  if (!mTrackPtr)
@@ -30,6 +30,7 @@ public:
30
30
  Napi::Value isOpen(const Napi::CallbackInfo &info);
31
31
  Napi::Value isClosed(const Napi::CallbackInfo &info);
32
32
  Napi::Value maxMessageSize(const Napi::CallbackInfo &info);
33
+ Napi::Value requestBitrate(const Napi::CallbackInfo &info);
33
34
  Napi::Value requestKeyframe(const Napi::CallbackInfo &info);
34
35
  void setMediaHandler(const Napi::CallbackInfo &info);
35
36
 
@@ -423,14 +423,12 @@ void VideoWrapper::setBitrate(const Napi::CallbackInfo &info)
423
423
  return;
424
424
  }
425
425
 
426
- int bitRate = static_cast<int>(info[0].As<Napi::Number>().ToNumber());
427
-
428
- mVideoPtr->setBitrate(bitRate);
426
+ unsigned int bitrate = info[0].As<Napi::Number>().ToNumber().Uint32Value();
427
+ mVideoPtr->setBitrate(bitrate);
429
428
  }
430
429
 
431
430
  Napi::Value VideoWrapper::getBitrate(const Napi::CallbackInfo &info)
432
431
  {
433
-
434
432
  return Napi::Number::New(info.Env(), mVideoPtr->bitrate());
435
433
  }
436
434
 
@@ -445,7 +443,7 @@ Napi::Value VideoWrapper::hasPayloadType(const Napi::CallbackInfo &info)
445
443
  return env.Null();
446
444
  }
447
445
 
448
- int payloadType = static_cast<int>(info[0].As<Napi::Number>().ToNumber());
446
+ int payloadType = static_cast<int32_t>(info[0].As<Napi::Number>().ToNumber());
449
447
 
450
448
  return Napi::Boolean::New(env, mVideoPtr->hasPayloadType(payloadType));
451
449
  }
@@ -461,9 +459,9 @@ void VideoWrapper::addRTXCodec(const Napi::CallbackInfo &info)
461
459
  return;
462
460
  }
463
461
 
464
- unsigned int payloadType = static_cast<unsigned int>(info[0].As<Napi::Number>().ToNumber());
465
- unsigned int originalPayloadType = static_cast<unsigned int>(info[1].As<Napi::Number>().ToNumber());
466
- unsigned int clockRate = static_cast<unsigned int>(info[2].As<Napi::Number>().ToNumber());
462
+ int payloadType = static_cast<int32_t>(info[0].As<Napi::Number>().ToNumber());
463
+ int originalPayloadType = static_cast<int32_t>(info[1].As<Napi::Number>().ToNumber());
464
+ unsigned int clockRate = static_cast<uint32_t>(info[2].As<Napi::Number>().ToNumber());
467
465
 
468
466
  mVideoPtr->addRtxCodec(payloadType, originalPayloadType, clockRate);
469
467
  }
@@ -237,7 +237,7 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
237
237
  // Create peer-connection
238
238
  try
239
239
  {
240
- PLOG_DEBUG << "Creating a new peer";
240
+ PLOG_DEBUG << "Creating a new Peer Connection";
241
241
  mRtcPeerConnPtr = std::make_unique<rtc::PeerConnection>(rtcConfig);
242
242
  }
243
243
  catch (std::exception &ex)
@@ -246,6 +246,11 @@ PeerConnectionWrapper::PeerConnectionWrapper(const Napi::CallbackInfo &info) : N
246
246
  return;
247
247
  }
248
248
 
249
+ PLOG_DEBUG << "Peer Connection created";
250
+
251
+ // State change callback must be set to trigger cleanup on close
252
+ mOnStateChangeCallback = std::make_unique<ThreadSafeCallback>(Napi::Function::New(info.Env(), [](const Napi::CallbackInfo&){}));
253
+
249
254
  instances.insert(this);
250
255
  }
251
256
 
@@ -552,10 +557,10 @@ Napi::Value PeerConnectionWrapper::createDataChannel(const Napi::CallbackInfo &i
552
557
  switch (reliability.Get("type").As<Napi::Number>().Uint32Value())
553
558
  {
554
559
  case 1:
555
- init.reliability.rexmit = static_cast<int>(reliability.Get("rexmit").As<Napi::Number>().ToNumber());
560
+ init.reliability.rexmit = int(reliability.Get("rexmit").As<Napi::Number>().ToNumber().Uint32Value());
556
561
  break;
557
562
  case 2:
558
- init.reliability.rexmit = std::chrono::milliseconds(reliability.Get("rexmit").As<Napi::Number>().Uint32Value());
563
+ init.reliability.rexmit = std::chrono::milliseconds(reliability.Get("rexmit").As<Napi::Number>().Int32Value());
559
564
  break;
560
565
  }
561
566
  }
@@ -572,25 +577,31 @@ Napi::Value PeerConnectionWrapper::createDataChannel(const Napi::CallbackInfo &i
572
577
  init.reliability.unordered = !initConfig.Get("ordered").As<Napi::Boolean>();
573
578
  }
574
579
 
575
- if (initConfig.Get("maxPacketLifeTime").IsNumber() && initConfig.Get("maxRetransmits").IsNumber())
580
+
581
+ if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull() &&
582
+ !initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
576
583
  {
577
584
  Napi::TypeError::New(env, "Wrong DataChannel Init Config, maxPacketLifeTime and maxRetransmits are exclusive").ThrowAsJavaScriptException();
578
585
  return info.Env().Null();
579
586
  }
580
587
 
581
- if (initConfig.Get("maxPacketLifeTime").IsNumber())
588
+ if (!initConfig.Get("maxPacketLifeTime").IsUndefined() && !initConfig.Get("maxPacketLifeTime").IsNull())
582
589
  {
583
- init.reliability.type = rtc::Reliability::Type::Timed;
584
- init.reliability.rexmit = std::chrono::milliseconds(initConfig.Get("maxPacketLifeTime").As<Napi::Number>().Uint32Value());
585
- }
586
- else if (initConfig.Get("maxRetransmits").IsNumber())
587
- {
588
- init.reliability.type = rtc::Reliability::Type::Rexmit;
589
- init.reliability.rexmit = int(initConfig.Get("maxRetransmits").As<Napi::Number>().Uint32Value());
590
+ if (!initConfig.Get("maxPacketLifeTime").IsNumber())
591
+ {
592
+ Napi::TypeError::New(env, "Wrong DataChannel Init Config (maxPacketLifeTime)").ThrowAsJavaScriptException();
593
+ return info.Env().Null();
594
+ }
595
+ init.reliability.maxPacketLifeTime = std::chrono::milliseconds(initConfig.Get("maxPacketLifeTime").As<Napi::Number>().Uint32Value());
590
596
  }
591
- else
597
+ else if (!initConfig.Get("maxRetransmits").IsUndefined() && !initConfig.Get("maxRetransmits").IsNull())
592
598
  {
593
- init.reliability.type = rtc::Reliability::Type::Reliable;
599
+ if (!initConfig.Get("maxRetransmits").IsNumber())
600
+ {
601
+ Napi::TypeError::New(env, "Wrong DataChannel Init Config (maxRetransmits)").ThrowAsJavaScriptException();
602
+ return info.Env().Null();
603
+ }
604
+ init.reliability.maxRetransmits = int(initConfig.Get("maxRetransmits").As<Napi::Number>().Int32Value());
594
605
  }
595
606
  }
596
607
 
@@ -9,16 +9,16 @@ const char *ThreadSafeCallback::CancelException::what() const throw()
9
9
 
10
10
  ThreadSafeCallback::ThreadSafeCallback(Napi::Function callback)
11
11
  {
12
- if (!callback.IsFunction())
13
- throw Napi::Error::New(callback.Env(), "Callback must be a function");
14
-
15
12
  Napi::Env env = callback.Env();
16
13
 
17
- receiver = Napi::Persistent(static_cast<Napi::Value>(Napi::Object::New(env)));
14
+ if (!callback.IsFunction())
15
+ throw Napi::Error::New(env, "Callback must be a function");
16
+
18
17
  tsfn = tsfn_t::New(env,
19
18
  std::move(callback),
20
19
  "ThreadSafeCallback callback",
21
- 0, 1, &receiver);
20
+ 0, // unlimited queue
21
+ 1);
22
22
  }
23
23
 
24
24
  ThreadSafeCallback::~ThreadSafeCallback()
@@ -38,10 +38,10 @@ void ThreadSafeCallback::call(arg_func_t argFunc, cleanup_func_t cleanupFunc)
38
38
 
39
39
  void ThreadSafeCallback::callbackFunc(Napi::Env env,
40
40
  Napi::Function callback,
41
- Napi::Reference<Napi::Value> *context,
41
+ ContextType *context,
42
42
  CallbackData *data)
43
43
  {
44
- // if env is gone this could mean cb fn has changed. See issue#176
44
+ // if env is gone, it could mean this cb was destroyed. See issue#176
45
45
  if (!data || !env)
46
46
  return;
47
47
 
@@ -59,9 +59,10 @@ void ThreadSafeCallback::callbackFunc(Napi::Env env,
59
59
  return;
60
60
  }
61
61
 
62
- if (env && callback)
62
+ if (callback)
63
63
  {
64
- callback.Call(context->Value(), args);
65
- cleanup();
64
+ callback.Call(args);
66
65
  }
66
+
67
+ cleanup();
67
68
  }
@@ -30,6 +30,7 @@ public:
30
30
  };
31
31
 
32
32
  private:
33
+ using ContextType = std::nullptr_t;
33
34
  struct CallbackData
34
35
  {
35
36
  arg_func_t argFunc;
@@ -38,12 +39,10 @@ private:
38
39
 
39
40
  static void callbackFunc(Napi::Env env,
40
41
  Napi::Function callback,
41
- Napi::Reference<Napi::Value> *context,
42
+ ContextType *context,
42
43
  CallbackData *data);
43
44
 
44
- using tsfn_t = Napi::TypedThreadSafeFunction<Napi::Reference<Napi::Value>, CallbackData, callbackFunc>;
45
-
46
- Napi::Reference<Napi::Value> receiver;
45
+ using tsfn_t = Napi::TypedThreadSafeFunction<ContextType, CallbackData, callbackFunc>;
47
46
  tsfn_t tsfn;
48
47
  };
49
48
 
@@ -238,6 +238,10 @@ WebSocketWrapper::WebSocketWrapper(const Napi::CallbackInfo &info) : Napi::Objec
238
238
  }
239
239
 
240
240
  PLOG_DEBUG << "WebSocket created";
241
+
242
+ // Closed callback must set to trigger cleanup
243
+ mOnClosedCallback = std::make_unique<ThreadSafeCallback>(Napi::Function::New(info.Env(), [](const Napi::CallbackInfo&){}));
244
+
241
245
  instances.insert(this);
242
246
  }
243
247
 
@@ -471,7 +475,7 @@ Napi::Value WebSocketWrapper::remoteAddress(const Napi::CallbackInfo &info)
471
475
 
472
476
  if (!mWebSocketPtr)
473
477
  {
474
- return env.Undefined();
478
+ return env.Undefined();
475
479
  }
476
480
 
477
481
  try
@@ -500,7 +504,7 @@ Napi::Value WebSocketWrapper::path(const Napi::CallbackInfo &info)
500
504
 
501
505
  if (!mWebSocketPtr)
502
506
  {
503
- return env.Undefined();
507
+ return env.Undefined();
504
508
  }
505
509
 
506
510
  try