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.
- package/CMakeLists.txt +8 -3
- package/README.md +229 -64
- package/examples/README.md +2 -2
- package/examples/media/README.md +22 -0
- package/examples/media/main.html +45 -0
- package/examples/media/media.js +55 -0
- package/lib/index.d.ts +100 -1
- package/package.json +8 -3
- package/src/data-channel-wrapper.cpp +32 -80
- package/src/data-channel-wrapper.h +0 -3
- package/src/main.cpp +8 -0
- package/src/media-audio-wrapper.cpp +457 -0
- package/src/media-audio-wrapper.h +54 -0
- package/src/media-direction.cpp +43 -0
- package/src/media-direction.h +10 -0
- package/src/media-rtcpreceivingsession-wrapper.cpp +63 -0
- package/src/media-rtcpreceivingsession-wrapper.h +36 -0
- package/src/media-track-wrapper.cpp +333 -0
- package/src/media-track-wrapper.h +58 -0
- package/src/media-video-wrapper.cpp +490 -0
- package/src/media-video-wrapper.h +56 -0
- package/src/peer-connection-wrapper.cpp +222 -29
- package/src/peer-connection-wrapper.h +12 -1
- package/src/rtc-wrapper.cpp +2 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
#include "media-track-wrapper.h"
|
|
2
|
+
#include "media-direction.h"
|
|
3
|
+
#include "media-rtcpreceivingsession-wrapper.h"
|
|
4
|
+
|
|
5
|
+
Napi::FunctionReference TrackWrapper::constructor;
|
|
6
|
+
std::unordered_set<TrackWrapper *> TrackWrapper::instances;
|
|
7
|
+
|
|
8
|
+
void TrackWrapper::CloseAll()
|
|
9
|
+
{
|
|
10
|
+
auto copy(instances);
|
|
11
|
+
for (auto inst : copy)
|
|
12
|
+
inst->doClose();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
Napi::Object TrackWrapper::Init(Napi::Env env, Napi::Object exports)
|
|
16
|
+
{
|
|
17
|
+
Napi::HandleScope scope(env);
|
|
18
|
+
|
|
19
|
+
Napi::Function func = DefineClass(
|
|
20
|
+
env,
|
|
21
|
+
"Track",
|
|
22
|
+
{
|
|
23
|
+
InstanceMethod("direction", &TrackWrapper::direction),
|
|
24
|
+
InstanceMethod("mid", &TrackWrapper::mid),
|
|
25
|
+
InstanceMethod("close", &TrackWrapper::close),
|
|
26
|
+
InstanceMethod("sendMessage", &TrackWrapper::sendMessage),
|
|
27
|
+
InstanceMethod("sendMessageBinary", &TrackWrapper::sendMessageBinary),
|
|
28
|
+
InstanceMethod("isOpen", &TrackWrapper::isOpen),
|
|
29
|
+
InstanceMethod("isClosed", &TrackWrapper::isClosed),
|
|
30
|
+
InstanceMethod("maxMessageSize", &TrackWrapper::maxMessageSize),
|
|
31
|
+
InstanceMethod("requestKeyframe", &TrackWrapper::requestKeyframe),
|
|
32
|
+
InstanceMethod("setMediaHandler", &TrackWrapper::setMediaHandler),
|
|
33
|
+
InstanceMethod("onOpen", &TrackWrapper::onOpen),
|
|
34
|
+
InstanceMethod("onClosed", &TrackWrapper::onClosed),
|
|
35
|
+
InstanceMethod("onError", &TrackWrapper::onError),
|
|
36
|
+
InstanceMethod("onMessage", &TrackWrapper::onMessage),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
constructor = Napi::Persistent(func);
|
|
40
|
+
constructor.SuppressDestruct();
|
|
41
|
+
|
|
42
|
+
exports.Set("Track", func);
|
|
43
|
+
return exports;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
TrackWrapper::TrackWrapper(const Napi::CallbackInfo &info) : Napi::ObjectWrap<TrackWrapper>(info)
|
|
47
|
+
{
|
|
48
|
+
mTrackPtr = *(info[0].As<Napi::External<std::shared_ptr<rtc::Track>>>().Data());
|
|
49
|
+
|
|
50
|
+
instances.insert(this);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
TrackWrapper::~TrackWrapper()
|
|
54
|
+
{
|
|
55
|
+
doClose();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
void TrackWrapper::doClose()
|
|
59
|
+
{
|
|
60
|
+
instances.erase(this);
|
|
61
|
+
|
|
62
|
+
if (mTrackPtr)
|
|
63
|
+
{
|
|
64
|
+
try
|
|
65
|
+
{
|
|
66
|
+
mOnOpenCallback.reset();
|
|
67
|
+
mOnClosedCallback.reset();
|
|
68
|
+
mOnErrorCallback.reset();
|
|
69
|
+
mOnMessageCallback.reset();
|
|
70
|
+
|
|
71
|
+
mTrackPtr->close();
|
|
72
|
+
mTrackPtr.reset();
|
|
73
|
+
}
|
|
74
|
+
catch (std::exception &ex)
|
|
75
|
+
{
|
|
76
|
+
std::cout << std::string("libdatachannel error while closing track# ") + ex.what() << std::endl;
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
void TrackWrapper::close(const Napi::CallbackInfo &info)
|
|
83
|
+
{
|
|
84
|
+
doClose();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
Napi::Value TrackWrapper::direction(const Napi::CallbackInfo &info)
|
|
88
|
+
{
|
|
89
|
+
Napi::Env env = info.Env();
|
|
90
|
+
return Napi::String::New(env, directionToStr(mTrackPtr->direction()));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
Napi::Value TrackWrapper::mid(const Napi::CallbackInfo &info)
|
|
94
|
+
{
|
|
95
|
+
Napi::Env env = info.Env();
|
|
96
|
+
return Napi::String::New(env, mTrackPtr->mid());
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Napi::Value TrackWrapper::sendMessage(const Napi::CallbackInfo &info)
|
|
100
|
+
{
|
|
101
|
+
if (!mTrackPtr)
|
|
102
|
+
{
|
|
103
|
+
Napi::Error::New(info.Env(), "It seems track is destroyed!").ThrowAsJavaScriptException();
|
|
104
|
+
return info.Env().Null();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
Napi::Env env = info.Env();
|
|
108
|
+
int length = info.Length();
|
|
109
|
+
|
|
110
|
+
// Allow call with NULL
|
|
111
|
+
if (length < 1 || (!info[0].IsString() && !info[0].IsNull()))
|
|
112
|
+
{
|
|
113
|
+
Napi::TypeError::New(env, "String or Null expected").ThrowAsJavaScriptException();
|
|
114
|
+
return info.Env().Null();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
try
|
|
118
|
+
{
|
|
119
|
+
return Napi::Boolean::New(info.Env(), mTrackPtr->send(info[0].As<Napi::String>().ToString()));
|
|
120
|
+
}
|
|
121
|
+
catch (std::exception &ex)
|
|
122
|
+
{
|
|
123
|
+
Napi::Error::New(env, std::string("libdatachannel error while sending track msg# ") + ex.what()).ThrowAsJavaScriptException();
|
|
124
|
+
return Napi::Boolean::New(info.Env(), false);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
Napi::Value TrackWrapper::sendMessageBinary(const Napi::CallbackInfo &info)
|
|
129
|
+
{
|
|
130
|
+
if (!mTrackPtr)
|
|
131
|
+
{
|
|
132
|
+
Napi::Error::New(info.Env(), "It seems track is destroyed!").ThrowAsJavaScriptException();
|
|
133
|
+
return info.Env().Null();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
Napi::Env env = info.Env();
|
|
137
|
+
int length = info.Length();
|
|
138
|
+
|
|
139
|
+
if (length < 1 || !info[0].IsBuffer())
|
|
140
|
+
{
|
|
141
|
+
Napi::TypeError::New(env, "Buffer expected").ThrowAsJavaScriptException();
|
|
142
|
+
return info.Env().Null();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
try
|
|
146
|
+
{
|
|
147
|
+
Napi::Uint8Array buffer = info[0].As<Napi::Uint8Array>();
|
|
148
|
+
return Napi::Boolean::New(info.Env(), mTrackPtr->send((std::byte *)buffer.Data(), buffer.ByteLength()));
|
|
149
|
+
}
|
|
150
|
+
catch (std::exception &ex)
|
|
151
|
+
{
|
|
152
|
+
Napi::Error::New(env, std::string("libdatachannel error while sending track msg# ") + ex.what()).ThrowAsJavaScriptException();
|
|
153
|
+
return Napi::Boolean::New(info.Env(), false);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
Napi::Value TrackWrapper::isOpen(const Napi::CallbackInfo &info)
|
|
158
|
+
{
|
|
159
|
+
Napi::Env env = info.Env();
|
|
160
|
+
return Napi::Boolean::New(env, mTrackPtr->isOpen());
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
Napi::Value TrackWrapper::isClosed(const Napi::CallbackInfo &info)
|
|
164
|
+
{
|
|
165
|
+
Napi::Env env = info.Env();
|
|
166
|
+
return Napi::Boolean::New(env, mTrackPtr->isClosed());
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
Napi::Value TrackWrapper::maxMessageSize(const Napi::CallbackInfo &info)
|
|
170
|
+
{
|
|
171
|
+
Napi::Env env = info.Env();
|
|
172
|
+
if (!mTrackPtr)
|
|
173
|
+
{
|
|
174
|
+
return Napi::Number::New(info.Env(), 0);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
try
|
|
178
|
+
{
|
|
179
|
+
return Napi::Number::New(info.Env(), mTrackPtr->maxMessageSize());
|
|
180
|
+
}
|
|
181
|
+
catch (std::exception &ex)
|
|
182
|
+
{
|
|
183
|
+
Napi::Error::New(env, std::string("libdatachannel error# ") + ex.what()).ThrowAsJavaScriptException();
|
|
184
|
+
return Napi::Number::New(info.Env(), 0);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
Napi::Value TrackWrapper::requestKeyframe(const Napi::CallbackInfo &info)
|
|
189
|
+
{
|
|
190
|
+
Napi::Env env = info.Env();
|
|
191
|
+
return Napi::Boolean::New(env, mTrackPtr->requestKeyframe());
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
void TrackWrapper::setMediaHandler(const Napi::CallbackInfo &info)
|
|
195
|
+
{
|
|
196
|
+
if (!mTrackPtr)
|
|
197
|
+
{
|
|
198
|
+
Napi::Error::New(info.Env(), "It seems track is destroyed!").ThrowAsJavaScriptException();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
Napi::Env env = info.Env();
|
|
203
|
+
int length = info.Length();
|
|
204
|
+
|
|
205
|
+
if (length < 1 || !info[0].IsObject())
|
|
206
|
+
{
|
|
207
|
+
Napi::TypeError::New(env, "Mediahandler class instance expected").ThrowAsJavaScriptException();
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
RtcpReceivingSessionWrapper *handler = Napi::ObjectWrap<RtcpReceivingSessionWrapper>::Unwrap(info[0].As<Napi::Object>());
|
|
212
|
+
mTrackPtr->setMediaHandler(handler->getSessionInstance());
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
void TrackWrapper::onOpen(const Napi::CallbackInfo &info)
|
|
216
|
+
{
|
|
217
|
+
Napi::Env env = info.Env();
|
|
218
|
+
int length = info.Length();
|
|
219
|
+
|
|
220
|
+
if (length < 1 || !info[0].IsFunction())
|
|
221
|
+
{
|
|
222
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Callback
|
|
227
|
+
mOnOpenCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
228
|
+
|
|
229
|
+
mTrackPtr->onOpen([&]()
|
|
230
|
+
{
|
|
231
|
+
if (mOnOpenCallback)
|
|
232
|
+
mOnOpenCallback->call([this](Napi::Env env, std::vector<napi_value> &args) {
|
|
233
|
+
// Check the peer connection is not closed
|
|
234
|
+
if(instances.find(this) == instances.end())
|
|
235
|
+
throw ThreadSafeCallback::CancelException();
|
|
236
|
+
|
|
237
|
+
// This will run in main thread and needs to construct the
|
|
238
|
+
// arguments for the call
|
|
239
|
+
args = {};
|
|
240
|
+
}); });
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
void TrackWrapper::onClosed(const Napi::CallbackInfo &info)
|
|
244
|
+
{
|
|
245
|
+
Napi::Env env = info.Env();
|
|
246
|
+
int length = info.Length();
|
|
247
|
+
|
|
248
|
+
if (length < 1 || !info[0].IsFunction())
|
|
249
|
+
{
|
|
250
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Callback
|
|
255
|
+
mOnClosedCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
256
|
+
|
|
257
|
+
mTrackPtr->onClosed([&]()
|
|
258
|
+
{
|
|
259
|
+
if (mOnClosedCallback)
|
|
260
|
+
mOnClosedCallback->call([this](Napi::Env env, std::vector<napi_value> &args) {
|
|
261
|
+
// Check the peer connection is not closed
|
|
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
|
+
args = {};
|
|
268
|
+
}); });
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
void TrackWrapper::onError(const Napi::CallbackInfo &info)
|
|
272
|
+
{
|
|
273
|
+
Napi::Env env = info.Env();
|
|
274
|
+
int length = info.Length();
|
|
275
|
+
|
|
276
|
+
if (length < 1 || !info[0].IsFunction())
|
|
277
|
+
{
|
|
278
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Callback
|
|
283
|
+
mOnErrorCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
284
|
+
|
|
285
|
+
mTrackPtr->onError([&](const std::string &error)
|
|
286
|
+
{
|
|
287
|
+
if (mOnErrorCallback)
|
|
288
|
+
mOnErrorCallback->call([this, error](Napi::Env env, std::vector<napi_value> &args) {
|
|
289
|
+
// Check the peer connection is not closed
|
|
290
|
+
if(instances.find(this) == instances.end())
|
|
291
|
+
throw ThreadSafeCallback::CancelException();
|
|
292
|
+
|
|
293
|
+
// This will run in main thread and needs to construct the
|
|
294
|
+
// arguments for the call
|
|
295
|
+
args = {Napi::String::New(env, error)};
|
|
296
|
+
}); });
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
void TrackWrapper::onMessage(const Napi::CallbackInfo &info)
|
|
300
|
+
{
|
|
301
|
+
Napi::Env env = info.Env();
|
|
302
|
+
int length = info.Length();
|
|
303
|
+
|
|
304
|
+
if (length < 1 || !info[0].IsFunction())
|
|
305
|
+
{
|
|
306
|
+
Napi::TypeError::New(env, "Function expected").ThrowAsJavaScriptException();
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Callback
|
|
311
|
+
mOnMessageCallback = std::make_unique<ThreadSafeCallback>(info[0].As<Napi::Function>());
|
|
312
|
+
|
|
313
|
+
mTrackPtr->onMessage([&](const std::variant<rtc::binary, std::string> &message)
|
|
314
|
+
{
|
|
315
|
+
if (mOnMessageCallback)
|
|
316
|
+
mOnMessageCallback->call([this, message](Napi::Env env, std::vector<napi_value> &args) {
|
|
317
|
+
// Check the peer connection is not closed
|
|
318
|
+
if(instances.find(this) == instances.end())
|
|
319
|
+
throw ThreadSafeCallback::CancelException();
|
|
320
|
+
|
|
321
|
+
// This will run in main thread and needs to construct the
|
|
322
|
+
// arguments for the call
|
|
323
|
+
Napi::Object payload = Napi::Object::New(env);
|
|
324
|
+
if (std::holds_alternative<std::string>(message))
|
|
325
|
+
{
|
|
326
|
+
args = {Napi::String::New(env, std::get<std::string>(message))};
|
|
327
|
+
}
|
|
328
|
+
else
|
|
329
|
+
{
|
|
330
|
+
args = {Napi::Buffer<std::byte>::Copy(env, std::get<rtc::binary>(message).data(), std::get<rtc::binary>(message).size())};
|
|
331
|
+
}
|
|
332
|
+
}); });
|
|
333
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#ifndef MEDIA_TRACK_WRAPPER_H
|
|
2
|
+
#define MEDIA_TRACK_WRAPPER_H
|
|
3
|
+
|
|
4
|
+
#include <iostream>
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <variant>
|
|
7
|
+
#include <memory>
|
|
8
|
+
#include <unordered_set>
|
|
9
|
+
|
|
10
|
+
#include <napi.h>
|
|
11
|
+
#include <rtc/rtc.hpp>
|
|
12
|
+
|
|
13
|
+
#include "thread-safe-callback.h"
|
|
14
|
+
|
|
15
|
+
class TrackWrapper : public Napi::ObjectWrap<TrackWrapper>
|
|
16
|
+
{
|
|
17
|
+
public:
|
|
18
|
+
static Napi::FunctionReference constructor;
|
|
19
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
20
|
+
TrackWrapper(const Napi::CallbackInfo &info);
|
|
21
|
+
~TrackWrapper();
|
|
22
|
+
|
|
23
|
+
// Functions
|
|
24
|
+
Napi::Value direction(const Napi::CallbackInfo &info);
|
|
25
|
+
Napi::Value mid(const Napi::CallbackInfo &info);
|
|
26
|
+
void close(const Napi::CallbackInfo &info);
|
|
27
|
+
Napi::Value sendMessage(const Napi::CallbackInfo &info);
|
|
28
|
+
Napi::Value sendMessageBinary(const Napi::CallbackInfo &info);
|
|
29
|
+
Napi::Value isOpen(const Napi::CallbackInfo &info);
|
|
30
|
+
Napi::Value isClosed(const Napi::CallbackInfo &info);
|
|
31
|
+
Napi::Value maxMessageSize(const Napi::CallbackInfo &info);
|
|
32
|
+
Napi::Value requestKeyframe(const Napi::CallbackInfo &info);
|
|
33
|
+
void setMediaHandler(const Napi::CallbackInfo &info);
|
|
34
|
+
|
|
35
|
+
// Callbacks
|
|
36
|
+
void onOpen(const Napi::CallbackInfo &info);
|
|
37
|
+
void onClosed(const Napi::CallbackInfo &info);
|
|
38
|
+
void onError(const Napi::CallbackInfo &info);
|
|
39
|
+
void onMessage(const Napi::CallbackInfo &info);
|
|
40
|
+
|
|
41
|
+
// Close all existing track
|
|
42
|
+
static void CloseAll();
|
|
43
|
+
|
|
44
|
+
private:
|
|
45
|
+
static std::unordered_set<TrackWrapper *> instances;
|
|
46
|
+
|
|
47
|
+
void doClose();
|
|
48
|
+
|
|
49
|
+
std::shared_ptr<rtc::Track> mTrackPtr = nullptr;
|
|
50
|
+
|
|
51
|
+
// Callback Ptrs
|
|
52
|
+
std::unique_ptr<ThreadSafeCallback> mOnOpenCallback = nullptr;
|
|
53
|
+
std::unique_ptr<ThreadSafeCallback> mOnClosedCallback = nullptr;
|
|
54
|
+
std::unique_ptr<ThreadSafeCallback> mOnErrorCallback = nullptr;
|
|
55
|
+
std::unique_ptr<ThreadSafeCallback> mOnMessageCallback = nullptr;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
#endif // MEDIA_TRACK_WRAPPER_H
|