grandi 1.0.0 → 1.2.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/README.md +150 -77
- package/dist/index.d.mts +418 -33
- package/dist/index.mjs +188 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +34 -32
- package/binding.gyp +0 -200
- package/lib/.clang-format +0 -297
- package/lib/grandi.cc +0 -96
- package/lib/grandi_find.cc +0 -365
- package/lib/grandi_find.h +0 -41
- package/lib/grandi_receive.cc +0 -1155
- package/lib/grandi_receive.h +0 -63
- package/lib/grandi_routing.cc +0 -460
- package/lib/grandi_routing.h +0 -37
- package/lib/grandi_send.cc +0 -960
- package/lib/grandi_send.h +0 -45
- package/lib/grandi_util.cc +0 -323
- package/lib/grandi_util.h +0 -137
- package/prebuilds/darwin-arm64/grandi.node +0 -0
- package/prebuilds/darwin-arm64/libndi.dylib +0 -0
- package/prebuilds/darwin-x64/grandi.node +0 -0
- package/prebuilds/darwin-x64/libndi.dylib +0 -0
- package/prebuilds/linux-arm/grandi.node +0 -0
- package/prebuilds/linux-arm/libndi.so.6 +0 -0
- package/prebuilds/linux-arm64/grandi.node +0 -0
- package/prebuilds/linux-arm64/libndi.so.6 +0 -0
- package/prebuilds/linux-ia32/grandi.node +0 -0
- package/prebuilds/linux-ia32/libndi.so.6 +0 -0
- package/prebuilds/linux-x64/grandi.node +0 -0
- package/prebuilds/linux-x64/libndi.so.6 +0 -0
- package/prebuilds/win32-ia32/Processing.NDI.Lib.x86.dll +0 -0
- package/prebuilds/win32-ia32/grandi.node +0 -0
- package/prebuilds/win32-x64/Processing.NDI.Lib.x64.dll +0 -0
- package/prebuilds/win32-x64/grandi.node +0 -0
- package/scripts/preinstall.mjs +0 -429
- package/src/index.ts +0 -141
- package/src/node-gyp-build.d.ts +0 -5
- package/src/types.ts +0 -228
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
import { fileURLToPath } from "node:url";
|
|
3
4
|
import nodeGypBuild from "node-gyp-build";
|
|
4
5
|
|
|
6
|
+
//#region rolldown:runtime
|
|
7
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
5
10
|
//#region node_modules/tsdown/esm-shims.js
|
|
6
11
|
const getFilename = () => fileURLToPath(import.meta.url);
|
|
7
12
|
const getDirname = () => path.dirname(getFilename());
|
|
@@ -23,7 +28,7 @@ let ColorFormat = /* @__PURE__ */ function(ColorFormat$1) {
|
|
|
23
28
|
ColorFormat$1[ColorFormat$1["UYVY_RGBA"] = 3] = "UYVY_RGBA";
|
|
24
29
|
ColorFormat$1[ColorFormat$1["Fastest"] = 100] = "Fastest";
|
|
25
30
|
ColorFormat$1[ColorFormat$1["Best"] = 101] = "Best";
|
|
26
|
-
ColorFormat$1[ColorFormat$1["BGRX_BGRA_FLIPPED"] =
|
|
31
|
+
ColorFormat$1[ColorFormat$1["BGRX_BGRA_FLIPPED"] = 1e3] = "BGRX_BGRA_FLIPPED";
|
|
27
32
|
return ColorFormat$1;
|
|
28
33
|
}({});
|
|
29
34
|
let AudioFormat = /* @__PURE__ */ function(AudioFormat$1) {
|
|
@@ -57,10 +62,56 @@ let FourCC = /* @__PURE__ */ function(FourCC$1) {
|
|
|
57
62
|
|
|
58
63
|
//#endregion
|
|
59
64
|
//#region src/index.ts
|
|
65
|
+
/**
|
|
66
|
+
* Checks if the current platform and architecture are supported by NDI.
|
|
67
|
+
* @returns {boolean} True if the platform is supported (darwin, linux, or win32 with ia32/x64), false otherwise.
|
|
68
|
+
*/
|
|
60
69
|
function isSupportedPlatform() {
|
|
61
70
|
return process.platform === "darwin" || process.platform === "linux" || process.platform === "win32" && ["ia32", "x64"].includes(process.arch);
|
|
62
71
|
}
|
|
63
|
-
|
|
72
|
+
function tryRequireArchPackage() {
|
|
73
|
+
const archKey = `${process.platform}-${process.arch}`;
|
|
74
|
+
const pkg = {
|
|
75
|
+
"linux-x64": "@grandi/linux-x64",
|
|
76
|
+
"linux-arm64": "@grandi/linux-arm64",
|
|
77
|
+
"linux-arm": "@grandi/linux-armv7l",
|
|
78
|
+
"win32-x64": "@grandi/win32-x64",
|
|
79
|
+
"win32-ia32": "@grandi/win32-ia32",
|
|
80
|
+
"darwin-x64": "@grandi/darwin-universal",
|
|
81
|
+
"darwin-arm64": "@grandi/darwin-universal"
|
|
82
|
+
}[archKey];
|
|
83
|
+
if (!pkg) throw new Error(`Unsupported platform or architecture: ${archKey}`);
|
|
84
|
+
try {
|
|
85
|
+
return __require(pkg);
|
|
86
|
+
} catch {
|
|
87
|
+
throw new Error(`Failed to find prebuilt package for ${archKey}. Please ensure that the package "${pkg}" is installed`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function loadAddon() {
|
|
91
|
+
const loadErrors = [];
|
|
92
|
+
if (!isSupportedPlatform()) {
|
|
93
|
+
console.error(`Unsupported platform or architecture: ${process.platform}-${process.arch}`);
|
|
94
|
+
return noopAddon;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const localBinding = nodeGypBuild(path.join(__dirname, ".."));
|
|
98
|
+
if (localBinding) return localBinding;
|
|
99
|
+
} catch (err) {
|
|
100
|
+
loadErrors.push(err);
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
const archAddon = tryRequireArchPackage();
|
|
104
|
+
if (archAddon) return archAddon;
|
|
105
|
+
} catch (err) {
|
|
106
|
+
loadErrors.push(err);
|
|
107
|
+
}
|
|
108
|
+
if (loadErrors.length > 0) {
|
|
109
|
+
const aggregateError = /* @__PURE__ */ new Error("Failed to load native addon:\n" + loadErrors.map((e, i) => ` [${i + 1}] ${e.message}`).join("\n"));
|
|
110
|
+
console.error(aggregateError);
|
|
111
|
+
}
|
|
112
|
+
return noopAddon;
|
|
113
|
+
}
|
|
114
|
+
const noopAddon = {
|
|
64
115
|
version() {
|
|
65
116
|
return "";
|
|
66
117
|
},
|
|
@@ -79,6 +130,9 @@ const addon = isSupportedPlatform() ? nodeGypBuild(path.join(__dirname, "..")) :
|
|
|
79
130
|
receive(_params) {
|
|
80
131
|
return Promise.reject(/* @__PURE__ */ new Error("Unsupported platform or CPU"));
|
|
81
132
|
},
|
|
133
|
+
framesync(_receiver) {
|
|
134
|
+
return Promise.reject(/* @__PURE__ */ new Error("Unsupported platform or CPU"));
|
|
135
|
+
},
|
|
82
136
|
routing() {
|
|
83
137
|
return Promise.reject(/* @__PURE__ */ new Error("Unsupported platform or CPU"));
|
|
84
138
|
},
|
|
@@ -86,15 +140,145 @@ const addon = isSupportedPlatform() ? nodeGypBuild(path.join(__dirname, "..")) :
|
|
|
86
140
|
return Promise.reject(/* @__PURE__ */ new Error("Unsupported platform or CPU"));
|
|
87
141
|
}
|
|
88
142
|
};
|
|
143
|
+
const addon = loadAddon();
|
|
144
|
+
/**
|
|
145
|
+
* Creates a finder to discover NDI sources on the network.
|
|
146
|
+
* @param {FindOptions} [params={}] - Options for finding sources.
|
|
147
|
+
* @param {boolean} [params.showLocalSources] - Whether to show local sources.
|
|
148
|
+
* @param {string} [params.groups] - Multicast groups to search in.
|
|
149
|
+
* @param {string} [params.extraIPs] - Additional IP addresses to search.
|
|
150
|
+
* @returns {Promise<Finder>} A promise that resolves to a Finder instance for discovering sources.
|
|
151
|
+
* @throws {Error} Promise rejects on unsupported platform/CPU or if the finder cannot be created.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```js
|
|
155
|
+
* import { find, initialize } from "grandi";
|
|
156
|
+
* initialize();
|
|
157
|
+
* const finder = await find({ showLocalSources: true });
|
|
158
|
+
* finder.wait(1000);
|
|
159
|
+
* console.log(finder.sources());
|
|
160
|
+
* finder.destroy();
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
89
163
|
function find(params = {}) {
|
|
90
164
|
return addon.find(params);
|
|
91
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Gets the version of the NDI SDK.
|
|
168
|
+
* @returns {string} The NDI SDK version string.
|
|
169
|
+
*/
|
|
92
170
|
const version = addon.version;
|
|
171
|
+
/**
|
|
172
|
+
* Checks if the current CPU architecture is supported by NDI.
|
|
173
|
+
* @returns {boolean} True if the CPU is supported, false otherwise.
|
|
174
|
+
*/
|
|
93
175
|
const isSupportedCPU = addon.isSupportedCPU;
|
|
176
|
+
/**
|
|
177
|
+
* Initializes the NDI library. Must be called before using any other NDI functions.
|
|
178
|
+
* @returns {boolean} True if initialization was successful, false otherwise.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```js
|
|
182
|
+
* import { initialize } from "grandi";
|
|
183
|
+
* if (!initialize()) throw new Error("NDI init failed");
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
94
186
|
const initialize = addon.initialize;
|
|
187
|
+
/**
|
|
188
|
+
* Destroys the NDI library instance and cleans up resources.
|
|
189
|
+
* Should be called when done using NDI to free resources.
|
|
190
|
+
* @returns {boolean} True if destruction was successful, false otherwise.
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```js
|
|
194
|
+
* import { destroy } from "grandi";
|
|
195
|
+
* destroy();
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
95
198
|
const destroy = addon.destroy;
|
|
199
|
+
/**
|
|
200
|
+
* Creates an NDI sender for transmitting video and audio over the network.
|
|
201
|
+
* @param {SendOptions} params - Options for creating the sender.
|
|
202
|
+
* @param {string} params.name - The name of the NDI source.
|
|
203
|
+
* @param {string} [params.groups] - Multicast groups to send to.
|
|
204
|
+
* @param {boolean} [params.clockVideo] - Whether to clock video frames.
|
|
205
|
+
* @param {boolean} [params.clockAudio] - Whether to clock audio frames.
|
|
206
|
+
* @returns {Promise<Sender>} A promise that resolves to a Sender instance for transmitting data.
|
|
207
|
+
* @throws {Error} Promise rejects on unsupported platform/CPU or if sender creation fails.
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```js
|
|
211
|
+
* import { initialize, send } from "grandi";
|
|
212
|
+
* initialize();
|
|
213
|
+
* const sender = await send({ name: "My Source" });
|
|
214
|
+
* // sender.video(...) / sender.audio(...)
|
|
215
|
+
* sender.destroy();
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
96
218
|
const send = addon.send;
|
|
219
|
+
/**
|
|
220
|
+
* Creates an NDI receiver for receiving video and audio from an NDI source.
|
|
221
|
+
* @param {ReceiveOptions} params - Options for creating the receiver.
|
|
222
|
+
* @param {ReceiveOptions["source"]} params.source - The NDI source to connect to.
|
|
223
|
+
* @param {ReceiveOptions["colorFormat"]} [params.colorFormat] - The color format for received video.
|
|
224
|
+
* @param {ReceiveOptions["bandwidth"]} [params.bandwidth] - The bandwidth limitation for the connection.
|
|
225
|
+
* @param {boolean} [params.allowVideoFields] - Whether to allow video fields.
|
|
226
|
+
* @param {string} [params.name] - The name for the receiver.
|
|
227
|
+
* @returns {Promise<Receiver>} A promise that resolves to a Receiver instance for receiving data.
|
|
228
|
+
* @throws {Error} Promise rejects on unsupported platform/CPU or if receiver creation fails.
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```js
|
|
232
|
+
* import { find, initialize, receive } from "grandi";
|
|
233
|
+
* initialize();
|
|
234
|
+
* const finder = await find({ showLocalSources: true });
|
|
235
|
+
* finder.wait(1000);
|
|
236
|
+
* const source = finder.sources()[0];
|
|
237
|
+
* finder.destroy();
|
|
238
|
+
* const receiver = await receive({ source });
|
|
239
|
+
* const frame = await receiver.video(1000);
|
|
240
|
+
* receiver.destroy();
|
|
241
|
+
* ```
|
|
242
|
+
*/
|
|
97
243
|
const receive = addon.receive;
|
|
244
|
+
/**
|
|
245
|
+
* Creates an NDI frame-synchronizer (time base corrector) backed by an existing receiver.
|
|
246
|
+
* Use this when you want smooth playback clocked to your own render/audio loop.
|
|
247
|
+
*
|
|
248
|
+
* Note: destroy the frame-sync before destroying the receiver.
|
|
249
|
+
* @param {Receiver} receiver - The receiver instance to frame-sync.
|
|
250
|
+
* @returns {Promise<FrameSync>} A promise that resolves to a FrameSync instance.
|
|
251
|
+
* @throws {Error} Promise rejects on unsupported platform/CPU or if framesync creation fails.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* ```js
|
|
255
|
+
* import grandi from "grandi";
|
|
256
|
+
* grandi.initialize();
|
|
257
|
+
* const receiver = await grandi.receive({ source });
|
|
258
|
+
* const fs = await grandi.framesync(receiver);
|
|
259
|
+
* const frame = await fs.video(grandi.FrameType.Progressive);
|
|
260
|
+
* fs.destroy();
|
|
261
|
+
* receiver.destroy();
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
const framesync = addon.framesync;
|
|
265
|
+
/**
|
|
266
|
+
* Creates an NDI router for switching between different NDI sources.
|
|
267
|
+
* @param {Object} params - Options for creating the router.
|
|
268
|
+
* @param {string} [params.name] - The name for the router.
|
|
269
|
+
* @param {string} [params.groups] - Multicast groups for the router.
|
|
270
|
+
* @returns {Promise<Routing>} A promise that resolves to a Routing instance for source switching.
|
|
271
|
+
* @throws {Error} Promise rejects on unsupported platform/CPU or if routing creation fails.
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```js
|
|
275
|
+
* import { initialize, routing } from "grandi";
|
|
276
|
+
* initialize();
|
|
277
|
+
* const router = await routing({ name: "My Router" });
|
|
278
|
+
* // router.change(source)
|
|
279
|
+
* router.destroy();
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
98
282
|
const routing = addon.routing;
|
|
99
283
|
const grandi = {
|
|
100
284
|
version,
|
|
@@ -103,6 +287,7 @@ const grandi = {
|
|
|
103
287
|
destroy,
|
|
104
288
|
send,
|
|
105
289
|
receive,
|
|
290
|
+
framesync,
|
|
106
291
|
routing,
|
|
107
292
|
find,
|
|
108
293
|
ColorFormat,
|
|
@@ -143,5 +328,5 @@ const grandi = {
|
|
|
143
328
|
var src_default = grandi;
|
|
144
329
|
|
|
145
330
|
//#endregion
|
|
146
|
-
export { AudioFormat, Bandwidth, ColorFormat, FourCC, FrameType, src_default as default, destroy, find, initialize, isSupportedCPU, receive, routing, send, version };
|
|
331
|
+
export { AudioFormat, Bandwidth, ColorFormat, FourCC, FrameType, src_default as default, destroy, find, framesync, initialize, isSupportedCPU, receive, routing, send, version };
|
|
147
332
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["addon: T.GrandiAddon"],"sources":["../node_modules/tsdown/esm-shims.js","../src/types.ts","../src/index.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","export enum FrameType {\n\tInterlaced = 0,\n\tProgressive = 1,\n\tField0 = 2,\n\tField1 = 3,\n}\n\nexport enum ColorFormat {\n\tBGRX_BGRA = 0,\n\tUYVY_BGRA = 1,\n\tRGBX_RGBA = 2,\n\tUYVY_RGBA = 3,\n\tFastest = 100,\n\tBest = 101,\n\tBGRX_BGRA_FLIPPED = 200,\n}\n\nexport enum AudioFormat {\n\tFloat32Separate = 0,\n\tFloat32Interleaved = 1,\n\tInt16Interleaved = 2,\n}\n\nexport enum Bandwidth {\n\tMetadataOnly = -10,\n\tAudioOnly = 10,\n\tLowest = 0,\n\tHighest = 100,\n}\n\nexport enum FourCC {\n\tUYVY = 1498831189,\n\tUYVA = 1096178005,\n\tP216 = 909193808,\n\tPA16 = 909197648,\n\tYV12 = 842094169,\n\tI420 = 808596553,\n\tNV12 = 842094158,\n\tBGRA = 1095911234,\n\tBGRX = 1481787202,\n\tRGBA = 1094862674,\n\tRGBX = 1480738642,\n\tFLTp = 1884572742,\n}\n\nexport type PtpTimestamp = [number, number]; // [seconds, nanoseconds]\nexport type Timecode = bigint | number | PtpTimestamp;\n\nexport interface Source {\n\tname: string;\n\turlAddress?: string;\n}\n\nexport interface VideoFrame {\n\ttype?: \"video\";\n\txres: number;\n\tyres: number;\n\tframeRateN: number;\n\tframeRateD: number;\n\tpictureAspectRatio: number;\n\tfourCC: FourCC;\n\tframeFormatType: FrameType;\n\tlineStrideBytes: number;\n\tdata: Buffer;\n\ttimecode?: Timecode;\n\ttimestamp?: PtpTimestamp;\n\tmetadata?: string;\n}\n\nexport interface ReceivedVideoFrame extends VideoFrame {\n\ttype: \"video\";\n\ttimecode: PtpTimestamp;\n\ttimestamp: PtpTimestamp;\n\tmetadata?: string;\n}\n\nexport interface AudioFrame {\n\ttype?: \"audio\";\n\tsampleRate: number;\n\tnoChannels: number;\n\tnoSamples: number;\n\tchannelStrideBytes: number;\n\tdata: Buffer;\n\tfourCC: FourCC;\n\ttimecode?: Timecode;\n\ttimestamp?: PtpTimestamp;\n\tmetadata?: string;\n}\n\nexport interface ReceivedAudioFrame {\n\ttype: \"audio\";\n\taudioFormat: AudioFormat;\n\treferenceLevel?: number;\n\tsampleRate: number;\n\tchannels: number;\n\tsamples: number;\n\tchannelStrideInBytes: number;\n\tdata: Buffer;\n\ttimecode: PtpTimestamp;\n\ttimestamp: PtpTimestamp;\n\tmetadata?: string;\n}\n\nexport interface ReceivedMetadataFrame {\n\ttype: \"metadata\";\n\tlength: number;\n\ttimecode: PtpTimestamp;\n\ttimestamp: PtpTimestamp;\n\tdata: string;\n}\n\nexport interface SourceChangeEvent {\n\ttype: \"sourceChange\";\n}\n\nexport interface StatusChangeEvent {\n\ttype: \"statusChange\";\n}\n\nexport type ReceiverDataFrame =\n\t| ReceivedVideoFrame\n\t| ReceivedAudioFrame\n\t| ReceivedMetadataFrame\n\t| SourceChangeEvent\n\t| StatusChangeEvent;\n\nexport interface AudioReceiveOptions {\n\taudioFormat?: AudioFormat;\n\treferenceLevel?: number;\n}\n\nexport interface Receiver {\n\tembedded: unknown;\n\tsource: Source;\n\tcolorFormat: ColorFormat;\n\tbandwidth: Bandwidth;\n\tallowVideoFields: boolean;\n\tname?: string;\n\tvideo(timeoutMs?: number): Promise<ReceivedVideoFrame>;\n\taudio(timeoutMs?: number): Promise<ReceivedAudioFrame>;\n\taudio(\n\t\toptions: AudioReceiveOptions,\n\t\ttimeoutMs?: number,\n\t): Promise<ReceivedAudioFrame>;\n\tmetadata(timeoutMs?: number): Promise<ReceivedMetadataFrame>;\n\tdata(timeoutMs?: number): Promise<ReceiverDataFrame>;\n\tdata(\n\t\toptions: AudioReceiveOptions,\n\t\ttimeoutMs?: number,\n\t): Promise<ReceiverDataFrame>;\n\ttally(state: ReceiverTallyState): boolean;\n\tdestroy(): boolean;\n}\n\nexport interface ReceiverTallyState {\n\tonProgram?: boolean;\n\tonPreview?: boolean;\n}\n\nexport interface SenderTally {\n\tchanged: boolean;\n\ton_program: boolean;\n\ton_preview: boolean;\n}\n\nexport interface Sender {\n\tembedded: unknown;\n\tname: string;\n\tgroups?: string;\n\tclockVideo: boolean;\n\tclockAudio: boolean;\n\tvideo(frame: VideoFrame): Promise<void>;\n\taudio(frame: AudioFrame): Promise<void>;\n\tconnections(): number;\n\tmetadata(data: string): boolean;\n\ttally(): SenderTally;\n\tsourcename(): string;\n\tdestroy(): boolean;\n}\n\nexport interface Routing {\n\tembedded: unknown;\n\tname?: string;\n\tgroups?: string;\n\tdestroy(): boolean;\n\tchange(source: Source): boolean;\n\tclear(): boolean;\n\tconnections(): number;\n\tsourcename(): string;\n}\n\nexport interface Finder {\n\tsources(): Source[];\n\twait(timeoutMs?: number): boolean;\n\tdestroy(): boolean;\n}\n\nexport interface FindOptions {\n\tshowLocalSources?: boolean;\n\tgroups?: string;\n\textraIPs?: string;\n}\n\nexport interface ReceiveOptions {\n\tsource: Source;\n\tcolorFormat?: ColorFormat;\n\tbandwidth?: Bandwidth;\n\tallowVideoFields?: boolean;\n\tname?: string;\n}\n\nexport interface SendOptions {\n\tname: string;\n\tgroups?: string;\n\tclockVideo?: boolean;\n\tclockAudio?: boolean;\n}\n\nexport interface GrandiAddon {\n\tversion(): string;\n\tisSupportedCPU(): boolean;\n\tinitialize(): boolean;\n\tdestroy(): boolean;\n\tfind(params: FindOptions): Promise<Finder>;\n\treceive(params: ReceiveOptions): Promise<Receiver>;\n\tsend(params: SendOptions): Promise<Sender>;\n\trouting(params: { name?: string; groups?: string }): Promise<Routing>;\n}\n","import path from \"node:path\";\nimport nodeGypBuild from \"node-gyp-build\";\n\nimport type * as T from \"./types\";\nimport {\n\tAudioFormat,\n\tBandwidth,\n\tColorFormat,\n\tFourCC,\n\tFrameType,\n} from \"./types\";\n\nfunction isSupportedPlatform(): boolean {\n\treturn (\n\t\tprocess.platform === \"darwin\" ||\n\t\tprocess.platform === \"linux\" ||\n\t\t(process.platform === \"win32\" && [\"ia32\", \"x64\"].includes(process.arch))\n\t);\n}\n\nconst noopAddon: T.GrandiAddon = {\n\tversion() {\n\t\treturn \"\";\n\t},\n\tisSupportedCPU() {\n\t\treturn false;\n\t},\n\tinitialize() {\n\t\treturn false;\n\t},\n\tdestroy() {\n\t\treturn false;\n\t},\n\tsend(_params) {\n\t\treturn Promise.reject(new Error(\"Unsupported platform or CPU\"));\n\t},\n\treceive(_params) {\n\t\treturn Promise.reject(new Error(\"Unsupported platform or CPU\"));\n\t},\n\trouting() {\n\t\treturn Promise.reject(new Error(\"Unsupported platform or CPU\"));\n\t},\n\tfind(_params) {\n\t\treturn Promise.reject(new Error(\"Unsupported platform or CPU\"));\n\t},\n};\n\nconst addon: T.GrandiAddon = isSupportedPlatform()\n\t? (nodeGypBuild(path.join(__dirname, \"..\")) as T.GrandiAddon)\n\t: noopAddon;\n\nexport function find(params: T.FindOptions = {}): Promise<T.Finder> {\n\treturn addon.find(params);\n}\n// Named runtime exports\nexport const version = addon.version;\nexport const isSupportedCPU = addon.isSupportedCPU;\nexport const initialize = addon.initialize;\nexport const destroy = addon.destroy;\nexport const send = addon.send;\nexport const receive = addon.receive;\nexport const routing = addon.routing;\n\n// Re-export enums and types for convenient named imports\nexport { ColorFormat, AudioFormat, Bandwidth, FrameType, FourCC };\nexport type {\n\tAudioFrame,\n\tAudioReceiveOptions,\n\tFinder,\n\tFindOptions,\n\tGrandiAddon,\n\tPtpTimestamp,\n\tReceivedAudioFrame,\n\tReceivedMetadataFrame,\n\tReceivedVideoFrame,\n\tReceiveOptions,\n\tReceiverDataFrame,\n\tReceiverTallyState,\n\tRouting,\n\tSender,\n\tSenderTally,\n\tSource,\n\tSourceChangeEvent,\n\tStatusChangeEvent,\n\tTimecode,\n\tVideoFrame,\n} from \"./types\";\n\nconst grandi = {\n\tversion,\n\tisSupportedCPU,\n\tinitialize,\n\tdestroy,\n\tsend,\n\treceive,\n\trouting,\n\tfind,\n\tColorFormat,\n\tAudioFormat,\n\tBandwidth,\n\tFrameType,\n\tFourCC,\n\n\t// Constants mapped to enum values\n\tCOLOR_FORMAT_BGRX_BGRA: ColorFormat.BGRX_BGRA,\n\tCOLOR_FORMAT_UYVY_BGRA: ColorFormat.UYVY_BGRA,\n\tCOLOR_FORMAT_RGBX_RGBA: ColorFormat.RGBX_RGBA,\n\tCOLOR_FORMAT_UYVY_RGBA: ColorFormat.UYVY_RGBA,\n\tCOLOR_FORMAT_FASTEST: ColorFormat.Fastest,\n\tCOLOR_FORMAT_BGRX_BGRA_FLIPPED: ColorFormat.BGRX_BGRA_FLIPPED,\n\n\tBANDWIDTH_METADATA_ONLY: Bandwidth.MetadataOnly,\n\tBANDWIDTH_AUDIO_ONLY: Bandwidth.AudioOnly,\n\tBANDWIDTH_LOWEST: Bandwidth.Lowest,\n\tBANDWIDTH_HIGHEST: Bandwidth.Highest,\n\n\tFORMAT_TYPE_PROGRESSIVE: FrameType.Progressive,\n\tFORMAT_TYPE_INTERLACED: FrameType.Interlaced,\n\tFORMAT_TYPE_FIELD_0: FrameType.Field0,\n\tFORMAT_TYPE_FIELD_1: FrameType.Field1,\n\n\tAUDIO_FORMAT_FLOAT_32_SEPARATE: AudioFormat.Float32Separate,\n\tAUDIO_FORMAT_FLOAT_32_INTERLEAVED: AudioFormat.Float32Interleaved,\n\tAUDIO_FORMAT_INT_16_INTERLEAVED: AudioFormat.Int16Interleaved,\n\n\t// FourCC helpers/constants\n\tFOURCC_UYVY: FourCC.UYVY,\n\tFOURCC_UYVA: FourCC.UYVA,\n\tFOURCC_P216: FourCC.P216,\n\tFOURCC_PA16: FourCC.PA16,\n\tFOURCC_YV12: FourCC.YV12,\n\tFOURCC_I420: FourCC.I420,\n\tFOURCC_NV12: FourCC.NV12,\n\tFOURCC_BGRA: FourCC.BGRA,\n\tFOURCC_BGRX: FourCC.BGRX,\n\tFOURCC_RGBA: FourCC.RGBA,\n\tFOURCC_RGBX: FourCC.RGBX,\n\tFOURCC_FLTp: FourCC.FLTp,\n};\n\nexport default grandi;\n"],"x_google_ignoreList":[0],"mappings":";;;;;AAIA,MAAM,oBAAoB,cAAc,OAAO,KAAK,IAAI;AACxD,MAAM,mBAAmB,KAAK,QAAQ,aAAa,CAAC;AAEpD,MAAa,YAA4B,4BAAY;;;;ACPrD,IAAY,kDAAL;AACN;AACA;AACA;AACA;;;AAGD,IAAY,sDAAL;AACN;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGD,IAAY,sDAAL;AACN;AACA;AACA;;;AAGD,IAAY,kDAAL;AACN;AACA;AACA;AACA;;;AAGD,IAAY,4CAAL;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;AC9BD,SAAS,sBAA+B;AACvC,QACC,QAAQ,aAAa,YACrB,QAAQ,aAAa,WACpB,QAAQ,aAAa,WAAW,CAAC,QAAQ,MAAM,CAAC,SAAS,QAAQ,KAAK;;AA+BzE,MAAMA,QAAuB,qBAAqB,GAC9C,aAAa,KAAK,KAAK,WAAW,KAAK,CAAC,GA5BX;CAChC,UAAU;AACT,SAAO;;CAER,iBAAiB;AAChB,SAAO;;CAER,aAAa;AACZ,SAAO;;CAER,UAAU;AACT,SAAO;;CAER,KAAK,SAAS;AACb,SAAO,QAAQ,uBAAO,IAAI,MAAM,8BAA8B,CAAC;;CAEhE,QAAQ,SAAS;AAChB,SAAO,QAAQ,uBAAO,IAAI,MAAM,8BAA8B,CAAC;;CAEhE,UAAU;AACT,SAAO,QAAQ,uBAAO,IAAI,MAAM,8BAA8B,CAAC;;CAEhE,KAAK,SAAS;AACb,SAAO,QAAQ,uBAAO,IAAI,MAAM,8BAA8B,CAAC;;CAEhE;AAMD,SAAgB,KAAK,SAAwB,EAAE,EAAqB;AACnE,QAAO,MAAM,KAAK,OAAO;;AAG1B,MAAa,UAAU,MAAM;AAC7B,MAAa,iBAAiB,MAAM;AACpC,MAAa,aAAa,MAAM;AAChC,MAAa,UAAU,MAAM;AAC7B,MAAa,OAAO,MAAM;AAC1B,MAAa,UAAU,MAAM;AAC7B,MAAa,UAAU,MAAM;AA2B7B,MAAM,SAAS;CACd;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA,wBAAwB,YAAY;CACpC,wBAAwB,YAAY;CACpC,wBAAwB,YAAY;CACpC,wBAAwB,YAAY;CACpC,sBAAsB,YAAY;CAClC,gCAAgC,YAAY;CAE5C,yBAAyB,UAAU;CACnC,sBAAsB,UAAU;CAChC,kBAAkB,UAAU;CAC5B,mBAAmB,UAAU;CAE7B,yBAAyB,UAAU;CACnC,wBAAwB,UAAU;CAClC,qBAAqB,UAAU;CAC/B,qBAAqB,UAAU;CAE/B,gCAAgC,YAAY;CAC5C,mCAAmC,YAAY;CAC/C,iCAAiC,YAAY;CAG7C,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB,aAAa,OAAO;CACpB;AAED,kBAAe"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["loadErrors: Error[]","noopAddon: GrandiAddon","addon: GrandiAddon","grandi: Grandi"],"sources":["../node_modules/tsdown/esm-shims.js","../src/types.ts","../src/index.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","export enum FrameType {\n\tInterlaced = 0,\n\tProgressive = 1,\n\tField0 = 2,\n\tField1 = 3,\n}\n\nexport enum ColorFormat {\n\tBGRX_BGRA = 0,\n\tUYVY_BGRA = 1,\n\tRGBX_RGBA = 2,\n\tUYVY_RGBA = 3,\n\tFastest = 100,\n\tBest = 101,\n\t// Windows-only NDI SDK extension: 1000 + BGRX_BGRA.\n\tBGRX_BGRA_FLIPPED = 1000,\n}\n\nexport enum AudioFormat {\n\tFloat32Separate = 0,\n\tFloat32Interleaved = 1,\n\tInt16Interleaved = 2,\n}\n\nexport enum Bandwidth {\n\tMetadataOnly = -10,\n\tAudioOnly = 10,\n\tLowest = 0,\n\tHighest = 100,\n}\n\nexport enum FourCC {\n\tUYVY = 1498831189,\n\tUYVA = 1096178005,\n\tP216 = 909193808,\n\tPA16 = 909197648,\n\tYV12 = 842094169,\n\tI420 = 808596553,\n\tNV12 = 842094158,\n\tBGRA = 1095911234,\n\tBGRX = 1481787202,\n\tRGBA = 1094862674,\n\tRGBX = 1480738642,\n\tFLTp = 1884572742,\n}\n\nexport type PtpTimestamp = [number, number]; // [seconds, nanoseconds]\nexport type Timecode = bigint | number | PtpTimestamp;\n\nexport interface Source {\n\tname: string;\n\turlAddress?: string;\n}\n\nexport interface VideoFrame {\n\ttype?: \"video\";\n\txres: number;\n\tyres: number;\n\tframeRateN: number;\n\tframeRateD: number;\n\tpictureAspectRatio: number;\n\tfourCC: FourCC;\n\tframeFormatType: FrameType;\n\tlineStrideBytes: number;\n\tdata: Buffer;\n\ttimecode?: Timecode;\n\t/**\n\t * Receive-only timestamp filled by the NDI SDK (UTC time, 100ns units under the hood).\n\t * NDI ignores this field when sending.\n\t */\n\ttimestamp?: PtpTimestamp;\n\tmetadata?: string;\n}\n\nexport interface ReceivedVideoFrame extends VideoFrame {\n\ttype: \"video\";\n\ttimecode: PtpTimestamp;\n\ttimestamp: PtpTimestamp;\n\tmetadata?: string;\n}\n\nexport interface AudioFrame {\n\ttype?: \"audio\";\n\tsampleRate: number;\n\tnoChannels: number;\n\tnoSamples: number;\n\tchannelStrideBytes: number;\n\tdata: Buffer;\n\tfourCC: FourCC;\n\ttimecode?: Timecode;\n\t/**\n\t * Receive-only timestamp filled by the NDI SDK (UTC time, 100ns units under the hood).\n\t * NDI ignores this field when sending.\n\t */\n\ttimestamp?: PtpTimestamp;\n\tmetadata?: string;\n}\n\nexport interface ReceivedAudioFrame {\n\ttype: \"audio\";\n\taudioFormat: AudioFormat;\n\treferenceLevel?: number;\n\tsampleRate: number;\n\tchannels: number;\n\tsamples: number;\n\tchannelStrideInBytes: number;\n\tdata: Buffer;\n\ttimecode: PtpTimestamp;\n\ttimestamp: PtpTimestamp;\n\tmetadata?: string;\n}\n\nexport interface ReceivedMetadataFrame {\n\ttype: \"metadata\";\n\tlength: number;\n\ttimecode: PtpTimestamp;\n\ttimestamp: PtpTimestamp;\n\tdata: string;\n}\n\nexport interface SourceChangeEvent {\n\ttype: \"sourceChange\";\n}\n\nexport interface StatusChangeEvent {\n\ttype: \"statusChange\";\n}\n\nexport interface TimeoutEvent {\n\ttype: \"timeout\";\n}\n\nexport type ReceiverDataFrame =\n\t| ReceivedVideoFrame\n\t| ReceivedAudioFrame\n\t| ReceivedMetadataFrame\n\t| SourceChangeEvent\n\t| StatusChangeEvent\n\t| TimeoutEvent;\n\nexport interface AudioReceiveOptions {\n\taudioFormat?: AudioFormat;\n\treferenceLevel?: number;\n}\n\nexport interface Receiver {\n\tembedded: unknown;\n\tsource: Source;\n\tcolorFormat: ColorFormat;\n\tbandwidth: Bandwidth;\n\tallowVideoFields: boolean;\n\tname?: string;\n\tvideo(timeoutMs?: number): Promise<ReceivedVideoFrame>;\n\taudio(timeoutMs?: number): Promise<ReceivedAudioFrame>;\n\taudio(\n\t\toptions: AudioReceiveOptions,\n\t\ttimeoutMs?: number,\n\t): Promise<ReceivedAudioFrame>;\n\tmetadata(timeoutMs?: number): Promise<ReceivedMetadataFrame>;\n\tdata(timeoutMs?: number): Promise<ReceiverDataFrame>;\n\tdata(\n\t\toptions: AudioReceiveOptions,\n\t\ttimeoutMs?: number,\n\t): Promise<ReceiverDataFrame>;\n\ttally(state: ReceiverTallyState): boolean;\n\tdestroy(): boolean;\n}\n\nexport interface ReceiverTallyState {\n\tonProgram?: boolean;\n\tonPreview?: boolean;\n}\n\nexport interface SenderTally {\n\tchanged: boolean;\n\ton_program: boolean;\n\ton_preview: boolean;\n}\n\nexport interface Sender {\n\tembedded: unknown;\n\tname: string;\n\tgroups?: string;\n\tclockVideo: boolean;\n\tclockAudio: boolean;\n\tvideo(frame: VideoFrame): Promise<void>;\n\taudio(frame: AudioFrame): Promise<void>;\n\tconnections(): number;\n\tmetadata(data: string): boolean;\n\ttally(): SenderTally;\n\tsourcename(): string;\n\tdestroy(): boolean;\n}\n\nexport interface Routing {\n\tembedded: unknown;\n\tname?: string;\n\tgroups?: string;\n\tdestroy(): boolean;\n\tchange(source: Source): boolean;\n\tclear(): boolean;\n\tconnections(): number;\n\tsourcename(): string;\n}\n\nexport interface FrameSyncAudioOptions {\n\tsampleRate?: number;\n\tnoChannels?: number;\n\tnoSamples?: number;\n}\n\nexport interface FrameSync {\n\tembedded: unknown;\n\t/**\n\t * Captures a video frame using NDI frame-synchronization (time base correction).\n\t * Always returns immediately.\n\t *\n\t * If no video has ever been received, resolves with `{ type: \"timeout\" }`.\n\t */\n\tvideo(fieldType?: FrameType): Promise<ReceivedVideoFrame | TimeoutEvent>;\n\t/**\n\t * Captures audio using NDI frame-synchronization (resampled to match your calls).\n\t * Always returns immediately and may insert silence if no audio is present.\n\t */\n\taudio(options?: FrameSyncAudioOptions): Promise<ReceivedAudioFrame>;\n\t/**\n\t * Returns an approximate depth of the internal audio queue in samples.\n\t */\n\taudioQueueDepth(): number;\n\tdestroy(): boolean;\n}\n\nexport interface Finder {\n\tsources(): Source[];\n\twait(timeoutMs?: number): boolean;\n\tdestroy(): boolean;\n}\n\nexport interface FindOptions {\n\tshowLocalSources?: boolean;\n\tgroups?: string;\n\textraIPs?: string;\n}\n\nexport interface ReceiveOptions {\n\tsource: Source;\n\tcolorFormat?: ColorFormat;\n\tbandwidth?: Bandwidth;\n\t/**\n\t * If `colorFormat` is `ColorFormat.Fastest` or `ColorFormat.Best`, the NDI SDK\n\t * implicitly enables video fields and this option is forced to `true`.\n\t */\n\tallowVideoFields?: boolean;\n\tname?: string;\n}\n\nexport interface SendOptions {\n\tname: string;\n\tgroups?: string;\n\tclockVideo?: boolean;\n\tclockAudio?: boolean;\n}\n\nexport interface Grandi {\n\t/**\n\t * Gets the NDI SDK version string (e.g. `\"NDI SDK 6.0.0.0\"`).\n\t * @returns The NDI SDK version string.\n\t *\n\t * @example\n\t * ```js\n\t * import grandi from \"grandi\";\n\t * console.log(grandi.version());\n\t * ```\n\t */\n\tversion(): string;\n\t/**\n\t * Checks if the current CPU architecture is supported by NDI.\n\t * @returns `true` when NDI is supported on this CPU/platform.\n\t *\n\t * @example\n\t * ```js\n\t * import grandi from \"grandi\";\n\t * if (!grandi.isSupportedCPU()) throw new Error(\"NDI unsupported here\");\n\t * ```\n\t */\n\tisSupportedCPU(): boolean;\n\t/**\n\t * Initializes the NDI library. Must be called before using any other NDI functions.\n\t * Call this once per process, before creating senders/receivers/finders.\n\t * @returns `true` if initialization was successful.\n\t *\n\t * @example\n\t * ```js\n\t * import grandi from \"grandi\";\n\t * if (!grandi.initialize()) throw new Error(\"NDI init failed\");\n\t * ```\n\t */\n\tinitialize(): boolean;\n\t/**\n\t * Destroys the NDI library instance and cleans up resources.\n\t * Should be called when done using NDI to free resources.\n\t * @returns `true` if destruction was successful.\n\t *\n\t * @example\n\t * ```js\n\t * import grandi from \"grandi\";\n\t * grandi.destroy();\n\t * ```\n\t */\n\tdestroy(): boolean;\n\t/**\n\t * Creates an NDI sender for transmitting video and audio over the network.\n\t * @param params Sender options.\n\t * @returns A promise that resolves to a Sender instance.\n\t * @throws {Error} Promise rejects on unsupported platform/CPU or if sender creation fails.\n\t *\n\t * @example\n\t * ```js\n\t * import grandi from \"grandi\";\n\t * grandi.initialize();\n\t * const sender = await grandi.send({ name: \"My Source\" });\n\t * ```\n\t */\n\tsend(params: SendOptions): Promise<Sender>;\n\t/**\n\t * Creates an NDI receiver for receiving video and audio from an NDI source.\n\t * @param params Receiver options.\n\t * @returns A promise that resolves to a Receiver instance.\n\t * @throws {Error} Promise rejects on unsupported platform/CPU or if receiver creation fails.\n\t *\n\t * @example\n\t * ```js\n\t * import grandi from \"grandi\";\n\t * grandi.initialize();\n\t * const finder = await grandi.find({ showLocalSources: true });\n\t * finder.wait(1000);\n\t * const source = finder.sources()[0];\n\t * finder.destroy();\n\t * const receiver = await grandi.receive({ source });\n\t * const frame = await receiver.video(1000);\n\t * receiver.destroy();\n\t * ```\n\t */\n\treceive(params: ReceiveOptions): Promise<Receiver>;\n\t/**\n\t * Creates an NDI frame-synchronizer (time base corrector) backed by an existing receiver.\n\t * Use this when you want smooth playback clocked to your own render/audio loop.\n\t *\n\t * Note: destroy the frame-sync before destroying the receiver.\n\t */\n\tframesync(receiver: Receiver): Promise<FrameSync>;\n\t/**\n\t * Creates an NDI router for switching between different NDI sources.\n\t * @param params Router options.\n\t * @returns A promise that resolves to a Routing instance.\n\t * @throws {Error} Promise rejects on unsupported platform/CPU or if routing creation fails.\n\t *\n\t * @example\n\t * ```js\n\t * import grandi from \"grandi\";\n\t * grandi.initialize();\n\t * const router = await grandi.routing({ name: \"My Router\" });\n\t * // router.change(source) to route a discovered source\n\t * router.destroy();\n\t * ```\n\t */\n\trouting(params: { name?: string; groups?: string }): Promise<Routing>;\n\t/**\n\t * Creates a finder to discover NDI sources on the network.\n\t * @param params Discovery options.\n\t * @returns A promise that resolves to a Finder instance.\n\t * @throws {Error} Promise rejects on unsupported platform/CPU or if the finder cannot be created.\n\t *\n\t * @example\n\t * ```js\n\t * import grandi from \"grandi\";\n\t * grandi.initialize();\n\t * const finder = await grandi.find({ showLocalSources: true });\n\t * finder.wait(1000);\n\t * console.log(finder.sources());\n\t * finder.destroy();\n\t * ```\n\t */\n\tfind(params?: FindOptions): Promise<Finder>;\n\n\t/**\n\t * Enum: receiver video color formats.\n\t */\n\tColorFormat: typeof ColorFormat;\n\t/**\n\t * Enum: supported raw audio formats for helpers/receive conversions.\n\t */\n\tAudioFormat: typeof AudioFormat;\n\t/**\n\t * Enum: receiver bandwidth modes.\n\t */\n\tBandwidth: typeof Bandwidth;\n\t/**\n\t * Enum: video frame format types (progressive/interlaced/fields).\n\t */\n\tFrameType: typeof FrameType;\n\t/**\n\t * Enum: FourCC pixel/audio formats used in frames.\n\t */\n\tFourCC: typeof FourCC;\n\n\t// Constant aliases for backwards compatibility / convenience.\n\t/**\n\t * Alias of `ColorFormat.BGRX_BGRA`.\n\t */\n\tCOLOR_FORMAT_BGRX_BGRA: ColorFormat;\n\t/**\n\t * Alias of `ColorFormat.UYVY_BGRA`.\n\t */\n\tCOLOR_FORMAT_UYVY_BGRA: ColorFormat;\n\t/**\n\t * Alias of `ColorFormat.RGBX_RGBA`.\n\t */\n\tCOLOR_FORMAT_RGBX_RGBA: ColorFormat;\n\t/**\n\t * Alias of `ColorFormat.UYVY_RGBA`.\n\t */\n\tCOLOR_FORMAT_UYVY_RGBA: ColorFormat;\n\t/**\n\t * Alias of `ColorFormat.Fastest`.\n\t */\n\tCOLOR_FORMAT_FASTEST: ColorFormat;\n\t/**\n\t * Alias of `ColorFormat.BGRX_BGRA_FLIPPED` (Windows-only).\n\t */\n\tCOLOR_FORMAT_BGRX_BGRA_FLIPPED: ColorFormat;\n\n\t/**\n\t * Alias of `Bandwidth.MetadataOnly`.\n\t */\n\tBANDWIDTH_METADATA_ONLY: Bandwidth;\n\t/**\n\t * Alias of `Bandwidth.AudioOnly`.\n\t */\n\tBANDWIDTH_AUDIO_ONLY: Bandwidth;\n\t/**\n\t * Alias of `Bandwidth.Lowest`.\n\t */\n\tBANDWIDTH_LOWEST: Bandwidth;\n\t/**\n\t * Alias of `Bandwidth.Highest`.\n\t */\n\tBANDWIDTH_HIGHEST: Bandwidth;\n\n\t/**\n\t * Alias of `FrameType.Progressive`.\n\t */\n\tFORMAT_TYPE_PROGRESSIVE: FrameType;\n\t/**\n\t * Alias of `FrameType.Interlaced`.\n\t */\n\tFORMAT_TYPE_INTERLACED: FrameType;\n\t/**\n\t * Alias of `FrameType.Field0`.\n\t */\n\tFORMAT_TYPE_FIELD_0: FrameType;\n\t/**\n\t * Alias of `FrameType.Field1`.\n\t */\n\tFORMAT_TYPE_FIELD_1: FrameType;\n\n\t/**\n\t * Alias of `AudioFormat.Float32Separate`.\n\t */\n\tAUDIO_FORMAT_FLOAT_32_SEPARATE: AudioFormat;\n\t/**\n\t * Alias of `AudioFormat.Float32Interleaved`.\n\t */\n\tAUDIO_FORMAT_FLOAT_32_INTERLEAVED: AudioFormat;\n\t/**\n\t * Alias of `AudioFormat.Int16Interleaved`.\n\t */\n\tAUDIO_FORMAT_INT_16_INTERLEAVED: AudioFormat;\n\n\t/**\n\t * Alias of `FourCC.UYVY`.\n\t */\n\tFOURCC_UYVY: FourCC;\n\t/**\n\t * Alias of `FourCC.UYVA`.\n\t */\n\tFOURCC_UYVA: FourCC;\n\t/**\n\t * Alias of `FourCC.P216`.\n\t */\n\tFOURCC_P216: FourCC;\n\t/**\n\t * Alias of `FourCC.PA16`.\n\t */\n\tFOURCC_PA16: FourCC;\n\t/**\n\t * Alias of `FourCC.YV12`.\n\t */\n\tFOURCC_YV12: FourCC;\n\t/**\n\t * Alias of `FourCC.I420`.\n\t */\n\tFOURCC_I420: FourCC;\n\t/**\n\t * Alias of `FourCC.NV12`.\n\t */\n\tFOURCC_NV12: FourCC;\n\t/**\n\t * Alias of `FourCC.BGRA`.\n\t */\n\tFOURCC_BGRA: FourCC;\n\t/**\n\t * Alias of `FourCC.BGRX`.\n\t */\n\tFOURCC_BGRX: FourCC;\n\t/**\n\t * Alias of `FourCC.RGBA`.\n\t */\n\tFOURCC_RGBA: FourCC;\n\t/**\n\t * Alias of `FourCC.RGBX`.\n\t */\n\tFOURCC_RGBX: FourCC;\n\t/**\n\t * Alias of `FourCC.FLTp`.\n\t */\n\tFOURCC_FLTp: FourCC;\n}\n","import path from \"node:path\";\nimport nodeGypBuild from \"node-gyp-build\";\n\nimport type {\n\tFinder,\n\tFindOptions,\n\tFrameSync,\n\tGrandi,\n\tReceiveOptions,\n\tReceiver,\n\tRouting,\n\tSender,\n\tSendOptions,\n} from \"./types\";\nimport {\n\tAudioFormat,\n\tBandwidth,\n\tColorFormat,\n\tFourCC,\n\tFrameType,\n} from \"./types\";\n\n/**\n * Checks if the current platform and architecture are supported by NDI.\n * @returns {boolean} True if the platform is supported (darwin, linux, or win32 with ia32/x64), false otherwise.\n */\nfunction isSupportedPlatform(): boolean {\n\treturn (\n\t\tprocess.platform === \"darwin\" ||\n\t\tprocess.platform === \"linux\" ||\n\t\t(process.platform === \"win32\" && [\"ia32\", \"x64\"].includes(process.arch))\n\t);\n}\n\nfunction tryRequireArchPackage(): GrandiAddon | null {\n\tconst archKey = `${process.platform}-${process.arch}`;\n\tconst map: Record<string, string> = {\n\t\t\"linux-x64\": \"@grandi/linux-x64\",\n\t\t\"linux-arm64\": \"@grandi/linux-arm64\",\n\t\t\"linux-arm\": \"@grandi/linux-armv7l\",\n\t\t\"win32-x64\": \"@grandi/win32-x64\",\n\t\t\"win32-ia32\": \"@grandi/win32-ia32\",\n\t\t\"darwin-x64\": \"@grandi/darwin-universal\",\n\t\t\"darwin-arm64\": \"@grandi/darwin-universal\",\n\t};\n\tconst pkg = map[archKey];\n\tif (!pkg) throw new Error(`Unsupported platform or architecture: ${archKey}`);\n\ttry {\n\t\t// eslint-disable-next-line @typescript-eslint/no-var-requires\n\t\treturn require(pkg) as GrandiAddon;\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`Failed to find prebuilt package for ${archKey}. Please ensure that the package \"${pkg}\" is installed`,\n\t\t);\n\t}\n}\n\nfunction loadAddon(): GrandiAddon {\n\tconst loadErrors: Error[] = [];\n\tif (!isSupportedPlatform()) {\n\t\tconsole.error(\n\t\t\t`Unsupported platform or architecture: ${process.platform}-${process.arch}`,\n\t\t);\n\t\treturn noopAddon;\n\t}\n\ttry {\n\t\tconst localBinding = nodeGypBuild(\n\t\t\tpath.join(__dirname, \"..\"),\n\t\t) as GrandiAddon;\n\t\tif (localBinding) return localBinding;\n\t} catch (err) {\n\t\tloadErrors.push(err as Error);\n\t}\n\ttry {\n\t\tconst archAddon = tryRequireArchPackage();\n\t\tif (archAddon) return archAddon;\n\t} catch (err) {\n\t\tloadErrors.push(err as Error);\n\t}\n\n\tif (loadErrors.length > 0) {\n\t\tconst aggregateError = new Error(\n\t\t\t\"Failed to load native addon:\\n\" +\n\t\t\t\tloadErrors.map((e, i) => ` [${i + 1}] ${e.message}`).join(\"\\n\"),\n\t\t);\n\t\tconsole.error(aggregateError);\n\t}\n\treturn noopAddon;\n}\n\nexport interface GrandiAddon {\n\tversion(): string;\n\tisSupportedCPU(): boolean;\n\tinitialize(): boolean;\n\tdestroy(): boolean;\n\tfind(params?: FindOptions): Promise<Finder>;\n\treceive(params: ReceiveOptions): Promise<Receiver>;\n\tframesync(receiver: Receiver): Promise<FrameSync>;\n\tsend(params: SendOptions): Promise<Sender>;\n\trouting(params: { name?: string; groups?: string }): Promise<Routing>;\n}\n\nconst noopAddon: GrandiAddon = {\n\tversion() {\n\t\treturn \"\";\n\t},\n\tisSupportedCPU() {\n\t\treturn false;\n\t},\n\tinitialize() {\n\t\treturn false;\n\t},\n\tdestroy() {\n\t\treturn false;\n\t},\n\tsend(_params) {\n\t\treturn Promise.reject(new Error(\"Unsupported platform or CPU\"));\n\t},\n\treceive(_params) {\n\t\treturn Promise.reject(new Error(\"Unsupported platform or CPU\"));\n\t},\n\tframesync(_receiver) {\n\t\treturn Promise.reject(new Error(\"Unsupported platform or CPU\"));\n\t},\n\trouting() {\n\t\treturn Promise.reject(new Error(\"Unsupported platform or CPU\"));\n\t},\n\tfind(_params) {\n\t\treturn Promise.reject(new Error(\"Unsupported platform or CPU\"));\n\t},\n};\n\nconst addon: GrandiAddon = loadAddon();\n/**\n * Creates a finder to discover NDI sources on the network.\n * @param {FindOptions} [params={}] - Options for finding sources.\n * @param {boolean} [params.showLocalSources] - Whether to show local sources.\n * @param {string} [params.groups] - Multicast groups to search in.\n * @param {string} [params.extraIPs] - Additional IP addresses to search.\n * @returns {Promise<Finder>} A promise that resolves to a Finder instance for discovering sources.\n * @throws {Error} Promise rejects on unsupported platform/CPU or if the finder cannot be created.\n *\n * @example\n * ```js\n * import { find, initialize } from \"grandi\";\n * initialize();\n * const finder = await find({ showLocalSources: true });\n * finder.wait(1000);\n * console.log(finder.sources());\n * finder.destroy();\n * ```\n */\nexport function find(params: FindOptions = {}): Promise<Finder> {\n\treturn addon.find(params);\n}\n// Named runtime exports\n/**\n * Gets the version of the NDI SDK.\n * @returns {string} The NDI SDK version string.\n */\nexport const version = addon.version;\n/**\n * Checks if the current CPU architecture is supported by NDI.\n * @returns {boolean} True if the CPU is supported, false otherwise.\n */\nexport const isSupportedCPU = addon.isSupportedCPU;\n/**\n * Initializes the NDI library. Must be called before using any other NDI functions.\n * @returns {boolean} True if initialization was successful, false otherwise.\n *\n * @example\n * ```js\n * import { initialize } from \"grandi\";\n * if (!initialize()) throw new Error(\"NDI init failed\");\n * ```\n */\nexport const initialize = addon.initialize;\n/**\n * Destroys the NDI library instance and cleans up resources.\n * Should be called when done using NDI to free resources.\n * @returns {boolean} True if destruction was successful, false otherwise.\n *\n * @example\n * ```js\n * import { destroy } from \"grandi\";\n * destroy();\n * ```\n */\nexport const destroy = addon.destroy;\n/**\n * Creates an NDI sender for transmitting video and audio over the network.\n * @param {SendOptions} params - Options for creating the sender.\n * @param {string} params.name - The name of the NDI source.\n * @param {string} [params.groups] - Multicast groups to send to.\n * @param {boolean} [params.clockVideo] - Whether to clock video frames.\n * @param {boolean} [params.clockAudio] - Whether to clock audio frames.\n * @returns {Promise<Sender>} A promise that resolves to a Sender instance for transmitting data.\n * @throws {Error} Promise rejects on unsupported platform/CPU or if sender creation fails.\n *\n * @example\n * ```js\n * import { initialize, send } from \"grandi\";\n * initialize();\n * const sender = await send({ name: \"My Source\" });\n * // sender.video(...) / sender.audio(...)\n * sender.destroy();\n * ```\n */\nexport const send = addon.send;\n/**\n * Creates an NDI receiver for receiving video and audio from an NDI source.\n * @param {ReceiveOptions} params - Options for creating the receiver.\n * @param {ReceiveOptions[\"source\"]} params.source - The NDI source to connect to.\n * @param {ReceiveOptions[\"colorFormat\"]} [params.colorFormat] - The color format for received video.\n * @param {ReceiveOptions[\"bandwidth\"]} [params.bandwidth] - The bandwidth limitation for the connection.\n * @param {boolean} [params.allowVideoFields] - Whether to allow video fields.\n * @param {string} [params.name] - The name for the receiver.\n * @returns {Promise<Receiver>} A promise that resolves to a Receiver instance for receiving data.\n * @throws {Error} Promise rejects on unsupported platform/CPU or if receiver creation fails.\n *\n * @example\n * ```js\n * import { find, initialize, receive } from \"grandi\";\n * initialize();\n * const finder = await find({ showLocalSources: true });\n * finder.wait(1000);\n * const source = finder.sources()[0];\n * finder.destroy();\n * const receiver = await receive({ source });\n * const frame = await receiver.video(1000);\n * receiver.destroy();\n * ```\n */\nexport const receive = addon.receive;\n/**\n * Creates an NDI frame-synchronizer (time base corrector) backed by an existing receiver.\n * Use this when you want smooth playback clocked to your own render/audio loop.\n *\n * Note: destroy the frame-sync before destroying the receiver.\n * @param {Receiver} receiver - The receiver instance to frame-sync.\n * @returns {Promise<FrameSync>} A promise that resolves to a FrameSync instance.\n * @throws {Error} Promise rejects on unsupported platform/CPU or if framesync creation fails.\n *\n * @example\n * ```js\n * import grandi from \"grandi\";\n * grandi.initialize();\n * const receiver = await grandi.receive({ source });\n * const fs = await grandi.framesync(receiver);\n * const frame = await fs.video(grandi.FrameType.Progressive);\n * fs.destroy();\n * receiver.destroy();\n * ```\n */\nexport const framesync = addon.framesync;\n/**\n * Creates an NDI router for switching between different NDI sources.\n * @param {Object} params - Options for creating the router.\n * @param {string} [params.name] - The name for the router.\n * @param {string} [params.groups] - Multicast groups for the router.\n * @returns {Promise<Routing>} A promise that resolves to a Routing instance for source switching.\n * @throws {Error} Promise rejects on unsupported platform/CPU or if routing creation fails.\n *\n * @example\n * ```js\n * import { initialize, routing } from \"grandi\";\n * initialize();\n * const router = await routing({ name: \"My Router\" });\n * // router.change(source)\n * router.destroy();\n * ```\n */\nexport const routing = addon.routing;\n\n// Re-export enums and types for convenient named imports\nexport { ColorFormat, AudioFormat, Bandwidth, FrameType, FourCC };\nexport type {\n\tAudioFrame,\n\tAudioReceiveOptions,\n\tFinder,\n\tFindOptions,\n\tFrameSync,\n\tFrameSyncAudioOptions,\n\tGrandi,\n\tPtpTimestamp,\n\tReceivedAudioFrame,\n\tReceivedMetadataFrame,\n\tReceivedVideoFrame,\n\tReceiveOptions,\n\tReceiverDataFrame,\n\tReceiverTallyState,\n\tRouting,\n\tSender,\n\tSenderTally,\n\tSource,\n\tSourceChangeEvent,\n\tStatusChangeEvent,\n\tTimecode,\n\tTimeoutEvent,\n\tVideoFrame,\n} from \"./types\";\n\nconst grandi: Grandi = {\n\tversion,\n\tisSupportedCPU,\n\tinitialize,\n\tdestroy,\n\tsend,\n\treceive,\n\tframesync,\n\trouting,\n\tfind,\n\tColorFormat,\n\tAudioFormat,\n\tBandwidth,\n\tFrameType,\n\tFourCC,\n\n\t// Constants mapped to enum values\n\tCOLOR_FORMAT_BGRX_BGRA: ColorFormat.BGRX_BGRA,\n\tCOLOR_FORMAT_UYVY_BGRA: ColorFormat.UYVY_BGRA,\n\tCOLOR_FORMAT_RGBX_RGBA: ColorFormat.RGBX_RGBA,\n\tCOLOR_FORMAT_UYVY_RGBA: ColorFormat.UYVY_RGBA,\n\tCOLOR_FORMAT_FASTEST: ColorFormat.Fastest,\n\tCOLOR_FORMAT_BGRX_BGRA_FLIPPED: ColorFormat.BGRX_BGRA_FLIPPED,\n\n\tBANDWIDTH_METADATA_ONLY: Bandwidth.MetadataOnly,\n\tBANDWIDTH_AUDIO_ONLY: Bandwidth.AudioOnly,\n\tBANDWIDTH_LOWEST: Bandwidth.Lowest,\n\tBANDWIDTH_HIGHEST: Bandwidth.Highest,\n\n\tFORMAT_TYPE_PROGRESSIVE: FrameType.Progressive,\n\tFORMAT_TYPE_INTERLACED: FrameType.Interlaced,\n\tFORMAT_TYPE_FIELD_0: FrameType.Field0,\n\tFORMAT_TYPE_FIELD_1: FrameType.Field1,\n\n\tAUDIO_FORMAT_FLOAT_32_SEPARATE: AudioFormat.Float32Separate,\n\tAUDIO_FORMAT_FLOAT_32_INTERLEAVED: AudioFormat.Float32Interleaved,\n\tAUDIO_FORMAT_INT_16_INTERLEAVED: AudioFormat.Int16Interleaved,\n\n\t// FourCC helpers/constants\n\tFOURCC_UYVY: FourCC.UYVY,\n\tFOURCC_UYVA: FourCC.UYVA,\n\tFOURCC_P216: FourCC.P216,\n\tFOURCC_PA16: FourCC.PA16,\n\tFOURCC_YV12: FourCC.YV12,\n\tFOURCC_I420: FourCC.I420,\n\tFOURCC_NV12: FourCC.NV12,\n\tFOURCC_BGRA: FourCC.BGRA,\n\tFOURCC_BGRX: FourCC.BGRX,\n\tFOURCC_RGBA: FourCC.RGBA,\n\tFOURCC_RGBX: FourCC.RGBX,\n\tFOURCC_FLTp: FourCC.FLTp,\n};\n\nexport default grandi;\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grandi",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Node.JS native bindings to the Newtek NDI SDK.",
|
|
5
5
|
"homepage": "https://github.com/tux-tn/grandi#readme",
|
|
6
6
|
"keywords": [
|
|
@@ -13,15 +13,10 @@
|
|
|
13
13
|
"author": "Sarhan Aissi <npm@tux.tn>",
|
|
14
14
|
"license": "Apache-2.0",
|
|
15
15
|
"files": [
|
|
16
|
-
"binding.gyp",
|
|
17
16
|
"dist",
|
|
18
|
-
"lib",
|
|
19
|
-
"src",
|
|
20
|
-
"scripts",
|
|
21
17
|
"LICENSE",
|
|
22
18
|
"NOTICE",
|
|
23
|
-
"README.md"
|
|
24
|
-
"prebuilds"
|
|
19
|
+
"README.md"
|
|
25
20
|
],
|
|
26
21
|
"main": "./dist/index.mjs",
|
|
27
22
|
"types": "./dist/index.d.mts",
|
|
@@ -32,51 +27,58 @@
|
|
|
32
27
|
"gypfile": true,
|
|
33
28
|
"repository": {
|
|
34
29
|
"type": "git",
|
|
35
|
-
"url": "https://github.com/tux-tn/grandi.git"
|
|
30
|
+
"url": "git+https://github.com/tux-tn/grandi.git"
|
|
36
31
|
},
|
|
37
32
|
"bugs": {
|
|
38
33
|
"url": "https://github.com/tux-tn/grandi/issues"
|
|
39
34
|
},
|
|
35
|
+
"optionalDependencies": {
|
|
36
|
+
"@grandi/darwin-universal": "1.2.0",
|
|
37
|
+
"@grandi/linux-arm64": "1.2.0",
|
|
38
|
+
"@grandi/linux-armv7l": "1.2.0",
|
|
39
|
+
"@grandi/linux-x64": "1.2.0",
|
|
40
|
+
"@grandi/win32-ia32": "1.2.0",
|
|
41
|
+
"@grandi/win32-x64": "1.2.0"
|
|
42
|
+
},
|
|
40
43
|
"dependencies": {
|
|
41
|
-
"
|
|
42
|
-
"cross-zip": "4.0.1",
|
|
43
|
-
"execa": "9.6.0",
|
|
44
|
-
"got": "14.6.3",
|
|
45
|
-
"node-gyp-build": "^4.8.4",
|
|
46
|
-
"shelljs": "0.10.0",
|
|
47
|
-
"tmp": "0.2.5"
|
|
44
|
+
"node-gyp-build": "^4.8.4"
|
|
48
45
|
},
|
|
49
46
|
"devDependencies": {
|
|
50
|
-
"@biomejs/biome": "2.3.
|
|
47
|
+
"@biomejs/biome": "2.3.9",
|
|
51
48
|
"@types/bindings": "^1.5.5",
|
|
52
49
|
"@types/cross-zip": "^4.0.2",
|
|
53
|
-
"@types/node": "^
|
|
54
|
-
"@types/shelljs": "^0.
|
|
50
|
+
"@types/node": "^25.0.2",
|
|
51
|
+
"@types/shelljs": "^0.10.0",
|
|
55
52
|
"@types/tmp": "^0.2.6",
|
|
56
|
-
"@vitest/coverage-v8": "^4.0.
|
|
53
|
+
"@vitest/coverage-v8": "^4.0.15",
|
|
57
54
|
"cross-env": "^10.1.0",
|
|
58
|
-
"
|
|
55
|
+
"cross-spawn": "7.0.6",
|
|
56
|
+
"cross-zip": "4.0.1",
|
|
57
|
+
"execa": "9.6.1",
|
|
58
|
+
"got": "14.6.5",
|
|
59
|
+
"node-gyp": "^12.1.0",
|
|
60
|
+
"shelljs": "0.10.0",
|
|
59
61
|
"shx": "0.4.0",
|
|
60
62
|
"standard-version": "^9.5.0",
|
|
61
|
-
"
|
|
63
|
+
"tmp": "0.2.5",
|
|
64
|
+
"tsdown": "^0.18.0",
|
|
62
65
|
"typescript": "^5.9.3",
|
|
63
|
-
"vitest": "^4.0.
|
|
66
|
+
"vitest": "^4.0.15"
|
|
64
67
|
},
|
|
65
68
|
"scripts": {
|
|
66
|
-
"
|
|
67
|
-
"install": "node-gyp-build",
|
|
68
|
-
"prebuild:download": "cross-env NDI_FORCE=1 node scripts/preinstall.mjs",
|
|
69
|
+
"bench": "node --expose-gc scripts/benchmark.mjs",
|
|
69
70
|
"build": "tsdown",
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"test:watch": "vitest",
|
|
73
|
-
"test:unit": "vitest run test/unit",
|
|
74
|
-
"test:integration": "cross-env RUN_NDI_TESTS=1 vitest run test/integration",
|
|
75
|
-
"test:coverage": "vitest run --coverage",
|
|
71
|
+
"build:addon": "node scripts/build-addon.mjs",
|
|
72
|
+
"clean": "shx rm -rf ndi build",
|
|
76
73
|
"format": "biome format",
|
|
77
74
|
"format:cpp": "clang-format -i lib/*.cc lib/*.h",
|
|
75
|
+
"install": "exit 0",
|
|
78
76
|
"lint": "biome lint",
|
|
79
|
-
"
|
|
77
|
+
"test": "vitest run",
|
|
78
|
+
"test:coverage": "vitest run --coverage",
|
|
79
|
+
"test:integration": "vitest run test/integration",
|
|
80
|
+
"test:unit": "vitest run test/unit",
|
|
81
|
+
"test:watch": "vitest"
|
|
80
82
|
},
|
|
81
83
|
"engines": {
|
|
82
84
|
"node": ">=20.19.5"
|
package/binding.gyp
DELETED
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"variables": {
|
|
3
|
-
"ndi_dir": "<(module_root_dir)/ndi",
|
|
4
|
-
"ndi_include_dir": "<(ndi_dir)/include",
|
|
5
|
-
"product_dir": "<(PRODUCT_DIR)"
|
|
6
|
-
},
|
|
7
|
-
"targets": [
|
|
8
|
-
{
|
|
9
|
-
"target_name": "grandi",
|
|
10
|
-
"sources": [
|
|
11
|
-
"lib/grandi_util.cc",
|
|
12
|
-
"lib/grandi_find.cc",
|
|
13
|
-
"lib/grandi_send.cc",
|
|
14
|
-
"lib/grandi_receive.cc",
|
|
15
|
-
"lib/grandi_routing.cc",
|
|
16
|
-
"lib/grandi.cc"
|
|
17
|
-
],
|
|
18
|
-
"include_dirs": [
|
|
19
|
-
"<(ndi_include_dir)"
|
|
20
|
-
],
|
|
21
|
-
"copies": [
|
|
22
|
-
{
|
|
23
|
-
"destination": "<(product_dir)",
|
|
24
|
-
"files": [
|
|
25
|
-
"<(ndi_dir)/lib/libndi_licenses.txt"
|
|
26
|
-
]
|
|
27
|
-
}
|
|
28
|
-
],
|
|
29
|
-
"conditions": [
|
|
30
|
-
[
|
|
31
|
-
"OS == 'win' and target_arch == 'ia32'",
|
|
32
|
-
{
|
|
33
|
-
"copies": [
|
|
34
|
-
{
|
|
35
|
-
"destination": "<(product_dir)",
|
|
36
|
-
"files": [
|
|
37
|
-
"<(ndi_dir)/lib/win-x86/Processing.NDI.Lib.x86.dll",
|
|
38
|
-
"<(ndi_dir)/lib/LICENSE.pdf"
|
|
39
|
-
]
|
|
40
|
-
}
|
|
41
|
-
],
|
|
42
|
-
"link_settings": {
|
|
43
|
-
"libraries": [
|
|
44
|
-
"Processing.NDI.Lib.x86.lib"
|
|
45
|
-
],
|
|
46
|
-
"library_dirs": [
|
|
47
|
-
"<(ndi_dir)/lib/win-x86"
|
|
48
|
-
]
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
],
|
|
52
|
-
[
|
|
53
|
-
"OS == 'win' and target_arch == 'x64'",
|
|
54
|
-
{
|
|
55
|
-
"copies": [
|
|
56
|
-
{
|
|
57
|
-
"destination": "<(product_dir)",
|
|
58
|
-
"files": [
|
|
59
|
-
"<(ndi_dir)/lib/win-x64/Processing.NDI.Lib.x64.dll",
|
|
60
|
-
"<(ndi_dir)/lib/LICENSE.pdf"
|
|
61
|
-
]
|
|
62
|
-
}
|
|
63
|
-
],
|
|
64
|
-
"link_settings": {
|
|
65
|
-
"libraries": [
|
|
66
|
-
"Processing.NDI.Lib.x64.lib"
|
|
67
|
-
],
|
|
68
|
-
"library_dirs": [
|
|
69
|
-
"<(ndi_dir)/lib/win-x64"
|
|
70
|
-
]
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
],
|
|
74
|
-
[
|
|
75
|
-
"OS == 'linux' and target_arch == 'ia32'",
|
|
76
|
-
{
|
|
77
|
-
"copies": [
|
|
78
|
-
{
|
|
79
|
-
"destination": "<(product_dir)",
|
|
80
|
-
"files": [
|
|
81
|
-
"<(ndi_dir)/lib/lnx-x86/libndi.so.6",
|
|
82
|
-
"<(ndi_dir)/lib/LICENSE",
|
|
83
|
-
]
|
|
84
|
-
}
|
|
85
|
-
],
|
|
86
|
-
"link_settings": {
|
|
87
|
-
"ldflags": [
|
|
88
|
-
"-Wl,-rpath,'$$ORIGIN'"
|
|
89
|
-
],
|
|
90
|
-
"libraries": [
|
|
91
|
-
"-lndi"
|
|
92
|
-
],
|
|
93
|
-
"library_dirs": [
|
|
94
|
-
"<(ndi_dir)/lib/lnx-x86"
|
|
95
|
-
]
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
],
|
|
99
|
-
[
|
|
100
|
-
"OS == 'linux' and target_arch == 'x64'",
|
|
101
|
-
{
|
|
102
|
-
"copies": [
|
|
103
|
-
{
|
|
104
|
-
"destination": "<(product_dir)",
|
|
105
|
-
"files": [
|
|
106
|
-
"<(ndi_dir)/lib/lnx-x64/libndi.so.6",
|
|
107
|
-
"<(ndi_dir)/lib/LICENSE"
|
|
108
|
-
]
|
|
109
|
-
}
|
|
110
|
-
],
|
|
111
|
-
"link_settings": {
|
|
112
|
-
"ldflags": [
|
|
113
|
-
"-Wl,-rpath,'$$ORIGIN'"
|
|
114
|
-
],
|
|
115
|
-
"libraries": [
|
|
116
|
-
"-lndi"
|
|
117
|
-
],
|
|
118
|
-
"library_dirs": [
|
|
119
|
-
"<(ndi_dir)/lib/lnx-x64"
|
|
120
|
-
]
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
],
|
|
124
|
-
[
|
|
125
|
-
"OS == 'linux' and target_arch == 'arm'",
|
|
126
|
-
{
|
|
127
|
-
"copies": [
|
|
128
|
-
{
|
|
129
|
-
"destination": "<(product_dir)",
|
|
130
|
-
"files": [
|
|
131
|
-
"<(ndi_dir)/lib/lnx-armv7l/libndi.so.6",
|
|
132
|
-
"<(ndi_dir)/lib/LICENSE"
|
|
133
|
-
]
|
|
134
|
-
}
|
|
135
|
-
],
|
|
136
|
-
"link_settings": {
|
|
137
|
-
"ldflags": [
|
|
138
|
-
"-Wl,-rpath,'$$ORIGIN'"
|
|
139
|
-
],
|
|
140
|
-
"libraries": [
|
|
141
|
-
"-lndi"
|
|
142
|
-
],
|
|
143
|
-
"library_dirs": [
|
|
144
|
-
"<(ndi_dir)/lib/lnx-armv7l"
|
|
145
|
-
]
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
],
|
|
149
|
-
[
|
|
150
|
-
"OS == 'linux' and target_arch == 'arm64'",
|
|
151
|
-
{
|
|
152
|
-
"copies": [
|
|
153
|
-
{
|
|
154
|
-
"destination": "<(product_dir)",
|
|
155
|
-
"files": [
|
|
156
|
-
"<(ndi_dir)/lib/lnx-arm64/libndi.so.6",
|
|
157
|
-
"<(ndi_dir)/lib/LICENSE"
|
|
158
|
-
]
|
|
159
|
-
}
|
|
160
|
-
],
|
|
161
|
-
"link_settings": {
|
|
162
|
-
"ldflags": [
|
|
163
|
-
"-Wl,-rpath,'$$ORIGIN'"
|
|
164
|
-
],
|
|
165
|
-
"libraries": [
|
|
166
|
-
"-lndi"
|
|
167
|
-
],
|
|
168
|
-
"library_dirs": [
|
|
169
|
-
"<(ndi_dir)/lib/lnx-arm64"
|
|
170
|
-
]
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
],
|
|
174
|
-
[
|
|
175
|
-
"OS == 'mac'",
|
|
176
|
-
{
|
|
177
|
-
"copies": [
|
|
178
|
-
{
|
|
179
|
-
"destination": "<(product_dir)",
|
|
180
|
-
"files": [
|
|
181
|
-
"<(ndi_dir)/lib/macOS/libndi.dylib",
|
|
182
|
-
"<(ndi_dir)/lib/LICENSE.pdf"
|
|
183
|
-
]
|
|
184
|
-
}
|
|
185
|
-
],
|
|
186
|
-
"link_settings": {
|
|
187
|
-
"libraries": [
|
|
188
|
-
"-Wl,-rpath,@loader_path",
|
|
189
|
-
"-lndi"
|
|
190
|
-
],
|
|
191
|
-
"library_dirs": [
|
|
192
|
-
"<(ndi_dir)/lib/macOS"
|
|
193
|
-
]
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
]
|
|
197
|
-
]
|
|
198
|
-
}
|
|
199
|
-
]
|
|
200
|
-
}
|