@camstack/types 1.2.42 → 1.2.44
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/dist/addon.js +8 -2
- package/dist/addon.mjs +8 -2
- package/dist/cap-call-context.d.ts +26 -0
- package/dist/capabilities/index.d.ts +8 -5
- package/dist/capabilities/osd-manager.cap.d.ts +900 -0
- package/dist/capabilities/pipeline-analytics.cap.d.ts +171 -4
- package/dist/capabilities/pipeline-orchestrator.cap.d.ts +36 -0
- package/dist/capabilities/privacy-mask.cap.d.ts +69 -9
- package/dist/capabilities/recording.cap.d.ts +27 -0
- package/dist/capabilities/schemas/streaming-shared.d.ts +2 -0
- package/dist/capabilities/server-management.cap.d.ts +3 -3
- package/dist/capabilities/snapshot.cap.d.ts +1 -1
- package/dist/capabilities/stream-broker.cap.d.ts +36 -0
- package/dist/capabilities/stream-params.cap.d.ts +8 -4
- package/dist/device/device-profile.d.ts +12 -4
- package/dist/device/system-mirror.d.ts +11 -0
- package/dist/ffmpeg/encode-defaults.d.ts +18 -0
- package/dist/ffmpeg/fmp4-box-splitter.d.ts +113 -0
- package/dist/ffmpeg/fmp4-fragment-child.d.ts +85 -0
- package/dist/ffmpeg/fmp4-fragment-plane.d.ts +142 -0
- package/dist/ffmpeg/invocation.d.ts +102 -2
- package/dist/ffmpeg/sharing-key.d.ts +54 -2
- package/dist/fmp4-box-splitter-B53u9-Nu.mjs +615 -0
- package/dist/fmp4-box-splitter-BkWH7O3L.js +686 -0
- package/dist/generated/addon-api.d.ts +117 -0
- package/dist/generated/cap-input-defaults.d.ts +1 -1
- package/dist/generated/capability-router-map.d.ts +5 -2
- package/dist/generated/device-proxy.d.ts +4 -2
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/system-proxy.d.ts +2 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1264 -394
- package/dist/index.mjs +1217 -385
- package/dist/interfaces/camera-switches.d.ts +211 -5
- package/dist/interfaces/inference-engine.d.ts +24 -3
- package/dist/interfaces/stream-broker.d.ts +18 -0
- package/dist/node.d.ts +4 -0
- package/dist/node.js +509 -3
- package/dist/node.mjs +507 -3
- package/dist/notification/schedule.d.ts +20 -0
- package/dist/pipeline/native-lease.d.ts +150 -0
- package/dist/{sleep-BmNKsY7v.mjs → sleep-cC4Fuup8.mjs} +59 -3
- package/dist/{sleep-Cvi1JxZp.js → sleep-eiC10_cX.js} +64 -2
- package/dist/types/pipeline-step.d.ts +1 -1
- package/dist/utils/addon-id.d.ts +30 -0
- package/package.json +1 -1
- package/dist/canonical-hash-7nfBbEqR.mjs +0 -35
- package/dist/canonical-hash-BcZHRHIx.js +0 -40
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* ## This file adds no state
|
|
6
6
|
*
|
|
7
7
|
* Every switch here is a VIEW onto an authority that already existed
|
|
8
|
-
* ([
|
|
8
|
+
* ([D62](../../../../docs/decisions/adr-0062.md)). The whole point of the
|
|
9
9
|
* group is that there is exactly one place each function is turned off, and
|
|
10
10
|
* the group routes to it:
|
|
11
11
|
*
|
|
@@ -16,6 +16,53 @@
|
|
|
16
16
|
* | `audio-analysis` | `deviceManager.setWrapperActive('audio-analysis')` | `AudioSubscriptionController.subscribeAudioStream` returns `null` before opening the stream |
|
|
17
17
|
* | `recording` | `recording.setDeviceConfig` → `RecordingConfig.enabled` | `band-decision.shouldRecord` returns false; the controller detaches the device |
|
|
18
18
|
* | `notifications` | `notificationRules.setDeviceMuted` | `NotificationCenter.evaluateAndEnqueue` returns before any rule is evaluated |
|
|
19
|
+
* | `privacy-mask` | `privacyMask.setMask({ enabled })` → the CAMERA | the camera blanks the masked regions itself; every stream and recording carries the black boxes |
|
|
20
|
+
* | `device-audio` | `privacyMask.setAudioEnabled` → the CAMERA | the camera stops encoding an audio track at all; every consumer sees silent video |
|
|
21
|
+
* | `broker-audio` | `streamBroker.setDeviceAudioMute` → `DeviceOverride.audioMuted` | `StreamBroker.setAudioMuted` drops the audio plane at the source: no `type:'audio'` packet leaves `fanOutEncoded`, no RTP reaches the restreamer, and the restreamer serves the video-only SDP |
|
|
22
|
+
*
|
|
23
|
+
* ## `device-audio` and `broker-audio` are two functions, not two knobs
|
|
24
|
+
*
|
|
25
|
+
* They look adjacent and they are not the same control ([D83](../../../../docs/decisions/adr-0083.md)):
|
|
26
|
+
* `device-audio` writes the CAMERA, so it is hardware privacy — the microphone
|
|
27
|
+
* genuinely stops, it survives CamStack entirely, and it costs a multi-second
|
|
28
|
+
* encoder restart on every flip. `broker-audio` writes THIS server, so it is
|
|
29
|
+
* instant, vendor-independent and reversible without touching the camera, and
|
|
30
|
+
* a camera that ignores or lacks the ISAPI/Reolink control is still silenced.
|
|
31
|
+
* D62 forbids a second switch that *disagrees* with the first; these two
|
|
32
|
+
* cannot disagree, because neither reads the other's store — the camera holds
|
|
33
|
+
* one, the broker holds the other, and each reports its own fact.
|
|
34
|
+
*
|
|
35
|
+
* ## The two switches whose authority is not on this server
|
|
36
|
+
*
|
|
37
|
+
* `privacy-mask` and `device-audio` write the CAMERA. That is not a loophole
|
|
38
|
+
* in "the group stores nothing" — it is the purest form of it: the camera
|
|
39
|
+
* holds the fact, every read is a read-through, and there is no server-side
|
|
40
|
+
* copy that could drift. Their availability therefore cannot come from
|
|
41
|
+
* `listBindableCapsForDeviceType` (a device-NATIVE cap carries no wrappers and
|
|
42
|
+
* is filtered out there); it comes from the cap's own camera-probed
|
|
43
|
+
* `privacyMask.getOptions()`, which is strictly more honest — it answers for
|
|
44
|
+
* THIS camera rather than for the device type
|
|
45
|
+
* ([D74](../../../../docs/decisions/adr-0074.md)).
|
|
46
|
+
*
|
|
47
|
+
* ## `privacy-mask` is the one row whose ON is not "the function is working"
|
|
48
|
+
*
|
|
49
|
+
* Every other switch means *this camera's function is doing its job*, so
|
|
50
|
+
* `enabled: false` is a thing an operator took away. `privacy-mask` means **the
|
|
51
|
+
* MASK is active** — `enabled: true` is video deliberately obscured. The
|
|
52
|
+
* polarity is not a choice made here: `addon-export-hap`'s privacy `Switch`
|
|
53
|
+
* (`builders/privacy-switch.ts`) already mirrors `patch.enabled` verbatim, and
|
|
54
|
+
* a HomeKit toggle that disagreed with the app's toggle for the same camera is
|
|
55
|
+
* worse than either surface not having one.
|
|
56
|
+
*
|
|
57
|
+
* Two consequences follow and both are load-bearing:
|
|
58
|
+
*
|
|
59
|
+
* - **It never counts as `switchedOff`.** `countsAsSwitchedOff` is `false` for
|
|
60
|
+
* exactly this row. With the polarity above, every camera that has NOT drawn
|
|
61
|
+
* a privacy mask would otherwise report `switchedOff: ['privacy-mask']` — the
|
|
62
|
+
* normal, healthy state of most cameras rendered as an operator disablement.
|
|
63
|
+
* - **Its cost line names BOTH directions.** `costWhenOff` is rendered
|
|
64
|
+
* unconditionally by both clients, so for this row it has to read correctly
|
|
65
|
+
* whichever way the switch is sitting.
|
|
19
66
|
*
|
|
20
67
|
* The wrapper-binding pair is not a new idea: `legacy-migrations.ts` already
|
|
21
68
|
* migrated the legacy `audioEnabled` / `pipelineEnabled` /
|
|
@@ -35,20 +82,39 @@
|
|
|
35
82
|
*/
|
|
36
83
|
import { z } from 'zod';
|
|
37
84
|
/**
|
|
38
|
-
* The
|
|
39
|
-
*
|
|
85
|
+
* The functions the operator named — five on 2026-08-05, plus the camera's own
|
|
86
|
+
* microphone on 2026-08-07. Deliberately NOT one id per pipeline step: face
|
|
87
|
+
* recognition and plate/LPR are per-step toggles on
|
|
40
88
|
* `pipelineOrchestrator.setCameraStepToggle` and belong in the pipeline
|
|
41
|
-
* editor, not in a
|
|
89
|
+
* editor, not in a safety group.
|
|
42
90
|
*/
|
|
43
91
|
export declare const CameraSwitchIdSchema: z.ZodEnum<{
|
|
92
|
+
"privacy-mask": "privacy-mask";
|
|
44
93
|
"audio-analysis": "audio-analysis";
|
|
45
94
|
recording: "recording";
|
|
46
95
|
"stream-broker": "stream-broker";
|
|
47
96
|
notifications: "notifications";
|
|
48
97
|
"object-detection": "object-detection";
|
|
98
|
+
"device-audio": "device-audio";
|
|
99
|
+
"broker-audio": "broker-audio";
|
|
49
100
|
}>;
|
|
50
101
|
export type CameraSwitchId = z.infer<typeof CameraSwitchIdSchema>;
|
|
51
|
-
/**
|
|
102
|
+
/**
|
|
103
|
+
* Stable render order — broadest blast radius first, and a source before the
|
|
104
|
+
* thing that consumes it. `device-audio` sits ABOVE `audio-analysis` because
|
|
105
|
+
* turning the microphone off leaves the analyzer with nothing to analyse; the
|
|
106
|
+
* reverse is not true.
|
|
107
|
+
*
|
|
108
|
+
* `privacy-mask` sits directly ABOVE `device-audio` because they are literal
|
|
109
|
+
* siblings — one cap, one device plane, video then audio — and NOT above
|
|
110
|
+
* `object-detection` despite feeding it: a mask blanks REGIONS, so its blast
|
|
111
|
+
* radius is partial, and the "broadest first" rule does not rank a partial
|
|
112
|
+
* control above a whole-function one.
|
|
113
|
+
*
|
|
114
|
+
* `broker-audio` sits directly BELOW `device-audio` by the same source-first
|
|
115
|
+
* rule: the camera's microphone feeds the broker, so silencing the camera
|
|
116
|
+
* leaves the broker's mute with nothing to suppress; the reverse is not true.
|
|
117
|
+
*/
|
|
52
118
|
export declare const CAMERA_SWITCH_ORDER: readonly CameraSwitchId[];
|
|
53
119
|
/**
|
|
54
120
|
* WHERE the switch's state actually lives. A discriminated union rather than a
|
|
@@ -65,6 +131,14 @@ export declare const CameraSwitchAuthoritySchema: z.ZodDiscriminatedUnion<[z.Zod
|
|
|
65
131
|
kind: z.ZodLiteral<"recording-config">;
|
|
66
132
|
}, z.core.$strip>, z.ZodObject<{
|
|
67
133
|
kind: z.ZodLiteral<"notification-mute">;
|
|
134
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
135
|
+
kind: z.ZodLiteral<"camera-audio">;
|
|
136
|
+
capName: z.ZodString;
|
|
137
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
138
|
+
kind: z.ZodLiteral<"camera-mask">;
|
|
139
|
+
capName: z.ZodString;
|
|
140
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
141
|
+
kind: z.ZodLiteral<"broker-audio-mute">;
|
|
68
142
|
}, z.core.$strip>], "kind">;
|
|
69
143
|
export type CameraSwitchAuthority = z.infer<typeof CameraSwitchAuthoritySchema>;
|
|
70
144
|
/**
|
|
@@ -75,6 +149,7 @@ export type CameraSwitchAuthority = z.infer<typeof CameraSwitchAuthoritySchema>;
|
|
|
75
149
|
export declare const CameraSwitchUnavailableReasonSchema: z.ZodEnum<{
|
|
76
150
|
"no-provider": "no-provider";
|
|
77
151
|
"source-unreachable": "source-unreachable";
|
|
152
|
+
"not-configured": "not-configured";
|
|
78
153
|
}>;
|
|
79
154
|
export type CameraSwitchUnavailableReason = z.infer<typeof CameraSwitchUnavailableReasonSchema>;
|
|
80
155
|
/**
|
|
@@ -87,11 +162,14 @@ export type CameraSwitchUnavailableReason = z.infer<typeof CameraSwitchUnavailab
|
|
|
87
162
|
*/
|
|
88
163
|
export declare const CameraSwitchSchema: z.ZodObject<{
|
|
89
164
|
id: z.ZodEnum<{
|
|
165
|
+
"privacy-mask": "privacy-mask";
|
|
90
166
|
"audio-analysis": "audio-analysis";
|
|
91
167
|
recording: "recording";
|
|
92
168
|
"stream-broker": "stream-broker";
|
|
93
169
|
notifications: "notifications";
|
|
94
170
|
"object-detection": "object-detection";
|
|
171
|
+
"device-audio": "device-audio";
|
|
172
|
+
"broker-audio": "broker-audio";
|
|
95
173
|
}>;
|
|
96
174
|
label: z.ZodString;
|
|
97
175
|
costWhenOff: z.ZodString;
|
|
@@ -99,6 +177,7 @@ export declare const CameraSwitchSchema: z.ZodObject<{
|
|
|
99
177
|
unavailableReason: z.ZodOptional<z.ZodEnum<{
|
|
100
178
|
"no-provider": "no-provider";
|
|
101
179
|
"source-unreachable": "source-unreachable";
|
|
180
|
+
"not-configured": "not-configured";
|
|
102
181
|
}>>;
|
|
103
182
|
enabled: z.ZodBoolean;
|
|
104
183
|
authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -110,6 +189,14 @@ export declare const CameraSwitchSchema: z.ZodObject<{
|
|
|
110
189
|
kind: z.ZodLiteral<"recording-config">;
|
|
111
190
|
}, z.core.$strip>, z.ZodObject<{
|
|
112
191
|
kind: z.ZodLiteral<"notification-mute">;
|
|
192
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
193
|
+
kind: z.ZodLiteral<"camera-audio">;
|
|
194
|
+
capName: z.ZodString;
|
|
195
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
196
|
+
kind: z.ZodLiteral<"camera-mask">;
|
|
197
|
+
capName: z.ZodString;
|
|
198
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
199
|
+
kind: z.ZodLiteral<"broker-audio-mute">;
|
|
113
200
|
}, z.core.$strip>], "kind">;
|
|
114
201
|
}, z.core.$strip>;
|
|
115
202
|
export type CameraSwitch = z.infer<typeof CameraSwitchSchema>;
|
|
@@ -118,11 +205,14 @@ export declare const CameraSwitchGroupSchema: z.ZodObject<{
|
|
|
118
205
|
deviceId: z.ZodNumber;
|
|
119
206
|
switches: z.ZodReadonly<z.ZodArray<z.ZodObject<{
|
|
120
207
|
id: z.ZodEnum<{
|
|
208
|
+
"privacy-mask": "privacy-mask";
|
|
121
209
|
"audio-analysis": "audio-analysis";
|
|
122
210
|
recording: "recording";
|
|
123
211
|
"stream-broker": "stream-broker";
|
|
124
212
|
notifications: "notifications";
|
|
125
213
|
"object-detection": "object-detection";
|
|
214
|
+
"device-audio": "device-audio";
|
|
215
|
+
"broker-audio": "broker-audio";
|
|
126
216
|
}>;
|
|
127
217
|
label: z.ZodString;
|
|
128
218
|
costWhenOff: z.ZodString;
|
|
@@ -130,6 +220,7 @@ export declare const CameraSwitchGroupSchema: z.ZodObject<{
|
|
|
130
220
|
unavailableReason: z.ZodOptional<z.ZodEnum<{
|
|
131
221
|
"no-provider": "no-provider";
|
|
132
222
|
"source-unreachable": "source-unreachable";
|
|
223
|
+
"not-configured": "not-configured";
|
|
133
224
|
}>>;
|
|
134
225
|
enabled: z.ZodBoolean;
|
|
135
226
|
authority: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
@@ -141,6 +232,14 @@ export declare const CameraSwitchGroupSchema: z.ZodObject<{
|
|
|
141
232
|
kind: z.ZodLiteral<"recording-config">;
|
|
142
233
|
}, z.core.$strip>, z.ZodObject<{
|
|
143
234
|
kind: z.ZodLiteral<"notification-mute">;
|
|
235
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
236
|
+
kind: z.ZodLiteral<"camera-audio">;
|
|
237
|
+
capName: z.ZodString;
|
|
238
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
239
|
+
kind: z.ZodLiteral<"camera-mask">;
|
|
240
|
+
capName: z.ZodString;
|
|
241
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
242
|
+
kind: z.ZodLiteral<"broker-audio-mute">;
|
|
144
243
|
}, z.core.$strip>], "kind">;
|
|
145
244
|
}, z.core.$strip>>>;
|
|
146
245
|
fetchedAt: z.ZodNumber;
|
|
@@ -154,12 +253,32 @@ export type CameraSwitchGroup = z.infer<typeof CameraSwitchGroupSchema>;
|
|
|
154
253
|
*/
|
|
155
254
|
export declare const DETECTION_PIPELINE_CAP_NAME = "detection-pipeline";
|
|
156
255
|
export declare const AUDIO_ANALYSIS_CAP_NAME = "audio-analysis";
|
|
256
|
+
/**
|
|
257
|
+
* The device-NATIVE cap that owns what the camera does not capture — masked
|
|
258
|
+
* video regions and, since 2026-08-07, the microphone. Named here because the
|
|
259
|
+
* `camera-audio` authority, the orchestrator's gather and the fake harness all
|
|
260
|
+
* have to agree on it.
|
|
261
|
+
*/
|
|
262
|
+
export declare const PRIVACY_MASK_CAP_NAME = "privacy-mask";
|
|
157
263
|
/** Static half of a switch: everything that does not depend on a device. */
|
|
158
264
|
export interface CameraSwitchDescriptor {
|
|
159
265
|
readonly id: CameraSwitchId;
|
|
160
266
|
readonly label: string;
|
|
161
267
|
readonly costWhenOff: string;
|
|
162
268
|
readonly authority: CameraSwitchAuthority;
|
|
269
|
+
/**
|
|
270
|
+
* May `enabled: false` on this row appear in {@link switchedOffIds}?
|
|
271
|
+
*
|
|
272
|
+
* `true` for every switch that means "this camera's function is doing its
|
|
273
|
+
* job", where OFF is something a person took away and a status surface must
|
|
274
|
+
* render as disabled rather than broken.
|
|
275
|
+
*
|
|
276
|
+
* `false` for `privacy-mask` alone, and only because its polarity is
|
|
277
|
+
* inverted: OFF there means the mask is not obscuring anything, which is the
|
|
278
|
+
* ordinary state of nearly every camera. Reporting it would put a
|
|
279
|
+
* `switchedOff` badge on healthy cameras and drown the badge that matters.
|
|
280
|
+
*/
|
|
281
|
+
readonly countsAsSwitchedOff: boolean;
|
|
163
282
|
}
|
|
164
283
|
/**
|
|
165
284
|
* THE catalog. One entry per switch; the cost lines are the operator-facing
|
|
@@ -195,6 +314,87 @@ export interface CameraSwitchDerivationInput {
|
|
|
195
314
|
readonly recordingEnabled: boolean | null;
|
|
196
315
|
/** `notificationRules` per-camera mute; `null` when the cap did not answer. */
|
|
197
316
|
readonly notificationsMuted: boolean | null;
|
|
317
|
+
/**
|
|
318
|
+
* The camera's own microphone, read through the `privacy-mask` native cap.
|
|
319
|
+
* `null` = the cap is bound to this camera but did not answer.
|
|
320
|
+
*
|
|
321
|
+
* A camera with no `privacy-mask` provider at all is `{ supported: false }`,
|
|
322
|
+
* not `null` — "this camera has no such control" and "we could not read it"
|
|
323
|
+
* are different answers and the operator is shown different copy for each.
|
|
324
|
+
*/
|
|
325
|
+
readonly deviceAudio: DeviceAudioSwitchState | null;
|
|
326
|
+
/**
|
|
327
|
+
* The camera's own VIDEO privacy mask, read through the same `privacy-mask`
|
|
328
|
+
* native cap and the same pair of round trips as {@link deviceAudio} — one
|
|
329
|
+
* `getOptions` + one `getStatus` answer both, so the second switch is free.
|
|
330
|
+
*
|
|
331
|
+
* `null` = the cap is bound to this camera but did not answer.
|
|
332
|
+
*/
|
|
333
|
+
readonly privacyMask: PrivacyMaskSwitchState | null;
|
|
334
|
+
/**
|
|
335
|
+
* The BROKER's audio-plane policy for this camera, read from the
|
|
336
|
+
* stream-broker on the device's source-owner node. `null` = the broker did
|
|
337
|
+
* not answer, which renders no control rather than a control defaulted to
|
|
338
|
+
* "audio flows".
|
|
339
|
+
*/
|
|
340
|
+
readonly brokerAudio: BrokerAudioSwitchState | null;
|
|
341
|
+
}
|
|
342
|
+
/** What the stream-broker reported about its audio plane for one camera. */
|
|
343
|
+
export interface BrokerAudioSwitchState {
|
|
344
|
+
/**
|
|
345
|
+
* `DeviceOverride.audioMuted` — the broker's own persisted policy. `true`
|
|
346
|
+
* means the broker drops this camera's audio on every plane it serves.
|
|
347
|
+
*
|
|
348
|
+
* There is no `supported` companion, deliberately. Muting a camera that is
|
|
349
|
+
* currently silent is not a dead control: the policy governs what happens
|
|
350
|
+
* when sound DOES appear (a camera unmuted at the device, a stream that
|
|
351
|
+
* only carries audio at night), so it is meaningful to set in advance.
|
|
352
|
+
* That is the opposite of the privacy mask with zero zones, where flipping
|
|
353
|
+
* the master enable is provably a no-op until something else changes.
|
|
354
|
+
*/
|
|
355
|
+
readonly muted: boolean;
|
|
356
|
+
}
|
|
357
|
+
/** What the camera-probed audio switch reported for one camera. */
|
|
358
|
+
export interface DeviceAudioSwitchState {
|
|
359
|
+
/**
|
|
360
|
+
* `privacyMask.getOptions().supportsAudioMute` — camera-probed, never a
|
|
361
|
+
* device-type guess. A camera that does not expose the control renders no
|
|
362
|
+
* switch rather than a toggle that silently does nothing.
|
|
363
|
+
*/
|
|
364
|
+
readonly supported: boolean;
|
|
365
|
+
/**
|
|
366
|
+
* `privacyMask.getStatus().audioEnabled` — the camera's current answer.
|
|
367
|
+
* `null` when unsupported, or when supported but unreadable; the second
|
|
368
|
+
* case yields `source-unreachable`, never a control defaulted to "on".
|
|
369
|
+
*/
|
|
370
|
+
readonly enabled: boolean | null;
|
|
371
|
+
}
|
|
372
|
+
/** What the camera-probed VIDEO privacy mask reported for one camera. */
|
|
373
|
+
export interface PrivacyMaskSwitchState {
|
|
374
|
+
/**
|
|
375
|
+
* Can this camera store privacy zones at all? Derived from the probed
|
|
376
|
+
* `getOptions()`: `maxRegions > 0` AND at least one supported shape kind.
|
|
377
|
+
* Reolink answers `maxNum: 0` / `supportedShapes: []` honestly on models
|
|
378
|
+
* that cannot, and that must render no control rather than a toggle whose
|
|
379
|
+
* write the camera discards.
|
|
380
|
+
*/
|
|
381
|
+
readonly supported: boolean;
|
|
382
|
+
/**
|
|
383
|
+
* How many zones are actually drawn on the camera right now
|
|
384
|
+
* (`getStatus().regions.length`). `null` = supported, but the status could
|
|
385
|
+
* not be read.
|
|
386
|
+
*
|
|
387
|
+
* **Zero is not "off", it is "nothing to switch".** Toggling the master
|
|
388
|
+
* enable with no zones changes not one pixel — the dead control D62 exists
|
|
389
|
+
* to remove — so it resolves to `not-configured`, which tells the operator
|
|
390
|
+
* to go and draw one instead of leaving them pressing a button.
|
|
391
|
+
*/
|
|
392
|
+
readonly configuredRegions: number | null;
|
|
393
|
+
/**
|
|
394
|
+
* `getStatus().enabled` — the camera's master mask flag, `true` when the
|
|
395
|
+
* zones are being blanked. `null` when unreadable; never defaulted.
|
|
396
|
+
*/
|
|
397
|
+
readonly enabled: boolean | null;
|
|
198
398
|
}
|
|
199
399
|
/**
|
|
200
400
|
* Pure derivation of the whole group. No I/O — the orchestrator gathers, this
|
|
@@ -213,5 +413,11 @@ export declare function deriveCameraSwitches(input: CameraSwitchDerivationInput)
|
|
|
213
413
|
* `switchedOff: ['object-detection']` was turned off; the same camera with an
|
|
214
414
|
* empty list is broken. Unavailable switches never appear — a function nobody
|
|
215
415
|
* provides was not switched off by anyone.
|
|
416
|
+
*
|
|
417
|
+
* `privacy-mask` never appears either, whichever way it is sitting, because its
|
|
418
|
+
* ON means "the mask is active" rather than "the function works"
|
|
419
|
+
* ({@link CameraSwitchDescriptor.countsAsSwitchedOff}). Without that filter the
|
|
420
|
+
* ordinary state of every camera nobody has masked would carry a
|
|
421
|
+
* "switched off" badge, and the badge that matters would be lost in it.
|
|
216
422
|
*/
|
|
217
423
|
export declare function switchedOffIds(switches: readonly CameraSwitch[]): readonly CameraSwitchId[];
|
|
@@ -16,16 +16,36 @@ import type { RawFrameFormat } from '../types/io.js';
|
|
|
16
16
|
* raw buffer to JPEG internally rather than throwing — `infer()` must
|
|
17
17
|
* always succeed for either kind.
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Fields every `InferenceInput` variant carries regardless of pixel transport.
|
|
21
|
+
*/
|
|
22
|
+
interface InferenceInputCommon {
|
|
23
|
+
/**
|
|
24
|
+
* The camera this frame belongs to — **diagnostic only**. It changes no
|
|
25
|
+
* dispatch decision, no deadline and no shed rule; it exists so an inference
|
|
26
|
+
* failure inside a SHARED pool can name the camera that paid for it.
|
|
27
|
+
*
|
|
28
|
+
* A `SharedInferencePool` serves every camera on its
|
|
29
|
+
* `(node, runtime, device)`, so its `inference request timed out` and
|
|
30
|
+
* `worker saturated` lines could describe the pool and nothing else — and
|
|
31
|
+
* "why is 617 worse than 615?" is the question those lines always get asked.
|
|
32
|
+
*
|
|
33
|
+
* Omitted by callers with no camera (commands, model loads, the benchmark);
|
|
34
|
+
* the failure line then carries no `deviceId` tag rather than a fabricated
|
|
35
|
+
* one.
|
|
36
|
+
*/
|
|
37
|
+
readonly deviceId?: number;
|
|
38
|
+
}
|
|
39
|
+
export type InferenceInput = ({
|
|
20
40
|
readonly kind: 'jpeg';
|
|
21
41
|
readonly data: Buffer;
|
|
22
|
-
} | {
|
|
42
|
+
} & InferenceInputCommon) | ({
|
|
23
43
|
readonly kind: 'raw';
|
|
24
44
|
readonly data: Buffer;
|
|
25
45
|
readonly width: number;
|
|
26
46
|
readonly height: number;
|
|
27
47
|
readonly format: RawFrameFormat;
|
|
28
|
-
};
|
|
48
|
+
} & InferenceInputCommon);
|
|
29
49
|
export interface IInferenceEngine {
|
|
30
50
|
readonly runtime: DetectionRuntime;
|
|
31
51
|
readonly device: DetectionDevice;
|
|
@@ -34,3 +54,4 @@ export interface IInferenceEngine {
|
|
|
34
54
|
run?(input: Float32Array, inputShape: readonly number[]): Promise<Float32Array>;
|
|
35
55
|
dispose(): Promise<void>;
|
|
36
56
|
}
|
|
57
|
+
export {};
|
|
@@ -208,6 +208,24 @@ export interface BrokerStats {
|
|
|
208
208
|
readonly channels: number;
|
|
209
209
|
readonly supported: boolean;
|
|
210
210
|
} | null;
|
|
211
|
+
/**
|
|
212
|
+
* BROKER-SIDE AUDIO MUTE ([D83](../../../../docs/decisions/adr-0083.md)).
|
|
213
|
+
* `true` = this broker is deliberately distributing none of the device's
|
|
214
|
+
* audio, live or recorded. It is what tells a silent camera apart from a
|
|
215
|
+
* broken one on the stream panel: a broker holding an `audio` descriptor
|
|
216
|
+
* with `audioMuted: true` is doing exactly what it was asked.
|
|
217
|
+
*
|
|
218
|
+
* `audioMutedDropped` counts the audio units the mute threw away since the
|
|
219
|
+
* current dial — the proof the mute is on the packet path and not merely
|
|
220
|
+
* persisted.
|
|
221
|
+
*
|
|
222
|
+
* NOTE: this interface is the hand-written twin of `BrokerStatsSchema` in
|
|
223
|
+
* `capabilities/schemas/streaming-shared.ts`. They are not generated from
|
|
224
|
+
* each other; a field added to one and not the other compiles and then
|
|
225
|
+
* silently disappears on the wire.
|
|
226
|
+
*/
|
|
227
|
+
readonly audioMuted?: boolean;
|
|
228
|
+
readonly audioMutedDropped?: number;
|
|
211
229
|
}
|
|
212
230
|
export interface IStreamBroker {
|
|
213
231
|
readonly deviceId: string;
|
package/dist/node.d.ts
CHANGED
|
@@ -8,3 +8,7 @@ export { canonicalDeviceFingerprint, diffExportTargets, resolveExportFingerprint
|
|
|
8
8
|
export type { DeviceExportShape, ExportDelta, ExportTargetEntry, } from './utils/export-reconciler.js';
|
|
9
9
|
export { FfmpegProcess } from './ffmpeg/process.js';
|
|
10
10
|
export type { FfmpegProcessOptions, FfmpegExit, FfmpegExitClass } from './ffmpeg/process.js';
|
|
11
|
+
export { Fmp4FragmentPlane } from './ffmpeg/fmp4-fragment-plane.js';
|
|
12
|
+
export type { Fmp4CloseReason, Fmp4Packet, Fmp4PrebufferOptions, Fmp4PrebufferStats, Fmp4SubscribeInput, Fmp4SubscriberInfo, Fmp4Subscription, } from './ffmpeg/fmp4-fragment-plane.js';
|
|
13
|
+
export { Fmp4FragmentChild } from './ffmpeg/fmp4-fragment-child.js';
|
|
14
|
+
export type { Fmp4FragmentChildArgs, Fmp4FragmentChildDeps, } from './ffmpeg/fmp4-fragment-child.js';
|