@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,89 @@
|
|
|
1
|
+
#ifndef PEER_CONNECTION_WRAPPER_H
|
|
2
|
+
#define PEER_CONNECTION_WRAPPER_H
|
|
3
|
+
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <memory>
|
|
6
|
+
#include <unordered_set>
|
|
7
|
+
|
|
8
|
+
#include <napi.h>
|
|
9
|
+
#include <rtc/rtc.hpp>
|
|
10
|
+
|
|
11
|
+
#include "thread-safe-callback.h"
|
|
12
|
+
|
|
13
|
+
class PeerConnectionWrapper : public Napi::ObjectWrap<PeerConnectionWrapper>
|
|
14
|
+
{
|
|
15
|
+
public:
|
|
16
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
17
|
+
PeerConnectionWrapper(const Napi::CallbackInfo &info);
|
|
18
|
+
~PeerConnectionWrapper();
|
|
19
|
+
|
|
20
|
+
// Functions
|
|
21
|
+
void close(const Napi::CallbackInfo &info);
|
|
22
|
+
void setLocalDescription(const Napi::CallbackInfo &info);
|
|
23
|
+
void setRemoteDescription(const Napi::CallbackInfo &info);
|
|
24
|
+
Napi::Value localDescription(const Napi::CallbackInfo &info);
|
|
25
|
+
Napi::Value remoteDescription(const Napi::CallbackInfo &info);
|
|
26
|
+
void addRemoteCandidate(const Napi::CallbackInfo &info);
|
|
27
|
+
Napi::Value createDataChannel(const Napi::CallbackInfo &info);
|
|
28
|
+
|
|
29
|
+
#if RTC_ENABLE_MEDIA == 1
|
|
30
|
+
Napi::Value addTrack(const Napi::CallbackInfo &info);
|
|
31
|
+
void onTrack(const Napi::CallbackInfo &info);
|
|
32
|
+
#endif
|
|
33
|
+
|
|
34
|
+
Napi::Value hasMedia(const Napi::CallbackInfo &info);
|
|
35
|
+
Napi::Value state(const Napi::CallbackInfo &info);
|
|
36
|
+
Napi::Value iceState(const Napi::CallbackInfo &info);
|
|
37
|
+
Napi::Value signalingState(const Napi::CallbackInfo &info);
|
|
38
|
+
Napi::Value gatheringState(const Napi::CallbackInfo &info);
|
|
39
|
+
Napi::Value remoteFingerprint(const Napi::CallbackInfo &info);
|
|
40
|
+
|
|
41
|
+
// Callbacks
|
|
42
|
+
void onLocalDescription(const Napi::CallbackInfo &info);
|
|
43
|
+
void onLocalCandidate(const Napi::CallbackInfo &info);
|
|
44
|
+
void onStateChange(const Napi::CallbackInfo &info);
|
|
45
|
+
void onIceStateChange(const Napi::CallbackInfo &info);
|
|
46
|
+
void onSignalingStateChange(const Napi::CallbackInfo &info);
|
|
47
|
+
void onGatheringStateChange(const Napi::CallbackInfo &info);
|
|
48
|
+
void onDataChannel(const Napi::CallbackInfo &info);
|
|
49
|
+
|
|
50
|
+
// Stats
|
|
51
|
+
Napi::Value bytesSent(const Napi::CallbackInfo &info);
|
|
52
|
+
Napi::Value bytesReceived(const Napi::CallbackInfo &info);
|
|
53
|
+
Napi::Value rtt(const Napi::CallbackInfo &info);
|
|
54
|
+
Napi::Value getSelectedCandidatePair(const Napi::CallbackInfo &info);
|
|
55
|
+
Napi::Value maxDataChannelId(const Napi::CallbackInfo &info);
|
|
56
|
+
Napi::Value maxMessageSize(const Napi::CallbackInfo &info);
|
|
57
|
+
|
|
58
|
+
// Close all existing Peer Connections
|
|
59
|
+
static void CloseAll();
|
|
60
|
+
|
|
61
|
+
// Reset all Callbacks for existing Peer Connections
|
|
62
|
+
static void CleanupAll();
|
|
63
|
+
|
|
64
|
+
private:
|
|
65
|
+
static Napi::FunctionReference constructor;
|
|
66
|
+
static std::unordered_set<PeerConnectionWrapper *> instances;
|
|
67
|
+
|
|
68
|
+
void doClose();
|
|
69
|
+
void doCleanup();
|
|
70
|
+
|
|
71
|
+
std::string mPeerName;
|
|
72
|
+
std::unique_ptr<rtc::PeerConnection> mRtcPeerConnPtr = nullptr;
|
|
73
|
+
|
|
74
|
+
// Callback Ptrs
|
|
75
|
+
std::unique_ptr<ThreadSafeCallback> mOnLocalDescriptionCallback = nullptr;
|
|
76
|
+
std::unique_ptr<ThreadSafeCallback> mOnLocalCandidateCallback = nullptr;
|
|
77
|
+
std::unique_ptr<ThreadSafeCallback> mOnStateChangeCallback = nullptr;
|
|
78
|
+
std::unique_ptr<ThreadSafeCallback> mOnIceStateChangeCallback = nullptr;
|
|
79
|
+
std::unique_ptr<ThreadSafeCallback> mOnSignalingStateChangeCallback = nullptr;
|
|
80
|
+
std::unique_ptr<ThreadSafeCallback> mOnGatheringStateChangeCallback = nullptr;
|
|
81
|
+
std::unique_ptr<ThreadSafeCallback> mOnDataChannelCallback = nullptr;
|
|
82
|
+
std::unique_ptr<ThreadSafeCallback> mOnTrackCallback = nullptr;
|
|
83
|
+
|
|
84
|
+
// Helpers
|
|
85
|
+
std::string candidateTypeToString(const rtc::Candidate::Type &type);
|
|
86
|
+
std::string candidateTransportTypeToString(const rtc::Candidate::TransportType &transportType);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
#endif // PEER_CONNECTION_WRAPPER_H
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#include "rtc-wrapper.h"
|
|
2
|
+
#include "peer-connection-wrapper.h"
|
|
3
|
+
#include "data-channel-wrapper.h"
|
|
4
|
+
|
|
5
|
+
#if RTC_ENABLE_MEDIA == 1
|
|
6
|
+
#include "media-track-wrapper.h"
|
|
7
|
+
#endif
|
|
8
|
+
|
|
9
|
+
#if RTC_ENABLE_WEBSOCKET == 1
|
|
10
|
+
#include "web-socket-wrapper.h"
|
|
11
|
+
#include "web-socket-server-wrapper.h"
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
#include "plog/Log.h"
|
|
15
|
+
|
|
16
|
+
#include <chrono>
|
|
17
|
+
#include <future>
|
|
18
|
+
|
|
19
|
+
Napi::Object RtcWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
20
|
+
{
|
|
21
|
+
Napi::HandleScope scope(env);
|
|
22
|
+
|
|
23
|
+
exports.Set("initLogger", Napi::Function::New(env, &RtcWrapper::initLogger));
|
|
24
|
+
exports.Set("cleanup", Napi::Function::New(env, &RtcWrapper::cleanup));
|
|
25
|
+
exports.Set("preload", Napi::Function::New(env, &RtcWrapper::preload));
|
|
26
|
+
exports.Set("setSctpSettings", Napi::Function::New(env, &RtcWrapper::setSctpSettings));
|
|
27
|
+
exports.Set("getLibraryVersion", Napi::Function::New(env, &RtcWrapper::getLibraryVersion));
|
|
28
|
+
|
|
29
|
+
return exports;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
void RtcWrapper::preload(const Napi::CallbackInfo &info)
|
|
33
|
+
{
|
|
34
|
+
PLOG_DEBUG << "preload() called";
|
|
35
|
+
Napi::Env env = info.Env();
|
|
36
|
+
try
|
|
37
|
+
{
|
|
38
|
+
rtc::Preload();
|
|
39
|
+
}
|
|
40
|
+
catch (std::exception &ex)
|
|
41
|
+
{
|
|
42
|
+
Napi::Error::New(env, std::string("libdatachannel error# ") + ex.what()).ThrowAsJavaScriptException();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
void RtcWrapper::initLogger(const Napi::CallbackInfo &info)
|
|
47
|
+
{
|
|
48
|
+
Napi::Env env = info.Env();
|
|
49
|
+
int length = info.Length();
|
|
50
|
+
|
|
51
|
+
// We expect (String, Object, Function) as param
|
|
52
|
+
if (length < 1 || !info[0].IsString())
|
|
53
|
+
{
|
|
54
|
+
Napi::TypeError::New(env, "LogLevel(String) expected").ThrowAsJavaScriptException();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
std::string logLevelStr = info[0].As<Napi::String>().ToString();
|
|
59
|
+
rtc::LogLevel logLevel = rtc::LogLevel::None;
|
|
60
|
+
|
|
61
|
+
if (logLevelStr == "Verbose")
|
|
62
|
+
logLevel = rtc::LogLevel::Verbose;
|
|
63
|
+
if (logLevelStr == "Debug")
|
|
64
|
+
logLevel = rtc::LogLevel::Debug;
|
|
65
|
+
if (logLevelStr == "Info")
|
|
66
|
+
logLevel = rtc::LogLevel::Info;
|
|
67
|
+
if (logLevelStr == "Warning")
|
|
68
|
+
logLevel = rtc::LogLevel::Warning;
|
|
69
|
+
if (logLevelStr == "Error")
|
|
70
|
+
logLevel = rtc::LogLevel::Error;
|
|
71
|
+
if (logLevelStr == "Fatal")
|
|
72
|
+
logLevel = rtc::LogLevel::Fatal;
|
|
73
|
+
|
|
74
|
+
try
|
|
75
|
+
{
|
|
76
|
+
if (length < 2)
|
|
77
|
+
{
|
|
78
|
+
rtc::InitLogger(logLevel);
|
|
79
|
+
}
|
|
80
|
+
else
|
|
81
|
+
{
|
|
82
|
+
if (!info[1].IsFunction())
|
|
83
|
+
{
|
|
84
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
logCallback = std::make_unique<ThreadSafeCallback>(info[1].As<Napi::Function>());
|
|
88
|
+
rtc::InitLogger(logLevel,
|
|
89
|
+
[&](rtc::LogLevel level, std::string message)
|
|
90
|
+
{
|
|
91
|
+
if (logCallback)
|
|
92
|
+
logCallback->call(
|
|
93
|
+
[level, message = std::move(message)](Napi::Env env, std::vector<napi_value> &args)
|
|
94
|
+
{
|
|
95
|
+
// This will run in main thread and needs to construct the
|
|
96
|
+
// arguments for the call
|
|
97
|
+
|
|
98
|
+
std::string logLevel;
|
|
99
|
+
if (level == rtc::LogLevel::Verbose)
|
|
100
|
+
logLevel = "Verbose";
|
|
101
|
+
if (level == rtc::LogLevel::Debug)
|
|
102
|
+
logLevel = "Debug";
|
|
103
|
+
if (level == rtc::LogLevel::Info)
|
|
104
|
+
logLevel = "Info";
|
|
105
|
+
if (level == rtc::LogLevel::Warning)
|
|
106
|
+
logLevel = "Warning";
|
|
107
|
+
if (level == rtc::LogLevel::Error)
|
|
108
|
+
logLevel = "Error";
|
|
109
|
+
if (level == rtc::LogLevel::Fatal)
|
|
110
|
+
logLevel = "Fatal";
|
|
111
|
+
args = {Napi::String::New(env, logLevel), Napi::String::New(env, message)};
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (std::exception &ex)
|
|
117
|
+
{
|
|
118
|
+
Napi::Error::New(env, std::string("libdatachannel error# ") + ex.what()).ThrowAsJavaScriptException();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
void RtcWrapper::cleanup(const Napi::CallbackInfo &info)
|
|
124
|
+
{
|
|
125
|
+
PLOG_DEBUG << "cleanup() called";
|
|
126
|
+
Napi::Env env = info.Env();
|
|
127
|
+
try
|
|
128
|
+
{
|
|
129
|
+
PeerConnectionWrapper::CloseAll();
|
|
130
|
+
DataChannelWrapper::CloseAll();
|
|
131
|
+
|
|
132
|
+
#if RTC_ENABLE_MEDIA == 1
|
|
133
|
+
TrackWrapper::CloseAll();
|
|
134
|
+
#endif
|
|
135
|
+
|
|
136
|
+
#if RTC_ENABLE_WEBSOCKET == 1
|
|
137
|
+
WebSocketWrapper::CloseAll();
|
|
138
|
+
WebSocketServerWrapper::StopAll();
|
|
139
|
+
#endif
|
|
140
|
+
|
|
141
|
+
const auto timeout = std::chrono::seconds(10);
|
|
142
|
+
if (rtc::Cleanup().wait_for(std::chrono::seconds(timeout)) == std::future_status::timeout)
|
|
143
|
+
throw std::runtime_error("cleanup timeout (possible deadlock)");
|
|
144
|
+
|
|
145
|
+
// Cleanup the instances
|
|
146
|
+
PeerConnectionWrapper::CleanupAll();
|
|
147
|
+
DataChannelWrapper::CleanupAll();
|
|
148
|
+
|
|
149
|
+
#if RTC_ENABLE_MEDIA == 1
|
|
150
|
+
TrackWrapper::CleanupAll();
|
|
151
|
+
#endif
|
|
152
|
+
|
|
153
|
+
#if RTC_ENABLE_WEBSOCKET == 1
|
|
154
|
+
WebSocketWrapper::CleanupAll();
|
|
155
|
+
#endif
|
|
156
|
+
|
|
157
|
+
if (logCallback)
|
|
158
|
+
logCallback.reset();
|
|
159
|
+
}
|
|
160
|
+
catch (std::exception &ex)
|
|
161
|
+
{
|
|
162
|
+
Napi::Error::New(env, std::string("libdatachannel error# ") + ex.what()).ThrowAsJavaScriptException();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
void RtcWrapper::setSctpSettings(const Napi::CallbackInfo &info)
|
|
168
|
+
{
|
|
169
|
+
PLOG_DEBUG << "setSctpSettings() called";
|
|
170
|
+
Napi::Env env = info.Env();
|
|
171
|
+
int length = info.Length();
|
|
172
|
+
|
|
173
|
+
// We expect (Object) as param
|
|
174
|
+
if (length < 1 || !info[0].IsObject())
|
|
175
|
+
{
|
|
176
|
+
Napi::TypeError::New(env, "Configuration (Object) expected").ThrowAsJavaScriptException();
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
rtc::SctpSettings settings;
|
|
181
|
+
Napi::Object config = info[0].As<Napi::Object>();
|
|
182
|
+
|
|
183
|
+
if (config.Get("recvBufferSize").IsNumber())
|
|
184
|
+
settings.recvBufferSize = config.Get("recvBufferSize").As<Napi::Number>().Uint32Value();
|
|
185
|
+
if (config.Get("sendBufferSize").IsNumber())
|
|
186
|
+
settings.sendBufferSize = config.Get("sendBufferSize").As<Napi::Number>().Uint32Value();
|
|
187
|
+
if (config.Get("maxChunksOnQueue").IsNumber())
|
|
188
|
+
settings.maxChunksOnQueue = config.Get("maxChunksOnQueue").As<Napi::Number>().Uint32Value();
|
|
189
|
+
if (config.Get("initialCongestionWindow").IsNumber())
|
|
190
|
+
settings.initialCongestionWindow = config.Get("initialCongestionWindow").As<Napi::Number>().Uint32Value();
|
|
191
|
+
if (config.Get("congestionControlModule").IsNumber())
|
|
192
|
+
settings.congestionControlModule = config.Get("congestionControlModule").As<Napi::Number>().Uint32Value();
|
|
193
|
+
if (config.Get("delayedSackTime").IsNumber())
|
|
194
|
+
settings.delayedSackTime =
|
|
195
|
+
std::chrono::milliseconds(config.Get("delayedSackTime").As<Napi::Number>().Uint32Value());
|
|
196
|
+
|
|
197
|
+
rtc::SetSctpSettings(settings);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
Napi::Value RtcWrapper::getLibraryVersion(const Napi::CallbackInfo &info)
|
|
201
|
+
{
|
|
202
|
+
PLOG_DEBUG << "getLibraryVersion() called";
|
|
203
|
+
Napi::Env env = info.Env();
|
|
204
|
+
return Napi::String::New(info.Env(), RTC_VERSION);
|
|
205
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#ifndef RTC_WRAPPER_H
|
|
2
|
+
#define RTC_WRAPPER_H
|
|
3
|
+
|
|
4
|
+
#include <napi.h>
|
|
5
|
+
|
|
6
|
+
#include "rtc/rtc.hpp"
|
|
7
|
+
|
|
8
|
+
#include "thread-safe-callback.h"
|
|
9
|
+
|
|
10
|
+
class RtcWrapper
|
|
11
|
+
{
|
|
12
|
+
public:
|
|
13
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
14
|
+
static void preload(const Napi::CallbackInfo &info);
|
|
15
|
+
static void initLogger(const Napi::CallbackInfo &info);
|
|
16
|
+
static void cleanup(const Napi::CallbackInfo &info);
|
|
17
|
+
static void setSctpSettings(const Napi::CallbackInfo &info);
|
|
18
|
+
static Napi::Value getLibraryVersion(const Napi::CallbackInfo &info);
|
|
19
|
+
|
|
20
|
+
private:
|
|
21
|
+
static inline std::unique_ptr<ThreadSafeCallback> logCallback = nullptr;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
#endif // RTC_WRAPPER_H
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#include "thread-safe-callback.h"
|
|
2
|
+
|
|
3
|
+
#include <stdexcept>
|
|
4
|
+
|
|
5
|
+
const char *ThreadSafeCallback::CancelException::what() const throw() { return "ThreadSafeCallback cancelled"; }
|
|
6
|
+
|
|
7
|
+
ThreadSafeCallback::ThreadSafeCallback(Napi::Function callback)
|
|
8
|
+
{
|
|
9
|
+
Napi::Env env = callback.Env();
|
|
10
|
+
|
|
11
|
+
if (!callback.IsFunction())
|
|
12
|
+
throw Napi::Error::New(env, "Callback must be a function");
|
|
13
|
+
|
|
14
|
+
tsfn = tsfn_t::New(env, std::move(callback), "ThreadSafeCallback callback",
|
|
15
|
+
0, // unlimited queue
|
|
16
|
+
1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
ThreadSafeCallback::~ThreadSafeCallback() { tsfn.Abort(); }
|
|
20
|
+
|
|
21
|
+
void ThreadSafeCallback::call(arg_func_t argFunc, cleanup_func_t cleanupFunc)
|
|
22
|
+
{
|
|
23
|
+
CallbackData *data = new CallbackData{std::move(argFunc), std::move(cleanupFunc)};
|
|
24
|
+
if (tsfn.BlockingCall(data) != napi_ok)
|
|
25
|
+
{
|
|
26
|
+
delete data;
|
|
27
|
+
throw std::runtime_error("Failed to call JavaScript callback");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
void ThreadSafeCallback::callbackFunc(Napi::Env env, Napi::Function callback, ContextType *context, CallbackData *data)
|
|
32
|
+
{
|
|
33
|
+
// if env is gone, it could mean this cb was destroyed. See issue#176
|
|
34
|
+
if (!data || !env)
|
|
35
|
+
return;
|
|
36
|
+
|
|
37
|
+
arg_vector_t args;
|
|
38
|
+
arg_func_t argFunc(std::move(data->argFunc));
|
|
39
|
+
cleanup_func_t cleanup(std::move(data->cleanupFunc));
|
|
40
|
+
delete data;
|
|
41
|
+
|
|
42
|
+
try
|
|
43
|
+
{
|
|
44
|
+
argFunc(env, args);
|
|
45
|
+
}
|
|
46
|
+
catch (CancelException &)
|
|
47
|
+
{
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (callback)
|
|
52
|
+
{
|
|
53
|
+
callback.Call(args);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
cleanup();
|
|
57
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#ifndef THREAD_SAFE_CALLBACK_H
|
|
2
|
+
#define THREAD_SAFE_CALLBACK_H
|
|
3
|
+
|
|
4
|
+
#include <napi.h>
|
|
5
|
+
|
|
6
|
+
#include <vector>
|
|
7
|
+
#include <functional>
|
|
8
|
+
|
|
9
|
+
class ThreadSafeCallback
|
|
10
|
+
{
|
|
11
|
+
public:
|
|
12
|
+
using arg_vector_t = std::vector<napi_value>;
|
|
13
|
+
using arg_func_t = std::function<void(napi_env, arg_vector_t &)>;
|
|
14
|
+
using cleanup_func_t = std::function<void()>;
|
|
15
|
+
|
|
16
|
+
ThreadSafeCallback(Napi::Function callback);
|
|
17
|
+
~ThreadSafeCallback();
|
|
18
|
+
|
|
19
|
+
ThreadSafeCallback(const ThreadSafeCallback &) = delete;
|
|
20
|
+
ThreadSafeCallback(ThreadSafeCallback &&) = delete;
|
|
21
|
+
|
|
22
|
+
ThreadSafeCallback &operator=(const ThreadSafeCallback &) = delete;
|
|
23
|
+
ThreadSafeCallback &operator=(ThreadSafeCallback &&) = delete;
|
|
24
|
+
|
|
25
|
+
void call(
|
|
26
|
+
arg_func_t argFunc, cleanup_func_t cleanupFunc = []() {});
|
|
27
|
+
|
|
28
|
+
class CancelException : public std::exception
|
|
29
|
+
{
|
|
30
|
+
const char *what() const throw();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
private:
|
|
34
|
+
using ContextType = std::nullptr_t;
|
|
35
|
+
struct CallbackData
|
|
36
|
+
{
|
|
37
|
+
arg_func_t argFunc;
|
|
38
|
+
cleanup_func_t cleanupFunc;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
static void callbackFunc(Napi::Env env, Napi::Function callback, ContextType *context, CallbackData *data);
|
|
42
|
+
|
|
43
|
+
using tsfn_t = Napi::TypedThreadSafeFunction<ContextType, CallbackData, callbackFunc>;
|
|
44
|
+
tsfn_t tsfn;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
#endif // THREAD_SAFE_CALLBACK_H
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
#include "web-socket-server-wrapper.h"
|
|
2
|
+
#include "web-socket-wrapper.h"
|
|
3
|
+
|
|
4
|
+
#include "plog/Log.h"
|
|
5
|
+
|
|
6
|
+
Napi::FunctionReference WebSocketServerWrapper::constructor = Napi::FunctionReference();
|
|
7
|
+
std::unordered_set<WebSocketServerWrapper *> WebSocketServerWrapper::instances;
|
|
8
|
+
|
|
9
|
+
void WebSocketServerWrapper::StopAll()
|
|
10
|
+
{
|
|
11
|
+
PLOG_DEBUG << "StopAll() called";
|
|
12
|
+
auto copy(instances);
|
|
13
|
+
for (auto inst : copy)
|
|
14
|
+
inst->doStop();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
Napi::Object WebSocketServerWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
18
|
+
{
|
|
19
|
+
Napi::HandleScope scope(env);
|
|
20
|
+
|
|
21
|
+
Napi::Function func = DefineClass(env, "WebSocketServer",
|
|
22
|
+
{InstanceMethod("stop", &WebSocketServerWrapper::stop),
|
|
23
|
+
InstanceMethod("port", &WebSocketServerWrapper::port),
|
|
24
|
+
InstanceMethod("onClient", &WebSocketServerWrapper::onClient)});
|
|
25
|
+
|
|
26
|
+
// If this is not the first call, we don't want to reassign the constructor (hot-reload problem)
|
|
27
|
+
if (constructor.IsEmpty())
|
|
28
|
+
{
|
|
29
|
+
constructor = Napi::Persistent(func);
|
|
30
|
+
constructor.SuppressDestruct();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
exports.Set("WebSocketServer", func);
|
|
34
|
+
return exports;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
WebSocketServerWrapper::WebSocketServerWrapper(const Napi::CallbackInfo &info)
|
|
38
|
+
: Napi::ObjectWrap<WebSocketServerWrapper>(info)
|
|
39
|
+
{
|
|
40
|
+
PLOG_DEBUG << "Constructor called";
|
|
41
|
+
Napi::Env env = info.Env();
|
|
42
|
+
|
|
43
|
+
// Create WebSocketServer without config
|
|
44
|
+
if (info.Length() == 0)
|
|
45
|
+
{
|
|
46
|
+
try
|
|
47
|
+
{
|
|
48
|
+
PLOG_DEBUG << "Creating a new WebSocketServer without config";
|
|
49
|
+
mWebSocketServerPtr = std::make_unique<rtc::WebSocketServer>();
|
|
50
|
+
}
|
|
51
|
+
catch (std::exception &ex)
|
|
52
|
+
{
|
|
53
|
+
Napi::Error::New(env,
|
|
54
|
+
std::string("libdatachannel error while creating WebSocketServer without config: ") + ex.what())
|
|
55
|
+
.ThrowAsJavaScriptException();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
PLOG_DEBUG << "WebSocketServer created without config";
|
|
60
|
+
|
|
61
|
+
instances.insert(this);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Create WebSocketServer with config
|
|
66
|
+
|
|
67
|
+
Napi::Object config = info[0].As<Napi::Object>();
|
|
68
|
+
rtc::WebSocketServerConfiguration webSocketServerConfig;
|
|
69
|
+
|
|
70
|
+
// Port
|
|
71
|
+
if (config.Has("port"))
|
|
72
|
+
{
|
|
73
|
+
if (!config.Get("port").IsNumber())
|
|
74
|
+
{
|
|
75
|
+
Napi::TypeError::New(info.Env(), "port must be a number").ThrowAsJavaScriptException();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
webSocketServerConfig.port = config.Get("port").ToNumber().Uint32Value();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Enable TLS
|
|
82
|
+
if (config.Has("enableTls"))
|
|
83
|
+
{
|
|
84
|
+
if (!config.Get("enableTls").IsBoolean())
|
|
85
|
+
{
|
|
86
|
+
Napi::TypeError::New(info.Env(), "enableTls must be boolean").ThrowAsJavaScriptException();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
webSocketServerConfig.enableTls = config.Get("enableTls").ToBoolean();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Certificate PEM File
|
|
93
|
+
if (config.Has("certificatePemFile"))
|
|
94
|
+
{
|
|
95
|
+
if (!config.Get("certificatePemFile").IsString())
|
|
96
|
+
{
|
|
97
|
+
Napi::TypeError::New(info.Env(), "certificatePemFile must be a string").ThrowAsJavaScriptException();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
webSocketServerConfig.certificatePemFile = config.Get("certificatePemFile").ToString();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Key PEM File
|
|
104
|
+
if (config.Has("keyPemFile"))
|
|
105
|
+
{
|
|
106
|
+
if (!config.Get("keyPemFile").IsString())
|
|
107
|
+
{
|
|
108
|
+
Napi::TypeError::New(info.Env(), "keyPemFile must be a string").ThrowAsJavaScriptException();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
webSocketServerConfig.keyPemFile = config.Get("keyPemFile").ToString();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Key PEM Pass
|
|
115
|
+
if (config.Has("keyPemPass"))
|
|
116
|
+
{
|
|
117
|
+
if (!config.Get("keyPemPass").IsString())
|
|
118
|
+
{
|
|
119
|
+
Napi::TypeError::New(info.Env(), "keyPemPass must be a string").ThrowAsJavaScriptException();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
webSocketServerConfig.keyPemPass = config.Get("keyPemPass").ToString();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Bind Address
|
|
126
|
+
if (config.Has("bindAddress"))
|
|
127
|
+
{
|
|
128
|
+
if (!config.Get("bindAddress").IsString())
|
|
129
|
+
{
|
|
130
|
+
Napi::TypeError::New(info.Env(), "bindAddress must be a string").ThrowAsJavaScriptException();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
webSocketServerConfig.bindAddress = config.Get("bindAddress").ToString();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Connection Timeout
|
|
137
|
+
if (config.Has("connectionTimeout"))
|
|
138
|
+
{
|
|
139
|
+
if (!config.Get("connectionTimeout").IsNumber())
|
|
140
|
+
{
|
|
141
|
+
Napi::TypeError::New(info.Env(), "connectionTimeout must be a number").ThrowAsJavaScriptException();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
webSocketServerConfig.connectionTimeout =
|
|
145
|
+
std::chrono::milliseconds(config.Get("connectionTimeout").ToNumber().Int64Value());
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Max Message Size
|
|
149
|
+
if (config.Has("maxMessageSize"))
|
|
150
|
+
{
|
|
151
|
+
if (!config.Get("maxMessageSize").IsNumber())
|
|
152
|
+
{
|
|
153
|
+
Napi::TypeError::New(info.Env(), "maxMessageSize must be a number").ThrowAsJavaScriptException();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
webSocketServerConfig.maxMessageSize = config.Get("maxMessageSize").ToNumber().Int32Value();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Create WebSocketServer with config
|
|
160
|
+
try
|
|
161
|
+
{
|
|
162
|
+
PLOG_DEBUG << "Creating a new WebSocketServer";
|
|
163
|
+
mWebSocketServerPtr = std::make_unique<rtc::WebSocketServer>(webSocketServerConfig);
|
|
164
|
+
}
|
|
165
|
+
catch (std::exception &ex)
|
|
166
|
+
{
|
|
167
|
+
Napi::Error::New(env, std::string("libdatachannel error while creating WebSocketServer: ") + ex.what())
|
|
168
|
+
.ThrowAsJavaScriptException();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
PLOG_DEBUG << "WebSocketServer created";
|
|
173
|
+
instances.insert(this);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
WebSocketServerWrapper::~WebSocketServerWrapper()
|
|
177
|
+
{
|
|
178
|
+
PLOG_DEBUG << "Destructor called";
|
|
179
|
+
doStop();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
void WebSocketServerWrapper::doStop()
|
|
183
|
+
{
|
|
184
|
+
PLOG_DEBUG << "doStop() called";
|
|
185
|
+
if (mWebSocketServerPtr)
|
|
186
|
+
{
|
|
187
|
+
PLOG_DEBUG << "Stopping...";
|
|
188
|
+
try
|
|
189
|
+
{
|
|
190
|
+
mWebSocketServerPtr->stop();
|
|
191
|
+
mWebSocketServerPtr.reset();
|
|
192
|
+
}
|
|
193
|
+
catch (std::exception &ex)
|
|
194
|
+
{
|
|
195
|
+
std::cerr << std::string("libdatachannel error while closing WebSocketServer: ") + ex.what() << std::endl;
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
mOnClientCallback.reset();
|
|
201
|
+
instances.erase(this);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
void WebSocketServerWrapper::stop(const Napi::CallbackInfo &info)
|
|
205
|
+
{
|
|
206
|
+
PLOG_DEBUG << "stop() called";
|
|
207
|
+
doStop();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
Napi::Value WebSocketServerWrapper::port(const Napi::CallbackInfo &info)
|
|
211
|
+
{
|
|
212
|
+
PLOG_DEBUG << "port() called";
|
|
213
|
+
Napi::Env env = info.Env();
|
|
214
|
+
|
|
215
|
+
if (!mWebSocketServerPtr)
|
|
216
|
+
{
|
|
217
|
+
return Napi::Number::New(info.Env(), 0);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
try
|
|
221
|
+
{
|
|
222
|
+
return Napi::Number::New(info.Env(), mWebSocketServerPtr->port());
|
|
223
|
+
}
|
|
224
|
+
catch (std::exception &ex)
|
|
225
|
+
{
|
|
226
|
+
Napi::Error::New(env, std::string("WebSocketServer error: ") + ex.what()).ThrowAsJavaScriptException();
|
|
227
|
+
return Napi::Number::New(info.Env(), 0);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
void WebSocketServerWrapper::onClient(const Napi::CallbackInfo &info)
|
|
232
|
+
{
|
|
233
|
+
PLOG_DEBUG << "onClient() called";
|
|
234
|
+
Napi::Env env = info.Env();
|
|
235
|
+
int length = info.Length();
|
|
236
|
+
|
|
237
|
+
if (!mWebSocketServerPtr)
|
|
238
|
+
{
|
|
239
|
+
Napi::Error::New(env, "onClient() called on destroyed WebSocketServer").ThrowAsJavaScriptException();
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (length < 1 || !info[0].IsFunction())
|
|
244
|
+
{
|
|
245
|
+
Napi::TypeError::New(env, "Function expected as onClient callback").ThrowAsJavaScriptException();
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Callback
|
|
250
|
+
mOnClientCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
251
|
+
|
|
252
|
+
mWebSocketServerPtr->onClient(
|
|
253
|
+
[&](std::shared_ptr<rtc::WebSocket> ws)
|
|
254
|
+
{
|
|
255
|
+
PLOG_DEBUG << "onClient ws received from WebSocketServer";
|
|
256
|
+
if (mOnClientCallback)
|
|
257
|
+
mOnClientCallback->call(
|
|
258
|
+
[this, ws](Napi::Env env, std::vector<napi_value> &args)
|
|
259
|
+
{
|
|
260
|
+
PLOG_DEBUG << "mOnClientCallback call(1)";
|
|
261
|
+
// Check the WebSocketServer is not stopped
|
|
262
|
+
if (instances.find(this) == instances.end())
|
|
263
|
+
throw ThreadSafeCallback::CancelException();
|
|
264
|
+
|
|
265
|
+
// This will run in main thread and needs to construct the
|
|
266
|
+
// arguments for the call
|
|
267
|
+
std::shared_ptr<rtc::WebSocket> webSocket = ws;
|
|
268
|
+
// First argument is just a placeholder
|
|
269
|
+
auto instance = WebSocketWrapper::constructor.New(
|
|
270
|
+
{Napi::Boolean::New(env, false), Napi::External<std::shared_ptr<rtc::WebSocket>>::New(env, &webSocket)});
|
|
271
|
+
args = {instance};
|
|
272
|
+
PLOG_DEBUG << "mOnClientCallback call(2)";
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
}
|