@camstack/addon-pipeline 1.2.245 → 1.2.247
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/audio-analyzer/index.js +2 -2
- package/dist/audio-analyzer/index.mjs +2 -2
- package/dist/{default-detection-model-DLFtoi4W.js → default-detection-model-ClJ9y701.js} +42 -1
- package/dist/{default-detection-model-UXQCoRj_.mjs → default-detection-model-pr2NMNpc.mjs} +31 -2
- package/dist/detection-pipeline/index.js +5 -16
- package/dist/detection-pipeline/index.mjs +5 -16
- package/dist/{dist-CWWQf3ci.js → dist-BjiM0e6J.js} +48 -8
- package/dist/{dist-CoZwNgzu.mjs → dist-Dzy3wAmT.mjs} +48 -8
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-Uh59Eo57.mjs → node-D9DBz5HF.mjs} +1 -1
- package/dist/{node-DLZWItaN.js → node-P2-C_t7H.js} +1 -1
- package/dist/pipeline-runner/index.js +45 -30
- package/dist/pipeline-runner/index.mjs +45 -30
- package/dist/{process-memory-BnFnR_nP.mjs → process-memory-BMpJ42op.mjs} +1 -1
- package/dist/{process-memory-Bv9SiLn-.js → process-memory-vWz15IrS.js} +1 -1
- package/dist/recorder/index.js +2 -9
- package/dist/recorder/index.mjs +2 -9
- package/dist/{segment-demux-js-7DukFIT6.mjs → segment-demux-js-DcF7tvrn.mjs} +1 -1
- package/dist/{segment-demux-js-C6B53KjT.js → segment-demux-js-Dd5asWZc.js} +1 -1
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-B20FCUk4.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-vEbg16EK.mjs} +3 -3
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-DCTAdB0n.mjs → hostInit-D1dVvyjN.mjs} +3 -3
- package/dist/stream-broker/index.js +69 -8
- package/dist/stream-broker/index.mjs +69 -8
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +1 -1
|
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_process_memory = require("../process-memory-
|
|
6
|
+
const require_dist = require("../dist-BjiM0e6J.js");
|
|
7
|
+
const require_process_memory = require("../process-memory-vWz15IrS.js");
|
|
8
8
|
let node_fs = require("node:fs");
|
|
9
9
|
node_fs = require_chunk.__toESM(node_fs);
|
|
10
10
|
let node_path = require("node:path");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { $t as hydrateSchema, Jt as audioChunkBytesPerSample, Lt as errMsg, N as audioAnalysisCapability, Ot as resolvePoolMemoryPolicy, P as audioAnalyzerCapability, Qt as expandAudioChunkToF32le, Wt as BaseAddon, bn as EventCategory, n as AUDIO_BACKEND_CHOICES, ot as mapAudioLabelToMacro, rn as nodePin, s as DEFAULT_AUDIO_ANALYZER_CONFIG, w as PoolMemoryWatchdog, y as HF_BASE_URL } from "../dist-
|
|
3
|
-
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-
|
|
2
|
+
import { $t as hydrateSchema, Jt as audioChunkBytesPerSample, Lt as errMsg, N as audioAnalysisCapability, Ot as resolvePoolMemoryPolicy, P as audioAnalyzerCapability, Qt as expandAudioChunkToF32le, Wt as BaseAddon, bn as EventCategory, n as AUDIO_BACKEND_CHOICES, ot as mapAudioLabelToMacro, rn as nodePin, s as DEFAULT_AUDIO_ANALYZER_CONFIG, w as PoolMemoryWatchdog, y as HF_BASE_URL } from "../dist-Dzy3wAmT.mjs";
|
|
3
|
+
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BMpJ42op.mjs";
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
5
|
import * as path$1 from "node:path";
|
|
6
6
|
import { downloadFile } from "@camstack/system/addon-utils";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_dist = require("./dist-
|
|
1
|
+
const require_dist = require("./dist-BjiM0e6J.js");
|
|
2
2
|
let node_crypto = require("node:crypto");
|
|
3
3
|
//#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
|
|
4
4
|
/**
|
|
@@ -2114,6 +2114,35 @@ var localFrameRegistry = new LocalFrameRegistry({
|
|
|
2114
2114
|
maxBytes: envPositiveInt("CAMSTACK_LOCAL_FRAME_BUDGET_MB", DEFAULT_MAX_BYTES / 1048576) * 1048576
|
|
2115
2115
|
});
|
|
2116
2116
|
//#endregion
|
|
2117
|
+
//#region src/detection-pipeline/pipeline/macro-gate.ts
|
|
2118
|
+
function capitalize(s) {
|
|
2119
|
+
if (s.length === 0) return s;
|
|
2120
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
2121
|
+
}
|
|
2122
|
+
/** Apply the operator's class list and per-macro confidence floor. */
|
|
2123
|
+
function macroGateVerdict(macroClass, score, settings) {
|
|
2124
|
+
if (!settings) return "pass";
|
|
2125
|
+
const enabled = settings["enabledMacroClasses"];
|
|
2126
|
+
if (Array.isArray(enabled) && enabled.length > 0) {
|
|
2127
|
+
if (!enabled.includes(macroClass)) return "class-filter";
|
|
2128
|
+
}
|
|
2129
|
+
const perMacroThreshold = settings[`minConfidence${capitalize(macroClass)}`];
|
|
2130
|
+
if (typeof perMacroThreshold === "number" && score < perMacroThreshold) return "below-threshold";
|
|
2131
|
+
return "pass";
|
|
2132
|
+
}
|
|
2133
|
+
/**
|
|
2134
|
+
* The operator's gate, read off the ROOT step.
|
|
2135
|
+
*
|
|
2136
|
+
* The root is the first ENABLED step — the same one `executor.ts` picks
|
|
2137
|
+
* (`enabledSteps[0]`) — because that is the step whose settings the device
|
|
2138
|
+
* UI writes `enabledMacroClasses` and `minConfidence<Macro>` into. `undefined`
|
|
2139
|
+
* when there is no enabled step or it carries no settings, which the gate
|
|
2140
|
+
* itself reads as "pass everything": an absent gate must never mute a camera.
|
|
2141
|
+
*/
|
|
2142
|
+
function rootObjectGate(steps) {
|
|
2143
|
+
return (steps?.find((s) => s.enabled !== false))?.settings;
|
|
2144
|
+
}
|
|
2145
|
+
//#endregion
|
|
2117
2146
|
//#region src/detection-pipeline/default-detection-model.ts
|
|
2118
2147
|
/** The object-detection step id — the only slot this resolver applies to. */
|
|
2119
2148
|
var OBJECT_DETECTION_STEP_ID = "object-detection";
|
|
@@ -2244,6 +2273,12 @@ Object.defineProperty(exports, "localFrameRegistry", {
|
|
|
2244
2273
|
return localFrameRegistry;
|
|
2245
2274
|
}
|
|
2246
2275
|
});
|
|
2276
|
+
Object.defineProperty(exports, "macroGateVerdict", {
|
|
2277
|
+
enumerable: true,
|
|
2278
|
+
get: function() {
|
|
2279
|
+
return macroGateVerdict;
|
|
2280
|
+
}
|
|
2281
|
+
});
|
|
2247
2282
|
Object.defineProperty(exports, "resolveDefaultDetectionModel", {
|
|
2248
2283
|
enumerable: true,
|
|
2249
2284
|
get: function() {
|
|
@@ -2262,3 +2297,9 @@ Object.defineProperty(exports, "resolveModelForFormat", {
|
|
|
2262
2297
|
return resolveModelForFormat;
|
|
2263
2298
|
}
|
|
2264
2299
|
});
|
|
2300
|
+
Object.defineProperty(exports, "rootObjectGate", {
|
|
2301
|
+
enumerable: true,
|
|
2302
|
+
get: function() {
|
|
2303
|
+
return rootObjectGate;
|
|
2304
|
+
}
|
|
2305
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { F as audioKindId, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS, tt as hfModelUrl } from "./dist-
|
|
1
|
+
import { F as audioKindId, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS, tt as hfModelUrl } from "./dist-Dzy3wAmT.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
//#region src/detection-pipeline/pipeline/landmark-precision-gate.ts
|
|
4
4
|
/**
|
|
@@ -2114,6 +2114,35 @@ var localFrameRegistry = new LocalFrameRegistry({
|
|
|
2114
2114
|
maxBytes: envPositiveInt("CAMSTACK_LOCAL_FRAME_BUDGET_MB", DEFAULT_MAX_BYTES / 1048576) * 1048576
|
|
2115
2115
|
});
|
|
2116
2116
|
//#endregion
|
|
2117
|
+
//#region src/detection-pipeline/pipeline/macro-gate.ts
|
|
2118
|
+
function capitalize(s) {
|
|
2119
|
+
if (s.length === 0) return s;
|
|
2120
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
2121
|
+
}
|
|
2122
|
+
/** Apply the operator's class list and per-macro confidence floor. */
|
|
2123
|
+
function macroGateVerdict(macroClass, score, settings) {
|
|
2124
|
+
if (!settings) return "pass";
|
|
2125
|
+
const enabled = settings["enabledMacroClasses"];
|
|
2126
|
+
if (Array.isArray(enabled) && enabled.length > 0) {
|
|
2127
|
+
if (!enabled.includes(macroClass)) return "class-filter";
|
|
2128
|
+
}
|
|
2129
|
+
const perMacroThreshold = settings[`minConfidence${capitalize(macroClass)}`];
|
|
2130
|
+
if (typeof perMacroThreshold === "number" && score < perMacroThreshold) return "below-threshold";
|
|
2131
|
+
return "pass";
|
|
2132
|
+
}
|
|
2133
|
+
/**
|
|
2134
|
+
* The operator's gate, read off the ROOT step.
|
|
2135
|
+
*
|
|
2136
|
+
* The root is the first ENABLED step — the same one `executor.ts` picks
|
|
2137
|
+
* (`enabledSteps[0]`) — because that is the step whose settings the device
|
|
2138
|
+
* UI writes `enabledMacroClasses` and `minConfidence<Macro>` into. `undefined`
|
|
2139
|
+
* when there is no enabled step or it carries no settings, which the gate
|
|
2140
|
+
* itself reads as "pass everything": an absent gate must never mute a camera.
|
|
2141
|
+
*/
|
|
2142
|
+
function rootObjectGate(steps) {
|
|
2143
|
+
return (steps?.find((s) => s.enabled !== false))?.settings;
|
|
2144
|
+
}
|
|
2145
|
+
//#endregion
|
|
2117
2146
|
//#region src/detection-pipeline/default-detection-model.ts
|
|
2118
2147
|
/** The object-detection step id — the only slot this resolver applies to. */
|
|
2119
2148
|
var OBJECT_DETECTION_STEP_ID = "object-detection";
|
|
@@ -2196,4 +2225,4 @@ function resolveDefaultDetectionModel(backend, device, format, getStepDef = getS
|
|
|
2196
2225
|
return getDefaultModelForFormatFromDef(def, format);
|
|
2197
2226
|
}
|
|
2198
2227
|
//#endregion
|
|
2199
|
-
export {
|
|
2228
|
+
export { localFrameRegistry as a, ALL_STEPS as c, getStepDefinition as d, resolveModelForFormat as f, rootObjectGate as i, getDefaultModelForFormat as l, resolveDefaultDetectionModel as n, resolveFrameViewGeometry as o, landmarkPrecisionVerdict as p, macroGateVerdict as r, ALL_PIPELINE_STEPS as s, OBJECT_DETECTION_STEP_ID as t, getStep as u };
|
|
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_node = require("../node-
|
|
8
|
-
const require_default_detection_model = require("../default-detection-model-
|
|
6
|
+
const require_dist = require("../dist-BjiM0e6J.js");
|
|
7
|
+
const require_node = require("../node-P2-C_t7H.js");
|
|
8
|
+
const require_default_detection_model = require("../default-detection-model-ClJ9y701.js");
|
|
9
9
|
const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
|
|
10
|
-
const require_process_memory = require("../process-memory-
|
|
10
|
+
const require_process_memory = require("../process-memory-vWz15IrS.js");
|
|
11
11
|
let node_os = require("node:os");
|
|
12
12
|
node_os = require_chunk.__toESM(node_os);
|
|
13
13
|
let node_fs = require("node:fs");
|
|
@@ -5891,20 +5891,9 @@ var PipelineExecutor = class {
|
|
|
5891
5891
|
* - `minConfidence<Macro>`: number (e.g. `minConfidencePerson: 0.5`)
|
|
5892
5892
|
*/
|
|
5893
5893
|
macroFilterVerdict(macroClass, score, settings) {
|
|
5894
|
-
|
|
5895
|
-
const enabled = settings["enabledMacroClasses"];
|
|
5896
|
-
if (Array.isArray(enabled) && enabled.length > 0) {
|
|
5897
|
-
if (!enabled.includes(macroClass)) return "class-filter";
|
|
5898
|
-
}
|
|
5899
|
-
const perMacroThreshold = settings[`minConfidence${capitalize(macroClass)}`];
|
|
5900
|
-
if (typeof perMacroThreshold === "number" && score < perMacroThreshold) return "below-threshold";
|
|
5901
|
-
return "pass";
|
|
5894
|
+
return require_default_detection_model.macroGateVerdict(macroClass, score, settings);
|
|
5902
5895
|
}
|
|
5903
5896
|
};
|
|
5904
|
-
function capitalize(s) {
|
|
5905
|
-
if (s.length === 0) return s;
|
|
5906
|
-
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
5907
|
-
}
|
|
5908
5897
|
//#endregion
|
|
5909
5898
|
//#region src/detection-pipeline/pipeline/native-crop-compose.ts
|
|
5910
5899
|
/** Clamp `v` into `[lo, hi]`. */
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { $t as hydrateSchema, At as runtimeDevices$1, Ft as supportedRuntimes$1, G as detectionPipelineCapability, J as enumerateInferenceDevices, Lt as errMsg, Ot as resolvePoolMemoryPolicy, Tt as resolveClusterStepModelId, V as defaultDeviceFor$1, Wt as BaseAddon, X as evaluateZoneRules, Yt as createEvent, bn as EventCategory, c as DEFAULT_CLUSTER_STEP_MODELS, gt as pickClusterStepSettings, hn as object, ht as pickClusterStepModels, in as parseJsonUnknown, it as loadContributionCapability, j as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, ln as array, m as DEVICE_BACKEND_TO_FORMAT, nt as inferModelProvider, pt as overlayClusterStepSettings, rn as nodePin, sn as sleep, t as APPLE_SA_TO_MACRO, vn as string, w as PoolMemoryWatchdog, yn as union, yt as pipelineExecutorCapability } from "../dist-
|
|
3
|
-
import { o as readProcessCost } from "../node-
|
|
4
|
-
import { a as
|
|
2
|
+
import { $t as hydrateSchema, At as runtimeDevices$1, Ft as supportedRuntimes$1, G as detectionPipelineCapability, J as enumerateInferenceDevices, Lt as errMsg, Ot as resolvePoolMemoryPolicy, Tt as resolveClusterStepModelId, V as defaultDeviceFor$1, Wt as BaseAddon, X as evaluateZoneRules, Yt as createEvent, bn as EventCategory, c as DEFAULT_CLUSTER_STEP_MODELS, gt as pickClusterStepSettings, hn as object, ht as pickClusterStepModels, in as parseJsonUnknown, it as loadContributionCapability, j as YAMNET_TO_MACRO, l as DEFAULT_CLUSTER_STEP_SETTINGS, ln as array, m as DEVICE_BACKEND_TO_FORMAT, nt as inferModelProvider, pt as overlayClusterStepSettings, rn as nodePin, sn as sleep, t as APPLE_SA_TO_MACRO, vn as string, w as PoolMemoryWatchdog, yn as union, yt as pipelineExecutorCapability } from "../dist-Dzy3wAmT.mjs";
|
|
3
|
+
import { o as readProcessCost } from "../node-D9DBz5HF.mjs";
|
|
4
|
+
import { a as localFrameRegistry, c as ALL_STEPS, d as getStepDefinition, f as resolveModelForFormat, l as getDefaultModelForFormat, n as resolveDefaultDetectionModel, p as landmarkPrecisionVerdict, r as macroGateVerdict, s as ALL_PIPELINE_STEPS, u as getStep } from "../default-detection-model-pr2NMNpc.mjs";
|
|
5
5
|
import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
|
|
6
|
-
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-
|
|
6
|
+
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-BMpJ42op.mjs";
|
|
7
7
|
import * as os from "node:os";
|
|
8
8
|
import * as fs from "node:fs";
|
|
9
9
|
import * as path$1 from "node:path";
|
|
@@ -5884,20 +5884,9 @@ var PipelineExecutor = class {
|
|
|
5884
5884
|
* - `minConfidence<Macro>`: number (e.g. `minConfidencePerson: 0.5`)
|
|
5885
5885
|
*/
|
|
5886
5886
|
macroFilterVerdict(macroClass, score, settings) {
|
|
5887
|
-
|
|
5888
|
-
const enabled = settings["enabledMacroClasses"];
|
|
5889
|
-
if (Array.isArray(enabled) && enabled.length > 0) {
|
|
5890
|
-
if (!enabled.includes(macroClass)) return "class-filter";
|
|
5891
|
-
}
|
|
5892
|
-
const perMacroThreshold = settings[`minConfidence${capitalize(macroClass)}`];
|
|
5893
|
-
if (typeof perMacroThreshold === "number" && score < perMacroThreshold) return "below-threshold";
|
|
5894
|
-
return "pass";
|
|
5887
|
+
return macroGateVerdict(macroClass, score, settings);
|
|
5895
5888
|
}
|
|
5896
5889
|
};
|
|
5897
|
-
function capitalize(s) {
|
|
5898
|
-
if (s.length === 0) return s;
|
|
5899
|
-
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
5900
|
-
}
|
|
5901
5890
|
//#endregion
|
|
5902
5891
|
//#region src/detection-pipeline/pipeline/native-crop-compose.ts
|
|
5903
5892
|
/** Clamp `v` into `[lo, hi]`. */
|
|
@@ -21905,13 +21905,26 @@ var TrackAudioLabelSchema = object({
|
|
|
21905
21905
|
* - `audio` — an audio event on the camera itself that was anomalous for
|
|
21906
21906
|
* THAT camera, loud, and heard while nothing visual was happening (D62).
|
|
21907
21907
|
*
|
|
21908
|
+
* - `onboard` — the CAMERA's own firmware, paired with a decoded frame in
|
|
21909
|
+
* that frame's pixel space. A real root detector and a SPATIAL one: its
|
|
21910
|
+
* boxes are the same kind of fact `pipeline`'s are, produced by a different
|
|
21911
|
+
* detector.
|
|
21912
|
+
*
|
|
21913
|
+
* `onboard` was missing here while `DetectionSourceSchema` already had it, so
|
|
21914
|
+
* a persisted onboard track failed `safeParse` on read and came back with NO
|
|
21915
|
+
* source at all — which `isSpatialTrack` then admitted by accident, through the
|
|
21916
|
+
* `undefined` arm rather than by anybody's decision, and which `excludeSources`
|
|
21917
|
+
* could not name.
|
|
21918
|
+
*
|
|
21908
21919
|
* The spatial subsystems (tracker association, occupancy count, re-id /
|
|
21909
21920
|
* embedding, resurrection) MUST skip every synthetic source. Test for that
|
|
21910
|
-
* with `isSpatialTrack`, which allow-lists
|
|
21911
|
-
* check silently readmits every source added after it was
|
|
21921
|
+
* with `isSpatialTrack`, which allow-lists the spatial sources explicitly — a
|
|
21922
|
+
* `!== 'sensor'` check silently readmits every source added after it was
|
|
21923
|
+
* written.
|
|
21912
21924
|
*/
|
|
21913
21925
|
var TrackSourceSchema = _enum([
|
|
21914
21926
|
"pipeline",
|
|
21927
|
+
"onboard",
|
|
21915
21928
|
"sensor",
|
|
21916
21929
|
"audio"
|
|
21917
21930
|
]);
|
|
@@ -22499,6 +22512,7 @@ var MediaFileKindEnum = _enum([
|
|
|
22499
22512
|
"keyFrame",
|
|
22500
22513
|
"keyFrameSmall",
|
|
22501
22514
|
"thumbnailSmall",
|
|
22515
|
+
"confirmationCrop",
|
|
22502
22516
|
"sceneFrame"
|
|
22503
22517
|
]);
|
|
22504
22518
|
/**
|
|
@@ -23993,13 +24007,39 @@ var MotionSourceEnum = _enum([
|
|
|
23993
24007
|
*/
|
|
23994
24008
|
var MotionSourcesSchema = array(MotionSourceEnum);
|
|
23995
24009
|
/**
|
|
23996
|
-
* Which root
|
|
23997
|
-
*
|
|
23998
|
-
*
|
|
23999
|
-
*
|
|
24000
|
-
*
|
|
24010
|
+
* Which root detector a camera runs — EXACTLY ONE.
|
|
24011
|
+
*
|
|
24012
|
+
* Deliberately the SAME vocabulary post-analysis already tags every detection
|
|
24013
|
+
* with (`DetectionSource`) rather than a second spelling of the same two
|
|
24014
|
+
* ideas: the value an operator picks here is the value that comes back on the
|
|
24015
|
+
* track, the overlay and the debug row.
|
|
24016
|
+
*
|
|
24017
|
+
* ## Why one, and why it is still an array
|
|
24018
|
+
*
|
|
24019
|
+
* Two roots on one camera is a capability nobody asked for and the operator has
|
|
24020
|
+
* since ruled out. It was never free: both planes feed the SAME per-device
|
|
24021
|
+
* stationary registry, both can promote the same parked object, and the two
|
|
24022
|
+
* detectors disagree about the same box by construction — which is the
|
|
24023
|
+
* disagreement D505 had to arbitrate. Removing the case removes the arbitration.
|
|
24024
|
+
*
|
|
24025
|
+
* The ARRAY shape survives because the stored settings and the attach payload
|
|
24026
|
+
* already speak it on every camera of every fleet, and a cap input that
|
|
24027
|
+
* suddenly refuses a stored value makes the camera un-attachable — a fail-closed
|
|
24028
|
+
* in the one direction that costs an operator their cameras. So the wire stays
|
|
24029
|
+
* tolerant and the TYPE is exact: a longer list is truncated to its first
|
|
24030
|
+
* element rather than refused, and `max(1)` is what every consumer can then
|
|
24031
|
+
* rely on.
|
|
24032
|
+
*
|
|
24033
|
+
* AT MOST one, not exactly one. The EMPTY list is a legal, deliberate pick —
|
|
24034
|
+
* a camera an operator left with no root detector — and `planDetectionSources`
|
|
24035
|
+
* has always said so: inventing a root for them is how a default acts without
|
|
24036
|
+
* anybody choosing it. Tightening this to `length(1)` broke that, and the
|
|
24037
|
+
* suite caught it.
|
|
24038
|
+
*
|
|
24039
|
+
* Measured before tightening (2026-09-15, this fleet, 6 h of attaches): 3327
|
|
24040
|
+
* `["pipeline"]` and 2 `["onboard"]`. Not one camera had two.
|
|
24001
24041
|
*/
|
|
24002
|
-
var DetectionSourcesSchema = array(DetectionSourceSchema);
|
|
24042
|
+
var DetectionSourcesSchema = preprocess((value) => Array.isArray(value) && value.length > 1 ? value.slice(0, 1) : value, array(DetectionSourceSchema).max(1));
|
|
24003
24043
|
/**
|
|
24004
24044
|
* Input shape for `pipeline-runner.reportMotion` cap method. Exported
|
|
24005
24045
|
* so cap-side consumers (the orchestrator forward, the runner addon's
|
|
@@ -21905,13 +21905,26 @@ var TrackAudioLabelSchema = object({
|
|
|
21905
21905
|
* - `audio` — an audio event on the camera itself that was anomalous for
|
|
21906
21906
|
* THAT camera, loud, and heard while nothing visual was happening (D62).
|
|
21907
21907
|
*
|
|
21908
|
+
* - `onboard` — the CAMERA's own firmware, paired with a decoded frame in
|
|
21909
|
+
* that frame's pixel space. A real root detector and a SPATIAL one: its
|
|
21910
|
+
* boxes are the same kind of fact `pipeline`'s are, produced by a different
|
|
21911
|
+
* detector.
|
|
21912
|
+
*
|
|
21913
|
+
* `onboard` was missing here while `DetectionSourceSchema` already had it, so
|
|
21914
|
+
* a persisted onboard track failed `safeParse` on read and came back with NO
|
|
21915
|
+
* source at all — which `isSpatialTrack` then admitted by accident, through the
|
|
21916
|
+
* `undefined` arm rather than by anybody's decision, and which `excludeSources`
|
|
21917
|
+
* could not name.
|
|
21918
|
+
*
|
|
21908
21919
|
* The spatial subsystems (tracker association, occupancy count, re-id /
|
|
21909
21920
|
* embedding, resurrection) MUST skip every synthetic source. Test for that
|
|
21910
|
-
* with `isSpatialTrack`, which allow-lists
|
|
21911
|
-
* check silently readmits every source added after it was
|
|
21921
|
+
* with `isSpatialTrack`, which allow-lists the spatial sources explicitly — a
|
|
21922
|
+
* `!== 'sensor'` check silently readmits every source added after it was
|
|
21923
|
+
* written.
|
|
21912
21924
|
*/
|
|
21913
21925
|
var TrackSourceSchema = _enum([
|
|
21914
21926
|
"pipeline",
|
|
21927
|
+
"onboard",
|
|
21915
21928
|
"sensor",
|
|
21916
21929
|
"audio"
|
|
21917
21930
|
]);
|
|
@@ -22499,6 +22512,7 @@ var MediaFileKindEnum = _enum([
|
|
|
22499
22512
|
"keyFrame",
|
|
22500
22513
|
"keyFrameSmall",
|
|
22501
22514
|
"thumbnailSmall",
|
|
22515
|
+
"confirmationCrop",
|
|
22502
22516
|
"sceneFrame"
|
|
22503
22517
|
]);
|
|
22504
22518
|
/**
|
|
@@ -23993,13 +24007,39 @@ var MotionSourceEnum = _enum([
|
|
|
23993
24007
|
*/
|
|
23994
24008
|
var MotionSourcesSchema = array(MotionSourceEnum);
|
|
23995
24009
|
/**
|
|
23996
|
-
* Which root
|
|
23997
|
-
*
|
|
23998
|
-
*
|
|
23999
|
-
*
|
|
24000
|
-
*
|
|
24010
|
+
* Which root detector a camera runs — EXACTLY ONE.
|
|
24011
|
+
*
|
|
24012
|
+
* Deliberately the SAME vocabulary post-analysis already tags every detection
|
|
24013
|
+
* with (`DetectionSource`) rather than a second spelling of the same two
|
|
24014
|
+
* ideas: the value an operator picks here is the value that comes back on the
|
|
24015
|
+
* track, the overlay and the debug row.
|
|
24016
|
+
*
|
|
24017
|
+
* ## Why one, and why it is still an array
|
|
24018
|
+
*
|
|
24019
|
+
* Two roots on one camera is a capability nobody asked for and the operator has
|
|
24020
|
+
* since ruled out. It was never free: both planes feed the SAME per-device
|
|
24021
|
+
* stationary registry, both can promote the same parked object, and the two
|
|
24022
|
+
* detectors disagree about the same box by construction — which is the
|
|
24023
|
+
* disagreement D505 had to arbitrate. Removing the case removes the arbitration.
|
|
24024
|
+
*
|
|
24025
|
+
* The ARRAY shape survives because the stored settings and the attach payload
|
|
24026
|
+
* already speak it on every camera of every fleet, and a cap input that
|
|
24027
|
+
* suddenly refuses a stored value makes the camera un-attachable — a fail-closed
|
|
24028
|
+
* in the one direction that costs an operator their cameras. So the wire stays
|
|
24029
|
+
* tolerant and the TYPE is exact: a longer list is truncated to its first
|
|
24030
|
+
* element rather than refused, and `max(1)` is what every consumer can then
|
|
24031
|
+
* rely on.
|
|
24032
|
+
*
|
|
24033
|
+
* AT MOST one, not exactly one. The EMPTY list is a legal, deliberate pick —
|
|
24034
|
+
* a camera an operator left with no root detector — and `planDetectionSources`
|
|
24035
|
+
* has always said so: inventing a root for them is how a default acts without
|
|
24036
|
+
* anybody choosing it. Tightening this to `length(1)` broke that, and the
|
|
24037
|
+
* suite caught it.
|
|
24038
|
+
*
|
|
24039
|
+
* Measured before tightening (2026-09-15, this fleet, 6 h of attaches): 3327
|
|
24040
|
+
* `["pipeline"]` and 2 `["onboard"]`. Not one camera had two.
|
|
24001
24041
|
*/
|
|
24002
|
-
var DetectionSourcesSchema = array(DetectionSourceSchema);
|
|
24042
|
+
var DetectionSourcesSchema = preprocess((value) => Array.isArray(value) && value.length > 1 ? value.slice(0, 1) : value, array(DetectionSourceSchema).max(1));
|
|
24003
24043
|
/**
|
|
24004
24044
|
* Input shape for `pipeline-runner.reportMotion` cap method. Exported
|
|
24005
24045
|
* so cap-side consumers (the orchestrator forward, the runner addon's
|
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_dist = require("../dist-BjiM0e6J.js");
|
|
6
6
|
const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
|
|
7
7
|
let node_fs = require("node:fs");
|
|
8
8
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $t as hydrateSchema, Wt as BaseAddon, X as evaluateZoneRules, ft as motionDetectionCapability, qt as DeviceType } from "../dist-
|
|
1
|
+
import { $t as hydrateSchema, Wt as BaseAddon, X as evaluateZoneRules, ft as motionDetectionCapability, qt as DeviceType } from "../dist-Dzy3wAmT.mjs";
|
|
2
2
|
import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import { join } from "node:path";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Bt as buildFfmpegArgs, Ht as isSoftwareDecode, Lt as errMsg, zt as Fmp4BoxSplitter } from "./dist-
|
|
1
|
+
import { Bt as buildFfmpegArgs, Ht as isSoftwareDecode, Lt as errMsg, zt as Fmp4BoxSplitter } from "./dist-Dzy3wAmT.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { realpathSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-emK7D4bc.js");
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-BjiM0e6J.js");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
let node_fs = require("node:fs");
|
|
5
5
|
node_fs = require_chunk.__toESM(node_fs, 1);
|
|
@@ -3,9 +3,9 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_node = require("../node-
|
|
8
|
-
const require_default_detection_model = require("../default-detection-model-
|
|
6
|
+
const require_dist = require("../dist-BjiM0e6J.js");
|
|
7
|
+
const require_node = require("../node-P2-C_t7H.js");
|
|
8
|
+
const require_default_detection_model = require("../default-detection-model-ClJ9y701.js");
|
|
9
9
|
const require_worker_protocol = require("../worker-protocol-B2MfQLlu.js");
|
|
10
10
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
11
11
|
const require_lazy_sharp = require("../lazy-sharp-BuwKlQLR.js");
|
|
@@ -2129,7 +2129,7 @@ function clamp(value, max) {
|
|
|
2129
2129
|
* the boxes travel with a real frame and a real handle, so they are scaled to
|
|
2130
2130
|
* that frame — the same space every other detection on this plane lives in.
|
|
2131
2131
|
*/
|
|
2132
|
-
function onboardRootDetections(slot, frame) {
|
|
2132
|
+
function onboardRootDetections(slot, frame, gate) {
|
|
2133
2133
|
if (slot === null || slot.detections.length === 0) return { kind: "none" };
|
|
2134
2134
|
const ageMs = Math.abs(frame.timestamp - slot.at);
|
|
2135
2135
|
if (ageMs > 1e3) return {
|
|
@@ -2141,26 +2141,33 @@ function onboardRootDetections(slot, frame) {
|
|
|
2141
2141
|
kind: "no-geometry",
|
|
2142
2142
|
classes: slot.detections.map((d) => d.class)
|
|
2143
2143
|
};
|
|
2144
|
+
const detections = boxed.map((d, i) => {
|
|
2145
|
+
const [nx, ny, nw, nh] = d.bbox;
|
|
2146
|
+
const x = clamp(nx * frame.width, frame.width);
|
|
2147
|
+
const y = clamp(ny * frame.height, frame.height);
|
|
2148
|
+
return {
|
|
2149
|
+
id: `onboard-${String(slot.at)}-${String(i)}`,
|
|
2150
|
+
kind: "first-level",
|
|
2151
|
+
macroClass: d.class,
|
|
2152
|
+
score: d.confidence ?? 1,
|
|
2153
|
+
labels: [],
|
|
2154
|
+
bbox: {
|
|
2155
|
+
x,
|
|
2156
|
+
y,
|
|
2157
|
+
width: clamp(nw * frame.width, frame.width - x),
|
|
2158
|
+
height: clamp(nh * frame.height, frame.height - y)
|
|
2159
|
+
}
|
|
2160
|
+
};
|
|
2161
|
+
});
|
|
2162
|
+
const admitted = detections.filter((d) => require_default_detection_model.macroGateVerdict(d.macroClass, d.score, gate) === "pass");
|
|
2163
|
+
if (admitted.length === 0) return {
|
|
2164
|
+
kind: "gated",
|
|
2165
|
+
refused: detections.length
|
|
2166
|
+
};
|
|
2144
2167
|
return {
|
|
2145
2168
|
kind: "paired",
|
|
2146
|
-
detections:
|
|
2147
|
-
|
|
2148
|
-
const x = clamp(nx * frame.width, frame.width);
|
|
2149
|
-
const y = clamp(ny * frame.height, frame.height);
|
|
2150
|
-
return {
|
|
2151
|
-
id: `onboard-${String(slot.at)}-${String(i)}`,
|
|
2152
|
-
kind: "first-level",
|
|
2153
|
-
macroClass: d.class,
|
|
2154
|
-
score: d.confidence ?? 1,
|
|
2155
|
-
labels: [],
|
|
2156
|
-
bbox: {
|
|
2157
|
-
x,
|
|
2158
|
-
y,
|
|
2159
|
-
width: clamp(nw * frame.width, frame.width - x),
|
|
2160
|
-
height: clamp(nh * frame.height, frame.height - y)
|
|
2161
|
-
}
|
|
2162
|
-
};
|
|
2163
|
-
})
|
|
2169
|
+
detections: admitted,
|
|
2170
|
+
...admitted.length < detections.length ? { refused: detections.length - admitted.length } : {}
|
|
2164
2171
|
};
|
|
2165
2172
|
}
|
|
2166
2173
|
//#endregion
|
|
@@ -5645,7 +5652,7 @@ function ownDetectionEntry(entry) {
|
|
|
5645
5652
|
return {
|
|
5646
5653
|
frame: ownFrame(entry.frame),
|
|
5647
5654
|
handle: entry.handle,
|
|
5648
|
-
|
|
5655
|
+
occasion: entry.occasion
|
|
5649
5656
|
};
|
|
5650
5657
|
}
|
|
5651
5658
|
/**
|
|
@@ -5964,7 +5971,8 @@ var PipelineRunner = class {
|
|
|
5964
5971
|
if (!state || state.phase !== "active") return false;
|
|
5965
5972
|
return state.preRollQueue.enqueue({
|
|
5966
5973
|
frame,
|
|
5967
|
-
handle
|
|
5974
|
+
handle,
|
|
5975
|
+
occasion: "session"
|
|
5968
5976
|
});
|
|
5969
5977
|
}
|
|
5970
5978
|
/**
|
|
@@ -6001,7 +6009,7 @@ var PipelineRunner = class {
|
|
|
6001
6009
|
state.detectionQueue.enqueue({
|
|
6002
6010
|
frame,
|
|
6003
6011
|
handle,
|
|
6004
|
-
occasion: "
|
|
6012
|
+
occasion: "session"
|
|
6005
6013
|
});
|
|
6006
6014
|
return true;
|
|
6007
6015
|
}
|
|
@@ -6313,7 +6321,7 @@ var PipelineRunner = class {
|
|
|
6313
6321
|
state.processedCount++;
|
|
6314
6322
|
if (result) {
|
|
6315
6323
|
if (result.shed === true) state.shedFrames++;
|
|
6316
|
-
await this.notifyCallbacks(deviceId, frame, plan.runsOnboard ? this.mergeOnboardDetections(state, result, frame) : result, streamType, handle, "pipeline", entry.occasion
|
|
6324
|
+
await this.notifyCallbacks(deviceId, frame, plan.runsOnboard ? this.mergeOnboardDetections(state, result, frame) : result, streamType, handle, "pipeline", entry.occasion);
|
|
6317
6325
|
frameReleaseReason = "success";
|
|
6318
6326
|
const emittedAt = Date.now();
|
|
6319
6327
|
const capturedAt = frame.capturedAt;
|
|
@@ -6352,7 +6360,7 @@ var PipelineRunner = class {
|
|
|
6352
6360
|
timestamp: Date.now(),
|
|
6353
6361
|
width: frame.width,
|
|
6354
6362
|
height: frame.height
|
|
6355
|
-
});
|
|
6363
|
+
}, state.registration.objectGate);
|
|
6356
6364
|
if (pairing.kind !== "paired") return result;
|
|
6357
6365
|
state.onboardSlot = null;
|
|
6358
6366
|
return {
|
|
@@ -6389,8 +6397,9 @@ var PipelineRunner = class {
|
|
|
6389
6397
|
timestamp: Date.now(),
|
|
6390
6398
|
width: frame.width,
|
|
6391
6399
|
height: frame.height
|
|
6392
|
-
});
|
|
6400
|
+
}, state.registration.objectGate);
|
|
6393
6401
|
if (pairing.kind !== "paired") {
|
|
6402
|
+
if (pairing.kind === "gated") state.onboardSlot = null;
|
|
6394
6403
|
this.noteOnboardRootIdle(deviceId, pairing.kind);
|
|
6395
6404
|
return;
|
|
6396
6405
|
}
|
|
@@ -6406,7 +6415,8 @@ var PipelineRunner = class {
|
|
|
6406
6415
|
detections: pairing.detections
|
|
6407
6416
|
};
|
|
6408
6417
|
state.lastResultDetections = pairing.detections.length;
|
|
6409
|
-
|
|
6418
|
+
if (handle) this.config.markFrameAskable?.(handle);
|
|
6419
|
+
await this.notifyCallbacks(deviceId, frame, result, streamType, handle, "onboard", entry.occasion);
|
|
6410
6420
|
frameReleaseReason = "success";
|
|
6411
6421
|
} catch {
|
|
6412
6422
|
frameReleaseReason = "error";
|
|
@@ -6554,7 +6564,7 @@ var PipelineRunner = class {
|
|
|
6554
6564
|
if (!deviceId) continue;
|
|
6555
6565
|
const state = this.cameras.get(deviceId);
|
|
6556
6566
|
if (!state) continue;
|
|
6557
|
-
if (state.phase === "active" && state.detectionQueue.size > 0 && state.inflight < this.maxInflightPerCamera()) {
|
|
6567
|
+
if ((state.phase === "active" || state.phase === "watching") && state.detectionQueue.size > 0 && state.inflight < this.maxInflightPerCamera()) {
|
|
6558
6568
|
this.defaultRoundRobinIndex = (idx + 1) % this.defaultRoundRobinKeys.length;
|
|
6559
6569
|
const entry = state.detectionQueue.dequeue();
|
|
6560
6570
|
if (!entry) continue;
|
|
@@ -7587,6 +7597,10 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
7587
7597
|
this.frameCutters.drop(handle);
|
|
7588
7598
|
},
|
|
7589
7599
|
hydrateRetainedFrame: (handle) => this.retainedFrames?.ensureContent(handle) ?? Promise.resolve(null),
|
|
7600
|
+
markFrameAskable: (handle) => {
|
|
7601
|
+
const found = this.nativeCropRegistry.lookup(handle);
|
|
7602
|
+
if (found.kind === "live") found.request.markInferred?.();
|
|
7603
|
+
},
|
|
7590
7604
|
onPhaseChanged: (deviceId, phase, meta) => this.handlePhaseChanged(deviceId, phase, meta),
|
|
7591
7605
|
logger: this.ctx.logger,
|
|
7592
7606
|
onOccupancyRecheck: (deviceId, frames) => {
|
|
@@ -8455,6 +8469,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
8455
8469
|
runner.registerCamera(config.deviceId, {
|
|
8456
8470
|
detectionMode: config.detectionMode,
|
|
8457
8471
|
...config.detectionSources !== void 0 ? { detectionSources: config.detectionSources } : {},
|
|
8472
|
+
...require_default_detection_model.rootObjectGate(config.steps) !== void 0 ? { objectGate: require_default_detection_model.rootObjectGate(config.steps) } : {},
|
|
8458
8473
|
fps: config.detectionFps,
|
|
8459
8474
|
motionCooldownMs: config.motionCooldownMs,
|
|
8460
8475
|
occupancyRecheckEnabled: config.occupancyRecheckEnabled,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { $ as failureContributionCapability, Lt as errMsg, S as NativeLeaseSettingsSchema, U as deriveDetailCropRect, Wt as BaseAddon, Xt as customAction, Yt as createEvent, Zt as defineCustomActions, _ as FailureCounters, _t as pickDetailCropConvention, b as MOTION_CLOSE_AFTER_MS, bn as EventCategory, bt as pipelineRunnerCapability, cn as _enum, fn as lazy, hn as object, it as loadContributionCapability, ln as array, m as DEVICE_BACKEND_TO_FORMAT, mn as number, p as DEFAULT_NATIVE_LEASE_SETTINGS, pn as literal, rn as nodePin, u as DEFAULT_DETAIL_CROP_CONVENTION, un as boolean, vn as string, vt as pickNativeLeaseOverride, x as NativeLeaseAdmissionSchema } from "../dist-
|
|
2
|
-
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-
|
|
3
|
-
import {
|
|
1
|
+
import { $ as failureContributionCapability, Lt as errMsg, S as NativeLeaseSettingsSchema, U as deriveDetailCropRect, Wt as BaseAddon, Xt as customAction, Yt as createEvent, Zt as defineCustomActions, _ as FailureCounters, _t as pickDetailCropConvention, b as MOTION_CLOSE_AFTER_MS, bn as EventCategory, bt as pipelineRunnerCapability, cn as _enum, fn as lazy, hn as object, it as loadContributionCapability, ln as array, m as DEVICE_BACKEND_TO_FORMAT, mn as number, p as DEFAULT_NATIVE_LEASE_SETTINGS, pn as literal, rn as nodePin, u as DEFAULT_DETAIL_CROP_CONVENTION, un as boolean, vn as string, vt as pickNativeLeaseOverride, x as NativeLeaseAdmissionSchema } from "../dist-Dzy3wAmT.mjs";
|
|
2
|
+
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-D9DBz5HF.mjs";
|
|
3
|
+
import { a as localFrameRegistry, d as getStepDefinition, i as rootObjectGate, o as resolveFrameViewGeometry, r as macroGateVerdict } from "../default-detection-model-pr2NMNpc.mjs";
|
|
4
4
|
import { t as isWorkerReply } from "../worker-protocol-C_W-P_g-.mjs";
|
|
5
5
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
6
6
|
import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
|
|
@@ -2122,7 +2122,7 @@ function clamp(value, max) {
|
|
|
2122
2122
|
* the boxes travel with a real frame and a real handle, so they are scaled to
|
|
2123
2123
|
* that frame — the same space every other detection on this plane lives in.
|
|
2124
2124
|
*/
|
|
2125
|
-
function onboardRootDetections(slot, frame) {
|
|
2125
|
+
function onboardRootDetections(slot, frame, gate) {
|
|
2126
2126
|
if (slot === null || slot.detections.length === 0) return { kind: "none" };
|
|
2127
2127
|
const ageMs = Math.abs(frame.timestamp - slot.at);
|
|
2128
2128
|
if (ageMs > 1e3) return {
|
|
@@ -2134,26 +2134,33 @@ function onboardRootDetections(slot, frame) {
|
|
|
2134
2134
|
kind: "no-geometry",
|
|
2135
2135
|
classes: slot.detections.map((d) => d.class)
|
|
2136
2136
|
};
|
|
2137
|
+
const detections = boxed.map((d, i) => {
|
|
2138
|
+
const [nx, ny, nw, nh] = d.bbox;
|
|
2139
|
+
const x = clamp(nx * frame.width, frame.width);
|
|
2140
|
+
const y = clamp(ny * frame.height, frame.height);
|
|
2141
|
+
return {
|
|
2142
|
+
id: `onboard-${String(slot.at)}-${String(i)}`,
|
|
2143
|
+
kind: "first-level",
|
|
2144
|
+
macroClass: d.class,
|
|
2145
|
+
score: d.confidence ?? 1,
|
|
2146
|
+
labels: [],
|
|
2147
|
+
bbox: {
|
|
2148
|
+
x,
|
|
2149
|
+
y,
|
|
2150
|
+
width: clamp(nw * frame.width, frame.width - x),
|
|
2151
|
+
height: clamp(nh * frame.height, frame.height - y)
|
|
2152
|
+
}
|
|
2153
|
+
};
|
|
2154
|
+
});
|
|
2155
|
+
const admitted = detections.filter((d) => macroGateVerdict(d.macroClass, d.score, gate) === "pass");
|
|
2156
|
+
if (admitted.length === 0) return {
|
|
2157
|
+
kind: "gated",
|
|
2158
|
+
refused: detections.length
|
|
2159
|
+
};
|
|
2137
2160
|
return {
|
|
2138
2161
|
kind: "paired",
|
|
2139
|
-
detections:
|
|
2140
|
-
|
|
2141
|
-
const x = clamp(nx * frame.width, frame.width);
|
|
2142
|
-
const y = clamp(ny * frame.height, frame.height);
|
|
2143
|
-
return {
|
|
2144
|
-
id: `onboard-${String(slot.at)}-${String(i)}`,
|
|
2145
|
-
kind: "first-level",
|
|
2146
|
-
macroClass: d.class,
|
|
2147
|
-
score: d.confidence ?? 1,
|
|
2148
|
-
labels: [],
|
|
2149
|
-
bbox: {
|
|
2150
|
-
x,
|
|
2151
|
-
y,
|
|
2152
|
-
width: clamp(nw * frame.width, frame.width - x),
|
|
2153
|
-
height: clamp(nh * frame.height, frame.height - y)
|
|
2154
|
-
}
|
|
2155
|
-
};
|
|
2156
|
-
})
|
|
2162
|
+
detections: admitted,
|
|
2163
|
+
...admitted.length < detections.length ? { refused: detections.length - admitted.length } : {}
|
|
2157
2164
|
};
|
|
2158
2165
|
}
|
|
2159
2166
|
//#endregion
|
|
@@ -5637,7 +5644,7 @@ function ownDetectionEntry(entry) {
|
|
|
5637
5644
|
return {
|
|
5638
5645
|
frame: ownFrame(entry.frame),
|
|
5639
5646
|
handle: entry.handle,
|
|
5640
|
-
|
|
5647
|
+
occasion: entry.occasion
|
|
5641
5648
|
};
|
|
5642
5649
|
}
|
|
5643
5650
|
/**
|
|
@@ -5956,7 +5963,8 @@ var PipelineRunner = class {
|
|
|
5956
5963
|
if (!state || state.phase !== "active") return false;
|
|
5957
5964
|
return state.preRollQueue.enqueue({
|
|
5958
5965
|
frame,
|
|
5959
|
-
handle
|
|
5966
|
+
handle,
|
|
5967
|
+
occasion: "session"
|
|
5960
5968
|
});
|
|
5961
5969
|
}
|
|
5962
5970
|
/**
|
|
@@ -5993,7 +6001,7 @@ var PipelineRunner = class {
|
|
|
5993
6001
|
state.detectionQueue.enqueue({
|
|
5994
6002
|
frame,
|
|
5995
6003
|
handle,
|
|
5996
|
-
occasion: "
|
|
6004
|
+
occasion: "session"
|
|
5997
6005
|
});
|
|
5998
6006
|
return true;
|
|
5999
6007
|
}
|
|
@@ -6305,7 +6313,7 @@ var PipelineRunner = class {
|
|
|
6305
6313
|
state.processedCount++;
|
|
6306
6314
|
if (result) {
|
|
6307
6315
|
if (result.shed === true) state.shedFrames++;
|
|
6308
|
-
await this.notifyCallbacks(deviceId, frame, plan.runsOnboard ? this.mergeOnboardDetections(state, result, frame) : result, streamType, handle, "pipeline", entry.occasion
|
|
6316
|
+
await this.notifyCallbacks(deviceId, frame, plan.runsOnboard ? this.mergeOnboardDetections(state, result, frame) : result, streamType, handle, "pipeline", entry.occasion);
|
|
6309
6317
|
frameReleaseReason = "success";
|
|
6310
6318
|
const emittedAt = Date.now();
|
|
6311
6319
|
const capturedAt = frame.capturedAt;
|
|
@@ -6344,7 +6352,7 @@ var PipelineRunner = class {
|
|
|
6344
6352
|
timestamp: Date.now(),
|
|
6345
6353
|
width: frame.width,
|
|
6346
6354
|
height: frame.height
|
|
6347
|
-
});
|
|
6355
|
+
}, state.registration.objectGate);
|
|
6348
6356
|
if (pairing.kind !== "paired") return result;
|
|
6349
6357
|
state.onboardSlot = null;
|
|
6350
6358
|
return {
|
|
@@ -6381,8 +6389,9 @@ var PipelineRunner = class {
|
|
|
6381
6389
|
timestamp: Date.now(),
|
|
6382
6390
|
width: frame.width,
|
|
6383
6391
|
height: frame.height
|
|
6384
|
-
});
|
|
6392
|
+
}, state.registration.objectGate);
|
|
6385
6393
|
if (pairing.kind !== "paired") {
|
|
6394
|
+
if (pairing.kind === "gated") state.onboardSlot = null;
|
|
6386
6395
|
this.noteOnboardRootIdle(deviceId, pairing.kind);
|
|
6387
6396
|
return;
|
|
6388
6397
|
}
|
|
@@ -6398,7 +6407,8 @@ var PipelineRunner = class {
|
|
|
6398
6407
|
detections: pairing.detections
|
|
6399
6408
|
};
|
|
6400
6409
|
state.lastResultDetections = pairing.detections.length;
|
|
6401
|
-
|
|
6410
|
+
if (handle) this.config.markFrameAskable?.(handle);
|
|
6411
|
+
await this.notifyCallbacks(deviceId, frame, result, streamType, handle, "onboard", entry.occasion);
|
|
6402
6412
|
frameReleaseReason = "success";
|
|
6403
6413
|
} catch {
|
|
6404
6414
|
frameReleaseReason = "error";
|
|
@@ -6546,7 +6556,7 @@ var PipelineRunner = class {
|
|
|
6546
6556
|
if (!deviceId) continue;
|
|
6547
6557
|
const state = this.cameras.get(deviceId);
|
|
6548
6558
|
if (!state) continue;
|
|
6549
|
-
if (state.phase === "active" && state.detectionQueue.size > 0 && state.inflight < this.maxInflightPerCamera()) {
|
|
6559
|
+
if ((state.phase === "active" || state.phase === "watching") && state.detectionQueue.size > 0 && state.inflight < this.maxInflightPerCamera()) {
|
|
6550
6560
|
this.defaultRoundRobinIndex = (idx + 1) % this.defaultRoundRobinKeys.length;
|
|
6551
6561
|
const entry = state.detectionQueue.dequeue();
|
|
6552
6562
|
if (!entry) continue;
|
|
@@ -7579,6 +7589,10 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
7579
7589
|
this.frameCutters.drop(handle);
|
|
7580
7590
|
},
|
|
7581
7591
|
hydrateRetainedFrame: (handle) => this.retainedFrames?.ensureContent(handle) ?? Promise.resolve(null),
|
|
7592
|
+
markFrameAskable: (handle) => {
|
|
7593
|
+
const found = this.nativeCropRegistry.lookup(handle);
|
|
7594
|
+
if (found.kind === "live") found.request.markInferred?.();
|
|
7595
|
+
},
|
|
7582
7596
|
onPhaseChanged: (deviceId, phase, meta) => this.handlePhaseChanged(deviceId, phase, meta),
|
|
7583
7597
|
logger: this.ctx.logger,
|
|
7584
7598
|
onOccupancyRecheck: (deviceId, frames) => {
|
|
@@ -8447,6 +8461,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
8447
8461
|
runner.registerCamera(config.deviceId, {
|
|
8448
8462
|
detectionMode: config.detectionMode,
|
|
8449
8463
|
...config.detectionSources !== void 0 ? { detectionSources: config.detectionSources } : {},
|
|
8464
|
+
...rootObjectGate(config.steps) !== void 0 ? { objectGate: rootObjectGate(config.steps) } : {},
|
|
8450
8465
|
fps: config.detectionFps,
|
|
8451
8466
|
motionCooldownMs: config.motionCooldownMs,
|
|
8452
8467
|
occupancyRecheckEnabled: config.occupancyRecheckEnabled,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-emK7D4bc.js");
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-BjiM0e6J.js");
|
|
3
3
|
let node_fs = require("node:fs");
|
|
4
4
|
node_fs = require_chunk.__toESM(node_fs);
|
|
5
5
|
let node_child_process = require("node:child_process");
|
package/dist/recorder/index.js
CHANGED
|
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_node = require("../node-
|
|
6
|
+
const require_dist = require("../dist-BjiM0e6J.js");
|
|
7
|
+
const require_node = require("../node-P2-C_t7H.js");
|
|
8
8
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
9
9
|
const require_restream_intent = require("../restream-intent-C4adO0P8.js");
|
|
10
10
|
const require_retire_root_keys = require("../retire-root-keys-Csb8z2f3.js");
|
|
@@ -555,8 +555,6 @@ var MfraTableStore = class {
|
|
|
555
555
|
*/
|
|
556
556
|
/** Il `kind` dell'unico ramo del topic che può aprire una finestra. */
|
|
557
557
|
var OBJECT_EVENT_KIND = "object";
|
|
558
|
-
/** La sorgente implicita delle righe legacy senza `source` (`DetectionSourceSchema`). */
|
|
559
|
-
var DEFAULT_DETECTION_SOURCE = "pipeline";
|
|
560
558
|
/** Type guard, non cast: `event.data` è `unknown` finché non passa di qui. */
|
|
561
559
|
function isDetectionEventEnvelope(value) {
|
|
562
560
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -589,11 +587,6 @@ function qualifyObjectTrigger(data) {
|
|
|
589
587
|
reason: "malformed-object",
|
|
590
588
|
deviceId
|
|
591
589
|
};
|
|
592
|
-
if ((data.source ?? DEFAULT_DETECTION_SOURCE) !== DEFAULT_DETECTION_SOURCE) return {
|
|
593
|
-
qualified: false,
|
|
594
|
-
reason: "not-pipeline",
|
|
595
|
-
deviceId
|
|
596
|
-
};
|
|
597
590
|
const className = data.className.trim().toLowerCase();
|
|
598
591
|
if (!require_dist.isFirstLevelMacroClass(className)) return {
|
|
599
592
|
qualified: false,
|
package/dist/recorder/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $t as hydrateSchema, C as OpsLogEntrySchema, Ct as recordingExportCapability, D as RECORDING_EXPORT_MAX_READ_BYTES, Dt as resolveLocationMode, H as deriveBatteryPresence, I as batteryCapability, Kt as DeviceFeature, Lt as errMsg, Mt as storageOccupancyCapability, O as RecordingConfigSchema, Pt as stripRetiredBandPreBufferSec, Q as evictionPolicyOfLocation, St as recordingCapability, W as deriveRecordingMode, Wt as BaseAddon, Xt as customAction, Y as evaluateSensorEdge, Z as evictionPolicyForMode, Zt as defineCustomActions, _n as record, bn as EventCategory, cn as _enum, ct as mayReadLocation, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, dt as modeMayWrite, et as gbToBytes, g as ExportRecordSchema, gn as preprocess, hn as object, i as BatteryStatusSchema, it as loadContributionCapability, jt as storageEvictableCapability, k as RecordingSignalStatusSchema, kt as resolveRecordingProfiles, ln as array, lt as mayWriteToLocation, mn as number, on as selectAssignedProfileSlots, qt as DeviceType, rn as nodePin, rt as isFirstLevelMacroClass, sn as sleep$1, un as boolean, ut as migrateLegacyDeviceSignalConfig, vn as string, wt as recordingSignalCapability } from "../dist-
|
|
2
|
-
import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-
|
|
1
|
+
import { $t as hydrateSchema, C as OpsLogEntrySchema, Ct as recordingExportCapability, D as RECORDING_EXPORT_MAX_READ_BYTES, Dt as resolveLocationMode, H as deriveBatteryPresence, I as batteryCapability, Kt as DeviceFeature, Lt as errMsg, Mt as storageOccupancyCapability, O as RecordingConfigSchema, Pt as stripRetiredBandPreBufferSec, Q as evictionPolicyOfLocation, St as recordingCapability, W as deriveRecordingMode, Wt as BaseAddon, Xt as customAction, Y as evaluateSensorEdge, Z as evictionPolicyForMode, Zt as defineCustomActions, _n as record, bn as EventCategory, cn as _enum, ct as mayReadLocation, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, dt as modeMayWrite, et as gbToBytes, g as ExportRecordSchema, gn as preprocess, hn as object, i as BatteryStatusSchema, it as loadContributionCapability, jt as storageEvictableCapability, k as RecordingSignalStatusSchema, kt as resolveRecordingProfiles, ln as array, lt as mayWriteToLocation, mn as number, on as selectAssignedProfileSlots, qt as DeviceType, rn as nodePin, rt as isFirstLevelMacroClass, sn as sleep$1, un as boolean, ut as migrateLegacyDeviceSignalConfig, vn as string, wt as recordingSignalCapability } from "../dist-Dzy3wAmT.mjs";
|
|
2
|
+
import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-D9DBz5HF.mjs";
|
|
3
3
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
4
4
|
import { c as PREBUFFER_MAX_MS, r as RECORDING_PRE_ROLL_REQUEST_MS, s as withRecordingIntent } from "../restream-intent-MeJhGCK9.mjs";
|
|
5
5
|
import { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DZvlso2l.mjs";
|
|
@@ -549,8 +549,6 @@ var MfraTableStore = class {
|
|
|
549
549
|
*/
|
|
550
550
|
/** Il `kind` dell'unico ramo del topic che può aprire una finestra. */
|
|
551
551
|
var OBJECT_EVENT_KIND = "object";
|
|
552
|
-
/** La sorgente implicita delle righe legacy senza `source` (`DetectionSourceSchema`). */
|
|
553
|
-
var DEFAULT_DETECTION_SOURCE = "pipeline";
|
|
554
552
|
/** Type guard, non cast: `event.data` è `unknown` finché non passa di qui. */
|
|
555
553
|
function isDetectionEventEnvelope(value) {
|
|
556
554
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -583,11 +581,6 @@ function qualifyObjectTrigger(data) {
|
|
|
583
581
|
reason: "malformed-object",
|
|
584
582
|
deviceId
|
|
585
583
|
};
|
|
586
|
-
if ((data.source ?? DEFAULT_DETECTION_SOURCE) !== DEFAULT_DETECTION_SOURCE) return {
|
|
587
|
-
qualified: false,
|
|
588
|
-
reason: "not-pipeline",
|
|
589
|
-
deviceId
|
|
590
|
-
};
|
|
591
584
|
const className = data.className.trim().toLowerCase();
|
|
592
585
|
if (!isFirstLevelMacroClass(className)) return {
|
|
593
586
|
qualified: false,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { Lt as errMsg } from "./dist-
|
|
2
|
+
import { Lt as errMsg } from "./dist-Dzy3wAmT.mjs";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
//#region ../../node_modules/mp4box/dist/mp4box.all.js
|
|
5
5
|
var require_mp4box_all = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-emK7D4bc.js");
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-BjiM0e6J.js");
|
|
3
3
|
let node_child_process = require("node:child_process");
|
|
4
4
|
//#region ../../node_modules/mp4box/dist/mp4box.all.js
|
|
5
5
|
var require_mp4box_all = /* @__PURE__ */ require_chunk.__commonJSMin(((exports) => {
|
|
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
|
|
|
3
3
|
var e = {
|
|
4
4
|
"@camstack/sdk": {
|
|
5
5
|
name: "@camstack/sdk",
|
|
6
|
-
version: "1.2.
|
|
6
|
+
version: "1.2.108",
|
|
7
7
|
scope: ["default"],
|
|
8
8
|
loaded: !1,
|
|
9
9
|
from: "addon_stream_broker_widgets",
|
|
@@ -18,7 +18,7 @@ var e = {
|
|
|
18
18
|
},
|
|
19
19
|
"@camstack/types": {
|
|
20
20
|
name: "@camstack/types",
|
|
21
|
-
version: "1.2.
|
|
21
|
+
version: "1.2.202",
|
|
22
22
|
scope: ["default"],
|
|
23
23
|
loaded: !1,
|
|
24
24
|
from: "addon_stream_broker_widgets",
|
|
@@ -33,7 +33,7 @@ var e = {
|
|
|
33
33
|
},
|
|
34
34
|
"@camstack/ui-library": {
|
|
35
35
|
name: "@camstack/ui-library",
|
|
36
|
-
version: "1.2.
|
|
36
|
+
version: "1.2.167",
|
|
37
37
|
scope: ["default"],
|
|
38
38
|
loaded: !1,
|
|
39
39
|
from: "addon_stream_broker_widgets",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_segment_demux_js = require("../segment-demux-js-
|
|
1
|
+
const require_segment_demux_js = require("../segment-demux-js-Dd5asWZc.js");
|
|
2
2
|
let node_worker_threads = require("node:worker_threads");
|
|
3
3
|
//#region src/stream-broker/recorded/demux-worker-child.ts
|
|
4
4
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as demuxSegmentFullJs } from "../segment-demux-js-
|
|
1
|
+
import { t as demuxSegmentFullJs } from "../segment-demux-js-DcF7tvrn.mjs";
|
|
2
2
|
import { parentPort } from "node:worker_threads";
|
|
3
3
|
//#region src/stream-broker/recorded/demux-worker-child.ts
|
|
4
4
|
/**
|
|
@@ -36,7 +36,7 @@ async function r() {
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"@camstack/types": {
|
|
39
|
-
version: "1.2.
|
|
39
|
+
version: "1.2.202",
|
|
40
40
|
scope: "default",
|
|
41
41
|
shareConfig: {
|
|
42
42
|
singleton: !0,
|
|
@@ -45,7 +45,7 @@ async function r() {
|
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
47
|
"@camstack/sdk": {
|
|
48
|
-
version: "1.2.
|
|
48
|
+
version: "1.2.108",
|
|
49
49
|
scope: "default",
|
|
50
50
|
shareConfig: {
|
|
51
51
|
singleton: !0,
|
|
@@ -81,7 +81,7 @@ async function r() {
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"@camstack/ui-library": {
|
|
84
|
-
version: "1.2.
|
|
84
|
+
version: "1.2.167",
|
|
85
85
|
scope: "default",
|
|
86
86
|
shareConfig: {
|
|
87
87
|
singleton: !0,
|
|
@@ -3,12 +3,12 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_node = require("../node-
|
|
6
|
+
const require_dist = require("../dist-BjiM0e6J.js");
|
|
7
|
+
const require_node = require("../node-P2-C_t7H.js");
|
|
8
8
|
const require_restream_intent = require("../restream-intent-C4adO0P8.js");
|
|
9
9
|
const require_remote_restream = require("../remote-restream-CO36Sr30.js");
|
|
10
10
|
const require_retire_root_keys = require("../retire-root-keys-Csb8z2f3.js");
|
|
11
|
-
const require_segment_demux_js = require("../segment-demux-js-
|
|
11
|
+
const require_segment_demux_js = require("../segment-demux-js-Dd5asWZc.js");
|
|
12
12
|
let node_os = require("node:os");
|
|
13
13
|
node_os = require_chunk.__toESM(node_os);
|
|
14
14
|
let node_crypto = require("node:crypto");
|
|
@@ -4207,6 +4207,8 @@ var RtspListenServer = class RtspListenServer {
|
|
|
4207
4207
|
brokerEnabled = /* @__PURE__ */ new Map();
|
|
4208
4208
|
/** brokerId → warm-up closure registered alongside the restreamer */
|
|
4209
4209
|
brokerWarmUps = /* @__PURE__ */ new Map();
|
|
4210
|
+
/** brokerId → prestream picture-window opener */
|
|
4211
|
+
brokerPrestreamOpeners = /* @__PURE__ */ new Map();
|
|
4210
4212
|
/** Generate a random token for a stream path */
|
|
4211
4213
|
static generateToken() {
|
|
4212
4214
|
return (0, node_crypto.randomBytes)(16).toString("hex");
|
|
@@ -4217,7 +4219,7 @@ var RtspListenServer = class RtspListenServer {
|
|
|
4217
4219
|
* If not, generate a new one.
|
|
4218
4220
|
* Returns the token used.
|
|
4219
4221
|
*/
|
|
4220
|
-
registerRestreamer(brokerId, restreamer, warmUp, existingToken) {
|
|
4222
|
+
registerRestreamer(brokerId, restreamer, warmUp, existingToken, prestreamOpener) {
|
|
4221
4223
|
const oldToken = this.brokerTokens.get(brokerId);
|
|
4222
4224
|
if (oldToken) {
|
|
4223
4225
|
this.restreamers.delete(oldToken);
|
|
@@ -4228,6 +4230,7 @@ var RtspListenServer = class RtspListenServer {
|
|
|
4228
4230
|
this.brokerTokens.set(brokerId, token);
|
|
4229
4231
|
this.tokenBrokers.set(token, brokerId);
|
|
4230
4232
|
if (warmUp) this.brokerWarmUps.set(brokerId, warmUp);
|
|
4233
|
+
if (prestreamOpener) this.brokerPrestreamOpeners.set(brokerId, prestreamOpener);
|
|
4231
4234
|
return token;
|
|
4232
4235
|
}
|
|
4233
4236
|
unregisterRestreamer(brokerId) {
|
|
@@ -4238,6 +4241,7 @@ var RtspListenServer = class RtspListenServer {
|
|
|
4238
4241
|
}
|
|
4239
4242
|
this.brokerTokens.delete(brokerId);
|
|
4240
4243
|
this.brokerWarmUps.delete(brokerId);
|
|
4244
|
+
this.brokerPrestreamOpeners.delete(brokerId);
|
|
4241
4245
|
}
|
|
4242
4246
|
/** Regenerate a random token for a broker. Returns the new token. */
|
|
4243
4247
|
regenerateToken(brokerId) {
|
|
@@ -4338,8 +4342,10 @@ var RtspListenServer = class RtspListenServer {
|
|
|
4338
4342
|
socket.destroy();
|
|
4339
4343
|
return;
|
|
4340
4344
|
}
|
|
4341
|
-
const
|
|
4342
|
-
const
|
|
4345
|
+
const prestreamDial = declaration.intent === "prestream";
|
|
4346
|
+
const warmUp = brokerId && !prestreamDial ? this.brokerWarmUps.get(brokerId) : void 0;
|
|
4347
|
+
const opener = brokerId && prestreamDial ? this.brokerPrestreamOpeners.get(brokerId) : void 0;
|
|
4348
|
+
const releaseWarmUp = warmUp ? warmUp() : opener?.() ?? null;
|
|
4343
4349
|
let released = false;
|
|
4344
4350
|
const releaseOnce = () => {
|
|
4345
4351
|
if (released) return;
|
|
@@ -13445,9 +13451,36 @@ var StreamBroker = class StreamBroker {
|
|
|
13445
13451
|
*/
|
|
13446
13452
|
hasAnyConsumer() {
|
|
13447
13453
|
if (this.hasLiveIntent()) return true;
|
|
13454
|
+
if (this.prestreamHolds > 0) return true;
|
|
13448
13455
|
return this.rtspRestreamer.getPrestreamSessionCount() > 0;
|
|
13449
13456
|
}
|
|
13450
13457
|
/**
|
|
13458
|
+
* Somebody is DESCRIBING a prestream and has no session yet.
|
|
13459
|
+
*
|
|
13460
|
+
* The RTSP dispatch reads the SDP before `addSession` runs, so a window that
|
|
13461
|
+
* waits for the session is too late: the consumer is handed an empty SDP and
|
|
13462
|
+
* quits. Measured against the live hub (2026-09-15 14:47): the window opened
|
|
13463
|
+
* on the attach and closed 42 ms later having emitted zero frames, because
|
|
13464
|
+
* ffmpeg had already given up.
|
|
13465
|
+
*
|
|
13466
|
+
* This is the prestream counterpart of `BrokerWarmUp` and its exact opposite
|
|
13467
|
+
* in effect: the warm-up subscribes demand, which DIALS; this opens the
|
|
13468
|
+
* picture, which never does. A battery camera is not touched.
|
|
13469
|
+
*/
|
|
13470
|
+
openPrestreamWindow() {
|
|
13471
|
+
this.prestreamHolds += 1;
|
|
13472
|
+
this.checkDemand();
|
|
13473
|
+
let released = false;
|
|
13474
|
+
return () => {
|
|
13475
|
+
if (released) return;
|
|
13476
|
+
released = true;
|
|
13477
|
+
this.prestreamHolds = Math.max(0, this.prestreamHolds - 1);
|
|
13478
|
+
this.checkDemand();
|
|
13479
|
+
};
|
|
13480
|
+
}
|
|
13481
|
+
/** DESCRIBE-window prestream holds: sessions that do not exist yet. */
|
|
13482
|
+
prestreamHolds = 0;
|
|
13483
|
+
/**
|
|
13451
13484
|
* Consumers that may DIAL. Every term of the former `hasDemand`, with the
|
|
13452
13485
|
* RTSP session count filtered to exclude prestream dials, plus the wake hold.
|
|
13453
13486
|
*
|
|
@@ -13607,6 +13640,31 @@ var StreamBroker = class StreamBroker {
|
|
|
13607
13640
|
}, SUSPEND_GRACE_MS);
|
|
13608
13641
|
}
|
|
13609
13642
|
this.prestreamWanted = this.hasAnyConsumer() && !this.hasLiveIntent();
|
|
13643
|
+
this.reconcilePrestreamWindow();
|
|
13644
|
+
}
|
|
13645
|
+
/**
|
|
13646
|
+
* Open or close the prestream window to match {@link prestreamWanted}.
|
|
13647
|
+
*
|
|
13648
|
+
* This is the half that was missing. `prestreamWanted` has been computed
|
|
13649
|
+
* correctly since the feature shipped, but the only thing that ever STARTED
|
|
13650
|
+
* the pump was the lazy branch of `start()` — a DIAL, which needs live
|
|
13651
|
+
* intent, which a prestream session does not have by construction. So the
|
|
13652
|
+
* window opened only when something else had already woken the camera, and
|
|
13653
|
+
* `suspend()` closed it for good.
|
|
13654
|
+
*
|
|
13655
|
+
* Driving it from the consumer edge is what the contract already claimed:
|
|
13656
|
+
* the pump follows CONSUMERS, and it neither dials nor wakes nor holds
|
|
13657
|
+
* anything open (D173). `start()` is idempotent, so being called on every
|
|
13658
|
+
* demand check costs one encode per window and no more.
|
|
13659
|
+
*/
|
|
13660
|
+
reconcilePrestreamWindow() {
|
|
13661
|
+
if (!this.prestreamPump) return;
|
|
13662
|
+
if (this.prestreamWanted && !this.prestreamWindowClosed) {
|
|
13663
|
+
const url = this.resolveCurrentSource()?.url ?? this.source?.url;
|
|
13664
|
+
if (url !== void 0) this.prestreamPump.start(url);
|
|
13665
|
+
return;
|
|
13666
|
+
}
|
|
13667
|
+
if (!this.prestreamWanted) this.prestreamPump.stop("no prestream consumer");
|
|
13610
13668
|
}
|
|
13611
13669
|
/**
|
|
13612
13670
|
* Whether a prestream picture should be flowing right now: somebody is
|
|
@@ -13642,6 +13700,7 @@ var StreamBroker = class StreamBroker {
|
|
|
13642
13700
|
}
|
|
13643
13701
|
this.prestreamPump?.stop("broker suspended");
|
|
13644
13702
|
this.prestreamWindowClosed = false;
|
|
13703
|
+
this.reconcilePrestreamWindow();
|
|
13645
13704
|
this.preBuffer.clear();
|
|
13646
13705
|
this.decoderSeedBuffer.clear();
|
|
13647
13706
|
this.clipBuffer?.clear();
|
|
@@ -19308,7 +19367,8 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
19308
19367
|
if (!sourceBroker) continue;
|
|
19309
19368
|
const existingToken = this.persistedTokens.get(profileBrokerId);
|
|
19310
19369
|
const warmUp = () => sourceBroker.onEncodedData(() => {});
|
|
19311
|
-
|
|
19370
|
+
const openPrestreamWindow = () => sourceBroker.openPrestreamWindow();
|
|
19371
|
+
this.rtspServer.registerRestreamer(profileBrokerId, sourceBroker.getRtspRestreamer(), warmUp, existingToken, openPrestreamWindow);
|
|
19312
19372
|
this.profileRestreamerBindings.set(profileBrokerId, sourceBrokerId);
|
|
19313
19373
|
if (!existingToken) this.rtspProvider.persistTokens();
|
|
19314
19374
|
}
|
|
@@ -20967,7 +21027,8 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
20967
21027
|
this.applyClipRetention(deviceId);
|
|
20968
21028
|
const existingToken = this.persistedTokens.get(brokerId);
|
|
20969
21029
|
const warmUp = () => broker.onEncodedData(() => {});
|
|
20970
|
-
|
|
21030
|
+
const openPrestreamWindow = () => broker.openPrestreamWindow();
|
|
21031
|
+
this.rtspServer.registerRestreamer(brokerId, broker.getRtspRestreamer(), warmUp, existingToken, openPrestreamWindow);
|
|
20971
21032
|
if (!existingToken) this.rtspProvider.persistTokens();
|
|
20972
21033
|
await this.fanOutRegistration(deviceId, brokerId, cam, broker);
|
|
20973
21034
|
this.syncProfileRestreamers(deviceId);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { r as __toESM } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { A as RingBuffer, B as declareLogChannel, Bt as buildFfmpegArgs$1, E as RATE_CONTROL_TIGHT, Et as resolveEgressDecodeHwAccel, Gt as CAM_PROFILE_ORDER, H as deriveBatteryPresence, Ht as isSoftwareDecode, I as batteryCapability, It as webrtcSessionCapability, K as egressTranscodeSharingKey, Kt as DeviceFeature, L as cameraStreamsCapability, Lt as errMsg, M as addonWidgetsSourceCapability, Nt as streamBrokerCapability, Qt as expandAudioChunkToF32le, R as createHwAccelCache, Rt as AUDIO_PRESETS, T as RATE_CONTROL_RELAXED, Ut as BOOT_RECOVERY_BACKOFF_MS, Vt as invocationFromEncodeProfile, Wt as BaseAddon, Yt as createEvent, _n as record, an as parseProfileBrokerId, at as logChannelsCapability, bn as EventCategory, cn as _enum, dn as discriminatedUnion, en as isEvent, h as EncodeProfileSchema, hn as object, i as BatteryStatusSchema, it as loadContributionCapability, ln as array, mn as number, nn as makeSourceBrokerId, pn as literal, q as egressTransportFromRequest, qt as DeviceType, rn as nodePin, st as maskUrlCredentials, tn as makeProfileBrokerId, un as boolean, v as G711_SCALE_CORRECTION_DB, vn as string, xt as rankStreams, yn as union, z as createLogChannelsProvider } from "../dist-
|
|
3
|
-
import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-
|
|
2
|
+
import { A as RingBuffer, B as declareLogChannel, Bt as buildFfmpegArgs$1, E as RATE_CONTROL_TIGHT, Et as resolveEgressDecodeHwAccel, Gt as CAM_PROFILE_ORDER, H as deriveBatteryPresence, Ht as isSoftwareDecode, I as batteryCapability, It as webrtcSessionCapability, K as egressTranscodeSharingKey, Kt as DeviceFeature, L as cameraStreamsCapability, Lt as errMsg, M as addonWidgetsSourceCapability, Nt as streamBrokerCapability, Qt as expandAudioChunkToF32le, R as createHwAccelCache, Rt as AUDIO_PRESETS, T as RATE_CONTROL_RELAXED, Ut as BOOT_RECOVERY_BACKOFF_MS, Vt as invocationFromEncodeProfile, Wt as BaseAddon, Yt as createEvent, _n as record, an as parseProfileBrokerId, at as logChannelsCapability, bn as EventCategory, cn as _enum, dn as discriminatedUnion, en as isEvent, h as EncodeProfileSchema, hn as object, i as BatteryStatusSchema, it as loadContributionCapability, ln as array, mn as number, nn as makeSourceBrokerId, pn as literal, q as egressTransportFromRequest, qt as DeviceType, rn as nodePin, st as maskUrlCredentials, tn as makeProfileBrokerId, un as boolean, v as G711_SCALE_CORRECTION_DB, vn as string, xt as rankStreams, yn as union, z as createLogChannelsProvider } from "../dist-Dzy3wAmT.mjs";
|
|
3
|
+
import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-D9DBz5HF.mjs";
|
|
4
4
|
import { c as PREBUFFER_MAX_MS, d as resolvePrebuffer, i as parseRestreamPath, l as capPreRollRequestMs, n as NO_DECLARATION, u as prebufferRetentionMs } from "../restream-intent-MeJhGCK9.mjs";
|
|
5
5
|
import { n as profileForStreamId } from "../remote-restream-BeHi78PZ.mjs";
|
|
6
6
|
import { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DZvlso2l.mjs";
|
|
7
|
-
import { i as require_mp4box_all, n as demuxSegmentPreferJs, r as runFfmpegOnce, t as demuxSegmentFullJs } from "../segment-demux-js-
|
|
7
|
+
import { i as require_mp4box_all, n as demuxSegmentPreferJs, r as runFfmpegOnce, t as demuxSegmentFullJs } from "../segment-demux-js-DcF7tvrn.mjs";
|
|
8
8
|
import { createRequire } from "node:module";
|
|
9
9
|
import * as os from "node:os";
|
|
10
10
|
import { networkInterfaces, tmpdir } from "node:os";
|
|
@@ -4203,6 +4203,8 @@ var RtspListenServer = class RtspListenServer {
|
|
|
4203
4203
|
brokerEnabled = /* @__PURE__ */ new Map();
|
|
4204
4204
|
/** brokerId → warm-up closure registered alongside the restreamer */
|
|
4205
4205
|
brokerWarmUps = /* @__PURE__ */ new Map();
|
|
4206
|
+
/** brokerId → prestream picture-window opener */
|
|
4207
|
+
brokerPrestreamOpeners = /* @__PURE__ */ new Map();
|
|
4206
4208
|
/** Generate a random token for a stream path */
|
|
4207
4209
|
static generateToken() {
|
|
4208
4210
|
return randomBytes(16).toString("hex");
|
|
@@ -4213,7 +4215,7 @@ var RtspListenServer = class RtspListenServer {
|
|
|
4213
4215
|
* If not, generate a new one.
|
|
4214
4216
|
* Returns the token used.
|
|
4215
4217
|
*/
|
|
4216
|
-
registerRestreamer(brokerId, restreamer, warmUp, existingToken) {
|
|
4218
|
+
registerRestreamer(brokerId, restreamer, warmUp, existingToken, prestreamOpener) {
|
|
4217
4219
|
const oldToken = this.brokerTokens.get(brokerId);
|
|
4218
4220
|
if (oldToken) {
|
|
4219
4221
|
this.restreamers.delete(oldToken);
|
|
@@ -4224,6 +4226,7 @@ var RtspListenServer = class RtspListenServer {
|
|
|
4224
4226
|
this.brokerTokens.set(brokerId, token);
|
|
4225
4227
|
this.tokenBrokers.set(token, brokerId);
|
|
4226
4228
|
if (warmUp) this.brokerWarmUps.set(brokerId, warmUp);
|
|
4229
|
+
if (prestreamOpener) this.brokerPrestreamOpeners.set(brokerId, prestreamOpener);
|
|
4227
4230
|
return token;
|
|
4228
4231
|
}
|
|
4229
4232
|
unregisterRestreamer(brokerId) {
|
|
@@ -4234,6 +4237,7 @@ var RtspListenServer = class RtspListenServer {
|
|
|
4234
4237
|
}
|
|
4235
4238
|
this.brokerTokens.delete(brokerId);
|
|
4236
4239
|
this.brokerWarmUps.delete(brokerId);
|
|
4240
|
+
this.brokerPrestreamOpeners.delete(brokerId);
|
|
4237
4241
|
}
|
|
4238
4242
|
/** Regenerate a random token for a broker. Returns the new token. */
|
|
4239
4243
|
regenerateToken(brokerId) {
|
|
@@ -4334,8 +4338,10 @@ var RtspListenServer = class RtspListenServer {
|
|
|
4334
4338
|
socket.destroy();
|
|
4335
4339
|
return;
|
|
4336
4340
|
}
|
|
4337
|
-
const
|
|
4338
|
-
const
|
|
4341
|
+
const prestreamDial = declaration.intent === "prestream";
|
|
4342
|
+
const warmUp = brokerId && !prestreamDial ? this.brokerWarmUps.get(brokerId) : void 0;
|
|
4343
|
+
const opener = brokerId && prestreamDial ? this.brokerPrestreamOpeners.get(brokerId) : void 0;
|
|
4344
|
+
const releaseWarmUp = warmUp ? warmUp() : opener?.() ?? null;
|
|
4339
4345
|
let released = false;
|
|
4340
4346
|
const releaseOnce = () => {
|
|
4341
4347
|
if (released) return;
|
|
@@ -13441,9 +13447,36 @@ var StreamBroker = class StreamBroker {
|
|
|
13441
13447
|
*/
|
|
13442
13448
|
hasAnyConsumer() {
|
|
13443
13449
|
if (this.hasLiveIntent()) return true;
|
|
13450
|
+
if (this.prestreamHolds > 0) return true;
|
|
13444
13451
|
return this.rtspRestreamer.getPrestreamSessionCount() > 0;
|
|
13445
13452
|
}
|
|
13446
13453
|
/**
|
|
13454
|
+
* Somebody is DESCRIBING a prestream and has no session yet.
|
|
13455
|
+
*
|
|
13456
|
+
* The RTSP dispatch reads the SDP before `addSession` runs, so a window that
|
|
13457
|
+
* waits for the session is too late: the consumer is handed an empty SDP and
|
|
13458
|
+
* quits. Measured against the live hub (2026-09-15 14:47): the window opened
|
|
13459
|
+
* on the attach and closed 42 ms later having emitted zero frames, because
|
|
13460
|
+
* ffmpeg had already given up.
|
|
13461
|
+
*
|
|
13462
|
+
* This is the prestream counterpart of `BrokerWarmUp` and its exact opposite
|
|
13463
|
+
* in effect: the warm-up subscribes demand, which DIALS; this opens the
|
|
13464
|
+
* picture, which never does. A battery camera is not touched.
|
|
13465
|
+
*/
|
|
13466
|
+
openPrestreamWindow() {
|
|
13467
|
+
this.prestreamHolds += 1;
|
|
13468
|
+
this.checkDemand();
|
|
13469
|
+
let released = false;
|
|
13470
|
+
return () => {
|
|
13471
|
+
if (released) return;
|
|
13472
|
+
released = true;
|
|
13473
|
+
this.prestreamHolds = Math.max(0, this.prestreamHolds - 1);
|
|
13474
|
+
this.checkDemand();
|
|
13475
|
+
};
|
|
13476
|
+
}
|
|
13477
|
+
/** DESCRIBE-window prestream holds: sessions that do not exist yet. */
|
|
13478
|
+
prestreamHolds = 0;
|
|
13479
|
+
/**
|
|
13447
13480
|
* Consumers that may DIAL. Every term of the former `hasDemand`, with the
|
|
13448
13481
|
* RTSP session count filtered to exclude prestream dials, plus the wake hold.
|
|
13449
13482
|
*
|
|
@@ -13603,6 +13636,31 @@ var StreamBroker = class StreamBroker {
|
|
|
13603
13636
|
}, SUSPEND_GRACE_MS);
|
|
13604
13637
|
}
|
|
13605
13638
|
this.prestreamWanted = this.hasAnyConsumer() && !this.hasLiveIntent();
|
|
13639
|
+
this.reconcilePrestreamWindow();
|
|
13640
|
+
}
|
|
13641
|
+
/**
|
|
13642
|
+
* Open or close the prestream window to match {@link prestreamWanted}.
|
|
13643
|
+
*
|
|
13644
|
+
* This is the half that was missing. `prestreamWanted` has been computed
|
|
13645
|
+
* correctly since the feature shipped, but the only thing that ever STARTED
|
|
13646
|
+
* the pump was the lazy branch of `start()` — a DIAL, which needs live
|
|
13647
|
+
* intent, which a prestream session does not have by construction. So the
|
|
13648
|
+
* window opened only when something else had already woken the camera, and
|
|
13649
|
+
* `suspend()` closed it for good.
|
|
13650
|
+
*
|
|
13651
|
+
* Driving it from the consumer edge is what the contract already claimed:
|
|
13652
|
+
* the pump follows CONSUMERS, and it neither dials nor wakes nor holds
|
|
13653
|
+
* anything open (D173). `start()` is idempotent, so being called on every
|
|
13654
|
+
* demand check costs one encode per window and no more.
|
|
13655
|
+
*/
|
|
13656
|
+
reconcilePrestreamWindow() {
|
|
13657
|
+
if (!this.prestreamPump) return;
|
|
13658
|
+
if (this.prestreamWanted && !this.prestreamWindowClosed) {
|
|
13659
|
+
const url = this.resolveCurrentSource()?.url ?? this.source?.url;
|
|
13660
|
+
if (url !== void 0) this.prestreamPump.start(url);
|
|
13661
|
+
return;
|
|
13662
|
+
}
|
|
13663
|
+
if (!this.prestreamWanted) this.prestreamPump.stop("no prestream consumer");
|
|
13606
13664
|
}
|
|
13607
13665
|
/**
|
|
13608
13666
|
* Whether a prestream picture should be flowing right now: somebody is
|
|
@@ -13638,6 +13696,7 @@ var StreamBroker = class StreamBroker {
|
|
|
13638
13696
|
}
|
|
13639
13697
|
this.prestreamPump?.stop("broker suspended");
|
|
13640
13698
|
this.prestreamWindowClosed = false;
|
|
13699
|
+
this.reconcilePrestreamWindow();
|
|
13641
13700
|
this.preBuffer.clear();
|
|
13642
13701
|
this.decoderSeedBuffer.clear();
|
|
13643
13702
|
this.clipBuffer?.clear();
|
|
@@ -19304,7 +19363,8 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
19304
19363
|
if (!sourceBroker) continue;
|
|
19305
19364
|
const existingToken = this.persistedTokens.get(profileBrokerId);
|
|
19306
19365
|
const warmUp = () => sourceBroker.onEncodedData(() => {});
|
|
19307
|
-
|
|
19366
|
+
const openPrestreamWindow = () => sourceBroker.openPrestreamWindow();
|
|
19367
|
+
this.rtspServer.registerRestreamer(profileBrokerId, sourceBroker.getRtspRestreamer(), warmUp, existingToken, openPrestreamWindow);
|
|
19308
19368
|
this.profileRestreamerBindings.set(profileBrokerId, sourceBrokerId);
|
|
19309
19369
|
if (!existingToken) this.rtspProvider.persistTokens();
|
|
19310
19370
|
}
|
|
@@ -20963,7 +21023,8 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
20963
21023
|
this.applyClipRetention(deviceId);
|
|
20964
21024
|
const existingToken = this.persistedTokens.get(brokerId);
|
|
20965
21025
|
const warmUp = () => broker.onEncodedData(() => {});
|
|
20966
|
-
|
|
21026
|
+
const openPrestreamWindow = () => broker.openPrestreamWindow();
|
|
21027
|
+
this.rtspServer.registerRestreamer(brokerId, broker.getRtspRestreamer(), warmUp, existingToken, openPrestreamWindow);
|
|
20967
21028
|
if (!existingToken) this.rtspProvider.persistTokens();
|
|
20968
21029
|
await this.fanOutRegistration(deviceId, brokerId, cam, broker);
|
|
20969
21030
|
this.syncProfileRestreamers(deviceId);
|
|
@@ -30,7 +30,7 @@ async function d(e) {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
async function f() {
|
|
33
|
-
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-
|
|
33
|
+
return l ||= d(() => import("./_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-vEbg16EK.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-pipeline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.247",
|
|
4
4
|
"description": "Pipeline bundle — runner, detection, motion, audio + stream broker. Multi-entry npm package shipping pipeline addons under a single bundle.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|