@lng2004/node-datachannel 0.31.0-20251228
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.
- package/.clang-format +17 -0
- package/.editorconfig +12 -0
- package/.eslintignore +8 -0
- package/.eslintrc.json +27 -0
- package/.gitmodules +3 -0
- package/.prettierignore +7 -0
- package/.prettierrc +13 -0
- package/API.md +247 -0
- package/BULDING.md +33 -0
- package/CMakeLists.txt +134 -0
- package/LICENSE +373 -0
- package/README.md +130 -0
- package/dist/cjs/index.cjs +11 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/lib/datachannel-stream.cjs +101 -0
- package/dist/cjs/lib/datachannel-stream.cjs.map +1 -0
- package/dist/cjs/lib/index.cjs +88 -0
- package/dist/cjs/lib/index.cjs.map +1 -0
- package/dist/cjs/lib/node-datachannel.cjs +8 -0
- package/dist/cjs/lib/node-datachannel.cjs.map +1 -0
- package/dist/cjs/lib/websocket-server.cjs +45 -0
- package/dist/cjs/lib/websocket-server.cjs.map +1 -0
- package/dist/cjs/lib/websocket.cjs +8 -0
- package/dist/cjs/lib/websocket.cjs.map +1 -0
- package/dist/cjs/polyfill/Events.cjs +86 -0
- package/dist/cjs/polyfill/Events.cjs.map +1 -0
- package/dist/cjs/polyfill/Exception.cjs +34 -0
- package/dist/cjs/polyfill/Exception.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCCertificate.cjs +34 -0
- package/dist/cjs/polyfill/RTCCertificate.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCDataChannel.cjs +214 -0
- package/dist/cjs/polyfill/RTCDataChannel.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCDtlsTransport.cjs +53 -0
- package/dist/cjs/polyfill/RTCDtlsTransport.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCError.cjs +83 -0
- package/dist/cjs/polyfill/RTCError.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCIceCandidate.cjs +132 -0
- package/dist/cjs/polyfill/RTCIceCandidate.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCIceTransport.cjs +94 -0
- package/dist/cjs/polyfill/RTCIceTransport.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCPeerConnection.cjs +434 -0
- package/dist/cjs/polyfill/RTCPeerConnection.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCSctpTransport.cjs +59 -0
- package/dist/cjs/polyfill/RTCSctpTransport.cjs.map +1 -0
- package/dist/cjs/polyfill/RTCSessionDescription.cjs +45 -0
- package/dist/cjs/polyfill/RTCSessionDescription.cjs.map +1 -0
- package/dist/cjs/polyfill/index.cjs +42 -0
- package/dist/cjs/polyfill/index.cjs.map +1 -0
- package/dist/esm/index.mjs +8 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/lib/datachannel-stream.mjs +78 -0
- package/dist/esm/lib/datachannel-stream.mjs.map +1 -0
- package/dist/esm/lib/index.mjs +62 -0
- package/dist/esm/lib/index.mjs.map +1 -0
- package/dist/esm/lib/node-datachannel.mjs +12 -0
- package/dist/esm/lib/node-datachannel.mjs.map +1 -0
- package/dist/esm/lib/websocket-server.mjs +43 -0
- package/dist/esm/lib/websocket-server.mjs.map +1 -0
- package/dist/esm/lib/websocket.mjs +6 -0
- package/dist/esm/lib/websocket.mjs.map +1 -0
- package/dist/esm/polyfill/Events.mjs +82 -0
- package/dist/esm/polyfill/Events.mjs.map +1 -0
- package/dist/esm/polyfill/Exception.mjs +28 -0
- package/dist/esm/polyfill/Exception.mjs.map +1 -0
- package/dist/esm/polyfill/RTCCertificate.mjs +30 -0
- package/dist/esm/polyfill/RTCCertificate.mjs.map +1 -0
- package/dist/esm/polyfill/RTCDataChannel.mjs +210 -0
- package/dist/esm/polyfill/RTCDataChannel.mjs.map +1 -0
- package/dist/esm/polyfill/RTCDtlsTransport.mjs +49 -0
- package/dist/esm/polyfill/RTCDtlsTransport.mjs.map +1 -0
- package/dist/esm/polyfill/RTCError.mjs +79 -0
- package/dist/esm/polyfill/RTCError.mjs.map +1 -0
- package/dist/esm/polyfill/RTCIceCandidate.mjs +128 -0
- package/dist/esm/polyfill/RTCIceCandidate.mjs.map +1 -0
- package/dist/esm/polyfill/RTCIceTransport.mjs +89 -0
- package/dist/esm/polyfill/RTCIceTransport.mjs.map +1 -0
- package/dist/esm/polyfill/RTCPeerConnection.mjs +430 -0
- package/dist/esm/polyfill/RTCPeerConnection.mjs.map +1 -0
- package/dist/esm/polyfill/RTCSctpTransport.mjs +55 -0
- package/dist/esm/polyfill/RTCSctpTransport.mjs.map +1 -0
- package/dist/esm/polyfill/RTCSessionDescription.mjs +41 -0
- package/dist/esm/polyfill/RTCSessionDescription.mjs.map +1 -0
- package/dist/esm/polyfill/index.mjs +27 -0
- package/dist/esm/polyfill/index.mjs.map +1 -0
- package/dist/types/lib/datachannel-stream.d.ts +24 -0
- package/dist/types/lib/index.d.ts +235 -0
- package/dist/types/lib/types.d.ts +118 -0
- package/dist/types/lib/websocket-server.d.ts +13 -0
- package/dist/types/lib/websocket.d.ts +25 -0
- package/dist/types/polyfill/Events.d.ts +15 -0
- package/dist/types/polyfill/RTCCertificate.d.ts +9 -0
- package/dist/types/polyfill/RTCDataChannel.d.ts +29 -0
- package/dist/types/polyfill/RTCDtlsTransport.d.ts +15 -0
- package/dist/types/polyfill/RTCError.d.ts +17 -0
- package/dist/types/polyfill/RTCIceCandidate.d.ts +21 -0
- package/dist/types/polyfill/RTCIceTransport.d.ts +30 -0
- package/dist/types/polyfill/RTCPeerConnection.d.ts +64 -0
- package/dist/types/polyfill/RTCSctpTransport.d.ts +15 -0
- package/dist/types/polyfill/RTCSessionDescription.d.ts +10 -0
- package/dist/types/polyfill/index.d.ts +26 -0
- package/jest.config.ts +14 -0
- package/package.json +121 -0
- package/rollup.config.mjs +72 -0
- package/src/cpp/data-channel-wrapper.cpp +530 -0
- package/src/cpp/data-channel-wrapper.h +63 -0
- package/src/cpp/ice-udp-mux-listener-wrapper.cpp +157 -0
- package/src/cpp/ice-udp-mux-listener-wrapper.h +43 -0
- package/src/cpp/main.cpp +58 -0
- package/src/cpp/media-audio-wrapper.cpp +457 -0
- package/src/cpp/media-audio-wrapper.h +52 -0
- package/src/cpp/media-av1packetization.cpp +24 -0
- package/src/cpp/media-av1packetization.h +11 -0
- package/src/cpp/media-av1rtppacketizer-wrapper.cpp +126 -0
- package/src/cpp/media-av1rtppacketizer-wrapper.h +29 -0
- package/src/cpp/media-direction.cpp +43 -0
- package/src/cpp/media-direction.h +10 -0
- package/src/cpp/media-h264rtppacketizer-wrapper.cpp +126 -0
- package/src/cpp/media-h264rtppacketizer-wrapper.h +30 -0
- package/src/cpp/media-h265rtppacketizer-wrapper.cpp +126 -0
- package/src/cpp/media-h265rtppacketizer-wrapper.h +30 -0
- package/src/cpp/media-h26xseparator.cpp +32 -0
- package/src/cpp/media-h26xseparator.h +11 -0
- package/src/cpp/media-mediahandler-helper.cpp +31 -0
- package/src/cpp/media-mediahandler-helper.h +11 -0
- package/src/cpp/media-pacinghandler-wrapper.cpp +79 -0
- package/src/cpp/media-pacinghandler-wrapper.h +28 -0
- package/src/cpp/media-rtcpnackresponder-wrapper.cpp +68 -0
- package/src/cpp/media-rtcpnackresponder-wrapper.h +28 -0
- package/src/cpp/media-rtcpreceivingsession-wrapper.cpp +57 -0
- package/src/cpp/media-rtcpreceivingsession-wrapper.h +28 -0
- package/src/cpp/media-rtcpsrreporter-wrapper.cpp +93 -0
- package/src/cpp/media-rtcpsrreporter-wrapper.h +30 -0
- package/src/cpp/media-rtppacketizationconfig-wrapper.cpp +167 -0
- package/src/cpp/media-rtppacketizationconfig-wrapper.h +35 -0
- package/src/cpp/media-rtppacketizer-wrapper.cpp +95 -0
- package/src/cpp/media-rtppacketizer-wrapper.h +30 -0
- package/src/cpp/media-track-wrapper.cpp +458 -0
- package/src/cpp/media-track-wrapper.h +61 -0
- package/src/cpp/media-video-wrapper.cpp +526 -0
- package/src/cpp/media-video-wrapper.h +56 -0
- package/src/cpp/peer-connection-wrapper.cpp +1298 -0
- package/src/cpp/peer-connection-wrapper.h +89 -0
- package/src/cpp/rtc-wrapper.cpp +205 -0
- package/src/cpp/rtc-wrapper.h +24 -0
- package/src/cpp/thread-safe-callback.cpp +57 -0
- package/src/cpp/thread-safe-callback.h +47 -0
- package/src/cpp/web-socket-server-wrapper.cpp +275 -0
- package/src/cpp/web-socket-server-wrapper.h +41 -0
- package/src/cpp/web-socket-wrapper.cpp +796 -0
- package/src/cpp/web-socket-wrapper.h +63 -0
- package/src/index.ts +9 -0
- package/src/lib/datachannel-stream.ts +100 -0
- package/src/lib/index.ts +283 -0
- package/src/lib/node-datachannel.ts +3 -0
- package/src/lib/types.ts +168 -0
- package/src/lib/websocket-server.ts +37 -0
- package/src/lib/websocket.ts +26 -0
- package/src/polyfill/Events.ts +82 -0
- package/src/polyfill/Exception.ts +37 -0
- package/src/polyfill/README.md +41 -0
- package/src/polyfill/RTCCertificate.ts +21 -0
- package/src/polyfill/RTCDataChannel.ts +225 -0
- package/src/polyfill/RTCDtlsTransport.ts +46 -0
- package/src/polyfill/RTCError.ts +78 -0
- package/src/polyfill/RTCIceCandidate.ts +128 -0
- package/src/polyfill/RTCIceTransport.ts +90 -0
- package/src/polyfill/RTCPeerConnection.ts +527 -0
- package/src/polyfill/RTCSctpTransport.ts +51 -0
- package/src/polyfill/RTCSessionDescription.ts +41 -0
- package/src/polyfill/index.ts +38 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#include "media-rtppacketizer-wrapper.h"
|
|
2
|
+
#include "media-rtppacketizationconfig-wrapper.h"
|
|
3
|
+
#include "media-mediahandler-helper.h"
|
|
4
|
+
|
|
5
|
+
Napi::FunctionReference RtpPacketizerWrapper::constructor = Napi::FunctionReference();
|
|
6
|
+
|
|
7
|
+
Napi::Object RtpPacketizerWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
8
|
+
{
|
|
9
|
+
Napi::HandleScope scope(env);
|
|
10
|
+
|
|
11
|
+
Napi::Function func = Napi::ObjectWrap<RtpPacketizerWrapper>::DefineClass(env, "RtpPacketizer",
|
|
12
|
+
{
|
|
13
|
+
// Instance Methods
|
|
14
|
+
InstanceMethod("addToChain", &RtpPacketizerWrapper::addToChain),
|
|
15
|
+
// Accessors
|
|
16
|
+
InstanceAccessor("rtpConfig", &RtpPacketizerWrapper::getRtpPacketizationConfig, nullptr),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// If this is not the first call, we don't want to reassign the constructor (hot-reload problem)
|
|
20
|
+
if (constructor.IsEmpty())
|
|
21
|
+
{
|
|
22
|
+
constructor = Napi::Persistent(func);
|
|
23
|
+
constructor.SuppressDestruct();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
exports.Set("RtpPacketizer", func);
|
|
27
|
+
return exports;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
RtpPacketizerWrapper::RtpPacketizerWrapper(const Napi::CallbackInfo &info)
|
|
31
|
+
: Napi::ObjectWrap<RtpPacketizerWrapper>(info)
|
|
32
|
+
{
|
|
33
|
+
Napi::Env env = info.Env();
|
|
34
|
+
|
|
35
|
+
if (!info[0].IsObject())
|
|
36
|
+
{
|
|
37
|
+
Napi::TypeError::New(env, "rtpConfig must be a RtpPacketizationConfig instance").ThrowAsJavaScriptException();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
auto obj = info[0].As<Napi::Object>();
|
|
41
|
+
if (!obj.InstanceOf(RtpPacketizationConfigWrapper::constructor.Value()))
|
|
42
|
+
{
|
|
43
|
+
Napi::TypeError::New(env, "rtpConfig must be a RtpPacketizationConfig instance").ThrowAsJavaScriptException();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// store original JS object so we can return it later
|
|
47
|
+
mRtpConfigObject = Napi::Persistent(obj);
|
|
48
|
+
mRtpConfigObject.SuppressDestruct();
|
|
49
|
+
auto rtpConfig = RtpPacketizationConfigWrapper::Unwrap(obj)->getConfigInstance();
|
|
50
|
+
|
|
51
|
+
mPacketizerPtr = std::make_unique<rtc::RtpPacketizer>(rtpConfig);
|
|
52
|
+
|
|
53
|
+
auto asMediaHandler = new std::shared_ptr<rtc::MediaHandler>(mPacketizerPtr);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
RtpPacketizerWrapper::~RtpPacketizerWrapper()
|
|
57
|
+
{
|
|
58
|
+
mPacketizerPtr.reset();
|
|
59
|
+
mRtpConfigObject.Reset();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
std::shared_ptr<rtc::RtpPacketizer> RtpPacketizerWrapper::getPacketizerInstance() { return mPacketizerPtr; }
|
|
63
|
+
|
|
64
|
+
void RtpPacketizerWrapper::addToChain(const Napi::CallbackInfo &info)
|
|
65
|
+
{
|
|
66
|
+
auto env = info.Env();
|
|
67
|
+
if (info.Length() < 1 || !info[0].IsObject())
|
|
68
|
+
{
|
|
69
|
+
Napi::TypeError::New(env, "Expected a MediaHandler instance").ThrowAsJavaScriptException();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
auto mediaHandler = asMediaHandler(info[0].As<Napi::Object>());
|
|
73
|
+
if (!mediaHandler)
|
|
74
|
+
{
|
|
75
|
+
Napi::TypeError::New(env, "Expected a MediaHandler instance. If this error is unexpected, please report a bug!")
|
|
76
|
+
.ThrowAsJavaScriptException();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
mPacketizerPtr->addToChain(mediaHandler);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Napi::Value RtpPacketizerWrapper::getRtpPacketizationConfig(const Napi::CallbackInfo &info)
|
|
83
|
+
{
|
|
84
|
+
Napi::Env env = info.Env();
|
|
85
|
+
if (!mPacketizerPtr)
|
|
86
|
+
{
|
|
87
|
+
Napi::Error::New(env, "getRtpPacketizationConfig() called on destroyed packetizer").ThrowAsJavaScriptException();
|
|
88
|
+
return env.Null();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (mRtpConfigObject.IsEmpty())
|
|
92
|
+
return env.Null();
|
|
93
|
+
|
|
94
|
+
return mRtpConfigObject.Value();
|
|
95
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#ifndef MEDIA_RTPPACKETIZER_WRAPPER_H
|
|
2
|
+
#define MEDIA_RTPPACKETIZER_WRAPPER_H
|
|
3
|
+
|
|
4
|
+
#include <memory>
|
|
5
|
+
#include <unordered_set>
|
|
6
|
+
|
|
7
|
+
#include <napi.h>
|
|
8
|
+
#include <rtc/rtc.hpp>
|
|
9
|
+
|
|
10
|
+
class RtpPacketizerWrapper : public Napi::ObjectWrap<RtpPacketizerWrapper>
|
|
11
|
+
{
|
|
12
|
+
public:
|
|
13
|
+
static Napi::FunctionReference constructor;
|
|
14
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
15
|
+
RtpPacketizerWrapper(const Napi::CallbackInfo &info);
|
|
16
|
+
~RtpPacketizerWrapper();
|
|
17
|
+
std::shared_ptr<rtc::RtpPacketizer> getPacketizerInstance();
|
|
18
|
+
|
|
19
|
+
// Functions
|
|
20
|
+
void addToChain(const Napi::CallbackInfo &info);
|
|
21
|
+
Napi::Value getRtpPacketizationConfig(const Napi::CallbackInfo &info);
|
|
22
|
+
|
|
23
|
+
// Callbacks
|
|
24
|
+
|
|
25
|
+
private:
|
|
26
|
+
std::shared_ptr<rtc::RtpPacketizer> mPacketizerPtr = nullptr;
|
|
27
|
+
Napi::ObjectReference mRtpConfigObject;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
#endif // MEDIA_RTPPACKETIZER_WRAPPER_H
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
#include "media-track-wrapper.h"
|
|
2
|
+
#include "media-direction.h"
|
|
3
|
+
#include "media-mediahandler-helper.h"
|
|
4
|
+
|
|
5
|
+
#include "plog/Log.h"
|
|
6
|
+
|
|
7
|
+
Napi::FunctionReference TrackWrapper::constructor = Napi::FunctionReference();
|
|
8
|
+
std::unordered_set<TrackWrapper *> TrackWrapper::instances;
|
|
9
|
+
|
|
10
|
+
void TrackWrapper::CloseAll()
|
|
11
|
+
{
|
|
12
|
+
auto copy(instances);
|
|
13
|
+
for (auto inst : copy)
|
|
14
|
+
inst->doClose();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
void TrackWrapper::CleanupAll()
|
|
18
|
+
{
|
|
19
|
+
PLOG_DEBUG << "CleanupAll() called";
|
|
20
|
+
auto copy(instances);
|
|
21
|
+
for (auto inst : copy)
|
|
22
|
+
inst->doCleanup();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
Napi::Object TrackWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
26
|
+
{
|
|
27
|
+
Napi::HandleScope scope(env);
|
|
28
|
+
|
|
29
|
+
Napi::Function func = DefineClass(env, "Track",
|
|
30
|
+
{
|
|
31
|
+
InstanceMethod("direction", &TrackWrapper::direction),
|
|
32
|
+
InstanceMethod("mid", &TrackWrapper::mid),
|
|
33
|
+
InstanceMethod("type", &TrackWrapper::type),
|
|
34
|
+
InstanceMethod("close", &TrackWrapper::close),
|
|
35
|
+
InstanceMethod("sendMessage", &TrackWrapper::sendMessage),
|
|
36
|
+
InstanceMethod("sendMessageBinary", &TrackWrapper::sendMessageBinary),
|
|
37
|
+
InstanceMethod("isOpen", &TrackWrapper::isOpen),
|
|
38
|
+
InstanceMethod("isClosed", &TrackWrapper::isClosed),
|
|
39
|
+
InstanceMethod("maxMessageSize", &TrackWrapper::maxMessageSize),
|
|
40
|
+
InstanceMethod("requestBitrate", &TrackWrapper::requestBitrate),
|
|
41
|
+
InstanceMethod("requestKeyframe", &TrackWrapper::requestKeyframe),
|
|
42
|
+
InstanceMethod("setMediaHandler", &TrackWrapper::setMediaHandler),
|
|
43
|
+
InstanceMethod("onOpen", &TrackWrapper::onOpen),
|
|
44
|
+
InstanceMethod("onClosed", &TrackWrapper::onClosed),
|
|
45
|
+
InstanceMethod("onError", &TrackWrapper::onError),
|
|
46
|
+
InstanceMethod("onMessage", &TrackWrapper::onMessage),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// If this is not the first call, we don't want to reassign the constructor (hot-reload problem)
|
|
50
|
+
if (constructor.IsEmpty())
|
|
51
|
+
{
|
|
52
|
+
constructor = Napi::Persistent(func);
|
|
53
|
+
constructor.SuppressDestruct();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
exports.Set("Track", func);
|
|
57
|
+
return exports;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
TrackWrapper::TrackWrapper(const Napi::CallbackInfo &info) : Napi::ObjectWrap<TrackWrapper>(info)
|
|
61
|
+
{
|
|
62
|
+
PLOG_DEBUG << "Constructor called";
|
|
63
|
+
mTrackPtr = *(info[0].As<Napi::External<std::shared_ptr<rtc::Track>>>().Data());
|
|
64
|
+
PLOG_DEBUG << "Track created";
|
|
65
|
+
|
|
66
|
+
// Closed callback must be set to trigger cleanup
|
|
67
|
+
mOnClosedCallback =
|
|
68
|
+
std::make_unique<ThreadSafeCallback>(Napi::Function::New(info.Env(), [](const Napi::CallbackInfo &) {}));
|
|
69
|
+
|
|
70
|
+
instances.insert(this);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
TrackWrapper::~TrackWrapper() { doClose(); }
|
|
74
|
+
|
|
75
|
+
void TrackWrapper::doClose()
|
|
76
|
+
{
|
|
77
|
+
if (mTrackPtr)
|
|
78
|
+
{
|
|
79
|
+
try
|
|
80
|
+
{
|
|
81
|
+
mTrackPtr->close();
|
|
82
|
+
mTrackPtr.reset();
|
|
83
|
+
}
|
|
84
|
+
catch (std::exception &ex)
|
|
85
|
+
{
|
|
86
|
+
std::cerr << std::string("libdatachannel error while closing track: ") + ex.what() << std::endl;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
mOnOpenCallback.reset();
|
|
92
|
+
mOnErrorCallback.reset();
|
|
93
|
+
mOnMessageCallback.reset();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
void TrackWrapper::doCleanup()
|
|
97
|
+
{
|
|
98
|
+
PLOG_DEBUG << "doCleanup() called";
|
|
99
|
+
mOnClosedCallback.reset();
|
|
100
|
+
instances.erase(this);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
void TrackWrapper::close(const Napi::CallbackInfo &info) { doClose(); }
|
|
104
|
+
|
|
105
|
+
Napi::Value TrackWrapper::direction(const Napi::CallbackInfo &info)
|
|
106
|
+
{
|
|
107
|
+
if (!mTrackPtr)
|
|
108
|
+
{
|
|
109
|
+
Napi::Error::New(info.Env(), "direction() called on destroyed track").ThrowAsJavaScriptException();
|
|
110
|
+
return info.Env().Null();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
Napi::Env env = info.Env();
|
|
114
|
+
return Napi::String::New(env, directionToStr(mTrackPtr->direction()));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
Napi::Value TrackWrapper::mid(const Napi::CallbackInfo &info)
|
|
118
|
+
{
|
|
119
|
+
if (!mTrackPtr)
|
|
120
|
+
{
|
|
121
|
+
Napi::Error::New(info.Env(), "mid() called on destroyed track").ThrowAsJavaScriptException();
|
|
122
|
+
return info.Env().Null();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
Napi::Env env = info.Env();
|
|
126
|
+
return Napi::String::New(env, mTrackPtr->mid());
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
Napi::Value TrackWrapper::type(const Napi::CallbackInfo &info)
|
|
130
|
+
{
|
|
131
|
+
if (!mTrackPtr)
|
|
132
|
+
{
|
|
133
|
+
Napi::Error::New(info.Env(), "type() called on destroyed track").ThrowAsJavaScriptException();
|
|
134
|
+
return info.Env().Null();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
Napi::Env env = info.Env();
|
|
138
|
+
return Napi::String::New(env, mTrackPtr->description().type());
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
Napi::Value TrackWrapper::sendMessage(const Napi::CallbackInfo &info)
|
|
142
|
+
{
|
|
143
|
+
if (!mTrackPtr)
|
|
144
|
+
{
|
|
145
|
+
Napi::Error::New(info.Env(), "sendMessage() called on destroyed track").ThrowAsJavaScriptException();
|
|
146
|
+
return info.Env().Null();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
Napi::Env env = info.Env();
|
|
150
|
+
int length = info.Length();
|
|
151
|
+
|
|
152
|
+
// Allow call with NULL
|
|
153
|
+
if (length < 1 || (!info[0].IsString() && !info[0].IsNull()))
|
|
154
|
+
{
|
|
155
|
+
Napi::TypeError::New(env, "String or Null expected").ThrowAsJavaScriptException();
|
|
156
|
+
return info.Env().Null();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try
|
|
160
|
+
{
|
|
161
|
+
return Napi::Boolean::New(info.Env(), mTrackPtr->send(info[0].As<Napi::String>().ToString()));
|
|
162
|
+
}
|
|
163
|
+
catch (std::exception &ex)
|
|
164
|
+
{
|
|
165
|
+
Napi::Error::New(env, std::string("libdatachannel error while sending track message: ") + ex.what())
|
|
166
|
+
.ThrowAsJavaScriptException();
|
|
167
|
+
return Napi::Boolean::New(info.Env(), false);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
Napi::Value TrackWrapper::sendMessageBinary(const Napi::CallbackInfo &info)
|
|
172
|
+
{
|
|
173
|
+
if (!mTrackPtr)
|
|
174
|
+
{
|
|
175
|
+
Napi::Error::New(info.Env(), "sendMessageBinary() called on destroyed track").ThrowAsJavaScriptException();
|
|
176
|
+
return info.Env().Null();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
Napi::Env env = info.Env();
|
|
180
|
+
int length = info.Length();
|
|
181
|
+
|
|
182
|
+
if (length < 1 || !info[0].IsBuffer())
|
|
183
|
+
{
|
|
184
|
+
Napi::TypeError::New(env, "Buffer expected").ThrowAsJavaScriptException();
|
|
185
|
+
return info.Env().Null();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
try
|
|
189
|
+
{
|
|
190
|
+
Napi::Uint8Array buffer = info[0].As<Napi::Uint8Array>();
|
|
191
|
+
return Napi::Boolean::New(info.Env(), mTrackPtr->send((std::byte *)buffer.Data(), buffer.ByteLength()));
|
|
192
|
+
}
|
|
193
|
+
catch (std::exception &ex)
|
|
194
|
+
{
|
|
195
|
+
Napi::Error::New(env, std::string("libdatachannel error while sending track message: ") + ex.what())
|
|
196
|
+
.ThrowAsJavaScriptException();
|
|
197
|
+
return Napi::Boolean::New(info.Env(), false);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
Napi::Value TrackWrapper::isOpen(const Napi::CallbackInfo &info)
|
|
202
|
+
{
|
|
203
|
+
Napi::Env env = info.Env();
|
|
204
|
+
|
|
205
|
+
if (!mTrackPtr)
|
|
206
|
+
{
|
|
207
|
+
return Napi::Boolean::New(env, false);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return Napi::Boolean::New(env, mTrackPtr->isOpen());
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
Napi::Value TrackWrapper::isClosed(const Napi::CallbackInfo &info)
|
|
214
|
+
{
|
|
215
|
+
Napi::Env env = info.Env();
|
|
216
|
+
|
|
217
|
+
if (!mTrackPtr)
|
|
218
|
+
{
|
|
219
|
+
return Napi::Boolean::New(env, true);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return Napi::Boolean::New(env, mTrackPtr->isClosed());
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
Napi::Value TrackWrapper::maxMessageSize(const Napi::CallbackInfo &info)
|
|
226
|
+
{
|
|
227
|
+
Napi::Env env = info.Env();
|
|
228
|
+
|
|
229
|
+
if (!mTrackPtr)
|
|
230
|
+
{
|
|
231
|
+
return Napi::Number::New(info.Env(), 0);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
try
|
|
235
|
+
{
|
|
236
|
+
return Napi::Number::New(info.Env(), mTrackPtr->maxMessageSize());
|
|
237
|
+
}
|
|
238
|
+
catch (std::exception &ex)
|
|
239
|
+
{
|
|
240
|
+
Napi::Error::New(env, std::string("libdatachannel error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
241
|
+
return Napi::Number::New(info.Env(), 0);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
Napi::Value TrackWrapper::requestBitrate(const Napi::CallbackInfo &info)
|
|
246
|
+
{
|
|
247
|
+
if (!mTrackPtr)
|
|
248
|
+
{
|
|
249
|
+
Napi::Error::New(info.Env(), "requestBitrate() called on destroyed track").ThrowAsJavaScriptException();
|
|
250
|
+
return info.Env().Null();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
Napi::Env env = info.Env();
|
|
254
|
+
int length = info.Length();
|
|
255
|
+
|
|
256
|
+
if (length < 1 || !info[0].IsNumber())
|
|
257
|
+
{
|
|
258
|
+
Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException();
|
|
259
|
+
return info.Env().Null();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
unsigned int bitrate = static_cast<uint32_t>(info[0].As<Napi::Number>());
|
|
263
|
+
return Napi::Boolean::New(env, mTrackPtr->requestBitrate(bitrate));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
Napi::Value TrackWrapper::requestKeyframe(const Napi::CallbackInfo &info)
|
|
267
|
+
{
|
|
268
|
+
if (!mTrackPtr)
|
|
269
|
+
{
|
|
270
|
+
Napi::Error::New(info.Env(), "requestKeyframe() called on destroyed track").ThrowAsJavaScriptException();
|
|
271
|
+
return info.Env().Null();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
Napi::Env env = info.Env();
|
|
275
|
+
return Napi::Boolean::New(env, mTrackPtr->requestKeyframe());
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
void TrackWrapper::setMediaHandler(const Napi::CallbackInfo &info)
|
|
279
|
+
{
|
|
280
|
+
if (!mTrackPtr)
|
|
281
|
+
{
|
|
282
|
+
Napi::Error::New(info.Env(), "setMediaHandler() called on destroyed track").ThrowAsJavaScriptException();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
Napi::Env env = info.Env();
|
|
287
|
+
int length = info.Length();
|
|
288
|
+
|
|
289
|
+
if (length < 1 || !info[0].IsObject())
|
|
290
|
+
{
|
|
291
|
+
Napi::TypeError::New(env, "MediaHandler class instance expected").ThrowAsJavaScriptException();
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
std::shared_ptr<rtc::MediaHandler> handler = asMediaHandler(info[0].As<Napi::Object>());
|
|
296
|
+
if (!handler)
|
|
297
|
+
{
|
|
298
|
+
Napi::TypeError::New(env, "MediaHandler class instance expected. If this error is unexpected, please report a bug!")
|
|
299
|
+
.ThrowAsJavaScriptException();
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
mTrackPtr->setMediaHandler(handler);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
void TrackWrapper::onOpen(const Napi::CallbackInfo &info)
|
|
306
|
+
{
|
|
307
|
+
if (!mTrackPtr)
|
|
308
|
+
{
|
|
309
|
+
Napi::Error::New(info.Env(), "onOpen() called on destroyed track").ThrowAsJavaScriptException();
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
Napi::Env env = info.Env();
|
|
314
|
+
int length = info.Length();
|
|
315
|
+
|
|
316
|
+
if (length < 1 || !info[0].IsFunction())
|
|
317
|
+
{
|
|
318
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Callback
|
|
323
|
+
mOnOpenCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
324
|
+
|
|
325
|
+
mTrackPtr->onOpen(
|
|
326
|
+
[&]()
|
|
327
|
+
{
|
|
328
|
+
if (mOnOpenCallback)
|
|
329
|
+
mOnOpenCallback->call(
|
|
330
|
+
[this](Napi::Env env, std::vector<napi_value> &args)
|
|
331
|
+
{
|
|
332
|
+
// Check the track is not closed
|
|
333
|
+
if (instances.find(this) == instances.end())
|
|
334
|
+
throw ThreadSafeCallback::CancelException();
|
|
335
|
+
|
|
336
|
+
// This will run in main thread and needs to construct the
|
|
337
|
+
// arguments for the call
|
|
338
|
+
args = {};
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
void TrackWrapper::onClosed(const Napi::CallbackInfo &info)
|
|
344
|
+
{
|
|
345
|
+
if (!mTrackPtr)
|
|
346
|
+
{
|
|
347
|
+
Napi::Error::New(info.Env(), "onClosed() called on destroyed track").ThrowAsJavaScriptException();
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
Napi::Env env = info.Env();
|
|
352
|
+
int length = info.Length();
|
|
353
|
+
|
|
354
|
+
if (length < 1 || !info[0].IsFunction())
|
|
355
|
+
{
|
|
356
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Callback
|
|
361
|
+
mOnClosedCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
362
|
+
|
|
363
|
+
mTrackPtr->onClosed(
|
|
364
|
+
[&]()
|
|
365
|
+
{
|
|
366
|
+
if (mOnClosedCallback)
|
|
367
|
+
mOnClosedCallback->call(
|
|
368
|
+
[this](Napi::Env env, std::vector<napi_value> &args)
|
|
369
|
+
{
|
|
370
|
+
// Do not check if the data channel has been closed here
|
|
371
|
+
|
|
372
|
+
// This will run in main thread and needs to construct the
|
|
373
|
+
// arguments for the call
|
|
374
|
+
args = {};
|
|
375
|
+
},
|
|
376
|
+
[this] { doCleanup(); });
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
void TrackWrapper::onError(const Napi::CallbackInfo &info)
|
|
381
|
+
{
|
|
382
|
+
if (!mTrackPtr)
|
|
383
|
+
{
|
|
384
|
+
Napi::Error::New(info.Env(), "onError() called on destroyed track").ThrowAsJavaScriptException();
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
Napi::Env env = info.Env();
|
|
389
|
+
int length = info.Length();
|
|
390
|
+
|
|
391
|
+
if (length < 1 || !info[0].IsFunction())
|
|
392
|
+
{
|
|
393
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Callback
|
|
398
|
+
mOnErrorCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
399
|
+
|
|
400
|
+
mTrackPtr->onError(
|
|
401
|
+
[&](const std::string &error)
|
|
402
|
+
{
|
|
403
|
+
if (mOnErrorCallback)
|
|
404
|
+
mOnErrorCallback->call(
|
|
405
|
+
[this, error](Napi::Env env, std::vector<napi_value> &args)
|
|
406
|
+
{
|
|
407
|
+
// Check the track is not closed
|
|
408
|
+
if (instances.find(this) == instances.end())
|
|
409
|
+
throw ThreadSafeCallback::CancelException();
|
|
410
|
+
|
|
411
|
+
// This will run in main thread and needs to construct the
|
|
412
|
+
// arguments for the call
|
|
413
|
+
args = {Napi::String::New(env, error)};
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
void TrackWrapper::onMessage(const Napi::CallbackInfo &info)
|
|
419
|
+
{
|
|
420
|
+
if (!mTrackPtr)
|
|
421
|
+
{
|
|
422
|
+
Napi::Error::New(info.Env(), "onMessage() called on destroyed track").ThrowAsJavaScriptException();
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
Napi::Env env = info.Env();
|
|
427
|
+
int length = info.Length();
|
|
428
|
+
|
|
429
|
+
if (length < 1 || !info[0].IsFunction())
|
|
430
|
+
{
|
|
431
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Callback
|
|
436
|
+
mOnMessageCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
437
|
+
|
|
438
|
+
mTrackPtr->onMessage(
|
|
439
|
+
[&](std::variant<rtc::binary, std::string> message)
|
|
440
|
+
{
|
|
441
|
+
if (mOnMessageCallback)
|
|
442
|
+
mOnMessageCallback->call(
|
|
443
|
+
[this, message = std::move(message)](Napi::Env env, std::vector<napi_value> &args)
|
|
444
|
+
{
|
|
445
|
+
// Check the track is not closed
|
|
446
|
+
if (instances.find(this) == instances.end())
|
|
447
|
+
throw ThreadSafeCallback::CancelException();
|
|
448
|
+
|
|
449
|
+
// This will run in main thread and needs to construct the
|
|
450
|
+
// arguments for the call
|
|
451
|
+
if (std::holds_alternative<rtc::binary>(message)) // Track will always receive messages as binary
|
|
452
|
+
{
|
|
453
|
+
auto bin = std::get<rtc::binary>(std::move(message));
|
|
454
|
+
args = {Napi::Buffer<std::byte>::Copy(env, bin.data(), bin.size())};
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
});
|
|
458
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#ifndef MEDIA_TRACK_WRAPPER_H
|
|
2
|
+
#define MEDIA_TRACK_WRAPPER_H
|
|
3
|
+
|
|
4
|
+
#include <memory>
|
|
5
|
+
#include <unordered_set>
|
|
6
|
+
|
|
7
|
+
#include <napi.h>
|
|
8
|
+
#include <rtc/rtc.hpp>
|
|
9
|
+
|
|
10
|
+
#include "thread-safe-callback.h"
|
|
11
|
+
|
|
12
|
+
class TrackWrapper : public Napi::ObjectWrap<TrackWrapper>
|
|
13
|
+
{
|
|
14
|
+
public:
|
|
15
|
+
static Napi::FunctionReference constructor;
|
|
16
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
17
|
+
TrackWrapper(const Napi::CallbackInfo &info);
|
|
18
|
+
~TrackWrapper();
|
|
19
|
+
|
|
20
|
+
// Functions
|
|
21
|
+
Napi::Value direction(const Napi::CallbackInfo &info);
|
|
22
|
+
Napi::Value mid(const Napi::CallbackInfo &info);
|
|
23
|
+
Napi::Value type(const Napi::CallbackInfo &info);
|
|
24
|
+
void close(const Napi::CallbackInfo &info);
|
|
25
|
+
Napi::Value sendMessage(const Napi::CallbackInfo &info);
|
|
26
|
+
Napi::Value sendMessageBinary(const Napi::CallbackInfo &info);
|
|
27
|
+
Napi::Value isOpen(const Napi::CallbackInfo &info);
|
|
28
|
+
Napi::Value isClosed(const Napi::CallbackInfo &info);
|
|
29
|
+
Napi::Value maxMessageSize(const Napi::CallbackInfo &info);
|
|
30
|
+
Napi::Value requestBitrate(const Napi::CallbackInfo &info);
|
|
31
|
+
Napi::Value requestKeyframe(const Napi::CallbackInfo &info);
|
|
32
|
+
void setMediaHandler(const Napi::CallbackInfo &info);
|
|
33
|
+
|
|
34
|
+
// Callbacks
|
|
35
|
+
void onOpen(const Napi::CallbackInfo &info);
|
|
36
|
+
void onClosed(const Napi::CallbackInfo &info);
|
|
37
|
+
void onError(const Napi::CallbackInfo &info);
|
|
38
|
+
void onMessage(const Napi::CallbackInfo &info);
|
|
39
|
+
|
|
40
|
+
// Close all existing tracks
|
|
41
|
+
static void CloseAll();
|
|
42
|
+
|
|
43
|
+
// Reset all Callbacks for existing tracks
|
|
44
|
+
static void CleanupAll();
|
|
45
|
+
|
|
46
|
+
private:
|
|
47
|
+
static std::unordered_set<TrackWrapper *> instances;
|
|
48
|
+
|
|
49
|
+
void doClose();
|
|
50
|
+
void doCleanup();
|
|
51
|
+
|
|
52
|
+
std::shared_ptr<rtc::Track> mTrackPtr = nullptr;
|
|
53
|
+
|
|
54
|
+
// Callback Ptrs
|
|
55
|
+
std::unique_ptr<ThreadSafeCallback> mOnOpenCallback = nullptr;
|
|
56
|
+
std::unique_ptr<ThreadSafeCallback> mOnClosedCallback = nullptr;
|
|
57
|
+
std::unique_ptr<ThreadSafeCallback> mOnErrorCallback = nullptr;
|
|
58
|
+
std::unique_ptr<ThreadSafeCallback> mOnMessageCallback = nullptr;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
#endif // MEDIA_TRACK_WRAPPER_H
|