@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,60 @@
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
+ #ifndef GRANDIOSE_RECEIVE_H
17
+ #define GRANDIOSE_RECEIVE_H
18
+
19
+ #include "node_api.h"
20
+ #include "grandiose_util.h"
21
+
22
+ napi_value receive(napi_env env, napi_callback_info info);
23
+ napi_value videoReceive(napi_env env, napi_callback_info info);
24
+ napi_value audioReceive(napi_env env, napi_callback_info info);
25
+ napi_value metadataReceive(napi_env env, napi_callback_info info);
26
+ napi_value dataReceive(napi_env env, napi_callback_info info);
27
+
28
+ struct receiveCarrier : carrier {
29
+ NDIlib_source_t* source = nullptr;
30
+ NDIlib_recv_color_format_e colorFormat = NDIlib_recv_color_format_fastest;
31
+ NDIlib_recv_bandwidth_e bandwidth = NDIlib_recv_bandwidth_highest;
32
+ bool allowVideoFields = true;
33
+ char* name = nullptr;
34
+ NDIlib_recv_instance_t recv;
35
+ ~receiveCarrier() {
36
+ free(name);
37
+ if (source != nullptr) {
38
+ delete source;
39
+ }
40
+ }
41
+ };
42
+
43
+ struct dataCarrier : carrier {
44
+ uint32_t wait = 10000;
45
+ NDIlib_recv_instance_t recv;
46
+ NDIlib_frame_type_e frameType;
47
+ NDIlib_video_frame_v2_t videoFrame;
48
+ NDIlib_audio_frame_v2_t audioFrame;
49
+ NDIlib_audio_frame_interleaved_16s_t audioFrame16s;
50
+ NDIlib_audio_frame_interleaved_32f_t audioFrame32fIlvd;
51
+ int32_t referenceLevel = 20;
52
+ Grandiose_audio_format_e audioFormat = Grandiose_audio_format_float_32_separate;
53
+ NDIlib_metadata_frame_t metadataFrame;
54
+ ~dataCarrier() {
55
+ delete[] audioFrame16s.p_data;
56
+ delete[] audioFrame32fIlvd.p_data;
57
+ }
58
+ };
59
+
60
+ #endif /* GRANDIOSE_RECEIVE_H */
@@ -0,0 +1,434 @@
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_routing.h"
34
+
35
+ /* own module API */
36
+ napi_value routing_destroy (napi_env, napi_callback_info);
37
+ napi_value routing_change (napi_env, napi_callback_info);
38
+ napi_value routing_clear (napi_env, napi_callback_info);
39
+ napi_value routing_connections(napi_env, napi_callback_info);
40
+ napi_value routing_sourcename (napi_env, napi_callback_info);
41
+
42
+ /* wrapper structure for embedded value */
43
+ typedef struct embeddedValue {
44
+ void *value;
45
+ } embeddedValue_t;
46
+
47
+ /* callback for destroying embedded value */
48
+ void finalizeRouting(napi_env env, void* data, void* hint) {
49
+ embeddedValue_t *embeddedValue = (embeddedValue_t *)data;
50
+ if (embeddedValue != nullptr) {
51
+ NDIlib_routing_instance_t routing = (NDIlib_routing_instance_t)(embeddedValue->value);
52
+ if (routing != nullptr)
53
+ NDIlib_routing_destroy(routing);
54
+ embeddedValue->value = nullptr;
55
+ }
56
+ free(data);
57
+ }
58
+
59
+ /* callback for executing method routing() */
60
+ void routingExecute(napi_env env, void* data) {
61
+ routingCarrier *c = (routingCarrier *)data;
62
+ NDIlib_routing_create_t routingConfig;
63
+ routingConfig.p_ndi_name = c->name;
64
+ routingConfig.p_groups = c->groups;
65
+ c->routing = NDIlib_routing_create(&routingConfig);
66
+ if (!c->routing) {
67
+ c->status = GRANDIOSE_ROUTING_CREATE_FAIL;
68
+ c->errorMsg = "Failed to create NDI routing.";
69
+ return;
70
+ }
71
+ }
72
+
73
+ /* callback for completing method routing() */
74
+ void routingComplete(napi_env env, napi_status asyncStatus, void* data) {
75
+ routingCarrier *c = (routingCarrier *)data;
76
+
77
+ /* check status */
78
+ if (asyncStatus != napi_ok) {
79
+ c->status = asyncStatus;
80
+ c->errorMsg = "Async routing creation failed to complete.";
81
+ }
82
+ REJECT_STATUS;
83
+
84
+ /* create result object */
85
+ napi_value result;
86
+ c->status = napi_create_object(env, &result);
87
+ REJECT_STATUS;
88
+
89
+ /* embed the native routing object */
90
+ napi_value embedded;
91
+ embeddedValue_t *embeddedValue = (embeddedValue_t *)malloc(sizeof(embeddedValue_t));
92
+ embeddedValue->value = c->routing;
93
+ c->status = napi_create_external(env, embeddedValue, finalizeRouting, nullptr, &embedded);
94
+ REJECT_STATUS;
95
+ c->status = napi_set_named_property(env, result, "embedded", embedded);
96
+ REJECT_STATUS;
97
+
98
+ /* create "name" property */
99
+ napi_value name;
100
+ if (c->name != nullptr) {
101
+ c->status = napi_create_string_utf8(env, c->name, NAPI_AUTO_LENGTH, &name);
102
+ REJECT_STATUS;
103
+ c->status = napi_set_named_property(env, result, "name", name);
104
+ REJECT_STATUS;
105
+ }
106
+
107
+ /* create "groups" property */
108
+ napi_value groups;
109
+ if (c->groups != nullptr) {
110
+ c->status = napi_create_string_utf8(env, c->groups, NAPI_AUTO_LENGTH, &groups);
111
+ REJECT_STATUS;
112
+ c->status = napi_set_named_property(env, result, "groups", groups);
113
+ REJECT_STATUS;
114
+ }
115
+
116
+ /* attach the "destroy()" method */
117
+ napi_value fn;
118
+ c->status = napi_create_function(env, "destroy", NAPI_AUTO_LENGTH, routing_destroy, nullptr, &fn);
119
+ REJECT_STATUS;
120
+ c->status = napi_set_named_property(env, result, "destroy", fn);
121
+ REJECT_STATUS;
122
+
123
+ /* attach the "change()" method */
124
+ c->status = napi_create_function(env, "change", NAPI_AUTO_LENGTH, routing_change, nullptr, &fn);
125
+ REJECT_STATUS;
126
+ c->status = napi_set_named_property(env, result, "change", fn);
127
+ REJECT_STATUS;
128
+
129
+ /* attach the "clear()" method */
130
+ c->status = napi_create_function(env, "clear", NAPI_AUTO_LENGTH, routing_clear, nullptr, &fn);
131
+ REJECT_STATUS;
132
+ c->status = napi_set_named_property(env, result, "clear", fn);
133
+ REJECT_STATUS;
134
+
135
+ /* attach the "connections()" method */
136
+ c->status = napi_create_function(env, "connections", NAPI_AUTO_LENGTH, routing_connections, nullptr, &fn);
137
+ REJECT_STATUS;
138
+ c->status = napi_set_named_property(env, result, "connections", fn);
139
+ REJECT_STATUS;
140
+
141
+ /* attach the "sourcename()" method */
142
+ c->status = napi_create_function(env, "sourcename", NAPI_AUTO_LENGTH, routing_sourcename, nullptr, &fn);
143
+ REJECT_STATUS;
144
+ c->status = napi_set_named_property(env, result, "sourcename", fn);
145
+ REJECT_STATUS;
146
+
147
+ /* resolve the promise */
148
+ napi_status status;
149
+ status = napi_resolve_deferred(env, c->_deferred, result);
150
+ FLOATING_STATUS;
151
+
152
+ /* cleanup */
153
+ tidyCarrier(env, c);
154
+ }
155
+
156
+ /* the API method "routing()" */
157
+ napi_value routing(napi_env env, napi_callback_info info) {
158
+ routingCarrier *c = new routingCarrier;
159
+ napi_valuetype type;
160
+
161
+ /* create result promise */
162
+ napi_value promise;
163
+ c->status = napi_create_promise(env, &c->_deferred, &promise);
164
+ REJECT_RETURN;
165
+
166
+ /* fetch argument */
167
+ size_t argc = 1;
168
+ napi_value args[1];
169
+ c->status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
170
+ REJECT_RETURN;
171
+ if (argc != (size_t) 1)
172
+ REJECT_ERROR_RETURN("Routing must be created with an object.", GRANDIOSE_INVALID_ARGS);
173
+ c->status = napi_typeof(env, args[0], &type);
174
+ REJECT_RETURN;
175
+ bool isArray;
176
+ c->status = napi_is_array(env, args[0], &isArray);
177
+ REJECT_RETURN;
178
+ if ((type != napi_object) || isArray)
179
+ REJECT_ERROR_RETURN("Single argument must be an object, not an array.", GRANDIOSE_INVALID_ARGS);
180
+ napi_value config = args[0];
181
+
182
+ /* fetch "name" property */
183
+ napi_value name;
184
+ c->status = napi_get_named_property(env, config, "name", &name);
185
+ REJECT_RETURN;
186
+ c->status = napi_typeof(env, name, &type);
187
+ if (type != napi_undefined) {
188
+ if (type != napi_string)
189
+ REJECT_ERROR_RETURN("Optional name property must be a string when present.", GRANDIOSE_INVALID_ARGS);
190
+ size_t namel;
191
+ c->status = napi_get_value_string_utf8(env, name, nullptr, 0, &namel);
192
+ REJECT_RETURN;
193
+ c->name = (char *)malloc(namel + 1);
194
+ c->status = napi_get_value_string_utf8(env, name, c->name, namel + 1, &namel);
195
+ REJECT_RETURN;
196
+ }
197
+
198
+ /* fetch "groups" property */
199
+ napi_value groups;
200
+ c->status = napi_get_named_property(env, config, "groups", &groups);
201
+ REJECT_RETURN;
202
+ c->status = napi_typeof(env, groups, &type);
203
+ if (type != napi_undefined) {
204
+ if (type != napi_string)
205
+ REJECT_ERROR_RETURN("Optional groups property must be a string when present.", GRANDIOSE_INVALID_ARGS);
206
+ size_t groupsl;
207
+ c->status = napi_get_value_string_utf8(env, groups, nullptr, 0, &groupsl);
208
+ REJECT_RETURN;
209
+ c->groups = (char *)malloc(groupsl + 1);
210
+ c->status = napi_get_value_string_utf8(env, groups, c->groups, groupsl + 1, &groupsl);
211
+ REJECT_RETURN;
212
+ }
213
+
214
+ /* create an internal async resource */
215
+ napi_value resource_name;
216
+ c->status = napi_create_string_utf8(env, "Routing", NAPI_AUTO_LENGTH, &resource_name);
217
+ REJECT_RETURN;
218
+ c->status = napi_create_async_work(env, NULL, resource_name, routingExecute, routingComplete, c, &c->_request);
219
+ REJECT_RETURN;
220
+ c->status = napi_queue_async_work(env, c->_request);
221
+ REJECT_RETURN;
222
+
223
+ return promise;
224
+ }
225
+
226
+ /* API method "routing.destroy()" */
227
+ napi_value routing_destroy(napi_env env, napi_callback_info info) {
228
+ /* create a new Promise carrier object */
229
+ carrier *c = new carrier;
230
+ napi_value promise;
231
+ c->status = napi_create_promise(env, &c->_deferred, &promise);
232
+ REJECT_RETURN;
233
+
234
+ /* fetch the NDI routing wrapper object ("this" of the "destroy" method) */
235
+ size_t argc = 1;
236
+ napi_value args[1];
237
+ napi_value thisValue;
238
+ c->status = napi_get_cb_info(env, info, &argc, args, &thisValue, nullptr);
239
+ REJECT_RETURN;
240
+
241
+ /* fetch NDI routing external object */
242
+ napi_value embeddedValue;
243
+ c->status = napi_get_named_property(env, thisValue, "embedded", &embeddedValue);
244
+ REJECT_RETURN;
245
+
246
+ /* ensure it was still not manually destroyed */
247
+ napi_valuetype result;
248
+ if (napi_typeof(env, embeddedValue, &result) != napi_ok)
249
+ NAPI_THROW_ERROR("NDI routing already destroyed");
250
+ if (result == napi_external) {
251
+ /* fetch NDI routing native object */
252
+ embeddedValue_t *embeddedData;
253
+ c->status = napi_get_value_external(env, embeddedValue, (void **)&embeddedData);
254
+ REJECT_RETURN;
255
+ NDIlib_routing_instance_t routing = (NDIlib_routing_instance_t)(embeddedData->value);
256
+
257
+ /* call the NDI API */
258
+ NDIlib_routing_destroy(routing);
259
+
260
+ /* indicate to finalizeRouting that the NDI routing native object is already destroyed */
261
+ embeddedData->value = nullptr;
262
+ REJECT_RETURN;
263
+ }
264
+
265
+ /* resolve promise */
266
+ napi_value undefined;
267
+ napi_get_undefined(env, &undefined);
268
+ napi_resolve_deferred(env, c->_deferred, undefined);
269
+
270
+ return promise;
271
+ }
272
+
273
+ /* API method "routing.change()" */
274
+ napi_value routing_change(napi_env env, napi_callback_info info) {
275
+ napi_status status;
276
+
277
+ /* fetch arguments */
278
+ size_t argc = 1;
279
+ napi_value args[1];
280
+ napi_value thisValue;
281
+ status = napi_get_cb_info(env, info, &argc, args, &thisValue, nullptr);
282
+ CHECK_STATUS;
283
+
284
+ /* fetch embedded NDI native routing object */
285
+ napi_value embeddedValue;
286
+ status = napi_get_named_property(env, thisValue, "embedded", &embeddedValue);
287
+ CHECK_STATUS;
288
+ embeddedValue_t *embeddedData;
289
+ status = napi_get_value_external(env, embeddedValue, (void **)&embeddedData);
290
+ CHECK_STATUS;
291
+ NDIlib_routing_instance_t routing = (NDIlib_routing_instance_t)(embeddedData->value);
292
+
293
+ /* fetch source argument */
294
+ if (argc != (size_t)1)
295
+ NAPI_THROW_ERROR("Missing source argument");
296
+ napi_value source = args[0];
297
+ napi_valuetype type;
298
+ status = napi_typeof(env, source, &type);
299
+ CHECK_STATUS;
300
+ bool isArray;
301
+ status = napi_is_array(env, source, &isArray);
302
+ CHECK_STATUS;
303
+ if ((type != napi_object) || isArray)
304
+ NAPI_THROW_ERROR("Source property must be an object and not an array.")
305
+
306
+ /* check source's name argument */
307
+ napi_value checkType;
308
+ status = napi_get_named_property(env, source, "name", &checkType);
309
+ CHECK_STATUS;
310
+ status = napi_typeof(env, checkType, &type);
311
+ CHECK_STATUS;
312
+ if (type != napi_string)
313
+ NAPI_THROW_ERROR("Source property must have a 'name' sub-property that is of type string.")
314
+
315
+ /* check source's urlAddress argument */
316
+ status = napi_get_named_property(env, source, "urlAddress", &checkType);
317
+ CHECK_STATUS;
318
+ status = napi_typeof(env, checkType, &type);
319
+ CHECK_STATUS;
320
+ if (type != napi_undefined && type != napi_string)
321
+ NAPI_THROW_ERROR("Source 'urlAddress' sub-property must be of type string.")
322
+
323
+ /* create NDI native source object */
324
+ NDIlib_source_t *ndi_source = new NDIlib_source_t();
325
+ status = makeNativeSource(env, source, ndi_source);
326
+ CHECK_STATUS;
327
+
328
+ /* call NDI API functionality */
329
+ int ok = NDIlib_routing_change(routing, ndi_source);
330
+
331
+ /* cleanup resource */
332
+ delete ndi_source;
333
+
334
+ /* return a boolean result */
335
+ napi_value result;
336
+ status = napi_get_boolean(env, ok, &result);
337
+ CHECK_STATUS;
338
+
339
+ return result;
340
+ }
341
+
342
+ /* API method "routing.clear()" */
343
+ napi_value routing_clear(napi_env env, napi_callback_info info) {
344
+ napi_status status;
345
+
346
+ /* fetch arguments */
347
+ size_t argc = 1;
348
+ napi_value args[1];
349
+ napi_value thisValue;
350
+ status = napi_get_cb_info(env, info, &argc, args, &thisValue, nullptr);
351
+ CHECK_STATUS;
352
+
353
+ /* fetch embedded NDI native routing object */
354
+ napi_value embeddedValue;
355
+ status = napi_get_named_property(env, thisValue, "embedded", &embeddedValue);
356
+ CHECK_STATUS;
357
+ embeddedValue_t *embeddedData;
358
+ status = napi_get_value_external(env, embeddedValue, (void **)&embeddedData);
359
+ CHECK_STATUS;
360
+ NDIlib_routing_instance_t routing = (NDIlib_routing_instance_t)(embeddedData->value);
361
+
362
+ /* call NDI API functionality */
363
+ int ok = NDIlib_routing_clear(routing);
364
+
365
+ /* return a boolean result */
366
+ napi_value result;
367
+ status = napi_get_boolean(env, ok, &result);
368
+ CHECK_STATUS;
369
+
370
+ return result;
371
+ }
372
+
373
+ /* API method "routing.connections()" */
374
+ napi_value routing_connections(napi_env env, napi_callback_info info) {
375
+ napi_status status;
376
+
377
+ /* fetch arguments */
378
+ size_t argc = 1;
379
+ napi_value args[1];
380
+ napi_value thisValue;
381
+ status = napi_get_cb_info(env, info, &argc, args, &thisValue, nullptr);
382
+ CHECK_STATUS;
383
+
384
+ /* fetch embedded NDI native routing object */
385
+ napi_value embeddedValue;
386
+ status = napi_get_named_property(env, thisValue, "embedded", &embeddedValue);
387
+ CHECK_STATUS;
388
+ embeddedValue_t *embeddedData;
389
+ status = napi_get_value_external(env, embeddedValue, (void **)&embeddedData);
390
+ CHECK_STATUS;
391
+ NDIlib_routing_instance_t routing = (NDIlib_routing_instance_t)(embeddedData->value);
392
+
393
+ /* call NDI API functionality */
394
+ int conns = NDIlib_routing_get_no_connections(routing, 0);
395
+
396
+ /* return a numeric result */
397
+ napi_value result;
398
+ status = napi_create_int32(env, (int32_t)conns, &result);
399
+ CHECK_STATUS;
400
+
401
+ return result;
402
+ }
403
+
404
+ /* API method "routing.sourcename()" */
405
+ napi_value routing_sourcename(napi_env env, napi_callback_info info) {
406
+ napi_status status;
407
+
408
+ /* fetch arguments */
409
+ size_t argc = 1;
410
+ napi_value args[1];
411
+ napi_value thisValue;
412
+ status = napi_get_cb_info(env, info, &argc, args, &thisValue, nullptr);
413
+ CHECK_STATUS;
414
+
415
+ /* fetch embedded NDI native routing object */
416
+ napi_value embeddedValue;
417
+ status = napi_get_named_property(env, thisValue, "embedded", &embeddedValue);
418
+ CHECK_STATUS;
419
+ embeddedValue_t *embeddedData;
420
+ status = napi_get_value_external(env, embeddedValue, (void **)&embeddedData);
421
+ CHECK_STATUS;
422
+ NDIlib_routing_instance_t routing = (NDIlib_routing_instance_t)(embeddedData->value);
423
+
424
+ /* call NDI API functionality */
425
+ const NDIlib_source_t *source = NDIlib_routing_get_source_name(routing);
426
+
427
+ /* return a string result */
428
+ napi_value result;
429
+ status = napi_create_string_utf8(env, source->p_ndi_name, NAPI_AUTO_LENGTH, &result);
430
+ CHECK_STATUS;
431
+
432
+ return result;
433
+ }
434
+
@@ -0,0 +1,38 @@
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_ROUTING_H
18
+ #define GRANDIOSE_ROUTING_H
19
+
20
+ #include "node_api.h"
21
+ #include "grandiose_util.h"
22
+
23
+ napi_value routing(napi_env, napi_callback_info);
24
+
25
+ struct routingCarrier: carrier {
26
+ char* name = nullptr;
27
+ char* groups = nullptr;
28
+ NDIlib_routing_instance_t routing;
29
+ ~routingCarrier() {
30
+ if (name != nullptr)
31
+ free(name);
32
+ if (groups != nullptr)
33
+ free(groups);
34
+ }
35
+ };
36
+
37
+ #endif /* GRANDIOSE_ROUTING_H */
38
+