@smartspectra/node-sdk 3.4.0-rc.5 → 3.4.0-rc.7
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 +27 -7
- package/js/camera-selection.js +57 -0
- package/js/constants.js +12 -3
- package/js/ffi.js +71 -12
- package/js/index.d.ts +71 -14
- package/js/index.js +4 -0
- package/js/messages/generated.d.ts +166 -8
- package/js/messages/generated.js +565 -37
- package/js/renderer/index.d.ts +2 -0
- package/js/smartspectra.js +50 -12
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -106,7 +106,7 @@ the missing package.
|
|
|
106
106
|
- Electron desktop app: use `@smartspectra/node-sdk/main`,
|
|
107
107
|
`@smartspectra/node-sdk/preload`, and `@smartspectra/node-sdk/renderer`.
|
|
108
108
|
- Headless Node process with a local camera: use `@smartspectra/node-sdk`
|
|
109
|
-
directly with `useCamera()`.
|
|
109
|
+
directly with `useCamera(CameraSelection.default)`.
|
|
110
110
|
- Headless or server-side Node process with host-provided frames: use
|
|
111
111
|
`useCustomInput()` / `sendFrame()`.
|
|
112
112
|
- Runnable reference app: [electron-quickstart](https://github.com/Presage-Security/SmartSpectra/tree/main/nodejs/samples/electron-quickstart)
|
|
@@ -118,7 +118,7 @@ the missing package.
|
|
|
118
118
|
> wrap the `await` calls in an `async` function.
|
|
119
119
|
|
|
120
120
|
```ts
|
|
121
|
-
import { SmartSpectraSDK, breathingMetrics, cardioMetrics, decodeMetrics } from '@smartspectra/node-sdk';
|
|
121
|
+
import { SmartSpectraSDK, CameraSelection, breathingMetrics, cardioMetrics, decodeMetrics } from '@smartspectra/node-sdk';
|
|
122
122
|
|
|
123
123
|
const sdk = new SmartSpectraSDK({
|
|
124
124
|
apiKey: 'YOUR_API_KEY',
|
|
@@ -134,7 +134,7 @@ sdk.on('metrics', (buf, ts) => {
|
|
|
134
134
|
sdk.on('error', (code, message, retryable) =>
|
|
135
135
|
console.error('SmartSpectra error', code, message, 'retryable=', retryable));
|
|
136
136
|
|
|
137
|
-
sdk.useCamera();
|
|
137
|
+
sdk.useCamera(CameraSelection.default);
|
|
138
138
|
sdk.start();
|
|
139
139
|
|
|
140
140
|
console.log('Measuring from the default camera. Press Ctrl+C to stop.');
|
|
@@ -147,10 +147,30 @@ process.on('SIGINT', async () => {
|
|
|
147
147
|
});
|
|
148
148
|
```
|
|
149
149
|
|
|
150
|
-
`useCamera()`
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
`useCamera(CameraSelection.default)` selects the default camera while stopped; capture begins at
|
|
151
|
+
`start()`. You can discover cameras without creating an SDK instance:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { CameraSelection, SmartSpectraSDK } from '@smartspectra/node-sdk';
|
|
155
|
+
|
|
156
|
+
const cameras = SmartSpectraSDK.availableCameras();
|
|
157
|
+
if (cameras.length > 0) {
|
|
158
|
+
sdk.useCamera(CameraSelection.byId(cameras[0].id), { width: 1280, height: 720 });
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`CameraSelection.default`, `.front`, `.back`, and `.byId(id)` share the camera
|
|
163
|
+
selection contract across SDKs. Explicit requests never fall back. Stop/start/reset
|
|
164
|
+
retain the chosen input. Native Node.js supports camera discovery and typed
|
|
165
|
+
selection on macOS, Linux, and Windows. Linux and Windows cameras may report
|
|
166
|
+
unknown facing or lens type, so select those cameras by discovered ID. On
|
|
167
|
+
Windows, `.front` and `.back` fail with `kInputUnavailable` because facing is
|
|
168
|
+
not reported. See the
|
|
169
|
+
[migration guide](docs/migration-guide.md) and [API reference](docs/api-reference.md#cameraoptions).
|
|
170
|
+
|
|
171
|
+
Electron renderer capture uses browser-owned streams and `useMediaStream()`;
|
|
172
|
+
browser device IDs cannot be used for native camera selection. Use the
|
|
173
|
+
custom-input path below when your app already owns frame capture.
|
|
154
174
|
|
|
155
175
|
## Custom Input Quickstart
|
|
156
176
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Copyright (C) 2026 Presage Technologies, Inc.
|
|
2
|
+
// SPDX-License-Identifier: LicenseRef-Proprietary
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const { SmartSpectraErrorCode } = require('./constants');
|
|
6
|
+
|
|
7
|
+
const CameraSelection = Object.freeze({
|
|
8
|
+
default: Object.freeze({ kind: 'default' }),
|
|
9
|
+
front: Object.freeze({ kind: 'front' }),
|
|
10
|
+
back: Object.freeze({ kind: 'back' }),
|
|
11
|
+
byId: (id) => Object.freeze({ kind: 'byId', id }),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
function configurationError(message) {
|
|
15
|
+
return Object.assign(new Error(message), {
|
|
16
|
+
code: SmartSpectraErrorCode.kConfigurationFailed, retryable: false,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalizeCameraSelection(selection) {
|
|
21
|
+
if (!selection || typeof selection !== 'object') {
|
|
22
|
+
throw configurationError('useCamera: expected a CameraSelection');
|
|
23
|
+
}
|
|
24
|
+
switch (selection.kind) {
|
|
25
|
+
case 'default': case 'front': case 'back':
|
|
26
|
+
if (selection.id !== undefined) throw configurationError('Camera ID requires byId selection');
|
|
27
|
+
return Object.freeze({ kind: selection.kind });
|
|
28
|
+
case 'byId':
|
|
29
|
+
if (typeof selection.id !== 'string' || !selection.id || selection.id.includes('\0')) {
|
|
30
|
+
throw configurationError('Camera ID must be a non-empty string without NUL characters');
|
|
31
|
+
}
|
|
32
|
+
return CameraSelection.byId(selection.id);
|
|
33
|
+
default: throw configurationError('Unknown camera selection kind');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function normalizeCameraOptions(options) {
|
|
38
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
39
|
+
throw configurationError('useCamera: expected capture options');
|
|
40
|
+
}
|
|
41
|
+
if ('deviceIndex' in options) throw configurationError('Use CameraSelection.byId(id) instead of deviceIndex');
|
|
42
|
+
const copy = {};
|
|
43
|
+
for (const field of ['width', 'height', 'fps', 'frameTransform']) {
|
|
44
|
+
const value = options[field] ?? 0;
|
|
45
|
+
const max = field === 'frameTransform' ? 5 : 2147483647;
|
|
46
|
+
if (!Number.isInteger(value) || value < 0 || value > max) {
|
|
47
|
+
throw configurationError(`Invalid camera ${field}`);
|
|
48
|
+
}
|
|
49
|
+
copy[field] = value;
|
|
50
|
+
}
|
|
51
|
+
if (Boolean(copy.width) !== Boolean(copy.height)) {
|
|
52
|
+
throw configurationError('Camera width and height must be specified together');
|
|
53
|
+
}
|
|
54
|
+
return Object.freeze(copy);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = { CameraSelection, normalizeCameraSelection, normalizeCameraOptions };
|
package/js/constants.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
//
|
|
4
4
|
// SPDX-License-Identifier: LicenseRef-Proprietary
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
6
|
+
// Public enums and metric bundles. No Node-only dependencies, so this module
|
|
7
|
+
// can be bundled into a browser renderer without dragging in koffi, fs, or
|
|
8
|
+
// path. MetricType is sourced from the generated protobuf module below.
|
|
9
9
|
//
|
|
10
10
|
// Integer values must match the SmartSpectra C++ headers and
|
|
11
11
|
// metric_types.proto wire values; stable across SDK versions.
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
'use strict';
|
|
16
16
|
|
|
17
|
+
const generatedMetricType = require('./messages/generated').presage.smartspectra.MetricType;
|
|
18
|
+
|
|
17
19
|
const ProcessingStatus = Object.freeze({
|
|
18
20
|
kUninitialized: 0,
|
|
19
21
|
kIdle: 1,
|
|
@@ -91,6 +93,12 @@ const FrameTransform = Object.freeze({
|
|
|
91
93
|
kMirrorVertical: 5,
|
|
92
94
|
});
|
|
93
95
|
|
|
96
|
+
// protobufjs enums include reverse numeric keys. Keep the existing public
|
|
97
|
+
// name-to-number-only shape while deriving every value from metric_types.proto.
|
|
98
|
+
const MetricType = Object.freeze(Object.fromEntries(
|
|
99
|
+
Object.entries(generatedMetricType).filter(([name]) => Number.isNaN(Number(name))),
|
|
100
|
+
));
|
|
101
|
+
|
|
94
102
|
// MetricType integer codes grouped by measurement type. Spread into
|
|
95
103
|
// `requestedMetrics`; omitting `requestedMetrics` is equivalent to passing
|
|
96
104
|
// `breathingMetrics`.
|
|
@@ -138,6 +146,7 @@ module.exports = {
|
|
|
138
146
|
ValidationCode,
|
|
139
147
|
SmartSpectraErrorCode,
|
|
140
148
|
FrameTransform,
|
|
149
|
+
MetricType,
|
|
141
150
|
breathingMetrics,
|
|
142
151
|
cardioMetrics,
|
|
143
152
|
faceMetrics,
|
package/js/ffi.js
CHANGED
|
@@ -27,6 +27,8 @@ const lib = koffi.load(resolveNativeLibrary());
|
|
|
27
27
|
|
|
28
28
|
// Opaque session token. C side: `struct smartspectra_session_s*`.
|
|
29
29
|
koffi.opaque('smartspectra_session_t');
|
|
30
|
+
koffi.opaque('smartspectra_camera_list_t');
|
|
31
|
+
koffi.struct('smartspectra_camera_info_t', { id: 'const char *', name: 'const char *', facing: 'int', lens_type: 'int' });
|
|
30
32
|
|
|
31
33
|
// smartspectra_error_t — keep field order identical to the C struct; koffi
|
|
32
34
|
// computes offsets by declaration order.
|
|
@@ -102,13 +104,6 @@ koffi.struct('smartspectra_file_options_t', {
|
|
|
102
104
|
max_duration_ms: 'int',
|
|
103
105
|
frame_transform: 'int',
|
|
104
106
|
});
|
|
105
|
-
koffi.struct('smartspectra_camera_options_t', {
|
|
106
|
-
device_index: 'int',
|
|
107
|
-
width: 'int',
|
|
108
|
-
height: 'int',
|
|
109
|
-
fps: 'int',
|
|
110
|
-
frame_transform: 'int',
|
|
111
|
-
});
|
|
112
107
|
|
|
113
108
|
// Non-blocking file source: configure + start, returns immediately. Caller
|
|
114
109
|
// blocks via sessionWait when it wants end-of-file.
|
|
@@ -117,10 +112,48 @@ const sessionStartFile = lib.func(
|
|
|
117
112
|
'const char *video_path, const char *timestamps_path, ' +
|
|
118
113
|
'const smartspectra_file_options_t *opts, _Out_ smartspectra_error_t *out_err)');
|
|
119
114
|
|
|
120
|
-
|
|
115
|
+
koffi.struct('smartspectra_camera_options_t', {
|
|
116
|
+
device_index: 'int', width: 'int', height: 'int', fps: 'int', frame_transform: 'int',
|
|
117
|
+
});
|
|
118
|
+
const sessionStartLegacyCamera = lib.func(
|
|
121
119
|
'int smartspectra_session_start_camera(smartspectra_session_t *sess, ' +
|
|
122
120
|
'const smartspectra_camera_options_t *opts, _Out_ smartspectra_error_t *out_err)');
|
|
123
121
|
|
|
122
|
+
koffi.struct('smartspectra_camera_capture_options_t', {
|
|
123
|
+
width: 'int', height: 'int', fps: 'int', frame_transform: 'int',
|
|
124
|
+
});
|
|
125
|
+
const sessionStartCamera = lib.func(
|
|
126
|
+
'int smartspectra_session_start_selected_camera(smartspectra_session_t *sess, ' +
|
|
127
|
+
'int selection_kind, const char *camera_id, const smartspectra_camera_capture_options_t *opts, ' +
|
|
128
|
+
'_Out_ smartspectra_error_t *out_err)');
|
|
129
|
+
const discoverCameras = lib.func('int smartspectra_available_cameras(' +
|
|
130
|
+
'_Out_ smartspectra_camera_list_t **out_list, _Out_ smartspectra_error_t *out_err)');
|
|
131
|
+
const cameraListSize = lib.func('size_t smartspectra_camera_list_size(const smartspectra_camera_list_t *list)');
|
|
132
|
+
const cameraListGet = lib.func('const smartspectra_camera_info_t *smartspectra_camera_list_get(' +
|
|
133
|
+
'const smartspectra_camera_list_t *list, size_t index)');
|
|
134
|
+
const cameraListFree = lib.func('void smartspectra_camera_list_free(smartspectra_camera_list_t *list)');
|
|
135
|
+
|
|
136
|
+
function availableCameras() {
|
|
137
|
+
const out = [null];
|
|
138
|
+
const error = {};
|
|
139
|
+
if (discoverCameras(out, error) !== 0) throw makeFfiError(error);
|
|
140
|
+
const list = out[0];
|
|
141
|
+
try {
|
|
142
|
+
const cameras = [];
|
|
143
|
+
const count = Number(cameraListSize(list));
|
|
144
|
+
for (let index = 0; index < count; index++) {
|
|
145
|
+
const camera = koffi.decode(cameraListGet(list, index), 'smartspectra_camera_info_t');
|
|
146
|
+
cameras.push({ id: camera.id, name: camera.name,
|
|
147
|
+
facing: camera.facing === 1 ? 'front' : camera.facing === 2 ? 'back' : 'unknown',
|
|
148
|
+
lensType: camera.lens_type === 1 ? 'wideAngle' : camera.lens_type === 2 ? 'ultraWide' :
|
|
149
|
+
camera.lens_type === 3 ? 'telephoto' : 'unknown' });
|
|
150
|
+
}
|
|
151
|
+
return cameras;
|
|
152
|
+
} finally {
|
|
153
|
+
cameraListFree(list);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
124
157
|
const sessionStartCustom = lib.func(
|
|
125
158
|
'int smartspectra_session_start_custom(smartspectra_session_t *sess, ' +
|
|
126
159
|
'int frame_transform, _Out_ smartspectra_error_t *out_err)');
|
|
@@ -343,8 +376,7 @@ class Session {
|
|
|
343
376
|
this._takeKeepAlive();
|
|
344
377
|
}
|
|
345
378
|
|
|
346
|
-
|
|
347
|
-
startCamera(options = null) {
|
|
379
|
+
startLegacyCamera(options = null) {
|
|
348
380
|
this._assertAlive();
|
|
349
381
|
const err = {};
|
|
350
382
|
const opts = options ? {
|
|
@@ -354,7 +386,23 @@ class Session {
|
|
|
354
386
|
fps: options.fps | 0,
|
|
355
387
|
frame_transform: options.frameTransform | 0,
|
|
356
388
|
} : null;
|
|
357
|
-
const rc =
|
|
389
|
+
const rc = sessionStartLegacyCamera(this._sess, opts, err);
|
|
390
|
+
if (rc !== 0) throw makeFfiError(err);
|
|
391
|
+
this._takeKeepAlive();
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Selection and capture settings are separate, matching the C++ API.
|
|
395
|
+
startCamera(selection, options = null) {
|
|
396
|
+
this._assertAlive();
|
|
397
|
+
const err = {};
|
|
398
|
+
const opts = options ? {
|
|
399
|
+
width: options.width | 0,
|
|
400
|
+
height: options.height | 0,
|
|
401
|
+
fps: options.fps | 0,
|
|
402
|
+
frame_transform: options.frameTransform | 0,
|
|
403
|
+
} : null;
|
|
404
|
+
const kind = { default: 0, front: 1, back: 2, byId: 3 }[selection.kind];
|
|
405
|
+
const rc = sessionStartCamera(this._sess, kind, selection.id ?? null, opts, err);
|
|
358
406
|
if (rc !== 0) throw makeFfiError(err);
|
|
359
407
|
this._takeKeepAlive();
|
|
360
408
|
}
|
|
@@ -416,8 +464,18 @@ class Session {
|
|
|
416
464
|
return sessionGetStatus(this._sess);
|
|
417
465
|
}
|
|
418
466
|
|
|
419
|
-
|
|
467
|
+
assertSourceSelectionAllowed() {
|
|
468
|
+
const status = this.getStatus();
|
|
469
|
+
if (this._destroyed || this._stopAsyncPromise || (status !== 0 && status !== 1)) {
|
|
470
|
+
throw Object.assign(new Error('Select an input while stopped'), { code: 1, retryable: false });
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
reset(requireStopSettled = false) {
|
|
420
475
|
this._assertAlive();
|
|
476
|
+
if (requireStopSettled && this._stopAsyncPromise) {
|
|
477
|
+
throw Object.assign(new Error('Await stopAsync before reset'), { code: 1, retryable: false });
|
|
478
|
+
}
|
|
421
479
|
const err = {};
|
|
422
480
|
const rc = sessionReset(this._sess, err);
|
|
423
481
|
if (rc !== 0) throw makeFfiError(err);
|
|
@@ -587,6 +645,7 @@ function ensurePreconfigured() {
|
|
|
587
645
|
|
|
588
646
|
module.exports = {
|
|
589
647
|
Session,
|
|
648
|
+
availableCameras,
|
|
590
649
|
preconfigure,
|
|
591
650
|
ensurePreconfigured,
|
|
592
651
|
};
|
package/js/index.d.ts
CHANGED
|
@@ -90,6 +90,31 @@ export declare const FrameTransform: {
|
|
|
90
90
|
};
|
|
91
91
|
export type FrameTransformValue = typeof FrameTransform[keyof typeof FrameTransform];
|
|
92
92
|
|
|
93
|
+
/** MetricType integer codes accepted by `requestedMetrics`. Runtime values are generated from protobuf. */
|
|
94
|
+
export declare const MetricType: {
|
|
95
|
+
readonly CHEST_BREATHING: 0;
|
|
96
|
+
readonly ABDOMEN_BREATHING: 1;
|
|
97
|
+
readonly BREATHING_RATE: 2;
|
|
98
|
+
readonly BREATHING_AMPLITUDE: 3;
|
|
99
|
+
readonly APNEA: 4;
|
|
100
|
+
readonly RESPIRATORY_LINE_LENGTH: 5;
|
|
101
|
+
readonly BASELINE: 6;
|
|
102
|
+
readonly INHALE_EXHALE_RATIO: 7;
|
|
103
|
+
readonly GLUTES_MICROMOTION: 8;
|
|
104
|
+
readonly KNEES_MICROMOTION: 9;
|
|
105
|
+
readonly EDA_TRACE: 10;
|
|
106
|
+
readonly FACE_LANDMARKS: 11;
|
|
107
|
+
readonly BLINKING: 12;
|
|
108
|
+
readonly TALKING: 13;
|
|
109
|
+
readonly EXPRESSIONS: 14;
|
|
110
|
+
readonly PULSE_RATE: 15;
|
|
111
|
+
readonly ARTERIAL_PRESSURE_TRACE: 16;
|
|
112
|
+
readonly HRV: 17;
|
|
113
|
+
readonly PULSE_RATE_STRICT: 18;
|
|
114
|
+
readonly BREATHING_RATE_STRICT: 19;
|
|
115
|
+
};
|
|
116
|
+
export type MetricTypeValue = typeof MetricType[keyof typeof MetricType];
|
|
117
|
+
|
|
93
118
|
/** Options passed to the SmartSpectra constructor. */
|
|
94
119
|
export interface SmartSpectraOptions {
|
|
95
120
|
/** API key for server-validated auth. */
|
|
@@ -127,9 +152,36 @@ export interface VideoFileOptions {
|
|
|
127
152
|
frameTransform?: FrameTransformValue;
|
|
128
153
|
}
|
|
129
154
|
|
|
130
|
-
/** Camera capture
|
|
155
|
+
/** Camera request resolved at capture startup. Explicit requests never fall back. */
|
|
156
|
+
export type CameraSelection =
|
|
157
|
+
| Readonly<{ kind: 'default' }>
|
|
158
|
+
| Readonly<{ kind: 'front' }>
|
|
159
|
+
| Readonly<{ kind: 'back' }>
|
|
160
|
+
| Readonly<{ kind: 'byId'; id: string }>;
|
|
161
|
+
|
|
162
|
+
export declare const CameraSelection: {
|
|
163
|
+
readonly default: Readonly<{ kind: 'default' }>;
|
|
164
|
+
readonly front: Readonly<{ kind: 'front' }>;
|
|
165
|
+
readonly back: Readonly<{ kind: 'back' }>;
|
|
166
|
+
readonly byId: (id: string) => Readonly<{ kind: 'byId'; id: string }>;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export type CameraFacing = 'front' | 'back' | 'unknown';
|
|
170
|
+
|
|
171
|
+
/** Best-effort classification. Missing metadata and multi-lens cameras are unknown; independent of digital zoom. */
|
|
172
|
+
export type CameraLensType = 'unknown' | 'wideAngle' | 'ultraWide' | 'telephoto';
|
|
173
|
+
|
|
174
|
+
/** Discovery snapshot. IDs are opaque and platform-local; rediscover before reuse. */
|
|
175
|
+
export interface CameraInfo {
|
|
176
|
+
readonly id: string;
|
|
177
|
+
readonly name: string | null;
|
|
178
|
+
readonly facing: CameraFacing;
|
|
179
|
+
readonly lensType: CameraLensType;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** Capture settings, separate from camera selection. */
|
|
131
183
|
export interface CameraOptions {
|
|
132
|
-
/**
|
|
184
|
+
/** @deprecated Use useCamera(CameraSelection.byId(id), options) instead. */
|
|
133
185
|
deviceIndex?: number;
|
|
134
186
|
/** Capture width in px; omit/0 = SDK default. */
|
|
135
187
|
width?: number;
|
|
@@ -163,15 +215,21 @@ export declare class SmartSpectraSDK {
|
|
|
163
215
|
/** SDK package version. */
|
|
164
216
|
static readonly version: string;
|
|
165
217
|
|
|
218
|
+
/** No SDK instance, authentication, or capture required. Throws when discovery is unsupported. */
|
|
219
|
+
static availableCameras(): CameraInfo[];
|
|
220
|
+
|
|
166
221
|
constructor(options?: SmartSpectraOptions);
|
|
167
222
|
|
|
168
|
-
/** Initialize and begin
|
|
223
|
+
/** Initialize and begin the input configured with useCamera, useCustomInput, or useFile. */
|
|
169
224
|
start(): void;
|
|
170
225
|
/** Request the session to stop. Idempotent. */
|
|
171
226
|
stop(): void;
|
|
172
227
|
/** Async variant of stop() — the native stop blocks until the pipeline drains; prefer this in event-loop-sensitive contexts. */
|
|
173
228
|
stopAsync(): Promise<void>;
|
|
174
|
-
/**
|
|
229
|
+
/**
|
|
230
|
+
* Rebuild after kError. Clears the source unless useCamera(selection, options) opted into retention.
|
|
231
|
+
* After typed selection, throws kInvalidState while stopAsync() is pending; await it before resetting.
|
|
232
|
+
*/
|
|
175
233
|
reset(): void;
|
|
176
234
|
/**
|
|
177
235
|
* Block until the session reaches a terminal state (idle or error), or the
|
|
@@ -211,6 +269,15 @@ export declare class SmartSpectraSDK {
|
|
|
211
269
|
* pumps frames internally on `start()` — no `sendFrame()` needed. Returns
|
|
212
270
|
* `this` for chaining. Captures in THIS process — for Electron, prefer
|
|
213
271
|
* the renderer SDK's `useMediaStream()`.
|
|
272
|
+
* Select while stopped; explicit requests never fall back. Selection is
|
|
273
|
+
* resolved at startup and retained across stop/start/reset. Invalid or busy
|
|
274
|
+
* requests preserve the previous source. Pass CameraSelection.default for SDK selection.
|
|
275
|
+
*/
|
|
276
|
+
useCamera(selection: CameraSelection, options?: Omit<CameraOptions, 'deviceIndex'>): this;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Select a camera by legacy index (default 0). Reset clears the source.
|
|
280
|
+
* @deprecated Pass an explicit CameraSelection and separate capture options instead.
|
|
214
281
|
*/
|
|
215
282
|
useCamera(options?: CameraOptions): this;
|
|
216
283
|
|
|
@@ -278,16 +345,6 @@ export declare class SmartSpectraSDK {
|
|
|
278
345
|
* MetricType integer codes grouped by measurement type. Spread into
|
|
279
346
|
* `requestedMetrics`; omitting it is equivalent to passing
|
|
280
347
|
* `breathingMetrics`.
|
|
281
|
-
*
|
|
282
|
-
* @example
|
|
283
|
-
* ```ts
|
|
284
|
-
* import { SmartSpectra, breathingMetrics, cardioMetrics } from '@smartspectra/node-sdk';
|
|
285
|
-
*
|
|
286
|
-
* const ss = new SmartSpectra({
|
|
287
|
-
* apiKey: 'YOUR_KEY',
|
|
288
|
-
* requestedMetrics: [...breathingMetrics, ...cardioMetrics],
|
|
289
|
-
* });
|
|
290
|
-
* ```
|
|
291
348
|
*/
|
|
292
349
|
export declare const breathingMetrics: readonly number[];
|
|
293
350
|
export declare const cardioMetrics: readonly number[];
|
package/js/index.js
CHANGED
|
@@ -7,12 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
const {
|
|
9
9
|
SmartSpectraSDK,
|
|
10
|
+
CameraSelection,
|
|
10
11
|
SmartSpectraLogLevel,
|
|
11
12
|
ProcessingStatus,
|
|
12
13
|
PixelFormat,
|
|
13
14
|
ValidationCode,
|
|
14
15
|
SmartSpectraErrorCode,
|
|
15
16
|
FrameTransform,
|
|
17
|
+
MetricType,
|
|
16
18
|
breathingMetrics,
|
|
17
19
|
cardioMetrics,
|
|
18
20
|
faceMetrics,
|
|
@@ -45,12 +47,14 @@ function decodeMetrics(buf) {
|
|
|
45
47
|
|
|
46
48
|
module.exports = {
|
|
47
49
|
SmartSpectraSDK,
|
|
50
|
+
CameraSelection,
|
|
48
51
|
SmartSpectraLogLevel,
|
|
49
52
|
ProcessingStatus,
|
|
50
53
|
PixelFormat,
|
|
51
54
|
ValidationCode,
|
|
52
55
|
SmartSpectraErrorCode,
|
|
53
56
|
FrameTransform,
|
|
57
|
+
MetricType,
|
|
54
58
|
breathingMetrics,
|
|
55
59
|
cardioMetrics,
|
|
56
60
|
faceMetrics,
|