@stagetimerio/grandiose 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,96 @@
1
+ /* Copyright 2018 Streampunk Media Ltd.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
14
+ */
15
+
16
+ #include <cstdio>
17
+ #include <chrono>
18
+ #include <Processing.NDI.Lib.h>
19
+
20
+ #ifdef _WIN32
21
+ #ifdef _WIN64
22
+ #pragma comment(lib, "Processing.NDI.Lib.x64.lib")
23
+ #else // _WIN64
24
+ #pragma comment(lib, "Processing.NDI.Lib.x86.lib")
25
+ #endif // _WIN64
26
+ #endif // _WIN32
27
+
28
+ #include "grandiose_util.h"
29
+ #include "grandiose_find.h"
30
+ #include "grandiose_send.h"
31
+ #include "grandiose_receive.h"
32
+ #include "grandiose_routing.h"
33
+ #include "node_api.h"
34
+
35
+ napi_value version(napi_env env, napi_callback_info info) {
36
+ napi_status status;
37
+
38
+ const char* ndiVersion = NDIlib_version();
39
+ napi_value result;
40
+ status = napi_create_string_utf8(env, ndiVersion, NAPI_AUTO_LENGTH, &result);
41
+ CHECK_STATUS;
42
+
43
+ return result;
44
+ }
45
+
46
+ napi_value isSupportedCPU(napi_env env, napi_callback_info info) {
47
+ napi_status status;
48
+
49
+ napi_value result;
50
+ status = napi_get_boolean(env, NDIlib_is_supported_CPU(), &result);
51
+ CHECK_STATUS;
52
+
53
+ return result;
54
+ }
55
+
56
+ napi_value initialize(napi_env env, napi_callback_info info) {
57
+ napi_status status;
58
+
59
+ bool ok = NDIlib_initialize();
60
+ napi_value result;
61
+ status = napi_get_boolean(env, ok, &result);
62
+ CHECK_STATUS;
63
+
64
+ return result;
65
+ }
66
+
67
+ napi_value destroy(napi_env env, napi_callback_info info) {
68
+ napi_status status;
69
+
70
+ NDIlib_destroy();
71
+ napi_value result;
72
+ status = napi_get_boolean(env, true, &result);
73
+ CHECK_STATUS;
74
+
75
+ return result;
76
+ }
77
+
78
+ napi_value Init(napi_env env, napi_value exports) {
79
+ napi_status status;
80
+ napi_property_descriptor desc[] = {
81
+ DECLARE_NAPI_METHOD("version", version),
82
+ DECLARE_NAPI_METHOD("isSupportedCPU", isSupportedCPU),
83
+ DECLARE_NAPI_METHOD("initialize", initialize),
84
+ DECLARE_NAPI_METHOD("destroy", destroy),
85
+ DECLARE_NAPI_METHOD("find", find),
86
+ DECLARE_NAPI_METHOD("send", send),
87
+ DECLARE_NAPI_METHOD("receive", receive),
88
+ DECLARE_NAPI_METHOD("routing", routing)
89
+ };
90
+ status = napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
91
+ CHECK_STATUS;
92
+
93
+ return exports;
94
+ }
95
+
96
+ NAPI_MODULE(nodencl, Init)
@@ -0,0 +1,344 @@
1
+ /*
2
+ ** Copyright (c) 2022 Dr. Ralf S. Engelschall <rse@engelschall.com>
3
+ **
4
+ ** Licensed under the Apache License, Version 2.0 (the "License");
5
+ ** you may not use this file except in compliance with the License.
6
+ ** You may obtain a copy of the License at
7
+ **
8
+ ** http://www.apache.org/licenses/LICENSE-2.0
9
+ **
10
+ ** Unless required by applicable law or agreed to in writing, software
11
+ ** distributed under the License is distributed on an "AS IS" BASIS,
12
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ ** See the License for the specific language governing permissions and
14
+ ** limitations under the License.
15
+ */
16
+
17
+ /* standard includes */
18
+ #include <string>
19
+
20
+ /* NDI API */
21
+ #include <Processing.NDI.Lib.h>
22
+ #ifdef _WIN32
23
+ #ifdef _WIN64
24
+ #pragma comment(lib, "Processing.NDI.Lib.x64.lib")
25
+ #else // _WIN64
26
+ #pragma comment(lib, "Processing.NDI.Lib.x86.lib")
27
+ #endif // _WIN64
28
+ #endif // _WIN32
29
+
30
+ /* own library API */
31
+ #include "grandiose_util.h"
32
+ #include "grandiose_find.h"
33
+ #include "grandiose_find.h"
34
+
35
+ /* own module API */
36
+ napi_value find_destroy (napi_env, napi_callback_info);
37
+ napi_value find_sources (napi_env, napi_callback_info);
38
+ napi_value find_wait (napi_env, napi_callback_info);
39
+
40
+ /* wrapper structure for embedded value */
41
+ typedef struct embeddedValue {
42
+ void *value;
43
+ } embeddedValue_t;
44
+
45
+ /* callback for destroying embedded value */
46
+ void finalizeFind(napi_env env, void *data, void *hint) {
47
+ embeddedValue_t *embeddedValue = (embeddedValue_t *)data;
48
+ if (embeddedValue != nullptr) {
49
+ NDIlib_find_instance_t find = (NDIlib_find_instance_t)(embeddedValue->value);
50
+ if (find != nullptr)
51
+ NDIlib_find_destroy(find);
52
+ embeddedValue->value = nullptr;
53
+ }
54
+ free(data);
55
+ }
56
+
57
+ /* callback for executing method find() */
58
+ void findExecute(napi_env env, void* data) {
59
+ findCarrier *c = (findCarrier *)data;
60
+ NDIlib_find_create_t findConfig;
61
+ findConfig.show_local_sources = c->show_local_sources;
62
+ findConfig.p_groups = c->groups;
63
+ findConfig.p_extra_ips = c->extra_ips;
64
+ c->find = NDIlib_find_create_v2(&findConfig);
65
+ if (!c->find) {
66
+ c->status = GRANDIOSE_FIND_CREATE_FAIL;
67
+ c->errorMsg = "Failed to create NDI find instance.";
68
+ return;
69
+ }
70
+ }
71
+
72
+ /* callback for completing method find() */
73
+ void findComplete(napi_env env, napi_status asyncStatus, void* data) {
74
+ findCarrier *c = (findCarrier *)data;
75
+
76
+ /* check status */
77
+ if (asyncStatus != napi_ok) {
78
+ c->status = asyncStatus;
79
+ c->errorMsg = "Async find instance creation failed to complete.";
80
+ }
81
+ REJECT_STATUS;
82
+
83
+ /* create result object */
84
+ napi_value result;
85
+ c->status = napi_create_object(env, &result);
86
+ REJECT_STATUS;
87
+
88
+ /* embed the native find object */
89
+ napi_value embedded;
90
+ embeddedValue_t *embeddedValue = (embeddedValue_t *)malloc(sizeof(embeddedValue_t));
91
+ embeddedValue->value = c->find;
92
+ c->status = napi_create_external(env, embeddedValue, finalizeFind, nullptr, &embedded);
93
+ REJECT_STATUS;
94
+ c->status = napi_set_named_property(env, result, "embedded", embedded);
95
+ REJECT_STATUS;
96
+
97
+ /* attach the "destroy()" method */
98
+ napi_value fn;
99
+ c->status = napi_create_function(env, "destroy", NAPI_AUTO_LENGTH, find_destroy, nullptr, &fn);
100
+ REJECT_STATUS;
101
+ c->status = napi_set_named_property(env, result, "destroy", fn);
102
+ REJECT_STATUS;
103
+
104
+ /* attach the "sources()" method */
105
+ c->status = napi_create_function(env, "sources", NAPI_AUTO_LENGTH, find_sources, nullptr, &fn);
106
+ REJECT_STATUS;
107
+ c->status = napi_set_named_property(env, result, "sources", fn);
108
+ REJECT_STATUS;
109
+
110
+ /* attach the "wait()" method */
111
+ c->status = napi_create_function(env, "wait", NAPI_AUTO_LENGTH, find_wait, nullptr, &fn);
112
+ REJECT_STATUS;
113
+ c->status = napi_set_named_property(env, result, "wait", fn);
114
+ REJECT_STATUS;
115
+
116
+ /* resolve the promise */
117
+ napi_status status;
118
+ status = napi_resolve_deferred(env, c->_deferred, result);
119
+ FLOATING_STATUS;
120
+
121
+ /* cleanup */
122
+ tidyCarrier(env, c);
123
+ }
124
+
125
+ /* the API method "find()" */
126
+ napi_value find(napi_env env, napi_callback_info info) {
127
+ findCarrier *c = new findCarrier;
128
+ napi_valuetype type;
129
+
130
+ /* create result promise */
131
+ napi_value promise;
132
+ c->status = napi_create_promise(env, &c->_deferred, &promise);
133
+ REJECT_RETURN;
134
+
135
+ /* fetch argument */
136
+ size_t argc = 1;
137
+ napi_value args[1];
138
+ c->status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
139
+ REJECT_RETURN;
140
+ if (argc != (size_t) 1)
141
+ REJECT_ERROR_RETURN("Find must be created with an object.", GRANDIOSE_INVALID_ARGS);
142
+ c->status = napi_typeof(env, args[0], &type);
143
+ REJECT_RETURN;
144
+ bool isArray;
145
+ c->status = napi_is_array(env, args[0], &isArray);
146
+ REJECT_RETURN;
147
+ if ((type != napi_object) || isArray)
148
+ REJECT_ERROR_RETURN("Single argument must be an object, not an array.", GRANDIOSE_INVALID_ARGS);
149
+ napi_value config = args[0];
150
+
151
+ /* fetch "showLocalSources" property */
152
+ napi_value showLocalSources;
153
+ c->status = napi_get_named_property(env, config, "showLocalSources", &showLocalSources);
154
+ REJECT_RETURN;
155
+ c->status = napi_typeof(env, showLocalSources, &type);
156
+ if (type != napi_undefined) {
157
+ if (type != napi_boolean)
158
+ REJECT_ERROR_RETURN("Optional showLocalSources property must be a boolean when present.", GRANDIOSE_INVALID_ARGS);
159
+ c->status = napi_get_value_bool(env, showLocalSources, &c->show_local_sources);
160
+ REJECT_RETURN;
161
+ }
162
+
163
+ /* fetch "groups" property */
164
+ napi_value groups;
165
+ c->status = napi_get_named_property(env, config, "groups", &groups);
166
+ REJECT_RETURN;
167
+ c->status = napi_typeof(env, groups, &type);
168
+ if (type != napi_undefined) {
169
+ if (type != napi_string)
170
+ REJECT_ERROR_RETURN("Optional groups property must be a string when present.", GRANDIOSE_INVALID_ARGS);
171
+ size_t groupsl;
172
+ c->status = napi_get_value_string_utf8(env, groups, nullptr, 0, &groupsl);
173
+ REJECT_RETURN;
174
+ c->groups = (char *)malloc(groupsl + 1);
175
+ c->status = napi_get_value_string_utf8(env, groups, c->groups, groupsl + 1, &groupsl);
176
+ REJECT_RETURN;
177
+ }
178
+
179
+ /* fetch "extraIPs" property */
180
+ napi_value extraIPs;
181
+ c->status = napi_get_named_property(env, config, "extraIPs", &extraIPs);
182
+ REJECT_RETURN;
183
+ c->status = napi_typeof(env, extraIPs, &type);
184
+ if (type != napi_undefined) {
185
+ if (type != napi_string)
186
+ REJECT_ERROR_RETURN("Optional extraIPs property must be a string when present.", GRANDIOSE_INVALID_ARGS);
187
+ size_t extraIPsl;
188
+ c->status = napi_get_value_string_utf8(env, extraIPs, nullptr, 0, &extraIPsl);
189
+ REJECT_RETURN;
190
+ c->extra_ips = (char *)malloc(extraIPsl + 1);
191
+ c->status = napi_get_value_string_utf8(env, extraIPs, c->extra_ips, extraIPsl + 1, &extraIPsl);
192
+ REJECT_RETURN;
193
+ }
194
+
195
+ /* create an internal async resource */
196
+ napi_value resource_name;
197
+ c->status = napi_create_string_utf8(env, "Find", NAPI_AUTO_LENGTH, &resource_name);
198
+ REJECT_RETURN;
199
+ c->status = napi_create_async_work(env, NULL, resource_name, findExecute, findComplete, c, &c->_request);
200
+ REJECT_RETURN;
201
+ c->status = napi_queue_async_work(env, c->_request);
202
+ REJECT_RETURN;
203
+
204
+ return promise;
205
+ }
206
+
207
+ /* API method "find.destroy()" */
208
+ napi_value find_destroy(napi_env env, napi_callback_info info) {
209
+ /* create a new Promise carrier object */
210
+ carrier *c = new carrier;
211
+ napi_value promise;
212
+ c->status = napi_create_promise(env, &c->_deferred, &promise);
213
+ REJECT_RETURN;
214
+
215
+ /* fetch the NDI find wrapper object ("this" of the "destroy" method) */
216
+ size_t argc = 1;
217
+ napi_value args[1];
218
+ napi_value thisValue;
219
+ c->status = napi_get_cb_info(env, info, &argc, args, &thisValue, nullptr);
220
+ REJECT_RETURN;
221
+
222
+ /* fetch NDI find external object */
223
+ napi_value embeddedValue;
224
+ c->status = napi_get_named_property(env, thisValue, "embedded", &embeddedValue);
225
+ REJECT_RETURN;
226
+
227
+ /* ensure it was still not manually destroyed */
228
+ napi_valuetype result;
229
+ if (napi_typeof(env, embeddedValue, &result) != napi_ok)
230
+ NAPI_THROW_ERROR("NDI find already destroyed");
231
+ if (result == napi_external) {
232
+ /* fetch NDI find native object */
233
+ embeddedValue_t *embeddedData;
234
+ c->status = napi_get_value_external(env, embeddedValue, (void **)&embeddedData);
235
+ REJECT_RETURN;
236
+ NDIlib_find_instance_t find = (NDIlib_find_instance_t)(embeddedData->value);
237
+
238
+ /* call the NDI API */
239
+ NDIlib_find_destroy(find);
240
+
241
+ /* indicate to finalizeFind that the NDI find native object is already destroyed */
242
+ embeddedData->value = nullptr;
243
+ REJECT_RETURN;
244
+ }
245
+
246
+ /* resolve promise */
247
+ napi_value undefined;
248
+ napi_get_undefined(env, &undefined);
249
+ napi_resolve_deferred(env, c->_deferred, undefined);
250
+
251
+ return promise;
252
+ }
253
+
254
+ /* API method "find.sources()" */
255
+ napi_value find_sources(napi_env env, napi_callback_info info) {
256
+ napi_status status;
257
+
258
+ /* fetch arguments */
259
+ size_t argc = 1;
260
+ napi_value args[1];
261
+ napi_value thisValue;
262
+ status = napi_get_cb_info(env, info, &argc, args, &thisValue, nullptr);
263
+ CHECK_STATUS;
264
+
265
+ /* fetch embedded NDI native find object */
266
+ napi_value embeddedValue;
267
+ status = napi_get_named_property(env, thisValue, "embedded", &embeddedValue);
268
+ CHECK_STATUS;
269
+ embeddedValue_t *embeddedData;
270
+ status = napi_get_value_external(env, embeddedValue, (void **)&embeddedData);
271
+ CHECK_STATUS;
272
+ NDIlib_find_instance_t find = (NDIlib_find_instance_t)(embeddedData->value);
273
+
274
+ /* call NDI API functionality */
275
+ uint32_t no_sources;
276
+ const NDIlib_source_t *sources = NDIlib_find_get_current_sources(find, &no_sources);
277
+
278
+ /* return result */
279
+ napi_value result;
280
+ status = napi_create_array(env, &result);
281
+ CHECK_STATUS;
282
+ napi_value item;
283
+ for (uint32_t i = 0; i < no_sources; i++) {
284
+ napi_value name, uri;
285
+ status = napi_create_string_utf8(env, sources[i].p_ndi_name, NAPI_AUTO_LENGTH, &name);
286
+ CHECK_STATUS;
287
+ status = napi_create_string_utf8(env, sources[i].p_url_address, NAPI_AUTO_LENGTH, &uri);
288
+ CHECK_STATUS;
289
+ status = napi_create_object(env, &item);
290
+ CHECK_STATUS;
291
+ status = napi_set_named_property(env, item, "name", name);
292
+ CHECK_STATUS;
293
+ status = napi_set_named_property(env, item, "urlAddress", uri);
294
+ CHECK_STATUS;
295
+ status = napi_set_element(env, result, i, item);
296
+ CHECK_STATUS;
297
+ }
298
+
299
+ return result;
300
+ }
301
+
302
+ /* API method "find.wait()" */
303
+ napi_value find_wait(napi_env env, napi_callback_info info) {
304
+ napi_status status;
305
+
306
+ /* fetch arguments */
307
+ size_t argc = 2;
308
+ napi_value args[2];
309
+ napi_value thisValue;
310
+ status = napi_get_cb_info(env, info, &argc, args, &thisValue, nullptr);
311
+ CHECK_STATUS;
312
+
313
+ /* fetch embedded NDI native find object */
314
+ napi_value embeddedValue;
315
+ status = napi_get_named_property(env, thisValue, "embedded", &embeddedValue);
316
+ CHECK_STATUS;
317
+ embeddedValue_t *embeddedData;
318
+ status = napi_get_value_external(env, embeddedValue, (void **)&embeddedData);
319
+ CHECK_STATUS;
320
+ NDIlib_find_instance_t find = (NDIlib_find_instance_t)(embeddedData->value);
321
+
322
+ /* handle optional "wait" argument */
323
+ uint32_t wait = 10000;
324
+ if (argc == 2) {
325
+ napi_valuetype type;
326
+ status = napi_typeof(env, args[1], &type);
327
+ CHECK_STATUS;
328
+ if (type == napi_number) {
329
+ status = napi_get_value_uint32(env, args[1], &wait);
330
+ CHECK_STATUS;
331
+ }
332
+ }
333
+
334
+ /* call NDI API functionality */
335
+ bool ok = NDIlib_find_wait_for_sources(find, wait);
336
+
337
+ /* return a boolean result */
338
+ napi_value result;
339
+ status = napi_get_boolean(env, ok, &result);
340
+ CHECK_STATUS;
341
+
342
+ return result;
343
+ }
344
+
@@ -0,0 +1,42 @@
1
+ /*
2
+ ** Copyright (c) 2022 Dr. Ralf S. Engelschall <rse@engelschall.com>
3
+ **
4
+ ** Licensed under the Apache License, Version 2.0 (the "License");
5
+ ** you may not use this file except in compliance with the License.
6
+ ** You may obtain a copy of the License at
7
+ **
8
+ ** http://www.apache.org/licenses/LICENSE-2.0
9
+ **
10
+ ** Unless required by applicable law or agreed to in writing, software
11
+ ** distributed under the License is distributed on an "AS IS" BASIS,
12
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ ** See the License for the specific language governing permissions and
14
+ ** limitations under the License.
15
+ */
16
+
17
+ #ifndef GRANDIOSE_FIND_H
18
+ #define GRANDIOSE_FIND_H
19
+
20
+ #include "node_api.h"
21
+ #include "grandiose_util.h"
22
+
23
+ napi_value find(napi_env, napi_callback_info);
24
+
25
+ struct findCarrier: carrier {
26
+ bool show_local_sources = true;
27
+ char *groups = nullptr;
28
+ char *extra_ips = nullptr;
29
+ NDIlib_find_instance_t find;
30
+ uint32_t wait = 10000;
31
+ uint32_t no_sources = 0;
32
+ const NDIlib_source_t *sources;
33
+ ~findCarrier() {
34
+ if (groups != nullptr)
35
+ free(groups);
36
+ if (extra_ips != nullptr)
37
+ free(extra_ips);
38
+ }
39
+ };
40
+
41
+ #endif /* GRANDIOSE_FIND_H */
42
+