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.
@@ -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