@camstack/addon-pipeline 1.1.23 → 1.1.25
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/audio-codec-ffmpeg/index.js +1 -1
- package/dist/audio-codec-ffmpeg/index.mjs +1 -1
- package/dist/decoder-ffmpeg/index.js +84 -12
- package/dist/decoder-ffmpeg/index.mjs +84 -12
- package/dist/detection-pipeline/index.js +2 -2
- package/dist/detection-pipeline/index.mjs +2 -2
- package/dist/{dist-pd_-3C0T.mjs → dist-BecXbIzJ.mjs} +64 -2
- package/dist/{dist-CE3a05qT.js → dist-wzWBZ26C.js} +69 -1
- package/dist/frame-handle-plane-BAKiW6t4.js +647 -0
- package/dist/frame-handle-plane-DGg0Aevs.mjs +636 -0
- package/dist/hub-hostname-DAJXlOgV.js +54 -0
- package/dist/hub-hostname-cCknRYKj.mjs +49 -0
- package/dist/{model-download-service-C-IHWnXx-BnQ_awK4.js → model-download-service-C-IHWnXx-DxM2DSns.js} +1 -2
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/pipeline-runner/index.js +305 -10
- package/dist/pipeline-runner/index.mjs +305 -10
- package/dist/recorder/index.js +267 -65
- package/dist/recorder/index.mjs +267 -65
- package/dist/stream-broker/_stub.js +39 -39
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-BVFAEkIB.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CWPU9tbs.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-wfWYFiTT.mjs +26 -0
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-lpFwIH9e.mjs +26 -0
- package/dist/stream-broker/{hostInit-DHej3Ep9.mjs → hostInit-B7Fx3R_6.mjs} +2 -2
- package/dist/stream-broker/index.js +7 -611
- package/dist/stream-broker/index.mjs +5 -609
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/embed-dist/assets/{MaskShapeCanvas-DI4BY7W2-BqXU75it.js → MaskShapeCanvas-DI4BY7W2-CPkQfKnu.js} +1 -1
- package/embed-dist/assets/{MotionZonesSettings-NcxxQN8r-Ct2fpgCd.js → MotionZonesSettings-NcxxQN8r-DlLMQBag.js} +1 -1
- package/embed-dist/assets/{PrivacyMaskSettings-APgPLF7p-a9eFVPPl.js → PrivacyMaskSettings-APgPLF7p-kNcauIAN.js} +1 -1
- package/embed-dist/assets/index-DrJ0ee3f.css +2 -0
- package/embed-dist/assets/index-xpPLFfsT.js +80 -0
- package/embed-dist/index.html +2 -2
- package/package.json +1 -1
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BFeBlYRQ.mjs +0 -26
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BC1Jt6G8.mjs +0 -26
- package/embed-dist/assets/index-C7SSikPl.css +0 -2
- package/embed-dist/assets/index-DhdVxWXL.js +0 -80
- package/dist/{model-download-service-C-IHWnXx-3Mmeob3l.mjs → model-download-service-C-IHWnXx-BPy6aoAx.mjs} +1 -1
|
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_model_download_service_C_IHWnXx = require("../model-download-service-C-IHWnXx-
|
|
6
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_model_download_service_C_IHWnXx = require("../model-download-service-C-IHWnXx-DxM2DSns.js");
|
|
6
|
+
const require_dist = require("../dist-wzWBZ26C.js");
|
|
7
7
|
let node_fs = require("node:fs");
|
|
8
8
|
node_fs = require_model_download_service_C_IHWnXx.__toESM(node_fs);
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __require } from "../chunk-BdkLduGY.mjs";
|
|
2
|
-
import { B as
|
|
3
|
-
import { r as downloadFile } from "../model-download-service-C-IHWnXx-
|
|
2
|
+
import { B as errMsg, D as mapAudioLabelToMacro, V as BaseAddon, Y as hydrateSchema, _ as audioAnalyzerCapability, g as audioAnalysisCapability, n as AUDIO_BACKEND_CHOICES, o as DEFAULT_AUDIO_ANALYZER_CONFIG, u as HF_BASE_URL } from "../dist-BecXbIzJ.mjs";
|
|
3
|
+
import { r as downloadFile } from "../model-download-service-C-IHWnXx-BPy6aoAx.mjs";
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
5
|
import * as path$1 from "node:path";
|
|
6
6
|
//#region src/audio-analyzer/audio-pipeline.ts
|
|
@@ -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-wzWBZ26C.js");
|
|
6
6
|
let node_crypto = require("node:crypto");
|
|
7
7
|
let node_child_process = require("node:child_process");
|
|
8
8
|
//#region src/audio-codec-ffmpeg/ffmpeg-audio-process.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as
|
|
1
|
+
import { B as errMsg, V as BaseAddon, v as audioCodecCapability } from "../dist-BecXbIzJ.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
//#region src/audio-codec-ffmpeg/ffmpeg-audio-process.ts
|
|
@@ -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-wzWBZ26C.js");
|
|
6
6
|
const require_frame_dropper = require("../frame-dropper-7RTo_YyG.js");
|
|
7
7
|
let _camstack_shm_ring = require("@camstack/shm-ring");
|
|
8
8
|
let node_crypto = require("node:crypto");
|
|
@@ -145,8 +145,10 @@ function buildVideoFilter(hwaccel, pixel, outWidth, outHeight, maxW, gpuScaleFil
|
|
|
145
145
|
* stream line from stderr to learn the exact output W×H (the broker does not
|
|
146
146
|
* pass source geometry for the shm path). `-nostats` suppresses the periodic
|
|
147
147
|
* `frame= …` counter while keeping the one-shot Output block.
|
|
148
|
-
* - The input is `pipe:0` (Annex-B packets written to stdin)
|
|
149
|
-
*
|
|
148
|
+
* - The input is `pipe:0` (Annex-B packets written to stdin) in push mode, or
|
|
149
|
+
* `options.inputUrl` (the owner's restream, dialed by ffmpeg itself —
|
|
150
|
+
* `-rtsp_transport tcp` for rtsp URLs) in pull mode; the output is raw video
|
|
151
|
+
* on `pipe:1` either way.
|
|
150
152
|
*/
|
|
151
153
|
function buildFfmpegDecodeArgs(config, options) {
|
|
152
154
|
const inputFormat = codecToInputFormat(config.codec);
|
|
@@ -162,6 +164,16 @@ function buildFfmpegDecodeArgs(config, options) {
|
|
|
162
164
|
if (needsHwDownload(hwaccel)) hwaccelArgs.push("-hwaccel_device", options.renderDevice ?? "/dev/dri/renderD128");
|
|
163
165
|
if (keepFramesOnGpu(hwaccel, gpuScaleFilter)) hwaccelArgs.push("-hwaccel_output_format", hwaccel);
|
|
164
166
|
}
|
|
167
|
+
const inputArgs = options.inputUrl !== void 0 ? [
|
|
168
|
+
...options.inputUrl.startsWith("rtsp") ? ["-rtsp_transport", "tcp"] : [],
|
|
169
|
+
"-i",
|
|
170
|
+
options.inputUrl
|
|
171
|
+
] : [
|
|
172
|
+
"-f",
|
|
173
|
+
inputFormat,
|
|
174
|
+
"-i",
|
|
175
|
+
"pipe:0"
|
|
176
|
+
];
|
|
165
177
|
return [
|
|
166
178
|
...require_frame_dropper.logBannerArgs("info"),
|
|
167
179
|
"-nostats",
|
|
@@ -174,10 +186,7 @@ function buildFfmpegDecodeArgs(config, options) {
|
|
|
174
186
|
"-analyzeduration",
|
|
175
187
|
"0",
|
|
176
188
|
...hwaccelArgs,
|
|
177
|
-
|
|
178
|
-
inputFormat,
|
|
179
|
-
"-i",
|
|
180
|
-
"pipe:0",
|
|
189
|
+
...inputArgs,
|
|
181
190
|
"-vf",
|
|
182
191
|
vf,
|
|
183
192
|
"-f",
|
|
@@ -650,6 +659,16 @@ var noopLogger = {
|
|
|
650
659
|
* hwaccel init failure (missing render node, unsupported codec on GPU, the
|
|
651
660
|
* Intel `qsv` `code=171`) surfaces this early. */
|
|
652
661
|
var HWACCEL_FALLBACK_WINDOW_MS = 4e3;
|
|
662
|
+
/**
|
|
663
|
+
* Delay before a PULL-MODE session re-dials its input URL after the child
|
|
664
|
+
* exits (RTSP EOF, restream teardown, network blip). Push mode never
|
|
665
|
+
* self-respawns on a plain exit — the broker's packet feed drives recovery —
|
|
666
|
+
* but a pull-mode child owns its own input, so the session must re-dial or a
|
|
667
|
+
* single EOF would silence it forever. The delay turns a hard-down source
|
|
668
|
+
* into a slow probe instead of a spawn storm; the consumer tearing the
|
|
669
|
+
* session down (`destroy`) cancels the pending re-dial.
|
|
670
|
+
*/
|
|
671
|
+
var PULL_REDIAL_DELAY_MS = 3e3;
|
|
653
672
|
var FfmpegDecoderSession = class {
|
|
654
673
|
config;
|
|
655
674
|
logger;
|
|
@@ -680,6 +699,15 @@ var FfmpegDecoderSession = class {
|
|
|
680
699
|
process = null;
|
|
681
700
|
spawnedAtMs = 0;
|
|
682
701
|
/**
|
|
702
|
+
* PULL-MODE input URL (P2b). `null` = push mode (packets via stdin — the
|
|
703
|
+
* default). Set by {@link openStream}; every (re)spawn since reads this URL
|
|
704
|
+
* directly instead of `pipe:0`. A session is push-mode or pull-mode for its
|
|
705
|
+
* whole life — `openStream` on a packet-fed session throws.
|
|
706
|
+
*/
|
|
707
|
+
pullUrl = null;
|
|
708
|
+
/** Pending pull-mode re-dial timer (armed on a pull child exit). */
|
|
709
|
+
pullRedialTimer = null;
|
|
710
|
+
/**
|
|
683
711
|
* Splits ffmpeg's raw stdout byte stream into frames, filling each DIRECTLY
|
|
684
712
|
* into its shm slot (zero-copy) — created once the output geometry is known.
|
|
685
713
|
*/
|
|
@@ -733,7 +761,25 @@ var FfmpegDecoderSession = class {
|
|
|
733
761
|
return this.frameRingSink;
|
|
734
762
|
}
|
|
735
763
|
get isPullMode() {
|
|
736
|
-
return
|
|
764
|
+
return this.pullUrl !== null;
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Switch the session to PULL MODE: (re)spawn ffmpeg reading `url` directly
|
|
768
|
+
* (`-rtsp_transport tcp -i <url>` for rtsp) instead of stdin. The whole
|
|
769
|
+
* output path (filtergraph, rawvideo pipe, shm ring sink) is unchanged.
|
|
770
|
+
*
|
|
771
|
+
* - Calling it again re-dials with the FRESH url (a hub restream bounce
|
|
772
|
+
* mints a new token URL — never cache the old one).
|
|
773
|
+
* - Calling it on a session already fed via `pushPacket` throws: a session
|
|
774
|
+
* is push-mode or pull-mode, never both (mixing inputs would corrupt the
|
|
775
|
+
* decode).
|
|
776
|
+
*/
|
|
777
|
+
async openStream(url) {
|
|
778
|
+
if (this.destroyed) return;
|
|
779
|
+
if (this.pullUrl === null && this.inputPackets > 0) throw new Error("ffmpeg decoder: openStream on a push-fed session — a session is push-mode or pull-mode, never both");
|
|
780
|
+
this.pullUrl = url;
|
|
781
|
+
this.logger.info("ffmpeg decoder: pull-mode openStream — dialing input URL", { meta: { url } });
|
|
782
|
+
this.spawnFfmpeg();
|
|
737
783
|
}
|
|
738
784
|
ensureFrameRingSink() {
|
|
739
785
|
if (this.frameRingSink === null) {
|
|
@@ -751,6 +797,7 @@ var FfmpegDecoderSession = class {
|
|
|
751
797
|
}
|
|
752
798
|
spawnFfmpeg() {
|
|
753
799
|
if (this.destroyed) return;
|
|
800
|
+
this.clearPullRedial();
|
|
754
801
|
this.killFfmpeg();
|
|
755
802
|
this.abortOpenSlot();
|
|
756
803
|
this.splitter = null;
|
|
@@ -767,7 +814,8 @@ var FfmpegDecoderSession = class {
|
|
|
767
814
|
}, {
|
|
768
815
|
hwaccel: this.hwaccel,
|
|
769
816
|
renderDevice: this.renderDevice,
|
|
770
|
-
gpuScaleFilter: this.activeGpuScaleFilter
|
|
817
|
+
gpuScaleFilter: this.activeGpuScaleFilter,
|
|
818
|
+
...this.pullUrl !== null ? { inputUrl: this.pullUrl } : {}
|
|
771
819
|
});
|
|
772
820
|
let child;
|
|
773
821
|
try {
|
|
@@ -854,6 +902,27 @@ var FfmpegDecoderSession = class {
|
|
|
854
902
|
signal,
|
|
855
903
|
outputFrames: this.outputFrames
|
|
856
904
|
} });
|
|
905
|
+
if (this.pullUrl !== null) {
|
|
906
|
+
this.clearPullRedial();
|
|
907
|
+
const timer = setTimeout(() => {
|
|
908
|
+
this.pullRedialTimer = null;
|
|
909
|
+
this.spawnFfmpeg();
|
|
910
|
+
}, PULL_REDIAL_DELAY_MS);
|
|
911
|
+
timer.unref?.();
|
|
912
|
+
this.pullRedialTimer = timer;
|
|
913
|
+
this.logger.info("ffmpeg decoder: pull-mode child exited — re-dial scheduled", { meta: {
|
|
914
|
+
code,
|
|
915
|
+
signal,
|
|
916
|
+
redialInMs: PULL_REDIAL_DELAY_MS
|
|
917
|
+
} });
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
/** Cancel a pending pull-mode re-dial, if armed. */
|
|
921
|
+
clearPullRedial() {
|
|
922
|
+
if (this.pullRedialTimer !== null) {
|
|
923
|
+
clearTimeout(this.pullRedialTimer);
|
|
924
|
+
this.pullRedialTimer = null;
|
|
925
|
+
}
|
|
857
926
|
}
|
|
858
927
|
handleStderr(data) {
|
|
859
928
|
const text = data.toString();
|
|
@@ -958,6 +1027,7 @@ var FfmpegDecoderSession = class {
|
|
|
958
1027
|
}
|
|
959
1028
|
pushPacket(packet) {
|
|
960
1029
|
if (this.destroyed) return;
|
|
1030
|
+
if (this.pullUrl !== null) return;
|
|
961
1031
|
const stdin = this.process?.stdin;
|
|
962
1032
|
if (!stdin) return;
|
|
963
1033
|
this.inputPackets++;
|
|
@@ -990,6 +1060,7 @@ var FfmpegDecoderSession = class {
|
|
|
990
1060
|
async destroy() {
|
|
991
1061
|
if (this.destroyed) return;
|
|
992
1062
|
this.destroyed = true;
|
|
1063
|
+
this.clearPullRedial();
|
|
993
1064
|
this.killFfmpeg();
|
|
994
1065
|
this.abortOpenSlot();
|
|
995
1066
|
this.splitter = null;
|
|
@@ -1235,7 +1306,7 @@ var DecoderFfmpegAddon = class extends require_dist.BaseAddon {
|
|
|
1235
1306
|
return {
|
|
1236
1307
|
id: "decoder-ffmpeg",
|
|
1237
1308
|
name: "Decoder (ffmpeg)",
|
|
1238
|
-
isPullMode:
|
|
1309
|
+
isPullMode: true,
|
|
1239
1310
|
priority: 20
|
|
1240
1311
|
};
|
|
1241
1312
|
}
|
|
@@ -1346,8 +1417,9 @@ var DecoderFfmpegAddon = class extends require_dist.BaseAddon {
|
|
|
1346
1417
|
});
|
|
1347
1418
|
}
|
|
1348
1419
|
async openStream(input) {
|
|
1349
|
-
|
|
1350
|
-
input.
|
|
1420
|
+
const session = this.sessions.get(input.sessionId);
|
|
1421
|
+
if (!session) throw new Error(`decoder-ffmpeg: unknown sessionId ${input.sessionId}`);
|
|
1422
|
+
await session.openStream(input.url);
|
|
1351
1423
|
}
|
|
1352
1424
|
async pullFrames(input) {
|
|
1353
1425
|
if (!this.sessions.has(input.sessionId)) throw new Error(`decoder-ffmpeg: unknown sessionId ${input.sessionId}`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as
|
|
1
|
+
import { B as errMsg, V as BaseAddon, d as HWACCEL_OPTIONS, p as RingBuffer, s as DEFAULT_DECODER_HWACCEL_CONFIG, x as decoderCapability } from "../dist-BecXbIzJ.mjs";
|
|
2
2
|
import { r as logBannerArgs, t as FrameDropper } from "../frame-dropper-CwkBTPGV.mjs";
|
|
3
3
|
import { FrameRingReaderCache, FrameRingWriter, MIN_RING_SLOTS, computeSegmentSize, computeSlotByteLength, createSegment, deriveSlotCount } from "@camstack/shm-ring";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -141,8 +141,10 @@ function buildVideoFilter(hwaccel, pixel, outWidth, outHeight, maxW, gpuScaleFil
|
|
|
141
141
|
* stream line from stderr to learn the exact output W×H (the broker does not
|
|
142
142
|
* pass source geometry for the shm path). `-nostats` suppresses the periodic
|
|
143
143
|
* `frame= …` counter while keeping the one-shot Output block.
|
|
144
|
-
* - The input is `pipe:0` (Annex-B packets written to stdin)
|
|
145
|
-
*
|
|
144
|
+
* - The input is `pipe:0` (Annex-B packets written to stdin) in push mode, or
|
|
145
|
+
* `options.inputUrl` (the owner's restream, dialed by ffmpeg itself —
|
|
146
|
+
* `-rtsp_transport tcp` for rtsp URLs) in pull mode; the output is raw video
|
|
147
|
+
* on `pipe:1` either way.
|
|
146
148
|
*/
|
|
147
149
|
function buildFfmpegDecodeArgs(config, options) {
|
|
148
150
|
const inputFormat = codecToInputFormat(config.codec);
|
|
@@ -158,6 +160,16 @@ function buildFfmpegDecodeArgs(config, options) {
|
|
|
158
160
|
if (needsHwDownload(hwaccel)) hwaccelArgs.push("-hwaccel_device", options.renderDevice ?? "/dev/dri/renderD128");
|
|
159
161
|
if (keepFramesOnGpu(hwaccel, gpuScaleFilter)) hwaccelArgs.push("-hwaccel_output_format", hwaccel);
|
|
160
162
|
}
|
|
163
|
+
const inputArgs = options.inputUrl !== void 0 ? [
|
|
164
|
+
...options.inputUrl.startsWith("rtsp") ? ["-rtsp_transport", "tcp"] : [],
|
|
165
|
+
"-i",
|
|
166
|
+
options.inputUrl
|
|
167
|
+
] : [
|
|
168
|
+
"-f",
|
|
169
|
+
inputFormat,
|
|
170
|
+
"-i",
|
|
171
|
+
"pipe:0"
|
|
172
|
+
];
|
|
161
173
|
return [
|
|
162
174
|
...logBannerArgs("info"),
|
|
163
175
|
"-nostats",
|
|
@@ -170,10 +182,7 @@ function buildFfmpegDecodeArgs(config, options) {
|
|
|
170
182
|
"-analyzeduration",
|
|
171
183
|
"0",
|
|
172
184
|
...hwaccelArgs,
|
|
173
|
-
|
|
174
|
-
inputFormat,
|
|
175
|
-
"-i",
|
|
176
|
-
"pipe:0",
|
|
185
|
+
...inputArgs,
|
|
177
186
|
"-vf",
|
|
178
187
|
vf,
|
|
179
188
|
"-f",
|
|
@@ -646,6 +655,16 @@ var noopLogger = {
|
|
|
646
655
|
* hwaccel init failure (missing render node, unsupported codec on GPU, the
|
|
647
656
|
* Intel `qsv` `code=171`) surfaces this early. */
|
|
648
657
|
var HWACCEL_FALLBACK_WINDOW_MS = 4e3;
|
|
658
|
+
/**
|
|
659
|
+
* Delay before a PULL-MODE session re-dials its input URL after the child
|
|
660
|
+
* exits (RTSP EOF, restream teardown, network blip). Push mode never
|
|
661
|
+
* self-respawns on a plain exit — the broker's packet feed drives recovery —
|
|
662
|
+
* but a pull-mode child owns its own input, so the session must re-dial or a
|
|
663
|
+
* single EOF would silence it forever. The delay turns a hard-down source
|
|
664
|
+
* into a slow probe instead of a spawn storm; the consumer tearing the
|
|
665
|
+
* session down (`destroy`) cancels the pending re-dial.
|
|
666
|
+
*/
|
|
667
|
+
var PULL_REDIAL_DELAY_MS = 3e3;
|
|
649
668
|
var FfmpegDecoderSession = class {
|
|
650
669
|
config;
|
|
651
670
|
logger;
|
|
@@ -676,6 +695,15 @@ var FfmpegDecoderSession = class {
|
|
|
676
695
|
process = null;
|
|
677
696
|
spawnedAtMs = 0;
|
|
678
697
|
/**
|
|
698
|
+
* PULL-MODE input URL (P2b). `null` = push mode (packets via stdin — the
|
|
699
|
+
* default). Set by {@link openStream}; every (re)spawn since reads this URL
|
|
700
|
+
* directly instead of `pipe:0`. A session is push-mode or pull-mode for its
|
|
701
|
+
* whole life — `openStream` on a packet-fed session throws.
|
|
702
|
+
*/
|
|
703
|
+
pullUrl = null;
|
|
704
|
+
/** Pending pull-mode re-dial timer (armed on a pull child exit). */
|
|
705
|
+
pullRedialTimer = null;
|
|
706
|
+
/**
|
|
679
707
|
* Splits ffmpeg's raw stdout byte stream into frames, filling each DIRECTLY
|
|
680
708
|
* into its shm slot (zero-copy) — created once the output geometry is known.
|
|
681
709
|
*/
|
|
@@ -729,7 +757,25 @@ var FfmpegDecoderSession = class {
|
|
|
729
757
|
return this.frameRingSink;
|
|
730
758
|
}
|
|
731
759
|
get isPullMode() {
|
|
732
|
-
return
|
|
760
|
+
return this.pullUrl !== null;
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Switch the session to PULL MODE: (re)spawn ffmpeg reading `url` directly
|
|
764
|
+
* (`-rtsp_transport tcp -i <url>` for rtsp) instead of stdin. The whole
|
|
765
|
+
* output path (filtergraph, rawvideo pipe, shm ring sink) is unchanged.
|
|
766
|
+
*
|
|
767
|
+
* - Calling it again re-dials with the FRESH url (a hub restream bounce
|
|
768
|
+
* mints a new token URL — never cache the old one).
|
|
769
|
+
* - Calling it on a session already fed via `pushPacket` throws: a session
|
|
770
|
+
* is push-mode or pull-mode, never both (mixing inputs would corrupt the
|
|
771
|
+
* decode).
|
|
772
|
+
*/
|
|
773
|
+
async openStream(url) {
|
|
774
|
+
if (this.destroyed) return;
|
|
775
|
+
if (this.pullUrl === null && this.inputPackets > 0) throw new Error("ffmpeg decoder: openStream on a push-fed session — a session is push-mode or pull-mode, never both");
|
|
776
|
+
this.pullUrl = url;
|
|
777
|
+
this.logger.info("ffmpeg decoder: pull-mode openStream — dialing input URL", { meta: { url } });
|
|
778
|
+
this.spawnFfmpeg();
|
|
733
779
|
}
|
|
734
780
|
ensureFrameRingSink() {
|
|
735
781
|
if (this.frameRingSink === null) {
|
|
@@ -747,6 +793,7 @@ var FfmpegDecoderSession = class {
|
|
|
747
793
|
}
|
|
748
794
|
spawnFfmpeg() {
|
|
749
795
|
if (this.destroyed) return;
|
|
796
|
+
this.clearPullRedial();
|
|
750
797
|
this.killFfmpeg();
|
|
751
798
|
this.abortOpenSlot();
|
|
752
799
|
this.splitter = null;
|
|
@@ -763,7 +810,8 @@ var FfmpegDecoderSession = class {
|
|
|
763
810
|
}, {
|
|
764
811
|
hwaccel: this.hwaccel,
|
|
765
812
|
renderDevice: this.renderDevice,
|
|
766
|
-
gpuScaleFilter: this.activeGpuScaleFilter
|
|
813
|
+
gpuScaleFilter: this.activeGpuScaleFilter,
|
|
814
|
+
...this.pullUrl !== null ? { inputUrl: this.pullUrl } : {}
|
|
767
815
|
});
|
|
768
816
|
let child;
|
|
769
817
|
try {
|
|
@@ -850,6 +898,27 @@ var FfmpegDecoderSession = class {
|
|
|
850
898
|
signal,
|
|
851
899
|
outputFrames: this.outputFrames
|
|
852
900
|
} });
|
|
901
|
+
if (this.pullUrl !== null) {
|
|
902
|
+
this.clearPullRedial();
|
|
903
|
+
const timer = setTimeout(() => {
|
|
904
|
+
this.pullRedialTimer = null;
|
|
905
|
+
this.spawnFfmpeg();
|
|
906
|
+
}, PULL_REDIAL_DELAY_MS);
|
|
907
|
+
timer.unref?.();
|
|
908
|
+
this.pullRedialTimer = timer;
|
|
909
|
+
this.logger.info("ffmpeg decoder: pull-mode child exited — re-dial scheduled", { meta: {
|
|
910
|
+
code,
|
|
911
|
+
signal,
|
|
912
|
+
redialInMs: PULL_REDIAL_DELAY_MS
|
|
913
|
+
} });
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
/** Cancel a pending pull-mode re-dial, if armed. */
|
|
917
|
+
clearPullRedial() {
|
|
918
|
+
if (this.pullRedialTimer !== null) {
|
|
919
|
+
clearTimeout(this.pullRedialTimer);
|
|
920
|
+
this.pullRedialTimer = null;
|
|
921
|
+
}
|
|
853
922
|
}
|
|
854
923
|
handleStderr(data) {
|
|
855
924
|
const text = data.toString();
|
|
@@ -954,6 +1023,7 @@ var FfmpegDecoderSession = class {
|
|
|
954
1023
|
}
|
|
955
1024
|
pushPacket(packet) {
|
|
956
1025
|
if (this.destroyed) return;
|
|
1026
|
+
if (this.pullUrl !== null) return;
|
|
957
1027
|
const stdin = this.process?.stdin;
|
|
958
1028
|
if (!stdin) return;
|
|
959
1029
|
this.inputPackets++;
|
|
@@ -986,6 +1056,7 @@ var FfmpegDecoderSession = class {
|
|
|
986
1056
|
async destroy() {
|
|
987
1057
|
if (this.destroyed) return;
|
|
988
1058
|
this.destroyed = true;
|
|
1059
|
+
this.clearPullRedial();
|
|
989
1060
|
this.killFfmpeg();
|
|
990
1061
|
this.abortOpenSlot();
|
|
991
1062
|
this.splitter = null;
|
|
@@ -1231,7 +1302,7 @@ var DecoderFfmpegAddon = class extends BaseAddon {
|
|
|
1231
1302
|
return {
|
|
1232
1303
|
id: "decoder-ffmpeg",
|
|
1233
1304
|
name: "Decoder (ffmpeg)",
|
|
1234
|
-
isPullMode:
|
|
1305
|
+
isPullMode: true,
|
|
1235
1306
|
priority: 20
|
|
1236
1307
|
};
|
|
1237
1308
|
}
|
|
@@ -1342,8 +1413,9 @@ var DecoderFfmpegAddon = class extends BaseAddon {
|
|
|
1342
1413
|
});
|
|
1343
1414
|
}
|
|
1344
1415
|
async openStream(input) {
|
|
1345
|
-
|
|
1346
|
-
input.
|
|
1416
|
+
const session = this.sessions.get(input.sessionId);
|
|
1417
|
+
if (!session) throw new Error(`decoder-ffmpeg: unknown sessionId ${input.sessionId}`);
|
|
1418
|
+
await session.openStream(input.url);
|
|
1347
1419
|
}
|
|
1348
1420
|
async pullFrames(input) {
|
|
1349
1421
|
if (!this.sessions.has(input.sessionId)) throw new Error(`decoder-ffmpeg: unknown sessionId ${input.sessionId}`);
|
|
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_model_download_service_C_IHWnXx = require("../model-download-service-C-IHWnXx-
|
|
6
|
-
const require_dist = require("../dist-
|
|
5
|
+
const require_model_download_service_C_IHWnXx = require("../model-download-service-C-IHWnXx-DxM2DSns.js");
|
|
6
|
+
const require_dist = require("../dist-wzWBZ26C.js");
|
|
7
7
|
let node_fs = require("node:fs");
|
|
8
8
|
node_fs = require_model_download_service_C_IHWnXx.__toESM(node_fs);
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __require } from "../chunk-BdkLduGY.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { a as isModelDownloaded, i as ensureModel, n as deleteModelFromDisk } from "../model-download-service-C-IHWnXx-
|
|
2
|
+
import { B as errMsg, E as hfModelUrl, F as runtimeDevices$1, G as EventCategory, J as createEvent, M as pipelineExecutorCapability, Q as parseJsonUnknown, R as supportedRuntimes$1, S as defaultDeviceFor$1, T as evaluateZoneRules, V as BaseAddon, Y as hydrateSchema, a as COCO_TO_MACRO, i as COCO_80_LABELS, j as nodePin, m as YAMNET_TO_MACRO, r as AUDIO_MACRO_LABELS, t as APPLE_SA_TO_MACRO, tt as sleep, w as detectionPipelineCapability } from "../dist-BecXbIzJ.mjs";
|
|
3
|
+
import { a as isModelDownloaded, i as ensureModel, n as deleteModelFromDisk } from "../model-download-service-C-IHWnXx-BPy6aoAx.mjs";
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
5
|
import * as path$1 from "node:path";
|
|
6
6
|
import * as os from "node:os";
|
|
@@ -6923,6 +6923,25 @@ var ConvertResultSchema = object({
|
|
|
6923
6923
|
})).readonly()
|
|
6924
6924
|
});
|
|
6925
6925
|
/**
|
|
6926
|
+
* THE canonical event-clip pad: the time window a single-timestamp analytics
|
|
6927
|
+
* event expands to when joined with footage (clip window = `[timestamp - preMs,
|
|
6928
|
+
* timestamp + postMs]`). Matches the admin-ui clip window (−5s/+10s).
|
|
6929
|
+
*
|
|
6930
|
+
* Every consumer derives from this ONE constant so event↔footage boundaries
|
|
6931
|
+
* agree everywhere (C1):
|
|
6932
|
+
* - the `videoclips` default provider (addon-post-analysis) pads its clip
|
|
6933
|
+
* windows with it;
|
|
6934
|
+
* - the recorder's ephemeral in-RAM `EventMap` markers (addon-pipeline) pad
|
|
6935
|
+
* their `startMs/endMs` with it.
|
|
6936
|
+
*
|
|
6937
|
+
* NOTE: this is a UI/JOIN convention, NOT the `events`-band keep/discard gate —
|
|
6938
|
+
* that uses the per-device `preBufferSec`/`postBufferSec` config.
|
|
6939
|
+
*/
|
|
6940
|
+
var EVENT_PAD_MS = {
|
|
6941
|
+
preMs: 5e3,
|
|
6942
|
+
postMs: 1e4
|
|
6943
|
+
};
|
|
6944
|
+
/**
|
|
6926
6945
|
* Numeric day-of-week: 0 = Sunday … 6 = Saturday (matches `Date.getDay`).
|
|
6927
6946
|
* Named `RecordingWeekday` to avoid collision with the string-union
|
|
6928
6947
|
* `Weekday` exported from `interfaces/timezones.ts`.
|
|
@@ -10813,6 +10832,31 @@ var ReportMotionInputSchema = object({
|
|
|
10813
10832
|
regions: array(MotionRegionSchema).readonly().optional()
|
|
10814
10833
|
});
|
|
10815
10834
|
/**
|
|
10835
|
+
* Where a runner gets a camera's decoded frames (cross-node Phase 2,
|
|
10836
|
+
* restream-owner model — P2c).
|
|
10837
|
+
*
|
|
10838
|
+
* - `local-broker` (DEFAULT): today's path — subscribe to the co-located
|
|
10839
|
+
* stream-broker's shm frame plane. Every pre-P2c attach payload (no
|
|
10840
|
+
* `frameSource` key) parses to this, so the field is additive with zero
|
|
10841
|
+
* behavior change.
|
|
10842
|
+
* - `remote-restream`: the detect node is NOT the camera's source-owner.
|
|
10843
|
+
* The runner acquires the owner's COMPRESSED passthrough restream
|
|
10844
|
+
* (`streamBroker.getStreamWithCodec({video:'copy'})` — refcounted, the
|
|
10845
|
+
* double-pull guard) and decodes LOCALLY via a satellite frame plane +
|
|
10846
|
+
* pull-mode decoder session pinned to its own node. The shm ring stays
|
|
10847
|
+
* node-local; only H.264/H.265 packets cross the wire.
|
|
10848
|
+
* `hubHostnameOverride` mirrors the recorder's `recordingHubHostname`:
|
|
10849
|
+
* when set it overrides the `CAMSTACK_HUB_URL`-derived host the runner
|
|
10850
|
+
* dials for the owner's restream.
|
|
10851
|
+
*/
|
|
10852
|
+
var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal("local-broker") }), object({
|
|
10853
|
+
kind: literal("remote-restream"),
|
|
10854
|
+
/** The camera's source-owner node (slice 1: always the hub). */
|
|
10855
|
+
ownerNodeId: string(),
|
|
10856
|
+
/** Operator override for the owner host the runner dials. */
|
|
10857
|
+
hubHostnameOverride: string().optional()
|
|
10858
|
+
})]).describe("Per-camera frame-source mode for the runner (P2c)");
|
|
10859
|
+
/**
|
|
10816
10860
|
* Camera assignment payload sent by `addon-pipeline-orchestrator` to a
|
|
10817
10861
|
* specific runner instance via `attachCamera`. Carries everything the
|
|
10818
10862
|
* runner needs to subscribe to the local broker and execute inference.
|
|
@@ -10910,7 +10954,15 @@ var RunnerCameraConfigSchema = object({
|
|
|
10910
10954
|
*/
|
|
10911
10955
|
onboardMotionDrivesAnalyzer: boolean().default(true),
|
|
10912
10956
|
occupancyRecheckSec: number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
|
|
10913
|
-
occupancyRecheckFrames: number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default)
|
|
10957
|
+
occupancyRecheckFrames: number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
|
|
10958
|
+
/**
|
|
10959
|
+
* Where this runner gets the camera's decoded frames (P2c). Defaulted so
|
|
10960
|
+
* every existing payload behaves as `local-broker` — the pre-Phase-2 path.
|
|
10961
|
+
* Populated with `remote-restream` by the orchestrator ONLY when the
|
|
10962
|
+
* camera's detect node differs from its source-owner (P2d, gated by the
|
|
10963
|
+
* `remoteSourcingNodes` rollout setting).
|
|
10964
|
+
*/
|
|
10965
|
+
frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
|
|
10914
10966
|
});
|
|
10915
10967
|
motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
|
|
10916
10968
|
/**
|
|
@@ -18144,6 +18196,16 @@ DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceI
|
|
|
18144
18196
|
kind: "mutation",
|
|
18145
18197
|
auth: "admin"
|
|
18146
18198
|
});
|
|
18199
|
+
/**
|
|
18200
|
+
* `recording` cap — footage availability + HLS playback manifests + per-device
|
|
18201
|
+
* recording config. NOTE on events (source of truth, R5/C3): this cap carries
|
|
18202
|
+
* NO event surface — `getPlaybackManifest` returns playlist URLs only. Timeline
|
|
18203
|
+
* events (motion/object/audio) come from `pipelineAnalytics` (durable SQLite
|
|
18204
|
+
* rows); the recorder's internal EventMap markers are ephemeral in-RAM
|
|
18205
|
+
* annotations that are not exposed here and must not be treated as an event
|
|
18206
|
+
* feed. Event<->footage joins are by time, padded with the shared `EVENT_PAD_MS`
|
|
18207
|
+
* (`interfaces/recording-config.ts`).
|
|
18208
|
+
*/
|
|
18147
18209
|
var RecordingStatusSchema = object({
|
|
18148
18210
|
deviceId: number(),
|
|
18149
18211
|
enabled: boolean(),
|
|
@@ -23203,4 +23265,4 @@ function defaultDeviceFor(id) {
|
|
|
23203
23265
|
return def(id).defaultDevice;
|
|
23204
23266
|
}
|
|
23205
23267
|
//#endregion
|
|
23206
|
-
export {
|
|
23268
|
+
export { parseProfileBrokerId as $, motionDetectionCapability as A, errMsg as B, defineCustomActions as C, mapAudioLabelToMacro as D, hfModelUrl as E, runtimeDevices as F, EventCategory as G, CAM_PROFILE_ORDER as H, storageEvictableCapability as I, createEvent as J, asJsonObject as K, streamBrokerCapability as L, pipelineExecutorCapability as M, pipelineRunnerCapability as N, maskUrlCredentials as O, recordingCapability as P, parseJsonUnknown as Q, supportedRuntimes as R, defaultDeviceFor as S, evaluateZoneRules as T, DeviceFeature as U, BaseAddon as V, DeviceType as W, makeProfileBrokerId as X, hydrateSchema as Y, makeSourceBrokerId as Z, audioAnalyzerCapability as _, COCO_TO_MACRO as a, discriminatedUnion as at, customAction as b, EVENT_PAD_MS as c, number as ct, HWACCEL_OPTIONS as d, string as dt, selectAssignedProfileSlots as et, RecordingConfigSchema as f, union as ft, audioAnalysisCapability as g, addonWidgetsSourceCapability as h, COCO_80_LABELS as i, boolean as it, nodePin as j, migrateConfigToBands as k, EncodeProfileSchema as l, object as lt, YAMNET_TO_MACRO as m, AUDIO_BACKEND_CHOICES as n, _enum as nt, DEFAULT_AUDIO_ANALYZER_CONFIG as o, lazy as ot, RingBuffer as p, createDurableState as q, AUDIO_MACRO_LABELS as r, array as rt, DEFAULT_DECODER_HWACCEL_CONFIG as s, literal as st, APPLE_SA_TO_MACRO as t, sleep as tt, HF_BASE_URL as u, record as ut, audioCodecCapability as v, detectionPipelineCapability as w, decoderCapability as x, cameraStreamsCapability as y, webrtcSessionCapability as z };
|
|
@@ -6923,6 +6923,25 @@ var ConvertResultSchema = object({
|
|
|
6923
6923
|
})).readonly()
|
|
6924
6924
|
});
|
|
6925
6925
|
/**
|
|
6926
|
+
* THE canonical event-clip pad: the time window a single-timestamp analytics
|
|
6927
|
+
* event expands to when joined with footage (clip window = `[timestamp - preMs,
|
|
6928
|
+
* timestamp + postMs]`). Matches the admin-ui clip window (−5s/+10s).
|
|
6929
|
+
*
|
|
6930
|
+
* Every consumer derives from this ONE constant so event↔footage boundaries
|
|
6931
|
+
* agree everywhere (C1):
|
|
6932
|
+
* - the `videoclips` default provider (addon-post-analysis) pads its clip
|
|
6933
|
+
* windows with it;
|
|
6934
|
+
* - the recorder's ephemeral in-RAM `EventMap` markers (addon-pipeline) pad
|
|
6935
|
+
* their `startMs/endMs` with it.
|
|
6936
|
+
*
|
|
6937
|
+
* NOTE: this is a UI/JOIN convention, NOT the `events`-band keep/discard gate —
|
|
6938
|
+
* that uses the per-device `preBufferSec`/`postBufferSec` config.
|
|
6939
|
+
*/
|
|
6940
|
+
var EVENT_PAD_MS = {
|
|
6941
|
+
preMs: 5e3,
|
|
6942
|
+
postMs: 1e4
|
|
6943
|
+
};
|
|
6944
|
+
/**
|
|
6926
6945
|
* Numeric day-of-week: 0 = Sunday … 6 = Saturday (matches `Date.getDay`).
|
|
6927
6946
|
* Named `RecordingWeekday` to avoid collision with the string-union
|
|
6928
6947
|
* `Weekday` exported from `interfaces/timezones.ts`.
|
|
@@ -10813,6 +10832,31 @@ var ReportMotionInputSchema = object({
|
|
|
10813
10832
|
regions: array(MotionRegionSchema).readonly().optional()
|
|
10814
10833
|
});
|
|
10815
10834
|
/**
|
|
10835
|
+
* Where a runner gets a camera's decoded frames (cross-node Phase 2,
|
|
10836
|
+
* restream-owner model — P2c).
|
|
10837
|
+
*
|
|
10838
|
+
* - `local-broker` (DEFAULT): today's path — subscribe to the co-located
|
|
10839
|
+
* stream-broker's shm frame plane. Every pre-P2c attach payload (no
|
|
10840
|
+
* `frameSource` key) parses to this, so the field is additive with zero
|
|
10841
|
+
* behavior change.
|
|
10842
|
+
* - `remote-restream`: the detect node is NOT the camera's source-owner.
|
|
10843
|
+
* The runner acquires the owner's COMPRESSED passthrough restream
|
|
10844
|
+
* (`streamBroker.getStreamWithCodec({video:'copy'})` — refcounted, the
|
|
10845
|
+
* double-pull guard) and decodes LOCALLY via a satellite frame plane +
|
|
10846
|
+
* pull-mode decoder session pinned to its own node. The shm ring stays
|
|
10847
|
+
* node-local; only H.264/H.265 packets cross the wire.
|
|
10848
|
+
* `hubHostnameOverride` mirrors the recorder's `recordingHubHostname`:
|
|
10849
|
+
* when set it overrides the `CAMSTACK_HUB_URL`-derived host the runner
|
|
10850
|
+
* dials for the owner's restream.
|
|
10851
|
+
*/
|
|
10852
|
+
var RunnerFrameSourceSchema = discriminatedUnion("kind", [object({ kind: literal("local-broker") }), object({
|
|
10853
|
+
kind: literal("remote-restream"),
|
|
10854
|
+
/** The camera's source-owner node (slice 1: always the hub). */
|
|
10855
|
+
ownerNodeId: string(),
|
|
10856
|
+
/** Operator override for the owner host the runner dials. */
|
|
10857
|
+
hubHostnameOverride: string().optional()
|
|
10858
|
+
})]).describe("Per-camera frame-source mode for the runner (P2c)");
|
|
10859
|
+
/**
|
|
10816
10860
|
* Camera assignment payload sent by `addon-pipeline-orchestrator` to a
|
|
10817
10861
|
* specific runner instance via `attachCamera`. Carries everything the
|
|
10818
10862
|
* runner needs to subscribe to the local broker and execute inference.
|
|
@@ -10910,7 +10954,15 @@ var RunnerCameraConfigSchema = object({
|
|
|
10910
10954
|
*/
|
|
10911
10955
|
onboardMotionDrivesAnalyzer: boolean().default(true),
|
|
10912
10956
|
occupancyRecheckSec: number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
|
|
10913
|
-
occupancyRecheckFrames: number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default)
|
|
10957
|
+
occupancyRecheckFrames: number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
|
|
10958
|
+
/**
|
|
10959
|
+
* Where this runner gets the camera's decoded frames (P2c). Defaulted so
|
|
10960
|
+
* every existing payload behaves as `local-broker` — the pre-Phase-2 path.
|
|
10961
|
+
* Populated with `remote-restream` by the orchestrator ONLY when the
|
|
10962
|
+
* camera's detect node differs from its source-owner (P2d, gated by the
|
|
10963
|
+
* `remoteSourcingNodes` rollout setting).
|
|
10964
|
+
*/
|
|
10965
|
+
frameSource: RunnerFrameSourceSchema.default({ kind: "local-broker" })
|
|
10914
10966
|
});
|
|
10915
10967
|
motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
|
|
10916
10968
|
/**
|
|
@@ -18144,6 +18196,16 @@ DeviceType.Camera, DeviceType.Sensor, DeviceType.Switch, method(object({ deviceI
|
|
|
18144
18196
|
kind: "mutation",
|
|
18145
18197
|
auth: "admin"
|
|
18146
18198
|
});
|
|
18199
|
+
/**
|
|
18200
|
+
* `recording` cap — footage availability + HLS playback manifests + per-device
|
|
18201
|
+
* recording config. NOTE on events (source of truth, R5/C3): this cap carries
|
|
18202
|
+
* NO event surface — `getPlaybackManifest` returns playlist URLs only. Timeline
|
|
18203
|
+
* events (motion/object/audio) come from `pipelineAnalytics` (durable SQLite
|
|
18204
|
+
* rows); the recorder's internal EventMap markers are ephemeral in-RAM
|
|
18205
|
+
* annotations that are not exposed here and must not be treated as an event
|
|
18206
|
+
* feed. Event<->footage joins are by time, padded with the shared `EVENT_PAD_MS`
|
|
18207
|
+
* (`interfaces/recording-config.ts`).
|
|
18208
|
+
*/
|
|
18147
18209
|
var RecordingStatusSchema = object({
|
|
18148
18210
|
deviceId: number(),
|
|
18149
18211
|
enabled: boolean(),
|
|
@@ -23269,6 +23331,12 @@ Object.defineProperty(exports, "DeviceType", {
|
|
|
23269
23331
|
return DeviceType;
|
|
23270
23332
|
}
|
|
23271
23333
|
});
|
|
23334
|
+
Object.defineProperty(exports, "EVENT_PAD_MS", {
|
|
23335
|
+
enumerable: true,
|
|
23336
|
+
get: function() {
|
|
23337
|
+
return EVENT_PAD_MS;
|
|
23338
|
+
}
|
|
23339
|
+
});
|
|
23272
23340
|
Object.defineProperty(exports, "EncodeProfileSchema", {
|
|
23273
23341
|
enumerable: true,
|
|
23274
23342
|
get: function() {
|