@smartspectra/node-sdk 3.4.0 → 3.5.0-rc.2

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 CHANGED
@@ -263,6 +263,20 @@ once the graph reports `Running`. Call `sdk.useMediaStream(stream)` before
263
263
  are managed by the host; SDK-acquired streams are released on
264
264
  `stop()` / `reset()` / `destroy()`.
265
265
 
266
+ For a camera mounted sideways or upside down, pass a `FrameTransform` with the
267
+ stream:
268
+
269
+ ```ts
270
+ import { FrameTransform } from '@smartspectra/node-sdk/renderer';
271
+ sdk.useMediaStream(stream, { frameTransform: FrameTransform.kRotate90CW });
272
+ ```
273
+
274
+ The default is `FrameTransform.kNone`. The SDK rotates or mirrors each frame
275
+ before processing from the next `start()`; your preview element is not
276
+ transformed. The selected transform survives `stop()` / `start()` and `reset()`.
277
+ Each `useMediaStream()` call replaces the previous transform, so pass it again
278
+ when you swap streams.
279
+
266
280
  The renderer uses `MediaStreamTrackProcessor` + `OffscreenCanvas` to
267
281
  extract RGBA pixels and ships each frame to the main process via the
268
282
  MessagePort. Graph callbacks flow back through the same port.
@@ -4,6 +4,7 @@
4
4
  // SPDX-License-Identifier: LicenseRef-Proprietary
5
5
 
