@camstack/addon-pipeline 1.2.93 → 1.2.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{addon-utils-CTRpEiSd.js → addon-utils-DnUCCZVx.js} +1 -1
- package/dist/audio-analyzer/index.js +2 -2
- package/dist/audio-analyzer/index.mjs +1 -1
- package/dist/detection-pipeline/index.js +4 -4
- package/dist/detection-pipeline/index.mjs +2 -2
- package/dist/{dist-D9To_r_d.js → dist-BbRv3bM2.js} +43 -19
- package/dist/{dist-6POVIYmC.mjs → dist-XbrYiMV3.mjs} +43 -19
- package/dist/{event-loop-stall-monitor-C-VvWOxS.mjs → event-loop-stall-monitor-CFWrOZ6G.mjs} +1 -1
- package/dist/{event-loop-stall-monitor-CGacbzXq.js → event-loop-stall-monitor-D9hqbc68.js} +1 -1
- package/dist/{lazy-sharp-C3zOnmiU.js → lazy-sharp-U0EtN7_C.js} +1 -1
- package/dist/motion-wasm/index.js +2 -2
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +195 -14
- package/dist/pipeline-runner/index.mjs +194 -13
- package/dist/recorder/index.js +523 -65
- package/dist/recorder/index.mjs +522 -64
- package/dist/session-decode/decode-worker-child.js +4 -4
- package/dist/session-decode/decode-worker-child.mjs +3 -3
- package/dist/stream-broker/_stub.js +1 -1
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C2woB6bY.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BNOPhQ-y.mjs} +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DMyOrQHq.mjs +26 -0
- package/dist/stream-broker/{hostInit-VCURcZLt.mjs → hostInit-DCV2-mSi.mjs} +1 -1
- package/dist/stream-broker/index.js +1 -1
- package/dist/stream-broker/index.mjs +1 -1
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-Bq28qobd.js → worker-protocol-CNC-ZcU3.js} +1 -1
- package/dist/{worker-protocol-PzAKg8mC.mjs → worker-protocol-D0ewr67U.mjs} +1 -1
- package/package.json +3 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Dut56EeQ.mjs +0 -26
|
@@ -2,9 +2,9 @@ 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-BbRv3bM2.js");
|
|
6
6
|
const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
|
|
7
|
-
const require_addon_utils = require("../addon-utils-
|
|
7
|
+
const require_addon_utils = require("../addon-utils-DnUCCZVx.js");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
node_path = require_dist.__toESM(node_path);
|
|
10
10
|
let node_fs = require("node:fs");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { D as audioAnalyzerCapability, E as audioAnalysisCapability, U as mapAudioLabelToMacro, at as errMsg, dt as BaseAddon, gt as hydrateSchema, h as HF_BASE_URL, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG } from "../dist-
|
|
2
|
+
import { D as audioAnalyzerCapability, E as audioAnalysisCapability, U as mapAudioLabelToMacro, at as errMsg, dt as BaseAddon, gt as hydrateSchema, h as HF_BASE_URL, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG } from "../dist-XbrYiMV3.mjs";
|
|
3
3
|
import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
|
|
4
4
|
import { i as downloadFile } from "../addon-utils-A2S9D7pu.mjs";
|
|
5
5
|
import * as path$1 from "node:path";
|
|
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-
|
|
7
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
5
|
+
const require_dist = require("../dist-BbRv3bM2.js");
|
|
6
|
+
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-D9hqbc68.js");
|
|
7
|
+
const require_lazy_sharp = require("../lazy-sharp-U0EtN7_C.js");
|
|
8
8
|
const require_node_topology_platform = require("../node-topology-platform-CFZ7F4xW.js");
|
|
9
|
-
const require_addon_utils = require("../addon-utils-
|
|
9
|
+
const require_addon_utils = require("../addon-utils-DnUCCZVx.js");
|
|
10
10
|
let sharp = require("sharp");
|
|
11
11
|
sharp = require_dist.__toESM(sharp);
|
|
12
12
|
let node_child_process = require("node:child_process");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as __require } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { B as enumerateInferenceDevices, Et as array, Ft as union, It as EventCategory, J as pipelineExecutorCapability, L as detectionPipelineCapability, M as defaultDeviceFor$1, Mt as object, Pt as string, V as evaluateZoneRules, at as errMsg, bt as nodePin, d as DEVICE_BACKEND_TO_FORMAT, dt as BaseAddon, et as runtimeDevices$1, gt as hydrateSchema, ht as createEvent, rt as supportedRuntimes$1, t as APPLE_SA_TO_MACRO, w as YAMNET_TO_MACRO, wt as sleep, xt as parseJsonUnknown } from "../dist-
|
|
3
|
-
import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-
|
|
2
|
+
import { B as enumerateInferenceDevices, Et as array, Ft as union, It as EventCategory, J as pipelineExecutorCapability, L as detectionPipelineCapability, M as defaultDeviceFor$1, Mt as object, Pt as string, V as evaluateZoneRules, at as errMsg, bt as nodePin, d as DEVICE_BACKEND_TO_FORMAT, dt as BaseAddon, et as runtimeDevices$1, gt as hydrateSchema, ht as createEvent, rt as supportedRuntimes$1, t as APPLE_SA_TO_MACRO, w as YAMNET_TO_MACRO, wt as sleep, xt as parseJsonUnknown } from "../dist-XbrYiMV3.mjs";
|
|
3
|
+
import { a as getDefaultModelForFormat, c as getStepDefinition, i as ALL_STEPS, l as resolveModelForFormat, n as startEventLoopStallMonitor, o as getDefaultModelForFormatFromDef, r as ALL_PIPELINE_STEPS, s as getStep } from "../event-loop-stall-monitor-CFWrOZ6G.mjs";
|
|
4
4
|
import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
|
|
5
5
|
import { t as pickNodePlatformArch } from "../node-topology-platform-BkR_k6WT.mjs";
|
|
6
6
|
import { a as ensureModel, o as isModelDownloaded, r as deleteModelFromDisk } from "../addon-utils-A2S9D7pu.mjs";
|
|
@@ -21996,20 +21996,6 @@ var VectorStatsResultSchema = object({
|
|
|
21996
21996
|
exact: boolean()
|
|
21997
21997
|
});
|
|
21998
21998
|
method(VectorDeclareIndexInputSchema, _void(), { kind: "mutation" }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, { kind: "mutation" }), method(VectorQueryInputSchema, VectorQueryResultSchema), method(VectorGetInputSchema, VectorGetResultSchema), method(VectorDeleteInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorStatsInputSchema, VectorStatsResultSchema);
|
|
21999
|
-
/**
|
|
22000
|
-
* `videoclips` — the unified, navigable-clip surface for a camera.
|
|
22001
|
-
*
|
|
22002
|
-
* A device-scoped WRAPPER cap (like `pipeline-analytics`): exactly one active
|
|
22003
|
-
* provider per device, substitutable. The DEFAULT provider (registered by
|
|
22004
|
-
* `addon-post-analysis`, `defaultActive: true`) composes the analytics event
|
|
22005
|
-
* log (markers + thumbnails) with the recorder's `getPlaybackManifest` — a clip
|
|
22006
|
-
* is a time-WINDOW over existing footage, never a separate file. A camera that
|
|
22007
|
-
* exposes NATIVE onboard clips (Reolink/Hikvision NVR) can later substitute the
|
|
22008
|
-
* wrapper provider for its device and serve its own clip catalog + URLs.
|
|
22009
|
-
*
|
|
22010
|
-
* A `Clip` is purely time-based (subtree-blind): playback resolves segments by
|
|
22011
|
-
* temporal overlap, so the API never decides `continuous` vs `events`.
|
|
22012
|
-
*/
|
|
22013
21999
|
var ClipSchema = object({
|
|
22014
22000
|
/** Opaque, provider-namespaced id. The default provider encodes the time
|
|
22015
22001
|
* window so `getClipPlayback` is self-contained (no event re-query). */
|
|
@@ -22035,12 +22021,41 @@ var ClipSchema = object({
|
|
|
22035
22021
|
* of the event that owns `kind` (object > motion > audio). Do not extract
|
|
22036
22022
|
* a keyframe from the recorded segments. Other providers (onboard, HKSV)
|
|
22037
22023
|
* mint their own stills.
|
|
22024
|
+
*
|
|
22025
|
+
* **VOUCHED, never fabricated.** A provider emits this only for an event it
|
|
22026
|
+
* has CONFIRMED owns at least one media row (its own, or its owning track's).
|
|
22027
|
+
* Absent is meaningful — "this visit has no event still" — never "we did not
|
|
22028
|
+
* look". Stamping it from a URL template made 35% of one camera's clips point
|
|
22029
|
+
* at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
|
|
22030
|
+
* A read that FAILS drops the claim; it never invents it.
|
|
22038
22031
|
*/
|
|
22039
22032
|
thumbnail: string().optional(),
|
|
22040
|
-
/**
|
|
22041
|
-
*
|
|
22042
|
-
*
|
|
22033
|
+
/**
|
|
22034
|
+
* An instant INSIDE this visit's footage, hole-safe, where a recorded still
|
|
22035
|
+
* can be decoded. Present whenever the visit came from recorded availability;
|
|
22036
|
+
* absent on a per-event padded window (there is no footage to promise).
|
|
22037
|
+
*
|
|
22038
|
+
* This is not a thumbnail and not a second byte path: it is the argument to
|
|
22039
|
+
* the recorder's existing still route. The surface — never the provider —
|
|
22040
|
+
* decides whether to use it. It is the midpoint of the visit's LONGEST
|
|
22041
|
+
* contiguous range, not of the visit: a visit spans its holes by
|
|
22042
|
+
* construction, so a naive midpoint lands in dead air.
|
|
22043
|
+
*/
|
|
22044
|
+
stillAtMs: number().optional(),
|
|
22045
|
+
/**
|
|
22046
|
+
* Analytics event ids that overlap this visit — a BOUNDED sample, newest
|
|
22047
|
+
* first within kind (object → motion → audio), capped at
|
|
22048
|
+
* {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
|
|
22049
|
+
*
|
|
22050
|
+
* Bounded because it is not a payload the surface pages through: one visit on
|
|
22051
|
+
* device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
|
|
22052
|
+
* camera-day. Read {@link eventCount} for the true total.
|
|
22053
|
+
*/
|
|
22043
22054
|
eventIds: array(string()).optional(),
|
|
22055
|
+
/** How many analytics events actually overlap this visit. Differs from
|
|
22056
|
+
* `eventIds.length` exactly when the sample was capped — so a truncated
|
|
22057
|
+
* list is never mistaken for a quiet visit. */
|
|
22058
|
+
eventCount: number().int().nonnegative().optional(),
|
|
22044
22059
|
/** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
|
|
22045
22060
|
* than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
|
|
22046
22061
|
* bar keeps showing them via `recording.getAvailability`. */
|
|
@@ -22591,7 +22606,14 @@ var SearchResultSchema = object({
|
|
|
22591
22606
|
});
|
|
22592
22607
|
var AutoUpdateSettingsSchema = object({
|
|
22593
22608
|
channel: ChannelSchema,
|
|
22594
|
-
intervalSeconds: number()
|
|
22609
|
+
intervalSeconds: number(),
|
|
22610
|
+
/**
|
|
22611
|
+
* Cadence of the "an update exists" POLLER, in seconds. Independent of
|
|
22612
|
+
* `channel`: the poller runs while auto-apply is `off`, because being told
|
|
22613
|
+
* about a publish and installing it are different decisions. Clamped
|
|
22614
|
+
* server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
|
|
22615
|
+
*/
|
|
22616
|
+
updateCheckIntervalSeconds: number()
|
|
22595
22617
|
});
|
|
22596
22618
|
var AddonAutoUpdateSchema = ChannelWithInheritSchema;
|
|
22597
22619
|
var RestartAddonResultSchema = unknown();
|
|
@@ -22732,7 +22754,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
|
|
|
22732
22754
|
auth: "admin"
|
|
22733
22755
|
}), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
|
|
22734
22756
|
channel: ChannelSchema,
|
|
22735
|
-
intervalSeconds: number().min(300).max(86400).optional()
|
|
22757
|
+
intervalSeconds: number().min(300).max(86400).optional(),
|
|
22758
|
+
/** Availability-poll cadence; see AutoUpdateSettingsSchema. */
|
|
22759
|
+
updateCheckIntervalSeconds: number().min(900).max(604800).optional()
|
|
22736
22760
|
}), unknown(), {
|
|
22737
22761
|
kind: "mutation",
|
|
22738
22762
|
auth: "admin"
|
|
@@ -21973,20 +21973,6 @@ var VectorStatsResultSchema = object({
|
|
|
21973
21973
|
exact: boolean()
|
|
21974
21974
|
});
|
|
21975
21975
|
method(VectorDeclareIndexInputSchema, _void(), { kind: "mutation" }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, { kind: "mutation" }), method(VectorQueryInputSchema, VectorQueryResultSchema), method(VectorGetInputSchema, VectorGetResultSchema), method(VectorDeleteInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorStatsInputSchema, VectorStatsResultSchema);
|
|
21976
|
-
/**
|
|
21977
|
-
* `videoclips` — the unified, navigable-clip surface for a camera.
|
|
21978
|
-
*
|
|
21979
|
-
* A device-scoped WRAPPER cap (like `pipeline-analytics`): exactly one active
|
|
21980
|
-
* provider per device, substitutable. The DEFAULT provider (registered by
|
|
21981
|
-
* `addon-post-analysis`, `defaultActive: true`) composes the analytics event
|
|
21982
|
-
* log (markers + thumbnails) with the recorder's `getPlaybackManifest` — a clip
|
|
21983
|
-
* is a time-WINDOW over existing footage, never a separate file. A camera that
|
|
21984
|
-
* exposes NATIVE onboard clips (Reolink/Hikvision NVR) can later substitute the
|
|
21985
|
-
* wrapper provider for its device and serve its own clip catalog + URLs.
|
|
21986
|
-
*
|
|
21987
|
-
* A `Clip` is purely time-based (subtree-blind): playback resolves segments by
|
|
21988
|
-
* temporal overlap, so the API never decides `continuous` vs `events`.
|
|
21989
|
-
*/
|
|
21990
21976
|
var ClipSchema = object({
|
|
21991
21977
|
/** Opaque, provider-namespaced id. The default provider encodes the time
|
|
21992
21978
|
* window so `getClipPlayback` is self-contained (no event re-query). */
|
|
@@ -22012,12 +21998,41 @@ var ClipSchema = object({
|
|
|
22012
21998
|
* of the event that owns `kind` (object > motion > audio). Do not extract
|
|
22013
21999
|
* a keyframe from the recorded segments. Other providers (onboard, HKSV)
|
|
22014
22000
|
* mint their own stills.
|
|
22001
|
+
*
|
|
22002
|
+
* **VOUCHED, never fabricated.** A provider emits this only for an event it
|
|
22003
|
+
* has CONFIRMED owns at least one media row (its own, or its owning track's).
|
|
22004
|
+
* Absent is meaningful — "this visit has no event still" — never "we did not
|
|
22005
|
+
* look". Stamping it from a URL template made 35% of one camera's clips point
|
|
22006
|
+
* at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
|
|
22007
|
+
* A read that FAILS drops the claim; it never invents it.
|
|
22015
22008
|
*/
|
|
22016
22009
|
thumbnail: string().optional(),
|
|
22017
|
-
/**
|
|
22018
|
-
*
|
|
22019
|
-
*
|
|
22010
|
+
/**
|
|
22011
|
+
* An instant INSIDE this visit's footage, hole-safe, where a recorded still
|
|
22012
|
+
* can be decoded. Present whenever the visit came from recorded availability;
|
|
22013
|
+
* absent on a per-event padded window (there is no footage to promise).
|
|
22014
|
+
*
|
|
22015
|
+
* This is not a thumbnail and not a second byte path: it is the argument to
|
|
22016
|
+
* the recorder's existing still route. The surface — never the provider —
|
|
22017
|
+
* decides whether to use it. It is the midpoint of the visit's LONGEST
|
|
22018
|
+
* contiguous range, not of the visit: a visit spans its holes by
|
|
22019
|
+
* construction, so a naive midpoint lands in dead air.
|
|
22020
|
+
*/
|
|
22021
|
+
stillAtMs: number().optional(),
|
|
22022
|
+
/**
|
|
22023
|
+
* Analytics event ids that overlap this visit — a BOUNDED sample, newest
|
|
22024
|
+
* first within kind (object → motion → audio), capped at
|
|
22025
|
+
* {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
|
|
22026
|
+
*
|
|
22027
|
+
* Bounded because it is not a payload the surface pages through: one visit on
|
|
22028
|
+
* device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
|
|
22029
|
+
* camera-day. Read {@link eventCount} for the true total.
|
|
22030
|
+
*/
|
|
22020
22031
|
eventIds: array(string()).optional(),
|
|
22032
|
+
/** How many analytics events actually overlap this visit. Differs from
|
|
22033
|
+
* `eventIds.length` exactly when the sample was capped — so a truncated
|
|
22034
|
+
* list is never mistaken for a quiet visit. */
|
|
22035
|
+
eventCount: number().int().nonnegative().optional(),
|
|
22021
22036
|
/** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
|
|
22022
22037
|
* than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
|
|
22023
22038
|
* bar keeps showing them via `recording.getAvailability`. */
|
|
@@ -22568,7 +22583,14 @@ var SearchResultSchema = object({
|
|
|
22568
22583
|
});
|
|
22569
22584
|
var AutoUpdateSettingsSchema = object({
|
|
22570
22585
|
channel: ChannelSchema,
|
|
22571
|
-
intervalSeconds: number()
|
|
22586
|
+
intervalSeconds: number(),
|
|
22587
|
+
/**
|
|
22588
|
+
* Cadence of the "an update exists" POLLER, in seconds. Independent of
|
|
22589
|
+
* `channel`: the poller runs while auto-apply is `off`, because being told
|
|
22590
|
+
* about a publish and installing it are different decisions. Clamped
|
|
22591
|
+
* server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
|
|
22592
|
+
*/
|
|
22593
|
+
updateCheckIntervalSeconds: number()
|
|
22572
22594
|
});
|
|
22573
22595
|
var AddonAutoUpdateSchema = ChannelWithInheritSchema;
|
|
22574
22596
|
var RestartAddonResultSchema = unknown();
|
|
@@ -22709,7 +22731,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
|
|
|
22709
22731
|
auth: "admin"
|
|
22710
22732
|
}), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
|
|
22711
22733
|
channel: ChannelSchema,
|
|
22712
|
-
intervalSeconds: number().min(300).max(86400).optional()
|
|
22734
|
+
intervalSeconds: number().min(300).max(86400).optional(),
|
|
22735
|
+
/** Availability-poll cadence; see AutoUpdateSettingsSchema. */
|
|
22736
|
+
updateCheckIntervalSeconds: number().min(900).max(604800).optional()
|
|
22713
22737
|
}), unknown(), {
|
|
22714
22738
|
kind: "mutation",
|
|
22715
22739
|
auth: "admin"
|
package/dist/{event-loop-stall-monitor-C-VvWOxS.mjs → event-loop-stall-monitor-CFWrOZ6G.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { H as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-
|
|
1
|
+
import { H as hfModelUrl, a as COCO_80_LABELS, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-XbrYiMV3.mjs";
|
|
2
2
|
import { PerformanceObserver } from "node:perf_hooks";
|
|
3
3
|
//#region src/detection-pipeline/registry/model-catalogs.ts
|
|
4
4
|
var HF_REPO = "camstack/camstack-models";
|
|
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
5
|
+
const require_dist = require("../dist-BbRv3bM2.js");
|
|
6
|
+
const require_lazy_sharp = require("../lazy-sharp-U0EtN7_C.js");
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
let node_fs = require("node:fs");
|
|
9
9
|
//#region src/motion-wasm/wasm-motion-detector.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { G as motionDetectionCapability, V as evaluateZoneRules, dt as BaseAddon, gt as hydrateSchema, mt as DeviceType } from "../dist-
|
|
1
|
+
import { G as motionDetectionCapability, V as evaluateZoneRules, dt as BaseAddon, gt as hydrateSchema, mt as DeviceType } from "../dist-XbrYiMV3.mjs";
|
|
2
2
|
import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { readFileSync } from "node:fs";
|
|
@@ -2,11 +2,11 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-
|
|
7
|
-
const require_worker_protocol = require("../worker-protocol-
|
|
5
|
+
const require_dist = require("../dist-BbRv3bM2.js");
|
|
6
|
+
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-D9hqbc68.js");
|
|
7
|
+
const require_worker_protocol = require("../worker-protocol-CNC-ZcU3.js");
|
|
8
8
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
9
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
9
|
+
const require_lazy_sharp = require("../lazy-sharp-U0EtN7_C.js");
|
|
10
10
|
const require_remote_restream = require("../remote-restream-BYbAsgUf.js");
|
|
11
11
|
let sharp = require("sharp");
|
|
12
12
|
sharp = require_dist.__toESM(sharp);
|
|
@@ -134,6 +134,8 @@ function startGuardedSessionDecode(deps) {
|
|
|
134
134
|
let stopPump = null;
|
|
135
135
|
let release = null;
|
|
136
136
|
let retryTimer = null;
|
|
137
|
+
/** The live-worker slot held by the RUNNING session, released on teardown. */
|
|
138
|
+
let workerLease = null;
|
|
137
139
|
const delays = deps.acquireRetryDelaysMs && deps.acquireRetryDelaysMs.length > 0 ? deps.acquireRetryDelaysMs : DEFAULT_ACQUIRE_RETRY_DELAYS_MS;
|
|
138
140
|
/** Resolves after the backoff for `attempt`, or immediately once aborted. */
|
|
139
141
|
const waitBackoff = (attempt) => new Promise((resolve) => {
|
|
@@ -146,10 +148,19 @@ function startGuardedSessionDecode(deps) {
|
|
|
146
148
|
});
|
|
147
149
|
(async () => {
|
|
148
150
|
for (let attempt = 0; !aborted; attempt++) {
|
|
151
|
+
let lease = null;
|
|
152
|
+
if (deps.admitWorker) {
|
|
153
|
+
lease = deps.admitWorker();
|
|
154
|
+
if (!lease) {
|
|
155
|
+
await waitBackoff(attempt);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
149
159
|
let acquired = null;
|
|
150
160
|
try {
|
|
151
161
|
acquired = await deps.acquire();
|
|
152
162
|
} catch (err) {
|
|
163
|
+
lease?.release();
|
|
153
164
|
(attempt === 0 ? deps.logger.warn : deps.logger.debug).call(deps.logger, "session-decode: acquire failed — retrying", { meta: {
|
|
154
165
|
attempt: attempt + 1,
|
|
155
166
|
error: require_dist.errMsg(err)
|
|
@@ -158,16 +169,19 @@ function startGuardedSessionDecode(deps) {
|
|
|
158
169
|
continue;
|
|
159
170
|
}
|
|
160
171
|
if (aborted) {
|
|
172
|
+
lease?.release();
|
|
161
173
|
if (acquired) acquired.release();
|
|
162
174
|
return;
|
|
163
175
|
}
|
|
164
176
|
if (!acquired) {
|
|
177
|
+
lease?.release();
|
|
165
178
|
(attempt === 0 ? deps.logger.warn : deps.logger.debug).call(deps.logger, "session-decode: no broker profile bound yet — retrying", { meta: { attempt: attempt + 1 } });
|
|
166
179
|
await waitBackoff(attempt);
|
|
167
180
|
continue;
|
|
168
181
|
}
|
|
169
182
|
if (attempt > 0) deps.logger.info("session-decode: acquire succeeded after retry", { meta: { attempts: attempt + 1 } });
|
|
170
183
|
release = acquired.release;
|
|
184
|
+
workerLease = lease;
|
|
171
185
|
stopPump = deps.startPump(acquired.source);
|
|
172
186
|
return;
|
|
173
187
|
}
|
|
@@ -181,6 +195,8 @@ function startGuardedSessionDecode(deps) {
|
|
|
181
195
|
retryTimer = null;
|
|
182
196
|
}
|
|
183
197
|
stopPump?.();
|
|
198
|
+
workerLease?.release();
|
|
199
|
+
workerLease = null;
|
|
184
200
|
if (release) release();
|
|
185
201
|
};
|
|
186
202
|
}
|
|
@@ -1394,7 +1410,9 @@ var RunSyntheticBenchInputSchema = require_dist.object({
|
|
|
1394
1410
|
sessionId: require_dist.string().optional(),
|
|
1395
1411
|
simulatePipeline: require_dist.boolean().optional(),
|
|
1396
1412
|
nodeId: require_dist.string().optional(),
|
|
1397
|
-
engine: BenchEngineChoiceSchema.optional()
|
|
1413
|
+
engine: BenchEngineChoiceSchema.optional(),
|
|
1414
|
+
deviceKey: require_dist.string().optional(),
|
|
1415
|
+
plane: require_dist._enum(["full", "frame"]).optional()
|
|
1398
1416
|
});
|
|
1399
1417
|
var TimingSplitSchema = require_dist.object({
|
|
1400
1418
|
mean: require_dist.number(),
|
|
@@ -1449,6 +1467,48 @@ var pipelineRunnerBenchActions = require_dist.defineCustomActions({
|
|
|
1449
1467
|
abortCapacityRamp: require_dist.customAction(AbortCapacityRampInputSchema, AbortCapacityRampResultSchema, { kind: "mutation" })
|
|
1450
1468
|
});
|
|
1451
1469
|
//#endregion
|
|
1470
|
+
//#region src/pipeline-runner/bench-dispatch.ts
|
|
1471
|
+
/**
|
|
1472
|
+
* Why the cached fast path is unavailable, or `null` if nothing blocks it.
|
|
1473
|
+
*
|
|
1474
|
+
* The fast path is `cacheFrameInPool` once + `inferCached` per call, and
|
|
1475
|
+
* NEITHER cap method takes a `deviceKey` or a `plane` — only `runPipeline`
|
|
1476
|
+
* does. Forwarding a device selector into it would scope the WARMUP
|
|
1477
|
+
* `runPipeline` to the chosen accelerator and leave every TIMED call on the
|
|
1478
|
+
* node's default pool: a measurement of the wrong device, reported as the
|
|
1479
|
+
* right one. Refusing the fast path costs a slower bench and buys a true
|
|
1480
|
+
* number.
|
|
1481
|
+
*/
|
|
1482
|
+
function fastPathRefusalReason(input) {
|
|
1483
|
+
if (input.deviceKey) return `deviceKey '${input.deviceKey}' requested — inferCached has no device selector, so the timed calls would land on the node's default pool; using the runPipeline path instead`;
|
|
1484
|
+
if (input.plane) return `plane '${input.plane}' requested — inferCached has no plane selector; using the runPipeline path instead`;
|
|
1485
|
+
return null;
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* The cached fast path is only for a plain, single-step, default-device,
|
|
1489
|
+
* default-plane inference bench.
|
|
1490
|
+
*/
|
|
1491
|
+
function canUseCachedFastPath(isSingleStep, input) {
|
|
1492
|
+
return isSingleStep && !input.simulatePipeline && fastPathRefusalReason(input) === null;
|
|
1493
|
+
}
|
|
1494
|
+
/**
|
|
1495
|
+
* Build the `pipelineExecutor.runPipeline` argument for one bench call.
|
|
1496
|
+
*
|
|
1497
|
+
* Every optional is ABSENT when unset rather than present-and-undefined: an
|
|
1498
|
+
* omitted `deviceKey` means "the runner's default device" and an omitted
|
|
1499
|
+
* `plane` means the cap's `'full'` default, and the two are not the same as
|
|
1500
|
+
* an explicit `undefined` on a `.loose()` router input.
|
|
1501
|
+
*/
|
|
1502
|
+
function buildBenchRunPipelineInput(req) {
|
|
1503
|
+
return {
|
|
1504
|
+
steps: [...req.steps],
|
|
1505
|
+
frame: req.frame,
|
|
1506
|
+
...req.engine ? { engine: req.engine } : {},
|
|
1507
|
+
...req.deviceKey ? { deviceKey: req.deviceKey } : {},
|
|
1508
|
+
...req.plane ? { plane: req.plane } : {}
|
|
1509
|
+
};
|
|
1510
|
+
}
|
|
1511
|
+
//#endregion
|
|
1452
1512
|
//#region src/pipeline-runner/capacity/capacity-runner.ts
|
|
1453
1513
|
/**
|
|
1454
1514
|
* Run ONE ramp step: `cameras` independent open-loop pacers for
|
|
@@ -3870,6 +3930,76 @@ var PipelineRunner = class {
|
|
|
3870
3930
|
}
|
|
3871
3931
|
};
|
|
3872
3932
|
//#endregion
|
|
3933
|
+
//#region src/session-decode/live-worker-admission.ts
|
|
3934
|
+
/**
|
|
3935
|
+
* The node's live-decode-worker budget.
|
|
3936
|
+
*
|
|
3937
|
+
* One instance per runner addon. Not a semaphore: a semaphore's contract is
|
|
3938
|
+
* "wait", and waiting is the thing this deliberately does not do — see
|
|
3939
|
+
* {@link DEFAULT_MAX_LIVE_DECODE_WORKERS}.
|
|
3940
|
+
*/
|
|
3941
|
+
var LiveDecodeWorkerAdmission = class {
|
|
3942
|
+
limit;
|
|
3943
|
+
logger;
|
|
3944
|
+
live = 0;
|
|
3945
|
+
constructor(options) {
|
|
3946
|
+
this.limit = Math.max(1, options.limit);
|
|
3947
|
+
this.logger = options.logger;
|
|
3948
|
+
}
|
|
3949
|
+
/** Workers currently holding a slot. */
|
|
3950
|
+
get inFlight() {
|
|
3951
|
+
return this.live;
|
|
3952
|
+
}
|
|
3953
|
+
get ceiling() {
|
|
3954
|
+
return this.limit;
|
|
3955
|
+
}
|
|
3956
|
+
/**
|
|
3957
|
+
* Apply an operator-changed ceiling.
|
|
3958
|
+
*
|
|
3959
|
+
* Lowering it never kills a running session — a decode worker torn down
|
|
3960
|
+
* mid-motion loses the event it was started for. It only stops the next
|
|
3961
|
+
* admission, so the count drains to the new ceiling as sessions end.
|
|
3962
|
+
*/
|
|
3963
|
+
resize(limit) {
|
|
3964
|
+
this.limit = Math.max(1, limit);
|
|
3965
|
+
}
|
|
3966
|
+
/**
|
|
3967
|
+
* Take a slot, or refuse.
|
|
3968
|
+
*
|
|
3969
|
+
* A refusal is a WARN and carries `tags.deviceId`, because the only useful
|
|
3970
|
+
* form of this question is per-camera ("why did 617 not run when 615 did?").
|
|
3971
|
+
* A branch that drops work silently reads as "it never happened".
|
|
3972
|
+
*/
|
|
3973
|
+
admit(deviceId, label) {
|
|
3974
|
+
if (this.live >= this.limit) {
|
|
3975
|
+
this.logger.warn("session-decode: REFUSED — node live decode-worker ceiling reached, will retry", {
|
|
3976
|
+
tags: { deviceId },
|
|
3977
|
+
meta: {
|
|
3978
|
+
label,
|
|
3979
|
+
live: this.live,
|
|
3980
|
+
ceiling: this.limit
|
|
3981
|
+
}
|
|
3982
|
+
});
|
|
3983
|
+
return null;
|
|
3984
|
+
}
|
|
3985
|
+
this.live += 1;
|
|
3986
|
+
this.logger.debug("session-decode: live decode-worker slot taken", {
|
|
3987
|
+
tags: { deviceId },
|
|
3988
|
+
meta: {
|
|
3989
|
+
label,
|
|
3990
|
+
live: this.live,
|
|
3991
|
+
ceiling: this.limit
|
|
3992
|
+
}
|
|
3993
|
+
});
|
|
3994
|
+
let released = false;
|
|
3995
|
+
return { release: () => {
|
|
3996
|
+
if (released) return;
|
|
3997
|
+
released = true;
|
|
3998
|
+
this.live -= 1;
|
|
3999
|
+
} };
|
|
4000
|
+
}
|
|
4001
|
+
};
|
|
4002
|
+
//#endregion
|
|
3873
4003
|
//#region src/pipeline-runner/stateless-step.ts
|
|
3874
4004
|
function modelServability(step, modelId, format) {
|
|
3875
4005
|
const entry = step.models.find((m) => m.id === modelId);
|
|
@@ -4008,7 +4138,8 @@ var DEFAULT_CONFIG = {
|
|
|
4008
4138
|
maxConcurrentInferences: 16,
|
|
4009
4139
|
targetLoadPercent: 80,
|
|
4010
4140
|
minThrottledFps: 1,
|
|
4011
|
-
maxConcurrentDecodeSpawns: 3
|
|
4141
|
+
maxConcurrentDecodeSpawns: 3,
|
|
4142
|
+
maxLiveDecodeWorkers: 8
|
|
4012
4143
|
};
|
|
4013
4144
|
/**
|
|
4014
4145
|
* Camera attachment record kept by the runner addon. Holds the original
|
|
@@ -4311,6 +4442,14 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
4311
4442
|
*/
|
|
4312
4443
|
spawnGate = null;
|
|
4313
4444
|
/**
|
|
4445
|
+
* Per-node ceiling on decode workers ALIVE at once, sized to
|
|
4446
|
+
* `config.maxLiveDecodeWorkers`. The spawn gate above bounds how fast workers
|
|
4447
|
+
* START; this bounds how many EXIST — measured live at 1 -> 8 workers and a
|
|
4448
|
+
* ~4 GiB move in 8 seconds, with nothing stopping the 9th. `resize()`d live in
|
|
4449
|
+
* `onConfigChanged`. Null until `onInitialize`.
|
|
4450
|
+
*/
|
|
4451
|
+
liveWorkers = null;
|
|
4452
|
+
/**
|
|
4314
4453
|
* Node-level map from a retention-ring `FrameHandle` to the decode worker
|
|
4315
4454
|
* still holding that frame's NATIVE surface — backs the `getNativeCrop` cap
|
|
4316
4455
|
* so post-analysis can cut native-res crops (best-effort; a miss falls back
|
|
@@ -4534,6 +4673,10 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
4534
4673
|
}
|
|
4535
4674
|
});
|
|
4536
4675
|
this.spawnGate = new Semaphore(Math.max(1, this.config.maxConcurrentDecodeSpawns));
|
|
4676
|
+
this.liveWorkers = new LiveDecodeWorkerAdmission({
|
|
4677
|
+
limit: this.config.maxLiveDecodeWorkers,
|
|
4678
|
+
logger: this.ctx.logger
|
|
4679
|
+
});
|
|
4537
4680
|
this.runner.timingSampler.setLogger(this.ctx.logger.child("timing"));
|
|
4538
4681
|
this.runner.onDetectionStreamChange((deviceId, action) => {
|
|
4539
4682
|
this.handleDetectionStreamChange(deviceId, action);
|
|
@@ -4694,8 +4837,14 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
4694
4837
|
children: s.children ?? []
|
|
4695
4838
|
}));
|
|
4696
4839
|
const enabledSteps = stepsToRun.filter((s) => s.enabled);
|
|
4697
|
-
const
|
|
4840
|
+
const isSingleStep = enabledSteps.length === 1 && (!enabledSteps[0].children || enabledSteps[0].children.filter((c) => c.enabled).length === 0);
|
|
4841
|
+
const useFastPath = canUseCachedFastPath(isSingleStep, input);
|
|
4698
4842
|
const rootStep = enabledSteps[0];
|
|
4843
|
+
const fastPathRefusal = isSingleStep ? fastPathRefusalReason(input) : null;
|
|
4844
|
+
if (fastPathRefusal) ctx.logger.info("synthetic bench: cached fast path declined", { meta: {
|
|
4845
|
+
reason: fastPathRefusal,
|
|
4846
|
+
node: benchNode
|
|
4847
|
+
} });
|
|
4699
4848
|
const sharedFrame = {
|
|
4700
4849
|
data: cached.data,
|
|
4701
4850
|
format: cached.format,
|
|
@@ -4715,11 +4864,11 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
4715
4864
|
height: cached.height,
|
|
4716
4865
|
format: cached.format
|
|
4717
4866
|
}, pin)).frameId;
|
|
4718
|
-
await api.pipelineExecutor.runPipeline.mutate({
|
|
4867
|
+
await api.pipelineExecutor.runPipeline.mutate({ ...buildBenchRunPipelineInput({
|
|
4719
4868
|
steps: stepsToRun,
|
|
4720
4869
|
frame: sharedFrame,
|
|
4721
4870
|
...input.engine ? { engine: input.engine } : {}
|
|
4722
|
-
}, pin);
|
|
4871
|
+
}) }, pin);
|
|
4723
4872
|
const warmupCount = input.warmup ?? 1;
|
|
4724
4873
|
for (let w = 0; w < warmupCount; w++) await api.pipelineExecutor.inferCached.mutate({
|
|
4725
4874
|
stepId: rootStep.addonId,
|
|
@@ -4812,16 +4961,20 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
4812
4961
|
}
|
|
4813
4962
|
ctx.logger.info("synthetic bench: using full runPipeline path", { meta: {
|
|
4814
4963
|
steps: enabledSteps.length,
|
|
4815
|
-
simulatePipeline: !!input.simulatePipeline
|
|
4964
|
+
simulatePipeline: !!input.simulatePipeline,
|
|
4965
|
+
deviceKey: input.deviceKey ?? null,
|
|
4966
|
+
plane: input.plane ?? null
|
|
4816
4967
|
} });
|
|
4817
4968
|
let _callCount = 0;
|
|
4818
4969
|
const callOnce = async () => {
|
|
4819
4970
|
const t0 = performance.now();
|
|
4820
|
-
const result = await api.pipelineExecutor.runPipeline.mutate({
|
|
4971
|
+
const result = await api.pipelineExecutor.runPipeline.mutate({ ...buildBenchRunPipelineInput({
|
|
4821
4972
|
steps: stepsToRun,
|
|
4822
4973
|
frame: sharedFrame,
|
|
4823
|
-
...input.engine ? { engine: input.engine } : {}
|
|
4824
|
-
|
|
4974
|
+
...input.engine ? { engine: input.engine } : {},
|
|
4975
|
+
...input.deviceKey ? { deviceKey: input.deviceKey } : {},
|
|
4976
|
+
...input.plane ? { plane: input.plane } : {}
|
|
4977
|
+
}) }, pin);
|
|
4825
4978
|
const wallMs = performance.now() - t0;
|
|
4826
4979
|
const n = ++_callCount;
|
|
4827
4980
|
if (n <= 20) ctx.logger.info("bench call trace", { meta: {
|
|
@@ -6198,6 +6351,18 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
6198
6351
|
* blocked by a missing gate. `label` distinguishes detect vs motion forks in
|
|
6199
6352
|
* the logs; the device id is already tagged on `log`.
|
|
6200
6353
|
*/
|
|
6354
|
+
/**
|
|
6355
|
+
* The node's live-decode-worker admission, bound to one camera.
|
|
6356
|
+
*
|
|
6357
|
+
* `undefined` when the ceiling is not configured (pre-`onInitialize`), which
|
|
6358
|
+
* `startGuardedSessionDecode` reads as "no ceiling" — the historical
|
|
6359
|
+
* behaviour. Never a queue: see {@link LiveDecodeWorkerAdmission}.
|
|
6360
|
+
*/
|
|
6361
|
+
buildLiveWorkerAdmit(deviceId, label) {
|
|
6362
|
+
const admission = this.liveWorkers;
|
|
6363
|
+
if (!admission) return void 0;
|
|
6364
|
+
return () => admission.admit(deviceId, label);
|
|
6365
|
+
}
|
|
6201
6366
|
buildDecodeSpawnAcquire(log, label) {
|
|
6202
6367
|
return async () => {
|
|
6203
6368
|
const gate = this.spawnGate;
|
|
@@ -6225,6 +6390,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
6225
6390
|
const requestedAt = Date.now();
|
|
6226
6391
|
const teardown = startGuardedSessionDecode({
|
|
6227
6392
|
logger: log,
|
|
6393
|
+
admitWorker: this.buildLiveWorkerAdmit(config.deviceId, "detect"),
|
|
6228
6394
|
acquire: () => this.acquireSessionDecodeRestream(api, config.deviceId, config.detectionStreamId, `session-decode:detect:${config.deviceId}`, resolveSessionDecodeHostname(config, process.env["CAMSTACK_HUB_URL"]), resolveSessionDecodeOwnerNodeId(config), true),
|
|
6229
6395
|
startPump: (source) => {
|
|
6230
6396
|
const dialMs = Date.now() - requestedAt;
|
|
@@ -6297,6 +6463,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
6297
6463
|
if (!runner) return () => {};
|
|
6298
6464
|
return startGuardedSessionDecode({
|
|
6299
6465
|
logger: log,
|
|
6466
|
+
admitWorker: this.buildLiveWorkerAdmit(config.deviceId, "motion"),
|
|
6300
6467
|
acquire: () => this.acquireSessionDecodeRestream(api, config.deviceId, config.motionStreamId, `session-decode:motion:${config.deviceId}`, resolveSessionDecodeHostname(config, process.env["CAMSTACK_HUB_URL"]), resolveSessionDecodeOwnerNodeId(config)),
|
|
6301
6468
|
startPump: (source) => {
|
|
6302
6469
|
log.info("session-decode: motion routed through per-session decode worker (gray)", { meta: {
|
|
@@ -6853,6 +7020,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
6853
7020
|
}, OCCUPANCY_BURST_SAFETY_TIMEOUT_MS);
|
|
6854
7021
|
teardown = startGuardedSessionDecode({
|
|
6855
7022
|
logger: log,
|
|
7023
|
+
admitWorker: this.buildLiveWorkerAdmit(deviceId, "occupancy"),
|
|
6856
7024
|
acquire: () => this.acquireSessionDecodeRestream(api, config.deviceId, config.detectionStreamId, `session-decode:occupancy:${config.deviceId}`, resolveSessionDecodeHostname(config, process.env["CAMSTACK_HUB_URL"]), resolveSessionDecodeOwnerNodeId(config)),
|
|
6857
7025
|
startPump: (source) => startSessionDecodePump({
|
|
6858
7026
|
fork: this.forkDecodeWorkerWithLease,
|
|
@@ -7026,6 +7194,17 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
7026
7194
|
step: 1,
|
|
7027
7195
|
default: DEFAULT_CONFIG.maxConcurrentDecodeSpawns,
|
|
7028
7196
|
showValue: true
|
|
7197
|
+
},
|
|
7198
|
+
{
|
|
7199
|
+
type: "slider",
|
|
7200
|
+
key: "maxLiveDecodeWorkers",
|
|
7201
|
+
label: "Max live decode workers",
|
|
7202
|
+
description: "Hard ceiling on decode workers ALIVE at once on this node (~320 MB of RAM each). Unlike the spawn gate above, which only limits how fast workers START, this limits how many EXIST. A camera that does not fit is REFUSED and logged, then retried automatically as soon as a slot frees — it is never queued, because a queued live session would decode a moment that has already passed. Raise it if the node has RAM to spare; lower it if the host is memory-constrained.",
|
|
7203
|
+
min: 1,
|
|
7204
|
+
max: 32,
|
|
7205
|
+
step: 1,
|
|
7206
|
+
default: DEFAULT_CONFIG.maxLiveDecodeWorkers,
|
|
7207
|
+
showValue: true
|
|
7029
7208
|
}
|
|
7030
7209
|
]
|
|
7031
7210
|
}] });
|
|
@@ -7033,12 +7212,14 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends require_dist.BaseAdd
|
|
|
7033
7212
|
async onConfigChanged() {
|
|
7034
7213
|
this.runner?.updateLimits(this.config);
|
|
7035
7214
|
this.spawnGate?.resize(Math.max(1, this.config.maxConcurrentDecodeSpawns));
|
|
7215
|
+
this.liveWorkers?.resize(this.config.maxLiveDecodeWorkers);
|
|
7036
7216
|
this.ctx.logger.info("pipeline-runner tuning updated", { meta: {
|
|
7037
7217
|
maxQueueDepth: this.config.maxQueueDepth,
|
|
7038
7218
|
maxConcurrentInferences: this.config.maxConcurrentInferences,
|
|
7039
7219
|
targetLoadPercent: this.config.targetLoadPercent,
|
|
7040
7220
|
minThrottledFps: this.config.minThrottledFps,
|
|
7041
|
-
maxConcurrentDecodeSpawns: this.config.maxConcurrentDecodeSpawns
|
|
7221
|
+
maxConcurrentDecodeSpawns: this.config.maxConcurrentDecodeSpawns,
|
|
7222
|
+
maxLiveDecodeWorkers: this.config.maxLiveDecodeWorkers
|
|
7042
7223
|
} });
|
|
7043
7224
|
}
|
|
7044
7225
|
};
|