@camstack/addon-pipeline 1.2.245 → 1.2.246
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-BokEDZLK.js} +42 -1
- package/dist/{default-detection-model-UXQCoRj_.mjs → default-detection-model-b1HWNGyF.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-FF-KPXS7.js} +47 -8
- package/dist/{dist-CoZwNgzu.mjs → dist-XAp9FVoN.mjs} +47 -8
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-DLZWItaN.js → node-C-KslKQf.js} +1 -1
- package/dist/{node-Uh59Eo57.mjs → node-umwnvSsV.mjs} +1 -1
- package/dist/pipeline-runner/index.js +38 -24
- package/dist/pipeline-runner/index.mjs +38 -24
- package/dist/{process-memory-Bv9SiLn-.js → process-memory-ByvPOmQm.js} +1 -1
- package/dist/{process-memory-BnFnR_nP.mjs → process-memory-DkBPSh44.mjs} +1 -1
- package/dist/recorder/index.js +2 -9
- package/dist/recorder/index.mjs +2 -9
- package/dist/{segment-demux-js-C6B53KjT.js → segment-demux-js-BCzxobGz.js} +1 -1
- package/dist/{segment-demux-js-7DukFIT6.mjs → segment-demux-js-BodSgaxj.mjs} +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-C2-mCqUf.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-BVEP1sys.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-FF-KPXS7.js");
|
|
7
|
+
const require_process_memory = require("../process-memory-ByvPOmQm.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-XAp9FVoN.mjs";
|
|
3
|
+
import { n as pickNodePlatformArch, t as readProcessMemory } from "../process-memory-DkBPSh44.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-FF-KPXS7.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-XAp9FVoN.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-FF-KPXS7.js");
|
|
7
|
+
const require_node = require("../node-C-KslKQf.js");
|
|
8
|
+
const require_default_detection_model = require("../default-detection-model-BokEDZLK.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-ByvPOmQm.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-XAp9FVoN.mjs";
|
|
3
|
+
import { o as readProcessCost } from "../node-umwnvSsV.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-b1HWNGyF.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-DkBPSh44.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
|
]);
|
|
@@ -23993,13 +24006,39 @@ var MotionSourceEnum = _enum([
|
|
|
23993
24006
|
*/
|
|
23994
24007
|
var MotionSourcesSchema = array(MotionSourceEnum);
|
|
23995
24008
|
/**
|
|
23996
|
-
* Which root
|
|
23997
|
-
*
|
|
23998
|
-
*
|
|
23999
|
-
*
|
|
24000
|
-
*
|
|
24009
|
+
* Which root detector a camera runs — EXACTLY ONE.
|
|
24010
|
+
*
|
|
24011
|
+
* Deliberately the SAME vocabulary post-analysis already tags every detection
|
|
24012
|
+
* with (`DetectionSource`) rather than a second spelling of the same two
|
|
24013
|
+
* ideas: the value an operator picks here is the value that comes back on the
|
|
24014
|
+
* track, the overlay and the debug row.
|
|
24015
|
+
*
|
|
24016
|
+
* ## Why one, and why it is still an array
|
|
24017
|
+
*
|
|
24018
|
+
* Two roots on one camera is a capability nobody asked for and the operator has
|
|
24019
|
+
* since ruled out. It was never free: both planes feed the SAME per-device
|
|
24020
|
+
* stationary registry, both can promote the same parked object, and the two
|
|
24021
|
+
* detectors disagree about the same box by construction — which is the
|
|
24022
|
+
* disagreement D505 had to arbitrate. Removing the case removes the arbitration.
|
|
24023
|
+
*
|
|
24024
|
+
* The ARRAY shape survives because the stored settings and the attach payload
|
|
24025
|
+
* already speak it on every camera of every fleet, and a cap input that
|
|
24026
|
+
* suddenly refuses a stored value makes the camera un-attachable — a fail-closed
|
|
24027
|
+
* in the one direction that costs an operator their cameras. So the wire stays
|
|
24028
|
+
* tolerant and the TYPE is exact: a longer list is truncated to its first
|
|
24029
|
+
* element rather than refused, and `max(1)` is what every consumer can then
|
|
24030
|
+
* rely on.
|
|
24031
|
+
*
|
|
24032
|
+
* AT MOST one, not exactly one. The EMPTY list is a legal, deliberate pick —
|
|
24033
|
+
* a camera an operator left with no root detector — and `planDetectionSources`
|
|
24034
|
+
* has always said so: inventing a root for them is how a default acts without
|
|
24035
|
+
* anybody choosing it. Tightening this to `length(1)` broke that, and the
|
|
24036
|
+
* suite caught it.
|
|
24037
|
+
*
|
|
24038
|
+
* Measured before tightening (2026-09-15, this fleet, 6 h of attaches): 3327
|
|
24039
|
+
* `["pipeline"]` and 2 `["onboard"]`. Not one camera had two.
|
|
24001
24040
|
*/
|
|
24002
|
-
var DetectionSourcesSchema = array(DetectionSourceSchema);
|
|
24041
|
+
var DetectionSourcesSchema = preprocess((value) => Array.isArray(value) && value.length > 1 ? value.slice(0, 1) : value, array(DetectionSourceSchema).max(1));
|
|
24003
24042
|
/**
|
|
24004
24043
|
* Input shape for `pipeline-runner.reportMotion` cap method. Exported
|
|
24005
24044
|
* 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
|
]);
|
|
@@ -23993,13 +24006,39 @@ var MotionSourceEnum = _enum([
|
|
|
23993
24006
|
*/
|
|
23994
24007
|
var MotionSourcesSchema = array(MotionSourceEnum);
|
|
23995
24008
|
/**
|
|
23996
|
-
* Which root
|
|
23997
|
-
*
|
|
23998
|
-
*
|
|
23999
|
-
*
|
|
24000
|
-
*
|
|
24009
|
+
* Which root detector a camera runs — EXACTLY ONE.
|
|
24010
|
+
*
|
|
24011
|
+
* Deliberately the SAME vocabulary post-analysis already tags every detection
|
|
24012
|
+
* with (`DetectionSource`) rather than a second spelling of the same two
|
|
24013
|
+
* ideas: the value an operator picks here is the value that comes back on the
|
|
24014
|
+
* track, the overlay and the debug row.
|
|
24015
|
+
*
|
|
24016
|
+
* ## Why one, and why it is still an array
|
|
24017
|
+
*
|
|
24018
|
+
* Two roots on one camera is a capability nobody asked for and the operator has
|
|
24019
|
+
* since ruled out. It was never free: both planes feed the SAME per-device
|
|
24020
|
+
* stationary registry, both can promote the same parked object, and the two
|
|
24021
|
+
* detectors disagree about the same box by construction — which is the
|
|
24022
|
+
* disagreement D505 had to arbitrate. Removing the case removes the arbitration.
|
|
24023
|
+
*
|
|
24024
|
+
* The ARRAY shape survives because the stored settings and the attach payload
|
|
24025
|
+
* already speak it on every camera of every fleet, and a cap input that
|
|
24026
|
+
* suddenly refuses a stored value makes the camera un-attachable — a fail-closed
|
|
24027
|
+
* in the one direction that costs an operator their cameras. So the wire stays
|
|
24028
|
+
* tolerant and the TYPE is exact: a longer list is truncated to its first
|
|
24029
|
+
* element rather than refused, and `max(1)` is what every consumer can then
|
|
24030
|
+
* rely on.
|
|
24031
|
+
*
|
|
24032
|
+
* AT MOST one, not exactly one. The EMPTY list is a legal, deliberate pick —
|
|
24033
|
+
* a camera an operator left with no root detector — and `planDetectionSources`
|
|
24034
|
+
* has always said so: inventing a root for them is how a default acts without
|
|
24035
|
+
* anybody choosing it. Tightening this to `length(1)` broke that, and the
|
|
24036
|
+
* suite caught it.
|
|
24037
|
+
*
|
|
24038
|
+
* Measured before tightening (2026-09-15, this fleet, 6 h of attaches): 3327
|
|
24039
|
+
* `["pipeline"]` and 2 `["onboard"]`. Not one camera had two.
|
|
24001
24040
|
*/
|
|
24002
|
-
var DetectionSourcesSchema = array(DetectionSourceSchema);
|
|
24041
|
+
var DetectionSourcesSchema = preprocess((value) => Array.isArray(value) && value.length > 1 ? value.slice(0, 1) : value, array(DetectionSourceSchema).max(1));
|
|
24003
24042
|
/**
|
|
24004
24043
|
* Input shape for `pipeline-runner.reportMotion` cap method. Exported
|
|
24005
24044
|
* 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-FF-KPXS7.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-XAp9FVoN.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,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-emK7D4bc.js");
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-FF-KPXS7.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);
|
|
@@ -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-XAp9FVoN.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { realpathSync } from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
@@ -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-FF-KPXS7.js");
|
|
7
|
+
const require_node = require("../node-C-KslKQf.js");
|
|
8
|
+
const require_default_detection_model = require("../default-detection-model-BokEDZLK.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
|
|
@@ -6352,7 +6359,7 @@ var PipelineRunner = class {
|
|
|
6352
6359
|
timestamp: Date.now(),
|
|
6353
6360
|
width: frame.width,
|
|
6354
6361
|
height: frame.height
|
|
6355
|
-
});
|
|
6362
|
+
}, state.registration.objectGate);
|
|
6356
6363
|
if (pairing.kind !== "paired") return result;
|
|
6357
6364
|
state.onboardSlot = null;
|
|
6358
6365
|
return {
|
|
@@ -6389,8 +6396,9 @@ var PipelineRunner = class {
|
|
|
6389
6396
|
timestamp: Date.now(),
|
|
6390
6397
|
width: frame.width,
|
|
6391
6398
|
height: frame.height
|
|
6392
|
-
});
|
|
6399
|
+
}, state.registration.objectGate);
|
|
6393
6400
|
if (pairing.kind !== "paired") {
|
|
6401
|
+
if (pairing.kind === "gated") state.onboardSlot = null;
|
|
6394
6402
|
this.noteOnboardRootIdle(deviceId, pairing.kind);
|
|
6395
6403
|
return;
|
|
6396
6404
|
}
|
|
@@ -6406,6 +6414,7 @@ var PipelineRunner = class {
|
|
|
6406
6414
|
detections: pairing.detections
|
|
6407
6415
|
};
|
|
6408
6416
|
state.lastResultDetections = pairing.detections.length;
|
|
6417
|
+
if (handle) this.config.markFrameAskable?.(handle);
|
|
6409
6418
|
await this.notifyCallbacks(deviceId, frame, result, streamType, handle, "onboard", entry.occasion ?? "session");
|
|
6410
6419
|
frameReleaseReason = "success";
|
|
6411
6420
|
} catch {
|
|
@@ -7587,6 +7596,10 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
7587
7596
|
this.frameCutters.drop(handle);
|
|
7588
7597
|
},
|
|
7589
7598
|
hydrateRetainedFrame: (handle) => this.retainedFrames?.ensureContent(handle) ?? Promise.resolve(null),
|
|
7599
|
+
markFrameAskable: (handle) => {
|
|
7600
|
+
const found = this.nativeCropRegistry.lookup(handle);
|
|
7601
|
+
if (found.kind === "live") found.request.markInferred?.();
|
|
7602
|
+
},
|
|
7590
7603
|
onPhaseChanged: (deviceId, phase, meta) => this.handlePhaseChanged(deviceId, phase, meta),
|
|
7591
7604
|
logger: this.ctx.logger,
|
|
7592
7605
|
onOccupancyRecheck: (deviceId, frames) => {
|
|
@@ -8455,6 +8468,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
8455
8468
|
runner.registerCamera(config.deviceId, {
|
|
8456
8469
|
detectionMode: config.detectionMode,
|
|
8457
8470
|
...config.detectionSources !== void 0 ? { detectionSources: config.detectionSources } : {},
|
|
8471
|
+
...require_default_detection_model.rootObjectGate(config.steps) !== void 0 ? { objectGate: require_default_detection_model.rootObjectGate(config.steps) } : {},
|
|
8458
8472
|
fps: config.detectionFps,
|
|
8459
8473
|
motionCooldownMs: config.motionCooldownMs,
|
|
8460
8474
|
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-XAp9FVoN.mjs";
|
|
2
|
+
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-umwnvSsV.mjs";
|
|
3
|
+
import { a as localFrameRegistry, d as getStepDefinition, i as rootObjectGate, o as resolveFrameViewGeometry, r as macroGateVerdict } from "../default-detection-model-b1HWNGyF.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
|
|
@@ -6344,7 +6351,7 @@ var PipelineRunner = class {
|
|
|
6344
6351
|
timestamp: Date.now(),
|
|
6345
6352
|
width: frame.width,
|
|
6346
6353
|
height: frame.height
|
|
6347
|
-
});
|
|
6354
|
+
}, state.registration.objectGate);
|
|
6348
6355
|
if (pairing.kind !== "paired") return result;
|
|
6349
6356
|
state.onboardSlot = null;
|
|
6350
6357
|
return {
|
|
@@ -6381,8 +6388,9 @@ var PipelineRunner = class {
|
|
|
6381
6388
|
timestamp: Date.now(),
|
|
6382
6389
|
width: frame.width,
|
|
6383
6390
|
height: frame.height
|
|
6384
|
-
});
|
|
6391
|
+
}, state.registration.objectGate);
|
|
6385
6392
|
if (pairing.kind !== "paired") {
|
|
6393
|
+
if (pairing.kind === "gated") state.onboardSlot = null;
|
|
6386
6394
|
this.noteOnboardRootIdle(deviceId, pairing.kind);
|
|
6387
6395
|
return;
|
|
6388
6396
|
}
|
|
@@ -6398,6 +6406,7 @@ var PipelineRunner = class {
|
|
|
6398
6406
|
detections: pairing.detections
|
|
6399
6407
|
};
|
|
6400
6408
|
state.lastResultDetections = pairing.detections.length;
|
|
6409
|
+
if (handle) this.config.markFrameAskable?.(handle);
|
|
6401
6410
|
await this.notifyCallbacks(deviceId, frame, result, streamType, handle, "onboard", entry.occasion ?? "session");
|
|
6402
6411
|
frameReleaseReason = "success";
|
|
6403
6412
|
} catch {
|
|
@@ -7579,6 +7588,10 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
7579
7588
|
this.frameCutters.drop(handle);
|
|
7580
7589
|
},
|
|
7581
7590
|
hydrateRetainedFrame: (handle) => this.retainedFrames?.ensureContent(handle) ?? Promise.resolve(null),
|
|
7591
|
+
markFrameAskable: (handle) => {
|
|
7592
|
+
const found = this.nativeCropRegistry.lookup(handle);
|
|
7593
|
+
if (found.kind === "live") found.request.markInferred?.();
|
|
7594
|
+
},
|
|
7582
7595
|
onPhaseChanged: (deviceId, phase, meta) => this.handlePhaseChanged(deviceId, phase, meta),
|
|
7583
7596
|
logger: this.ctx.logger,
|
|
7584
7597
|
onOccupancyRecheck: (deviceId, frames) => {
|
|
@@ -8447,6 +8460,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
8447
8460
|
runner.registerCamera(config.deviceId, {
|
|
8448
8461
|
detectionMode: config.detectionMode,
|
|
8449
8462
|
...config.detectionSources !== void 0 ? { detectionSources: config.detectionSources } : {},
|
|
8463
|
+
...rootObjectGate(config.steps) !== void 0 ? { objectGate: rootObjectGate(config.steps) } : {},
|
|
8450
8464
|
fps: config.detectionFps,
|
|
8451
8465
|
motionCooldownMs: config.motionCooldownMs,
|
|
8452
8466
|
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-FF-KPXS7.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-FF-KPXS7.js");
|
|
7
|
+
const require_node = require("../node-C-KslKQf.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-XAp9FVoN.mjs";
|
|
2
|
+
import { a as physicalRootOf, i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-umwnvSsV.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
|
const require_chunk = require("./chunk-emK7D4bc.js");
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-FF-KPXS7.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) => {
|
|
@@ -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-XAp9FVoN.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) => {
|
|
@@ -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.107",
|
|
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.201",
|
|
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.166",
|
|
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-BCzxobGz.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-BodSgaxj.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.201",
|
|
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.107",
|
|
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.166",
|
|
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-FF-KPXS7.js");
|
|
7
|
+
const require_node = require("../node-C-KslKQf.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-BCzxobGz.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-XAp9FVoN.mjs";
|
|
3
|
+
import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-umwnvSsV.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-BodSgaxj.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-C2-mCqUf.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.246",
|
|
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",
|