@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.
- package/LICENSE +201 -0
- package/README.md +220 -0
- package/binding.gyp +92 -0
- package/dist/index.d.ts +142 -0
- package/dist/index.js +101 -0
- package/index.d.ts +142 -0
- package/index.js +104 -0
- package/package.json +61 -0
- package/scripts/dist.js +45 -0
- package/scripts/ndi.js +159 -0
- package/src/grandiose.cc +96 -0
- package/src/grandiose_find.cc +344 -0
- package/src/grandiose_find.h +42 -0
- package/src/grandiose_receive.cc +923 -0
- package/src/grandiose_receive.h +60 -0
- package/src/grandiose_routing.cc +434 -0
- package/src/grandiose_routing.h +38 -0
- package/src/grandiose_send.cc +792 -0
- package/src/grandiose_send.h +47 -0
- package/src/grandiose_util.cc +282 -0
- package/src/grandiose_util.h +120 -0
|
@@ -0,0 +1,923 @@
|
|
|
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 <chrono>
|
|
17
|
+
#include <Processing.NDI.Lib.h>
|
|
18
|
+
#include <inttypes.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_receive.h"
|
|
29
|
+
#include "grandiose_util.h"
|
|
30
|
+
#include "grandiose_find.h"
|
|
31
|
+
|
|
32
|
+
void finalizeReceive(napi_env env, void* data, void* hint) {
|
|
33
|
+
NDIlib_recv_destroy((NDIlib_recv_instance_t) data);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
void receiveExecute(napi_env env, void* data) {
|
|
37
|
+
receiveCarrier* c = (receiveCarrier*) data;
|
|
38
|
+
|
|
39
|
+
NDIlib_recv_create_v3_t receiveConfig;
|
|
40
|
+
receiveConfig.color_format = c->colorFormat;
|
|
41
|
+
receiveConfig.bandwidth = c->bandwidth;
|
|
42
|
+
receiveConfig.allow_video_fields = c->allowVideoFields;
|
|
43
|
+
receiveConfig.p_ndi_recv_name = c->name;
|
|
44
|
+
|
|
45
|
+
c->recv = NDIlib_recv_create_v3(&receiveConfig);
|
|
46
|
+
if (!c->recv) {
|
|
47
|
+
c->status = GRANDIOSE_RECEIVE_CREATE_FAIL;
|
|
48
|
+
c->errorMsg = "Failed to create NDI receiver.";
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
NDIlib_recv_connect(c->recv, c->source);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
void receiveComplete(napi_env env, napi_status asyncStatus, void* data) {
|
|
56
|
+
receiveCarrier* c = (receiveCarrier*) data;
|
|
57
|
+
|
|
58
|
+
if (asyncStatus != napi_ok) {
|
|
59
|
+
c->status = asyncStatus;
|
|
60
|
+
c->errorMsg = "Async receiver creation failed to complete.";
|
|
61
|
+
}
|
|
62
|
+
REJECT_STATUS;
|
|
63
|
+
|
|
64
|
+
napi_value result;
|
|
65
|
+
c->status = napi_create_object(env, &result);
|
|
66
|
+
REJECT_STATUS;
|
|
67
|
+
|
|
68
|
+
napi_value embedded;
|
|
69
|
+
c->status = napi_create_external(env, c->recv, finalizeReceive, nullptr, &embedded);
|
|
70
|
+
REJECT_STATUS;
|
|
71
|
+
c->status = napi_set_named_property(env, result, "embedded", embedded);
|
|
72
|
+
REJECT_STATUS;
|
|
73
|
+
|
|
74
|
+
napi_value videoFn;
|
|
75
|
+
c->status = napi_create_function(env, "video", NAPI_AUTO_LENGTH, videoReceive,
|
|
76
|
+
nullptr, &videoFn);
|
|
77
|
+
REJECT_STATUS;
|
|
78
|
+
c->status = napi_set_named_property(env, result, "video", videoFn);
|
|
79
|
+
REJECT_STATUS;
|
|
80
|
+
|
|
81
|
+
napi_value audioFn;
|
|
82
|
+
c->status = napi_create_function(env, "audio", NAPI_AUTO_LENGTH, audioReceive,
|
|
83
|
+
nullptr, &audioFn);
|
|
84
|
+
REJECT_STATUS;
|
|
85
|
+
c->status = napi_set_named_property(env, result, "audio", audioFn);
|
|
86
|
+
REJECT_STATUS;
|
|
87
|
+
|
|
88
|
+
napi_value metadataFn;
|
|
89
|
+
c->status = napi_create_function(env, "metadata", NAPI_AUTO_LENGTH, metadataReceive,
|
|
90
|
+
nullptr, &metadataFn);
|
|
91
|
+
REJECT_STATUS;
|
|
92
|
+
c->status = napi_set_named_property(env, result, "metadata", metadataFn);
|
|
93
|
+
REJECT_STATUS;
|
|
94
|
+
|
|
95
|
+
napi_value dataFn;
|
|
96
|
+
c->status = napi_create_function(env, "data", NAPI_AUTO_LENGTH, dataReceive,
|
|
97
|
+
nullptr, &dataFn);
|
|
98
|
+
REJECT_STATUS;
|
|
99
|
+
c->status = napi_set_named_property(env, result, "data", dataFn);
|
|
100
|
+
REJECT_STATUS;
|
|
101
|
+
|
|
102
|
+
napi_value source, name, uri;
|
|
103
|
+
c->status = napi_create_string_utf8(env, c->source->p_ndi_name, NAPI_AUTO_LENGTH, &name);
|
|
104
|
+
REJECT_STATUS;
|
|
105
|
+
if (c->source->p_url_address != NULL) {
|
|
106
|
+
c->status = napi_create_string_utf8(env, c->source->p_url_address, NAPI_AUTO_LENGTH, &uri);
|
|
107
|
+
REJECT_STATUS;
|
|
108
|
+
}
|
|
109
|
+
c->status = napi_create_object(env, &source);
|
|
110
|
+
REJECT_STATUS;
|
|
111
|
+
c->status = napi_set_named_property(env, source, "name", name);
|
|
112
|
+
REJECT_STATUS;
|
|
113
|
+
c->status = napi_set_named_property(env, source, "urlAddress", uri);
|
|
114
|
+
REJECT_STATUS;
|
|
115
|
+
c->status = napi_set_named_property(env, result, "source", source);
|
|
116
|
+
REJECT_STATUS;
|
|
117
|
+
|
|
118
|
+
napi_value colorFormat;
|
|
119
|
+
c->status = napi_create_int32(env, (int32_t) c->colorFormat, &colorFormat);
|
|
120
|
+
REJECT_STATUS;
|
|
121
|
+
c->status = napi_set_named_property(env, result, "colorFormat", colorFormat);
|
|
122
|
+
REJECT_STATUS;
|
|
123
|
+
|
|
124
|
+
napi_value bandwidth;
|
|
125
|
+
c->status = napi_create_int32(env, (int32_t) c->bandwidth, &bandwidth);
|
|
126
|
+
REJECT_STATUS;
|
|
127
|
+
c->status = napi_set_named_property(env, result, "bandwidth", bandwidth);
|
|
128
|
+
REJECT_STATUS;
|
|
129
|
+
|
|
130
|
+
napi_value allowVideoFields;
|
|
131
|
+
c->status = napi_get_boolean(env, c->allowVideoFields, &allowVideoFields);
|
|
132
|
+
REJECT_STATUS;
|
|
133
|
+
c->status = napi_set_named_property(env, result, "allowVideoFields", allowVideoFields);
|
|
134
|
+
REJECT_STATUS;
|
|
135
|
+
|
|
136
|
+
if (c->name != nullptr) {
|
|
137
|
+
c->status = napi_create_string_utf8(env, c->name, NAPI_AUTO_LENGTH, &name);
|
|
138
|
+
REJECT_STATUS;
|
|
139
|
+
c->status = napi_set_named_property(env, result, "name", name);
|
|
140
|
+
REJECT_STATUS;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
napi_status status;
|
|
144
|
+
status = napi_resolve_deferred(env, c->_deferred, result);
|
|
145
|
+
FLOATING_STATUS;
|
|
146
|
+
|
|
147
|
+
tidyCarrier(env, c);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
napi_value receive(napi_env env, napi_callback_info info) {
|
|
151
|
+
napi_valuetype type;
|
|
152
|
+
receiveCarrier* c = new receiveCarrier;
|
|
153
|
+
|
|
154
|
+
napi_value promise;
|
|
155
|
+
c->status = napi_create_promise(env, &c->_deferred, &promise);
|
|
156
|
+
REJECT_RETURN;
|
|
157
|
+
|
|
158
|
+
size_t argc = 1;
|
|
159
|
+
napi_value args[1];
|
|
160
|
+
c->status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
|
|
161
|
+
REJECT_RETURN;
|
|
162
|
+
|
|
163
|
+
if (argc != (size_t) 1) REJECT_ERROR_RETURN(
|
|
164
|
+
"Receiver must be created with an object containing at least a 'source' property.",
|
|
165
|
+
GRANDIOSE_INVALID_ARGS);
|
|
166
|
+
|
|
167
|
+
c->status = napi_typeof(env, args[0], &type);
|
|
168
|
+
REJECT_RETURN;
|
|
169
|
+
bool isArray;
|
|
170
|
+
c->status = napi_is_array(env, args[0], &isArray);
|
|
171
|
+
REJECT_RETURN;
|
|
172
|
+
if ((type != napi_object) || isArray) REJECT_ERROR_RETURN(
|
|
173
|
+
"Single argument must be an object, not an array, containing at least a 'source' property.",
|
|
174
|
+
GRANDIOSE_INVALID_ARGS);
|
|
175
|
+
|
|
176
|
+
napi_value config = args[0];
|
|
177
|
+
napi_value source, colorFormat, bandwidth, allowVideoFields, name;
|
|
178
|
+
// source is an object, not an array, with name and urlAddress
|
|
179
|
+
// convert to a native source
|
|
180
|
+
c->status = napi_get_named_property(env, config, "source", &source);
|
|
181
|
+
REJECT_RETURN;
|
|
182
|
+
c->status = napi_typeof(env, source, &type);
|
|
183
|
+
REJECT_RETURN;
|
|
184
|
+
c->status = napi_is_array(env, source, &isArray);
|
|
185
|
+
REJECT_RETURN;
|
|
186
|
+
if ((type != napi_object) || isArray) REJECT_ERROR_RETURN(
|
|
187
|
+
"Source property must be an object and not an array.",
|
|
188
|
+
GRANDIOSE_INVALID_ARGS);
|
|
189
|
+
|
|
190
|
+
napi_value checkType;
|
|
191
|
+
c->status = napi_get_named_property(env, source, "name", &checkType);
|
|
192
|
+
REJECT_RETURN;
|
|
193
|
+
c->status = napi_typeof(env, checkType, &type);
|
|
194
|
+
REJECT_RETURN;
|
|
195
|
+
if (type != napi_string) REJECT_ERROR_RETURN(
|
|
196
|
+
"Source property must have a 'name' sub-property that is of type string.",
|
|
197
|
+
GRANDIOSE_INVALID_ARGS);
|
|
198
|
+
|
|
199
|
+
c->status = napi_get_named_property(env, source, "urlAddress", &checkType);
|
|
200
|
+
REJECT_RETURN;
|
|
201
|
+
c->status = napi_typeof(env, checkType, &type);
|
|
202
|
+
REJECT_RETURN;
|
|
203
|
+
if (type != napi_undefined && type != napi_string) REJECT_ERROR_RETURN(
|
|
204
|
+
"Source 'urlAddress' sub-property must be of type string.",
|
|
205
|
+
GRANDIOSE_INVALID_ARGS);
|
|
206
|
+
|
|
207
|
+
c->source = new NDIlib_source_t();
|
|
208
|
+
c->status = makeNativeSource(env, source, c->source);
|
|
209
|
+
REJECT_RETURN;
|
|
210
|
+
|
|
211
|
+
c->status = napi_get_named_property(env, config, "colorFormat", &colorFormat);
|
|
212
|
+
REJECT_RETURN;
|
|
213
|
+
c->status = napi_typeof(env, colorFormat, &type);
|
|
214
|
+
REJECT_RETURN;
|
|
215
|
+
if (type != napi_undefined) {
|
|
216
|
+
if (type != napi_number) REJECT_ERROR_RETURN(
|
|
217
|
+
"Color format property must be a number.",
|
|
218
|
+
GRANDIOSE_INVALID_ARGS);
|
|
219
|
+
int32_t enumValue;
|
|
220
|
+
c->status = napi_get_value_int32(env, colorFormat, &enumValue);
|
|
221
|
+
REJECT_RETURN;
|
|
222
|
+
|
|
223
|
+
c->colorFormat = (NDIlib_recv_color_format_e) enumValue;
|
|
224
|
+
if (!validColorFormat(c->colorFormat)) REJECT_ERROR_RETURN(
|
|
225
|
+
"Invalid colour format value.",
|
|
226
|
+
GRANDIOSE_INVALID_ARGS);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
c->status = napi_get_named_property(env, config, "bandwidth", &bandwidth);
|
|
230
|
+
REJECT_RETURN;
|
|
231
|
+
c->status = napi_typeof(env, bandwidth, &type);
|
|
232
|
+
REJECT_RETURN;
|
|
233
|
+
if (type != napi_undefined) {
|
|
234
|
+
if (type != napi_number) REJECT_ERROR_RETURN(
|
|
235
|
+
"Bandwidth property must be a number.",
|
|
236
|
+
GRANDIOSE_INVALID_ARGS);
|
|
237
|
+
int32_t enumValue;
|
|
238
|
+
c->status = napi_get_value_int32(env, bandwidth, &enumValue);
|
|
239
|
+
REJECT_RETURN;
|
|
240
|
+
|
|
241
|
+
c->bandwidth = (NDIlib_recv_bandwidth_e) enumValue;
|
|
242
|
+
if (!validBandwidth(c->bandwidth)) REJECT_ERROR_RETURN(
|
|
243
|
+
"Invalid bandwidth value.",
|
|
244
|
+
GRANDIOSE_INVALID_ARGS);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
c->status = napi_get_named_property(env, config, "allowVideoFields", &allowVideoFields);
|
|
248
|
+
REJECT_RETURN;
|
|
249
|
+
c->status = napi_typeof(env, allowVideoFields, &type);
|
|
250
|
+
REJECT_RETURN;
|
|
251
|
+
if (type != napi_undefined) {
|
|
252
|
+
if (type != napi_boolean) REJECT_ERROR_RETURN(
|
|
253
|
+
"Allow video fields property must be a Boolean.",
|
|
254
|
+
GRANDIOSE_INVALID_ARGS);
|
|
255
|
+
c->status = napi_get_value_bool(env, allowVideoFields, &c->allowVideoFields);
|
|
256
|
+
REJECT_RETURN;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
c->status = napi_get_named_property(env, config, "name", &name);
|
|
260
|
+
REJECT_RETURN;
|
|
261
|
+
c->status = napi_typeof(env, name, &type);
|
|
262
|
+
if (type != napi_undefined) {
|
|
263
|
+
if (type != napi_string) REJECT_ERROR_RETURN(
|
|
264
|
+
"Optional name property must be a string when present.",
|
|
265
|
+
GRANDIOSE_INVALID_ARGS);
|
|
266
|
+
size_t namel;
|
|
267
|
+
c->status = napi_get_value_string_utf8(env, name, nullptr, 0, &namel);
|
|
268
|
+
REJECT_RETURN;
|
|
269
|
+
c->name = (char *) malloc(namel + 1);
|
|
270
|
+
c->status = napi_get_value_string_utf8(env, name, c->name, namel + 1, &namel);
|
|
271
|
+
REJECT_RETURN;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
napi_value resource_name;
|
|
275
|
+
c->status = napi_create_string_utf8(env, "Receive", NAPI_AUTO_LENGTH, &resource_name);
|
|
276
|
+
REJECT_RETURN;
|
|
277
|
+
c->status = napi_create_async_work(env, NULL, resource_name, receiveExecute,
|
|
278
|
+
receiveComplete, c, &c->_request);
|
|
279
|
+
REJECT_RETURN;
|
|
280
|
+
c->status = napi_queue_async_work(env, c->_request);
|
|
281
|
+
REJECT_RETURN;
|
|
282
|
+
|
|
283
|
+
return promise;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
void videoReceiveExecute(napi_env env, void* data) {
|
|
287
|
+
dataCarrier* c = (dataCarrier*) data;
|
|
288
|
+
|
|
289
|
+
switch (NDIlib_recv_capture_v2(c->recv, &c->videoFrame, nullptr, nullptr, c->wait))
|
|
290
|
+
{
|
|
291
|
+
case NDIlib_frame_type_none:
|
|
292
|
+
c->status = GRANDIOSE_NOT_FOUND;
|
|
293
|
+
c->errorMsg = "No video data received in the requested time interval.";
|
|
294
|
+
break;
|
|
295
|
+
|
|
296
|
+
// Video data
|
|
297
|
+
case NDIlib_frame_type_video:
|
|
298
|
+
break;
|
|
299
|
+
|
|
300
|
+
default:
|
|
301
|
+
c->status = GRANDIOSE_NOT_VIDEO;
|
|
302
|
+
c->errorMsg = "Non-video data received on video capture.";
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
void videoReceiveComplete(napi_env env, napi_status asyncStatus, void* data) {
|
|
308
|
+
dataCarrier* c = (dataCarrier*) data;
|
|
309
|
+
|
|
310
|
+
if (asyncStatus != napi_ok) {
|
|
311
|
+
c->status = asyncStatus;
|
|
312
|
+
c->errorMsg = "Async video frame receive failed to complete.";
|
|
313
|
+
}
|
|
314
|
+
REJECT_STATUS;
|
|
315
|
+
|
|
316
|
+
napi_value result;
|
|
317
|
+
c->status = napi_create_object(env, &result);
|
|
318
|
+
REJECT_STATUS;
|
|
319
|
+
|
|
320
|
+
int32_t ptps, ptpn;
|
|
321
|
+
ptps = (int32_t) (c->videoFrame.timestamp / 10000000);
|
|
322
|
+
ptpn = (c->videoFrame.timestamp % 10000000) * 100;
|
|
323
|
+
|
|
324
|
+
napi_value param;
|
|
325
|
+
c->status = napi_create_string_utf8(env, "video", NAPI_AUTO_LENGTH, ¶m);
|
|
326
|
+
REJECT_STATUS;
|
|
327
|
+
c->status = napi_set_named_property(env, result, "type", param);
|
|
328
|
+
REJECT_STATUS;
|
|
329
|
+
|
|
330
|
+
c->status = napi_create_int32(env, c->videoFrame.xres, ¶m);
|
|
331
|
+
REJECT_STATUS;
|
|
332
|
+
c->status = napi_set_named_property(env, result, "xres", param);
|
|
333
|
+
REJECT_STATUS;
|
|
334
|
+
|
|
335
|
+
c->status = napi_create_int32(env, c->videoFrame.yres, ¶m);
|
|
336
|
+
REJECT_STATUS;
|
|
337
|
+
c->status = napi_set_named_property(env, result, "yres", param);
|
|
338
|
+
REJECT_STATUS;
|
|
339
|
+
|
|
340
|
+
c->status = napi_create_int32(env, c->videoFrame.frame_rate_N, ¶m);
|
|
341
|
+
REJECT_STATUS;
|
|
342
|
+
c->status = napi_set_named_property(env, result, "frameRateN", param);
|
|
343
|
+
REJECT_STATUS;
|
|
344
|
+
|
|
345
|
+
c->status = napi_create_int32(env, c->videoFrame.frame_rate_D, ¶m);
|
|
346
|
+
REJECT_STATUS;
|
|
347
|
+
c->status = napi_set_named_property(env, result, "frameRateD", param);
|
|
348
|
+
REJECT_STATUS;
|
|
349
|
+
|
|
350
|
+
c->status = napi_create_double(env, (double) c->videoFrame.picture_aspect_ratio, ¶m);
|
|
351
|
+
REJECT_STATUS;
|
|
352
|
+
c->status = napi_set_named_property(env, result, "pictureAspectRatio", param);
|
|
353
|
+
REJECT_STATUS;
|
|
354
|
+
|
|
355
|
+
napi_value params, paramn;
|
|
356
|
+
c->status = napi_create_int32(env, ptps, ¶ms);
|
|
357
|
+
REJECT_STATUS;
|
|
358
|
+
c->status = napi_create_int32(env, ptpn, ¶mn);
|
|
359
|
+
REJECT_STATUS;
|
|
360
|
+
c->status = napi_create_array(env, ¶m);
|
|
361
|
+
REJECT_STATUS;
|
|
362
|
+
c->status = napi_set_element(env, param, 0, params);
|
|
363
|
+
REJECT_STATUS;
|
|
364
|
+
c->status = napi_set_element(env, param, 1, paramn);
|
|
365
|
+
REJECT_STATUS;
|
|
366
|
+
c->status = napi_set_named_property(env, result, "timestamp", param);
|
|
367
|
+
REJECT_STATUS;
|
|
368
|
+
|
|
369
|
+
c->status = napi_create_int32(env, c->videoFrame.FourCC, ¶m);
|
|
370
|
+
REJECT_STATUS;
|
|
371
|
+
c->status = napi_set_named_property(env, result, "fourCC", param);
|
|
372
|
+
REJECT_STATUS;
|
|
373
|
+
|
|
374
|
+
c->status = napi_create_int32(env, c->videoFrame.frame_format_type, ¶m);
|
|
375
|
+
REJECT_STATUS;
|
|
376
|
+
c->status = napi_set_named_property(env, result, "frameFormatType", param);
|
|
377
|
+
REJECT_STATUS;
|
|
378
|
+
|
|
379
|
+
c->status = napi_create_int32(env, (int32_t) c->videoFrame.timecode / 10000000, ¶ms);
|
|
380
|
+
REJECT_STATUS;
|
|
381
|
+
c->status = napi_create_int32(env, (c->videoFrame.timecode % 10000000) * 100, ¶mn);
|
|
382
|
+
REJECT_STATUS;
|
|
383
|
+
c->status = napi_create_array(env, ¶m);
|
|
384
|
+
REJECT_STATUS;
|
|
385
|
+
c->status = napi_set_element(env, param, 0, params);
|
|
386
|
+
REJECT_STATUS;
|
|
387
|
+
c->status = napi_set_element(env, param, 1, paramn);
|
|
388
|
+
REJECT_STATUS;
|
|
389
|
+
c->status = napi_set_named_property(env, result, "timecode", param);
|
|
390
|
+
REJECT_STATUS;
|
|
391
|
+
|
|
392
|
+
c->status = napi_create_int32(env, c->videoFrame.line_stride_in_bytes, ¶m);
|
|
393
|
+
REJECT_STATUS;
|
|
394
|
+
c->status = napi_set_named_property(env, result, "lineStrideBytes", param);
|
|
395
|
+
REJECT_STATUS;
|
|
396
|
+
|
|
397
|
+
if (c->videoFrame.p_metadata != nullptr) {
|
|
398
|
+
c->status = napi_create_string_utf8(env, c->videoFrame.p_metadata, NAPI_AUTO_LENGTH, ¶m);
|
|
399
|
+
REJECT_STATUS;
|
|
400
|
+
c->status = napi_set_named_property(env, result, "metadata", param);
|
|
401
|
+
REJECT_STATUS;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
c->status = napi_create_buffer_copy(env,
|
|
405
|
+
c->videoFrame.line_stride_in_bytes * c->videoFrame.yres,
|
|
406
|
+
(void*) c->videoFrame.p_data, nullptr, ¶m);
|
|
407
|
+
REJECT_STATUS;
|
|
408
|
+
c->status = napi_set_named_property(env, result, "data", param);
|
|
409
|
+
REJECT_STATUS;
|
|
410
|
+
|
|
411
|
+
NDIlib_recv_free_video_v2(c->recv, &c->videoFrame);
|
|
412
|
+
|
|
413
|
+
napi_status status;
|
|
414
|
+
status = napi_resolve_deferred(env, c->_deferred, result);
|
|
415
|
+
FLOATING_STATUS;
|
|
416
|
+
|
|
417
|
+
tidyCarrier(env, c);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
napi_value videoReceive(napi_env env, napi_callback_info info) {
|
|
421
|
+
napi_valuetype type;
|
|
422
|
+
dataCarrier* c = new dataCarrier;
|
|
423
|
+
|
|
424
|
+
napi_value promise;
|
|
425
|
+
c->status = napi_create_promise(env, &c->_deferred, &promise);
|
|
426
|
+
REJECT_RETURN;
|
|
427
|
+
|
|
428
|
+
size_t argc = 1;
|
|
429
|
+
napi_value args[1];
|
|
430
|
+
napi_value thisValue;
|
|
431
|
+
c->status = napi_get_cb_info(env, info, &argc, args, &thisValue, nullptr);
|
|
432
|
+
REJECT_RETURN;
|
|
433
|
+
|
|
434
|
+
napi_value recvValue;
|
|
435
|
+
c->status = napi_get_named_property(env, thisValue, "embedded", &recvValue);
|
|
436
|
+
REJECT_RETURN;
|
|
437
|
+
void* recvData;
|
|
438
|
+
c->status = napi_get_value_external(env, recvValue, &recvData);
|
|
439
|
+
c->recv = (NDIlib_recv_instance_t) recvData;
|
|
440
|
+
REJECT_RETURN;
|
|
441
|
+
|
|
442
|
+
if (argc >= 1) {
|
|
443
|
+
c->status = napi_typeof(env, args[0], &type);
|
|
444
|
+
REJECT_RETURN;
|
|
445
|
+
if (type == napi_number) {
|
|
446
|
+
c->status = napi_get_value_uint32(env, args[0], &c->wait);
|
|
447
|
+
REJECT_RETURN;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
napi_value resource_name;
|
|
452
|
+
c->status = napi_create_string_utf8(env, "VideoReceive", NAPI_AUTO_LENGTH, &resource_name);
|
|
453
|
+
REJECT_RETURN;
|
|
454
|
+
c->status = napi_create_async_work(env, NULL, resource_name, videoReceiveExecute,
|
|
455
|
+
videoReceiveComplete, c, &c->_request);
|
|
456
|
+
REJECT_RETURN;
|
|
457
|
+
c->status = napi_queue_async_work(env, c->_request);
|
|
458
|
+
REJECT_RETURN;
|
|
459
|
+
|
|
460
|
+
return promise;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
void audioReceiveExecute(napi_env env, void* data) {
|
|
464
|
+
dataCarrier* c = (dataCarrier*) data;
|
|
465
|
+
|
|
466
|
+
switch (NDIlib_recv_capture_v2(c->recv, nullptr, &c->audioFrame, nullptr, c->wait))
|
|
467
|
+
{
|
|
468
|
+
case NDIlib_frame_type_none:
|
|
469
|
+
c->status = GRANDIOSE_NOT_FOUND;
|
|
470
|
+
c->errorMsg = "No audio data received in the requested time interval.";
|
|
471
|
+
break;
|
|
472
|
+
|
|
473
|
+
// Audio data
|
|
474
|
+
case NDIlib_frame_type_audio:
|
|
475
|
+
switch (c->audioFormat) {
|
|
476
|
+
case Grandiose_audio_format_int_16_interleaved:
|
|
477
|
+
c->audioFrame16s.reference_level = c->referenceLevel;
|
|
478
|
+
c->audioFrame16s.p_data = new short[c->audioFrame.no_samples * c->audioFrame.no_channels];
|
|
479
|
+
NDIlib_util_audio_to_interleaved_16s_v2(&c->audioFrame, &c->audioFrame16s);
|
|
480
|
+
break;
|
|
481
|
+
case Grandiose_audio_format_float_32_interleaved:
|
|
482
|
+
c->audioFrame32fIlvd.p_data = new float[c->audioFrame.no_samples * c->audioFrame.no_channels];
|
|
483
|
+
NDIlib_util_audio_to_interleaved_32f_v2(&c->audioFrame, &c->audioFrame32fIlvd);
|
|
484
|
+
break;
|
|
485
|
+
case Grandiose_audio_format_float_32_separate:
|
|
486
|
+
default:
|
|
487
|
+
break;
|
|
488
|
+
}
|
|
489
|
+
break;
|
|
490
|
+
|
|
491
|
+
default:
|
|
492
|
+
c->status = GRANDIOSE_NOT_AUDIO;
|
|
493
|
+
c->errorMsg = "Non-audio data received on audio capture.";
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
void audioReceiveComplete(napi_env env, napi_status asyncStatus, void* data) {
|
|
499
|
+
dataCarrier* c = (dataCarrier*) data;
|
|
500
|
+
|
|
501
|
+
if (asyncStatus != napi_ok) {
|
|
502
|
+
c->status = asyncStatus;
|
|
503
|
+
c->errorMsg = "Async audio frame receive failed to complete.";
|
|
504
|
+
}
|
|
505
|
+
REJECT_STATUS;
|
|
506
|
+
|
|
507
|
+
napi_value result;
|
|
508
|
+
c->status = napi_create_object(env, &result);
|
|
509
|
+
REJECT_STATUS;
|
|
510
|
+
|
|
511
|
+
int32_t ptps, ptpn;
|
|
512
|
+
ptps = (int32_t) (c->audioFrame.timestamp / 10000000);
|
|
513
|
+
ptpn = (c->audioFrame.timestamp % 10000000) * 100;
|
|
514
|
+
|
|
515
|
+
napi_value param;
|
|
516
|
+
c->status = napi_create_string_utf8(env, "audio", NAPI_AUTO_LENGTH, ¶m);
|
|
517
|
+
REJECT_STATUS;
|
|
518
|
+
c->status = napi_set_named_property(env, result, "type", param);
|
|
519
|
+
REJECT_STATUS;
|
|
520
|
+
|
|
521
|
+
c->status = napi_create_int32(env, c->audioFormat, ¶m);
|
|
522
|
+
REJECT_STATUS;
|
|
523
|
+
c->status = napi_set_named_property(env, result, "audioFormat", param);
|
|
524
|
+
REJECT_STATUS;
|
|
525
|
+
|
|
526
|
+
if (c->audioFormat == Grandiose_audio_format_int_16_interleaved) {
|
|
527
|
+
c->status = napi_create_int32(env, c->referenceLevel, ¶m);
|
|
528
|
+
REJECT_STATUS;
|
|
529
|
+
c->status = napi_set_named_property(env, result, "referenceLevel", param);
|
|
530
|
+
REJECT_STATUS;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
c->status = napi_create_int32(env, c->audioFrame.sample_rate, ¶m);
|
|
534
|
+
REJECT_STATUS;
|
|
535
|
+
c->status = napi_set_named_property(env, result, "sampleRate", param);
|
|
536
|
+
REJECT_STATUS;
|
|
537
|
+
|
|
538
|
+
c->status = napi_create_int32(env, c->audioFrame.no_channels, ¶m);
|
|
539
|
+
REJECT_STATUS;
|
|
540
|
+
c->status = napi_set_named_property(env, result, "channels", param);
|
|
541
|
+
REJECT_STATUS;
|
|
542
|
+
|
|
543
|
+
c->status = napi_create_int32(env, c->audioFrame.no_samples, ¶m);
|
|
544
|
+
REJECT_STATUS;
|
|
545
|
+
c->status = napi_set_named_property(env, result, "samples", param);
|
|
546
|
+
REJECT_STATUS;
|
|
547
|
+
|
|
548
|
+
int32_t factor = (c->audioFormat == Grandiose_audio_format_int_16_interleaved) ? 2 : 1;
|
|
549
|
+
c->status = napi_create_int32(env, c->audioFrame.channel_stride_in_bytes / factor, ¶m);
|
|
550
|
+
REJECT_STATUS;
|
|
551
|
+
c->status = napi_set_named_property(env, result, "channelStrideInBytes", param);
|
|
552
|
+
REJECT_STATUS;
|
|
553
|
+
|
|
554
|
+
napi_value params, paramn;
|
|
555
|
+
c->status = napi_create_int32(env, ptps, ¶ms);
|
|
556
|
+
REJECT_STATUS;
|
|
557
|
+
c->status = napi_create_int32(env, ptpn, ¶mn);
|
|
558
|
+
REJECT_STATUS;
|
|
559
|
+
c->status = napi_create_array(env, ¶m);
|
|
560
|
+
REJECT_STATUS;
|
|
561
|
+
c->status = napi_set_element(env, param, 0, params);
|
|
562
|
+
REJECT_STATUS;
|
|
563
|
+
c->status = napi_set_element(env, param, 1, paramn);
|
|
564
|
+
REJECT_STATUS;
|
|
565
|
+
c->status = napi_set_named_property(env, result, "timestamp", param);
|
|
566
|
+
REJECT_STATUS;
|
|
567
|
+
|
|
568
|
+
c->status = napi_create_int32(env, (int32_t) (c->audioFrame.timecode / 10000000), ¶ms);
|
|
569
|
+
REJECT_STATUS;
|
|
570
|
+
c->status = napi_create_int32(env, (c->audioFrame.timecode % 10000000) * 100, ¶mn);
|
|
571
|
+
REJECT_STATUS;
|
|
572
|
+
c->status = napi_create_array(env, ¶m);
|
|
573
|
+
REJECT_STATUS;
|
|
574
|
+
c->status = napi_set_element(env, param, 0, params);
|
|
575
|
+
REJECT_STATUS;
|
|
576
|
+
c->status = napi_set_element(env, param, 1, paramn);
|
|
577
|
+
REJECT_STATUS;
|
|
578
|
+
c->status = napi_set_named_property(env, result, "timecode", param);
|
|
579
|
+
REJECT_STATUS;
|
|
580
|
+
|
|
581
|
+
if (c->audioFrame.p_metadata != nullptr) {
|
|
582
|
+
c->status = napi_create_string_utf8(env, c->audioFrame.p_metadata, NAPI_AUTO_LENGTH, ¶m);
|
|
583
|
+
REJECT_STATUS;
|
|
584
|
+
c->status = napi_set_named_property(env, result, "metadata", param);
|
|
585
|
+
REJECT_STATUS;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
char * rawFloats;
|
|
589
|
+
switch (c->audioFormat) {
|
|
590
|
+
case Grandiose_audio_format_int_16_interleaved:
|
|
591
|
+
rawFloats = (char*) c->audioFrame16s.p_data;
|
|
592
|
+
break;
|
|
593
|
+
case Grandiose_audio_format_float_32_interleaved:
|
|
594
|
+
rawFloats = (char*) c->audioFrame32fIlvd.p_data;
|
|
595
|
+
break;
|
|
596
|
+
default:
|
|
597
|
+
case Grandiose_audio_format_float_32_separate:
|
|
598
|
+
rawFloats = (char*) c->audioFrame.p_data;
|
|
599
|
+
break;
|
|
600
|
+
}
|
|
601
|
+
c->status = napi_create_buffer_copy(env,
|
|
602
|
+
(c->audioFrame.channel_stride_in_bytes / factor) * c->audioFrame.no_channels,
|
|
603
|
+
rawFloats, nullptr, ¶m);
|
|
604
|
+
REJECT_STATUS;
|
|
605
|
+
|
|
606
|
+
c->status = napi_set_named_property(env, result, "data", param);
|
|
607
|
+
REJECT_STATUS;
|
|
608
|
+
|
|
609
|
+
NDIlib_recv_free_audio_v2(c->recv, &c->audioFrame);
|
|
610
|
+
|
|
611
|
+
napi_status status;
|
|
612
|
+
status = napi_resolve_deferred(env, c->_deferred, result);
|
|
613
|
+
FLOATING_STATUS;
|
|
614
|
+
|
|
615
|
+
tidyCarrier(env, c);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
napi_value dataAndAudioReceive(napi_env env, napi_callback_info info,
|
|
619
|
+
const char* resourceName, napi_async_execute_callback execute,
|
|
620
|
+
napi_async_complete_callback complete) {
|
|
621
|
+
napi_valuetype type;
|
|
622
|
+
dataCarrier* c = new dataCarrier;
|
|
623
|
+
|
|
624
|
+
napi_value promise;
|
|
625
|
+
c->status = napi_create_promise(env, &c->_deferred, &promise);
|
|
626
|
+
REJECT_RETURN;
|
|
627
|
+
|
|
628
|
+
size_t argc = 2;
|
|
629
|
+
napi_value args[2];
|
|
630
|
+
napi_value thisValue;
|
|
631
|
+
c->status = napi_get_cb_info(env, info, &argc, args, &thisValue, nullptr);
|
|
632
|
+
REJECT_RETURN;
|
|
633
|
+
|
|
634
|
+
napi_value recvValue;
|
|
635
|
+
c->status = napi_get_named_property(env, thisValue, "embedded", &recvValue);
|
|
636
|
+
REJECT_RETURN;
|
|
637
|
+
void* recvData;
|
|
638
|
+
c->status = napi_get_value_external(env, recvValue, &recvData);
|
|
639
|
+
c->recv = (NDIlib_recv_instance_t) recvData;
|
|
640
|
+
REJECT_RETURN;
|
|
641
|
+
|
|
642
|
+
if (argc >= 1) {
|
|
643
|
+
napi_value configValue, waitValue;
|
|
644
|
+
configValue = args[0];
|
|
645
|
+
c->status = napi_typeof(env, configValue, &type);
|
|
646
|
+
REJECT_RETURN;
|
|
647
|
+
waitValue = (type == napi_number) ? args[0] : args[1];
|
|
648
|
+
if (type == napi_object) {
|
|
649
|
+
bool isArray;
|
|
650
|
+
c->status = napi_is_array(env, configValue, &isArray);
|
|
651
|
+
REJECT_RETURN;
|
|
652
|
+
if (isArray) REJECT_ERROR_RETURN(
|
|
653
|
+
"First argument to audio receive cannot be an array.",
|
|
654
|
+
GRANDIOSE_INVALID_ARGS);
|
|
655
|
+
|
|
656
|
+
napi_value param;
|
|
657
|
+
c->status = napi_get_named_property(env, configValue, "audioFormat", ¶m);
|
|
658
|
+
REJECT_RETURN;
|
|
659
|
+
c->status = napi_typeof(env, param, &type);
|
|
660
|
+
REJECT_RETURN;
|
|
661
|
+
if (type == napi_number) {
|
|
662
|
+
uint32_t audioFormatN;
|
|
663
|
+
c->status = napi_get_value_uint32(env, param, &audioFormatN);
|
|
664
|
+
REJECT_RETURN;
|
|
665
|
+
if (!validAudioFormat((Grandiose_audio_format_e) audioFormatN)) REJECT_ERROR_RETURN(
|
|
666
|
+
"Invalid audio format specified.", GRANDIOSE_INVALID_ARGS);
|
|
667
|
+
c->audioFormat = (Grandiose_audio_format_e) audioFormatN;
|
|
668
|
+
}
|
|
669
|
+
else if (type != napi_undefined) REJECT_ERROR_RETURN(
|
|
670
|
+
"Audio format value must be a number if present.",
|
|
671
|
+
GRANDIOSE_INVALID_ARGS);
|
|
672
|
+
|
|
673
|
+
c->status = napi_get_named_property(env, configValue, "referenceLevel", ¶m);
|
|
674
|
+
REJECT_RETURN;
|
|
675
|
+
c->status = napi_typeof(env, param, &type);
|
|
676
|
+
REJECT_RETURN;
|
|
677
|
+
if (type == napi_number) {
|
|
678
|
+
c->status = napi_get_value_int32(env, param, &c->referenceLevel);
|
|
679
|
+
REJECT_RETURN;
|
|
680
|
+
}
|
|
681
|
+
else if (type != napi_undefined) REJECT_ERROR_RETURN(
|
|
682
|
+
"Audio reference level must be a number if present.",
|
|
683
|
+
GRANDIOSE_INVALID_ARGS);
|
|
684
|
+
}
|
|
685
|
+
c->status = napi_typeof(env, waitValue, &type);
|
|
686
|
+
REJECT_RETURN;
|
|
687
|
+
if (type == napi_number) {
|
|
688
|
+
c->status = napi_get_value_uint32(env, waitValue, &c->wait);
|
|
689
|
+
REJECT_RETURN;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
napi_value resource_name;
|
|
694
|
+
c->status = napi_create_string_utf8(env, resourceName, NAPI_AUTO_LENGTH, &resource_name);
|
|
695
|
+
REJECT_RETURN;
|
|
696
|
+
c->status = napi_create_async_work(env, NULL, resource_name, execute,
|
|
697
|
+
complete, c, &c->_request);
|
|
698
|
+
REJECT_RETURN;
|
|
699
|
+
c->status = napi_queue_async_work(env, c->_request);
|
|
700
|
+
REJECT_RETURN;
|
|
701
|
+
|
|
702
|
+
return promise;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
napi_value audioReceive(napi_env env, napi_callback_info info) {
|
|
706
|
+
return dataAndAudioReceive(env, info, "AudioReceive",
|
|
707
|
+
audioReceiveExecute, audioReceiveComplete);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
void metadataReceiveExecute(napi_env env, void* data) {
|
|
711
|
+
dataCarrier* c = (dataCarrier*) data;
|
|
712
|
+
|
|
713
|
+
switch (NDIlib_recv_capture_v2(c->recv, nullptr, nullptr, &c->metadataFrame, c->wait))
|
|
714
|
+
{
|
|
715
|
+
case NDIlib_frame_type_none:
|
|
716
|
+
c->status = GRANDIOSE_NOT_FOUND;
|
|
717
|
+
c->errorMsg = "No metadata received in the requested time interval.";
|
|
718
|
+
break;
|
|
719
|
+
|
|
720
|
+
// Metadata
|
|
721
|
+
case NDIlib_frame_type_metadata:
|
|
722
|
+
break;
|
|
723
|
+
|
|
724
|
+
default:
|
|
725
|
+
c->status = GRANDIOSE_NOT_AUDIO;
|
|
726
|
+
c->errorMsg = "Non-metadata payload received on metadata capture.";
|
|
727
|
+
break;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
void metadataReceiveComplete(napi_env env, napi_status asyncStatus, void* data) {
|
|
733
|
+
dataCarrier* c = (dataCarrier*) data;
|
|
734
|
+
|
|
735
|
+
if (asyncStatus != napi_ok) {
|
|
736
|
+
c->status = asyncStatus;
|
|
737
|
+
c->errorMsg = "Async metadata payload receive failed to complete.";
|
|
738
|
+
}
|
|
739
|
+
REJECT_STATUS;
|
|
740
|
+
|
|
741
|
+
napi_value result;
|
|
742
|
+
c->status = napi_create_object(env, &result);
|
|
743
|
+
REJECT_STATUS;
|
|
744
|
+
|
|
745
|
+
napi_value param;
|
|
746
|
+
c->status = napi_create_string_utf8(env, "metadata", NAPI_AUTO_LENGTH, ¶m);
|
|
747
|
+
REJECT_STATUS;
|
|
748
|
+
c->status = napi_set_named_property(env, result, "type", param);
|
|
749
|
+
REJECT_STATUS;
|
|
750
|
+
|
|
751
|
+
c->status = napi_create_int32(env, c->metadataFrame.length, ¶m);
|
|
752
|
+
REJECT_STATUS;
|
|
753
|
+
c->status = napi_set_named_property(env, result, "length", param);
|
|
754
|
+
REJECT_STATUS;
|
|
755
|
+
|
|
756
|
+
napi_value params, paramn;
|
|
757
|
+
c->status = napi_create_int32(env, (int32_t) (c->metadataFrame.timecode / 10000000), ¶ms);
|
|
758
|
+
REJECT_STATUS;
|
|
759
|
+
c->status = napi_create_int32(env, (c->metadataFrame.timecode % 10000000) * 100, ¶mn);
|
|
760
|
+
REJECT_STATUS;
|
|
761
|
+
c->status = napi_create_array(env, ¶m);
|
|
762
|
+
REJECT_STATUS;
|
|
763
|
+
c->status = napi_set_element(env, param, 0, params);
|
|
764
|
+
REJECT_STATUS;
|
|
765
|
+
c->status = napi_set_element(env, param, 1, paramn);
|
|
766
|
+
REJECT_STATUS;
|
|
767
|
+
c->status = napi_set_named_property(env, result, "timecode", param);
|
|
768
|
+
REJECT_STATUS;
|
|
769
|
+
|
|
770
|
+
c->status = napi_create_string_utf8(env, c->metadataFrame.p_data, NAPI_AUTO_LENGTH, ¶m);
|
|
771
|
+
REJECT_STATUS;
|
|
772
|
+
c->status = napi_set_named_property(env, result, "data", param);
|
|
773
|
+
REJECT_STATUS;
|
|
774
|
+
|
|
775
|
+
NDIlib_recv_free_metadata(c->recv, &c->metadataFrame);
|
|
776
|
+
|
|
777
|
+
napi_status status;
|
|
778
|
+
status = napi_resolve_deferred(env, c->_deferred, result);
|
|
779
|
+
FLOATING_STATUS;
|
|
780
|
+
|
|
781
|
+
tidyCarrier(env, c);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
napi_value metadataReceive(napi_env env, napi_callback_info info) {
|
|
785
|
+
napi_valuetype type;
|
|
786
|
+
dataCarrier* c = new dataCarrier;
|
|
787
|
+
|
|
788
|
+
napi_value promise;
|
|
789
|
+
c->status = napi_create_promise(env, &c->_deferred, &promise);
|
|
790
|
+
REJECT_RETURN;
|
|
791
|
+
|
|
792
|
+
size_t argc = 1;
|
|
793
|
+
napi_value args[1];
|
|
794
|
+
napi_value thisValue;
|
|
795
|
+
c->status = napi_get_cb_info(env, info, &argc, args, &thisValue, nullptr);
|
|
796
|
+
REJECT_RETURN;
|
|
797
|
+
|
|
798
|
+
napi_value recvValue;
|
|
799
|
+
c->status = napi_get_named_property(env, thisValue, "embedded", &recvValue);
|
|
800
|
+
REJECT_RETURN;
|
|
801
|
+
void* recvData;
|
|
802
|
+
c->status = napi_get_value_external(env, recvValue, &recvData);
|
|
803
|
+
c->recv = (NDIlib_recv_instance_t) recvData;
|
|
804
|
+
REJECT_RETURN;
|
|
805
|
+
|
|
806
|
+
if (argc >= 1) {
|
|
807
|
+
c->status = napi_typeof(env, args[0], &type);
|
|
808
|
+
REJECT_RETURN;
|
|
809
|
+
if (type == napi_number) {
|
|
810
|
+
c->status = napi_get_value_uint32(env, args[0], &c->wait);
|
|
811
|
+
REJECT_RETURN;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
napi_value resource_name;
|
|
816
|
+
c->status = napi_create_string_utf8(env, "MetadataReceive", NAPI_AUTO_LENGTH, &resource_name);
|
|
817
|
+
REJECT_RETURN;
|
|
818
|
+
c->status = napi_create_async_work(env, NULL, resource_name, metadataReceiveExecute,
|
|
819
|
+
metadataReceiveComplete, c, &c->_request);
|
|
820
|
+
REJECT_RETURN;
|
|
821
|
+
c->status = napi_queue_async_work(env, c->_request);
|
|
822
|
+
REJECT_RETURN;
|
|
823
|
+
|
|
824
|
+
return promise;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
void dataReceiveExecute(napi_env env, void* data) {
|
|
828
|
+
dataCarrier* c = (dataCarrier*) data;
|
|
829
|
+
|
|
830
|
+
c->frameType = NDIlib_recv_capture_v2(c->recv, &c->videoFrame, &c->audioFrame, &c->metadataFrame, c->wait);
|
|
831
|
+
switch (c->frameType) {
|
|
832
|
+
|
|
833
|
+
// Audio data
|
|
834
|
+
case NDIlib_frame_type_audio:
|
|
835
|
+
switch (c->audioFormat) {
|
|
836
|
+
case Grandiose_audio_format_int_16_interleaved:
|
|
837
|
+
c->audioFrame16s.reference_level = c->referenceLevel;
|
|
838
|
+
c->audioFrame16s.p_data = new short[c->audioFrame.no_samples * c->audioFrame.no_channels];
|
|
839
|
+
NDIlib_util_audio_to_interleaved_16s_v2(&c->audioFrame, &c->audioFrame16s);
|
|
840
|
+
break;
|
|
841
|
+
case Grandiose_audio_format_float_32_interleaved:
|
|
842
|
+
c->audioFrame32fIlvd.p_data = new float[c->audioFrame.no_samples * c->audioFrame.no_channels];
|
|
843
|
+
NDIlib_util_audio_to_interleaved_32f_v2(&c->audioFrame, &c->audioFrame32fIlvd);
|
|
844
|
+
break;
|
|
845
|
+
case Grandiose_audio_format_float_32_separate:
|
|
846
|
+
default:
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
849
|
+
break;
|
|
850
|
+
|
|
851
|
+
// Handle all other types on completion
|
|
852
|
+
default:
|
|
853
|
+
break;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
void dataReceiveComplete(napi_env env, napi_status asyncStatus, void* data) {
|
|
859
|
+
dataCarrier* c = (dataCarrier*) data;
|
|
860
|
+
|
|
861
|
+
if (asyncStatus != napi_ok) {
|
|
862
|
+
c->status = asyncStatus;
|
|
863
|
+
c->errorMsg = "Async data payload receive failed to complete.";
|
|
864
|
+
}
|
|
865
|
+
REJECT_STATUS;
|
|
866
|
+
|
|
867
|
+
switch (c->frameType) {
|
|
868
|
+
case NDIlib_frame_type_video:
|
|
869
|
+
videoReceiveComplete(env, asyncStatus, data);
|
|
870
|
+
break;
|
|
871
|
+
case NDIlib_frame_type_audio:
|
|
872
|
+
audioReceiveComplete(env, asyncStatus, data);
|
|
873
|
+
break;
|
|
874
|
+
case NDIlib_frame_type_metadata:
|
|
875
|
+
metadataReceiveComplete(env, asyncStatus, data);
|
|
876
|
+
break;
|
|
877
|
+
case NDIlib_frame_type_error:
|
|
878
|
+
c->errorMsg = "Received error response from NDI data request. Connection lost.";
|
|
879
|
+
c->status = GRANDIOSE_CONNECTION_LOST;
|
|
880
|
+
REJECT_STATUS;
|
|
881
|
+
break;
|
|
882
|
+
case NDIlib_frame_type_status_change: {
|
|
883
|
+
napi_value result, param;
|
|
884
|
+
c->status = napi_create_object(env, &result);
|
|
885
|
+
REJECT_STATUS;
|
|
886
|
+
c->status = napi_create_string_utf8(env, "statusChange", NAPI_AUTO_LENGTH, ¶m);
|
|
887
|
+
REJECT_STATUS;
|
|
888
|
+
c->status = napi_set_named_property(env, result, "type", param);
|
|
889
|
+
REJECT_STATUS;
|
|
890
|
+
|
|
891
|
+
napi_status status;
|
|
892
|
+
status = napi_resolve_deferred(env, c->_deferred, result);
|
|
893
|
+
FLOATING_STATUS;
|
|
894
|
+
|
|
895
|
+
tidyCarrier(env, c);
|
|
896
|
+
break;
|
|
897
|
+
}
|
|
898
|
+
case NDIlib_frame_type_source_change: {
|
|
899
|
+
napi_value result, param;
|
|
900
|
+
c->status = napi_create_object(env, &result);
|
|
901
|
+
REJECT_STATUS;
|
|
902
|
+
c->status = napi_create_string_utf8(env, "sourceChange", NAPI_AUTO_LENGTH, ¶m);
|
|
903
|
+
REJECT_STATUS;
|
|
904
|
+
c->status = napi_set_named_property(env, result, "type", param);
|
|
905
|
+
REJECT_STATUS;
|
|
906
|
+
|
|
907
|
+
napi_status status;
|
|
908
|
+
status = napi_resolve_deferred(env, c->_deferred, result);
|
|
909
|
+
FLOATING_STATUS;
|
|
910
|
+
|
|
911
|
+
tidyCarrier(env, c);
|
|
912
|
+
break;
|
|
913
|
+
}
|
|
914
|
+
case NDIlib_frame_type_none:
|
|
915
|
+
case NDIlib_frame_type_max:
|
|
916
|
+
break;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
napi_value dataReceive(napi_env env, napi_callback_info info) {
|
|
921
|
+
return dataAndAudioReceive(env, info, "DataReceive",
|
|
922
|
+
dataReceiveExecute, dataReceiveComplete);
|
|
923
|
+
}
|