6
6
  import type {
7
+ FrameTransformValue,
7
8
  ProcessingStatusValue,
8
9
  ValidationCodeValue,
9
10
  SmartSpectraErrorCodeValue,
@@ -52,6 +53,18 @@ export interface RendererSmartSpectraOptions extends SmartSpectraOptions {
52
53
  sendTimeoutMs?: number;
53
54
  }
54
55
 
56
+ /** Options for `useMediaStream()`. */
57
+ export interface MediaStreamOptions {
58
+ /**
59
+ * Spatial transform the SDK applies to every frame before processing,
60
+ * e.g. `FrameTransform.kRotate90CW` for a camera mounted sideways.
61
+ * Takes effect on the next `start()`; the host's preview is not
62
+ * transformed. Defaults to `FrameTransform.kNone`; each
63
+ * `useMediaStream()` call replaces the previous transform.
64
+ */
65
+ frameTransform?: FrameTransformValue;
66
+ }
67
+
55
68
  /**
56
69
  * Renderer-side `SmartSpectraSDK` for Electron applications. By default
57
70
  * the SDK acquires the host's front-facing camera at 1280x720 / 30 fps,
@@ -100,9 +113,10 @@ export declare class SmartSpectraSDK {
100
113
  * acquires its own MediaStream with sensible defaults and emits it via
101
114
  * the `'streamAvailable'` event. When the host supplies the stream
102
115
  * the host also owns its lifecycle; the SDK never stops the original
103
- * tracks.
116
+ * tracks. Throws an `Error` with `code` `kConfigurationFailed` when
117
+ * `options.frameTransform` is not a `FrameTransform` value.
104
118
  */
105
- useMediaStream(stream: MediaStream): this;
119
+ useMediaStream(stream: MediaStream, options?: MediaStreamOptions): this;
106
120
 
107
121
  /**
108
122
  * Begin processing. If no stream was provided via `useMediaStream()`,
@@ -16,6 +16,9 @@
16
16
  'use strict';
17
17
 
18
18
  const { FrameTimestampAnchor } = require('./timestamp');
19
+ const { FrameTransform, SmartSpectraErrorCode } = require('../constants');
20
+
21
+ const FRAME_TRANSFORM_VALUES = new Set(Object.values(FrameTransform));
19
22
 
20
23
  const SUPPORTED_EVENTS = new Set([
21
24
  'processingStatus',
@@ -109,6 +112,8 @@ class SmartSpectraSDK {
109
112
  // false when the host supplied the stream via useMediaStream() —
110
113
  // the host owns the lifecycle in that case.
111
114
  this._streamOwned = false;
115
+ // Applied by the main-process SDK to every frame; sent with `start`.
116
+ this._frameTransform = FrameTransform.kNone;
112
117
  this._track = null;
113
118
  this._processor = null;
114
119
  this._reader = null;
@@ -174,13 +179,30 @@ class SmartSpectraSDK {
174
179
  *
175
180
  * When the host supplies the stream the host also owns its lifecycle —
176
181
  * the SDK never stops the original tracks, only its own internal clone.
182
+ *
183
+ * `options.frameTransform` (a `FrameTransform` value, default `kNone`)
184
+ * rotates or mirrors every frame before processing, e.g. for a camera
185
+ * mounted sideways. It takes effect on the next `start()`; the host
186
+ * preview is not transformed. Each call replaces the previous stream and
187
+ * transform, so pass `frameTransform` again when swapping streams.
188
+ *
189
+ * @param {MediaStream} stream
190
+ * @param {Object} [options]
191
+ * @param {number} [options.frameTransform=FrameTransform.kNone]
177
192
  */
178
- useMediaStream(stream) {
193
+ useMediaStream(stream, options) {
179
194
  if (!(stream instanceof MediaStream)) {
180
195
  throw new TypeError('useMediaStream: argument must be a MediaStream');
181
196
  }
197
+ const frameTransform = options?.frameTransform ?? FrameTransform.kNone;
198
+ if (!FRAME_TRANSFORM_VALUES.has(frameTransform)) {
199
+ throw Object.assign(
200
+ new Error('useMediaStream: frameTransform must be a FrameTransform value'),
201
+ { code: SmartSpectraErrorCode.kConfigurationFailed, retryable: false });
202
+ }
182
203
  this._stream = stream;
183
204
  this._streamOwned = false;
205
+ this._frameTransform = frameTransform;
184
206
  return this;
185
207
  }
186
208
 
@@ -237,7 +259,7 @@ class SmartSpectraSDK {
237
259
  // and drained once the loop starts below.
238
260
 
239
261
  try {
240
- await this._send({ kind: 'start', frameTransform: 0 });
262
+ await this._send({ kind: 'start', frameTransform: this._frameTransform });
241
263
  } catch (err) {
242
264
  // _stopFrameLoop is idempotent: cleans up reader/track even if the
243
265
  // loop was never started.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartspectra/node-sdk",
3
- "version": "3.4.0",
3
+ "version": "3.5.0-rc.2",
4
4
  "description": "Node.js (Electron) FFI binding for SmartSpectra vitals measurement",
5
5
  "author": "Presage Technologies, Inc.",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -40,8 +40,8 @@
40
40
  "scripts": {
41
41
  "prepare": "node scripts/gen-proto.cjs",
42
42
  "build:proto": "node scripts/gen-proto.cjs",
43
- "test": "npm run test:types && node --test test/log-level-pin.js test/renderer-timestamp.js test/camera-selection.js test/reset-lifecycle.js test/smoke.js",
44
- "test:types": "tsc --noEmit --strict --skipLibCheck --target es2022 --module nodenext test/camera-selection-types.ts",
43
+ "test": "npm run test:types && node --test test/log-level-pin.js test/renderer-timestamp.js test/renderer-frame-transform.js test/camera-selection.js test/reset-lifecycle.js test/smoke.js",
44
+ "test:types": "tsc --noEmit --strict --skipLibCheck --target es2022 --module nodenext test/camera-selection-types.ts test/renderer-types.ts",
45
45
  "test:models-allowlist": "node test/models-allowlist.js"
46
46
  },
47
47
  "keywords": [
@@ -71,10 +71,10 @@
71
71
  "dependencies": {
72
72
  "koffi": "^2.10.0",
73
73
  "protobufjs": "^7.6.5",
74
- "@smartspectra/node-sdk-linux-x64": "3.4.0",
75
- "@smartspectra/node-sdk-linux-arm64": "3.4.0",
76
- "@smartspectra/node-sdk-darwin-arm64": "3.4.0",
77
- "@smartspectra/node-sdk-win32-x64": "3.4.0"
74
+ "@smartspectra/node-sdk-linux-x64": "3.5.0-rc.2",
75
+ "@smartspectra/node-sdk-linux-arm64": "3.5.0-rc.2",
76
+ "@smartspectra/node-sdk-darwin-arm64": "3.5.0-rc.2",
77
+ "@smartspectra/node-sdk-win32-x64": "3.5.0-rc.2"
78
78
  },
79
79
  "devDependencies": {
80
80
  "@types/node": "^24.0.0",