@camstack/addon-pipeline 1.2.81 → 1.2.83
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-CQFlZXSn.js → addon-utils-WtpcVuzP.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-DGp0dRiq.mjs → dist-CJI_8GVY.mjs} +10 -1
- package/dist/{dist-B57MztMq.js → dist-CYxusT1M.js} +10 -1
- package/dist/{event-loop-stall-monitor-DPA6Pu_h.js → event-loop-stall-monitor-CHvvXkQS.js} +1 -1
- package/dist/{event-loop-stall-monitor-8vYH44kg.mjs → event-loop-stall-monitor-D3FjNBpW.mjs} +1 -1
- package/dist/{lazy-sharp-BMgRSV9x.js → lazy-sharp-CTNP_35A.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 +4 -4
- package/dist/pipeline-runner/index.mjs +3 -3
- package/dist/recorder/index.js +54 -28
- package/dist/recorder/index.mjs +53 -27
- package/dist/session-decode/decode-worker-child.js +2 -2
- package/dist/session-decode/decode-worker-child.mjs +1 -1
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Cb8ynph1.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DKf1PFZt.mjs} +1 -1
- package/dist/stream-broker/{hostInit-GJipMxBe.mjs → hostInit-CP9inP-0.mjs} +1 -1
- package/dist/stream-broker/index.js +104 -65
- package/dist/stream-broker/index.mjs +104 -65
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-4L4SbSAo.js → worker-protocol-34kViYAj.js} +1 -1
- package/dist/{worker-protocol-_e84lGuR.mjs → worker-protocol-ZYA4xGRg.mjs} +1 -1
- package/package.json +1 -1
|
@@ -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-CYxusT1M.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-WtpcVuzP.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, h as HF_BASE_URL, ht as hydrateSchema, it as errMsg, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, ut as BaseAddon } from "../dist-
|
|
2
|
+
import { D as audioAnalyzerCapability, E as audioAnalysisCapability, U as mapAudioLabelToMacro, h as HF_BASE_URL, ht as hydrateSchema, it as errMsg, n as AUDIO_BACKEND_CHOICES, s as DEFAULT_AUDIO_ANALYZER_CONFIG, ut as BaseAddon } from "../dist-CJI_8GVY.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-CYxusT1M.js");
|
|
6
|
+
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-CHvvXkQS.js");
|
|
7
|
+
const require_lazy_sharp = require("../lazy-sharp-CTNP_35A.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-WtpcVuzP.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 { $ as runtimeDevices$1, B as enumerateInferenceDevices, Ct as sleep, Ft as EventCategory, J as pipelineExecutorCapability, L as detectionPipelineCapability, M as defaultDeviceFor$1, Nt as string, Pt as union, Tt as array, V as evaluateZoneRules, bt as parseJsonUnknown, d as DEVICE_BACKEND_TO_FORMAT, ht as hydrateSchema, it as errMsg, jt as object, mt as createEvent, nt as supportedRuntimes$1, t as APPLE_SA_TO_MACRO, ut as BaseAddon, w as YAMNET_TO_MACRO, yt as nodePin } 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 { $ as runtimeDevices$1, B as enumerateInferenceDevices, Ct as sleep, Ft as EventCategory, J as pipelineExecutorCapability, L as detectionPipelineCapability, M as defaultDeviceFor$1, Nt as string, Pt as union, Tt as array, V as evaluateZoneRules, bt as parseJsonUnknown, d as DEVICE_BACKEND_TO_FORMAT, ht as hydrateSchema, it as errMsg, jt as object, mt as createEvent, nt as supportedRuntimes$1, t as APPLE_SA_TO_MACRO, ut as BaseAddon, w as YAMNET_TO_MACRO, yt as nodePin } from "../dist-CJI_8GVY.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-D3FjNBpW.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";
|
|
@@ -21166,7 +21166,16 @@ targets: array(object({
|
|
|
21166
21166
|
/** A sleeping battery camera: the frame is deliberately stale and will
|
|
21167
21167
|
* NOT refresh in the background. A surface should say so rather than
|
|
21168
21168
|
* present it as current. */
|
|
21169
|
-
sleeping: boolean()
|
|
21169
|
+
sleeping: boolean(),
|
|
21170
|
+
/** Current device state rendered over the cached frame. State images
|
|
21171
|
+
* remain authoritative even when their photographic background is
|
|
21172
|
+
* old; null means the link must carry a current camera frame. */
|
|
21173
|
+
stateReason: _enum([
|
|
21174
|
+
"disabled",
|
|
21175
|
+
"sleeping",
|
|
21176
|
+
"unreachable",
|
|
21177
|
+
"waking"
|
|
21178
|
+
]).nullable()
|
|
21170
21179
|
})));
|
|
21171
21180
|
/**
|
|
21172
21181
|
* `sso-bridge` — internal hub-only cap that lets SSO-style auth
|
|
@@ -21189,7 +21189,16 @@ targets: array(object({
|
|
|
21189
21189
|
/** A sleeping battery camera: the frame is deliberately stale and will
|
|
21190
21190
|
* NOT refresh in the background. A surface should say so rather than
|
|
21191
21191
|
* present it as current. */
|
|
21192
|
-
sleeping: boolean()
|
|
21192
|
+
sleeping: boolean(),
|
|
21193
|
+
/** Current device state rendered over the cached frame. State images
|
|
21194
|
+
* remain authoritative even when their photographic background is
|
|
21195
|
+
* old; null means the link must carry a current camera frame. */
|
|
21196
|
+
stateReason: _enum([
|
|
21197
|
+
"disabled",
|
|
21198
|
+
"sleeping",
|
|
21199
|
+
"unreachable",
|
|
21200
|
+
"waking"
|
|
21201
|
+
]).nullable()
|
|
21193
21202
|
})));
|
|
21194
21203
|
/**
|
|
21195
21204
|
* `sso-bridge` — internal hub-only cap that lets SSO-style auth
|
package/dist/{event-loop-stall-monitor-8vYH44kg.mjs → event-loop-stall-monitor-D3FjNBpW.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-CJI_8GVY.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-CYxusT1M.js");
|
|
6
|
+
const require_lazy_sharp = require("../lazy-sharp-CTNP_35A.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, ht as hydrateSchema, pt as DeviceType, ut as BaseAddon } from "../dist-
|
|
1
|
+
import { G as motionDetectionCapability, V as evaluateZoneRules, ht as hydrateSchema, pt as DeviceType, ut as BaseAddon } from "../dist-CJI_8GVY.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-CYxusT1M.js");
|
|
6
|
+
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-CHvvXkQS.js");
|
|
7
|
+
const require_worker_protocol = require("../worker-protocol-34kViYAj.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-CTNP_35A.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);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { At as number, Et as boolean, F as deriveDetailCropRect, Ft as EventCategory, K as pickDetailCropConvention, N as defineCustomActions, Nt as string, Ot as lazy, Tt as array, Y as pipelineRunnerCapability, c as DEFAULT_DETAIL_CROP_CONVENTION, d as DEVICE_BACKEND_TO_FORMAT, it as errMsg, j as customAction, jt as object, kt as literal, mt as createEvent, q as pickNativeLeaseOverride, ut as BaseAddon, wt as _enum, yt as nodePin } from "../dist-
|
|
2
|
-
import { c as getStepDefinition, t as attributeStall } from "../event-loop-stall-monitor-
|
|
3
|
-
import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-
|
|
1
|
+
import { At as number, Et as boolean, F as deriveDetailCropRect, Ft as EventCategory, K as pickDetailCropConvention, N as defineCustomActions, Nt as string, Ot as lazy, Tt as array, Y as pipelineRunnerCapability, c as DEFAULT_DETAIL_CROP_CONVENTION, d as DEVICE_BACKEND_TO_FORMAT, it as errMsg, j as customAction, jt as object, kt as literal, mt as createEvent, q as pickNativeLeaseOverride, ut as BaseAddon, wt as _enum, yt as nodePin } from "../dist-CJI_8GVY.mjs";
|
|
2
|
+
import { c as getStepDefinition, t as attributeStall } from "../event-loop-stall-monitor-D3FjNBpW.mjs";
|
|
3
|
+
import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-ZYA4xGRg.mjs";
|
|
4
4
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
5
5
|
import { t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
|
|
6
6
|
import { i as withDetectionIntent, n as profileForStreamId, t as isRemoteRestream } from "../remote-restream-Ci7RXNGb.mjs";
|
package/dist/recorder/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const require_dist = require("../dist-
|
|
1
|
+
const require_dist = require("../dist-CYxusT1M.js");
|
|
2
2
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
3
|
-
const require_addon_utils = require("../addon-utils-
|
|
3
|
+
const require_addon_utils = require("../addon-utils-WtpcVuzP.js");
|
|
4
4
|
let node_crypto = require("node:crypto");
|
|
5
5
|
let node_child_process = require("node:child_process");
|
|
6
6
|
let node_path = require("node:path");
|
|
@@ -7482,6 +7482,17 @@ async function recoverStagingOrphans(dir, input, deps) {
|
|
|
7482
7482
|
};
|
|
7483
7483
|
}
|
|
7484
7484
|
/**
|
|
7485
|
+
* Staging directories recovered at once in {@link recoverAllStagedOrphans}.
|
|
7486
|
+
* The pass is serial stat+mkdir+rename per segment over what is usually a
|
|
7487
|
+
* network/FUSE share (shfs): measured on the live hub at 40 454 ms for 46
|
|
7488
|
+
* files in 28 dirs — ~880 ms per file of pure round-trip latency, nothing
|
|
7489
|
+
* CPU-bound (2026-08-15). Dirs are independent by construction (each relocate
|
|
7490
|
+
* is a same-fs rename of a distinct file), so lanes are free; WITHIN a dir the
|
|
7491
|
+
* pass stays serial so the shutdown guard still stops after at most one
|
|
7492
|
+
* in-flight relocate per lane.
|
|
7493
|
+
*/
|
|
7494
|
+
var STAGING_BOOT_DIR_CONCURRENCY = 4;
|
|
7495
|
+
/**
|
|
7485
7496
|
* Boot reconcile: relocate every previous-run segment stranded in staging, on
|
|
7486
7497
|
* every location, for every camera — attached or not.
|
|
7487
7498
|
*
|
|
@@ -7516,6 +7527,7 @@ async function recoverAllStagedOrphans(deps) {
|
|
|
7516
7527
|
locations: locations.map((l) => l.id),
|
|
7517
7528
|
bootMs: deps.bootMs
|
|
7518
7529
|
} });
|
|
7530
|
+
const work = [];
|
|
7519
7531
|
for (const location of locations) {
|
|
7520
7532
|
const stagingRoot = `${location.root}/${STAGING_DIR_NAME}`;
|
|
7521
7533
|
let deviceDirs;
|
|
@@ -7525,7 +7537,6 @@ async function recoverAllStagedOrphans(deps) {
|
|
|
7525
7537
|
continue;
|
|
7526
7538
|
}
|
|
7527
7539
|
for (const deviceDir of deviceDirs) {
|
|
7528
|
-
if (aborted) break;
|
|
7529
7540
|
const deviceId = Number(deviceDir);
|
|
7530
7541
|
if (!Number.isInteger(deviceId) || deviceId <= 0) continue;
|
|
7531
7542
|
let profileDirs;
|
|
@@ -7536,37 +7547,52 @@ async function recoverAllStagedOrphans(deps) {
|
|
|
7536
7547
|
}
|
|
7537
7548
|
const segmentSeconds = await deps.segmentSecondsFor(deviceId);
|
|
7538
7549
|
for (const profile of profileDirs) {
|
|
7539
|
-
if (aborted) break;
|
|
7540
7550
|
if (!KNOWN_PROFILES.has(profile)) continue;
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7544
|
-
|
|
7551
|
+
work.push({
|
|
7552
|
+
location,
|
|
7553
|
+
deviceId,
|
|
7554
|
+
profile,
|
|
7555
|
+
dir: `${stagingRoot}/${deviceDir}/${profile}`,
|
|
7545
7556
|
segmentSeconds
|
|
7546
|
-
}, {
|
|
7547
|
-
listDir: deps.listDir,
|
|
7548
|
-
readPlaylist: deps.readPlaylist,
|
|
7549
|
-
finalize: (orphan, flatAbsPath) => deps.finalize({
|
|
7550
|
-
deviceId,
|
|
7551
|
-
profile,
|
|
7552
|
-
locationId: location.id,
|
|
7553
|
-
locationRoot: location.root,
|
|
7554
|
-
flatAbsPath,
|
|
7555
|
-
startMs: orphan.startMs,
|
|
7556
|
-
durMs: orphan.durMs
|
|
7557
|
-
}),
|
|
7558
|
-
logger: withDeviceTag(deps.logger, deviceId),
|
|
7559
|
-
chunkSize: deps.chunkSize,
|
|
7560
|
-
yieldBetween,
|
|
7561
|
-
shouldStop: deps.shouldStop
|
|
7562
7557
|
});
|
|
7563
|
-
found += report.found;
|
|
7564
|
-
recovered += report.recovered;
|
|
7565
|
-
failed += report.failed;
|
|
7566
|
-
if (report.aborted) aborted = true;
|
|
7567
7558
|
}
|
|
7568
7559
|
}
|
|
7569
7560
|
}
|
|
7561
|
+
const queue = [...work];
|
|
7562
|
+
const lane = async () => {
|
|
7563
|
+
for (;;) {
|
|
7564
|
+
if (aborted || deps.shouldStop?.() === true) return;
|
|
7565
|
+
const item = queue.shift();
|
|
7566
|
+
if (item === void 0) return;
|
|
7567
|
+
dirs += 1;
|
|
7568
|
+
const report = await recoverStagingOrphans(item.dir, {
|
|
7569
|
+
writerStartedMs: deps.bootMs,
|
|
7570
|
+
segmentSeconds: item.segmentSeconds
|
|
7571
|
+
}, {
|
|
7572
|
+
listDir: deps.listDir,
|
|
7573
|
+
readPlaylist: deps.readPlaylist,
|
|
7574
|
+
finalize: (orphan, flatAbsPath) => deps.finalize({
|
|
7575
|
+
deviceId: item.deviceId,
|
|
7576
|
+
profile: item.profile,
|
|
7577
|
+
locationId: item.location.id,
|
|
7578
|
+
locationRoot: item.location.root,
|
|
7579
|
+
flatAbsPath,
|
|
7580
|
+
startMs: orphan.startMs,
|
|
7581
|
+
durMs: orphan.durMs
|
|
7582
|
+
}),
|
|
7583
|
+
logger: withDeviceTag(deps.logger, item.deviceId),
|
|
7584
|
+
chunkSize: deps.chunkSize,
|
|
7585
|
+
yieldBetween,
|
|
7586
|
+
shouldStop: deps.shouldStop
|
|
7587
|
+
});
|
|
7588
|
+
found += report.found;
|
|
7589
|
+
recovered += report.recovered;
|
|
7590
|
+
failed += report.failed;
|
|
7591
|
+
if (report.aborted) aborted = true;
|
|
7592
|
+
}
|
|
7593
|
+
};
|
|
7594
|
+
const lanes = Math.min(STAGING_BOOT_DIR_CONCURRENCY, Math.max(1, queue.length));
|
|
7595
|
+
await Promise.all(Array.from({ length: lanes }, lane));
|
|
7570
7596
|
deps.logger.info("recorder: staging boot reconcile complete", { meta: {
|
|
7571
7597
|
dirs,
|
|
7572
7598
|
found,
|
package/dist/recorder/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as number, Ft as EventCategory, I as deriveRecordingMode, Mt as record, Nt as string, S as RecordingConfigSchema, St as selectAssignedProfileSlots, Tt as array, X as recordingCapability, Z as recordingExportCapability, et as storageEvictableCapability, f as EVENT_PAD_MS, ht as hydrateSchema, it as errMsg, jt as object, l as DEFAULT_EVENTS_BAND_BUFFER_SEC, m as ExportRecordSchema, pt as DeviceType, ut as BaseAddon, v as OpsLogEntrySchema, x as RECORDING_EXPORT_MAX_READ_BYTES, yt as nodePin } from "../dist-
|
|
1
|
+
import { At as number, Ft as EventCategory, I as deriveRecordingMode, Mt as record, Nt as string, S as RecordingConfigSchema, St as selectAssignedProfileSlots, Tt as array, X as recordingCapability, Z as recordingExportCapability, et as storageEvictableCapability, f as EVENT_PAD_MS, ht as hydrateSchema, it as errMsg, jt as object, l as DEFAULT_EVENTS_BAND_BUFFER_SEC, m as ExportRecordSchema, pt as DeviceType, ut as BaseAddon, v as OpsLogEntrySchema, x as RECORDING_EXPORT_MAX_READ_BYTES, yt as nodePin } from "../dist-CJI_8GVY.mjs";
|
|
2
2
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
3
3
|
import { n as createFileDataPlaneHandler, s as parseRangeHeader, t as contentTypeFor } from "../addon-utils-A2S9D7pu.mjs";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -7481,6 +7481,17 @@ async function recoverStagingOrphans(dir, input, deps) {
|
|
|
7481
7481
|
};
|
|
7482
7482
|
}
|
|
7483
7483
|
/**
|
|
7484
|
+
* Staging directories recovered at once in {@link recoverAllStagedOrphans}.
|
|
7485
|
+
* The pass is serial stat+mkdir+rename per segment over what is usually a
|
|
7486
|
+
* network/FUSE share (shfs): measured on the live hub at 40 454 ms for 46
|
|
7487
|
+
* files in 28 dirs — ~880 ms per file of pure round-trip latency, nothing
|
|
7488
|
+
* CPU-bound (2026-08-15). Dirs are independent by construction (each relocate
|
|
7489
|
+
* is a same-fs rename of a distinct file), so lanes are free; WITHIN a dir the
|
|
7490
|
+
* pass stays serial so the shutdown guard still stops after at most one
|
|
7491
|
+
* in-flight relocate per lane.
|
|
7492
|
+
*/
|
|
7493
|
+
var STAGING_BOOT_DIR_CONCURRENCY = 4;
|
|
7494
|
+
/**
|
|
7484
7495
|
* Boot reconcile: relocate every previous-run segment stranded in staging, on
|
|
7485
7496
|
* every location, for every camera — attached or not.
|
|
7486
7497
|
*
|
|
@@ -7515,6 +7526,7 @@ async function recoverAllStagedOrphans(deps) {
|
|
|
7515
7526
|
locations: locations.map((l) => l.id),
|
|
7516
7527
|
bootMs: deps.bootMs
|
|
7517
7528
|
} });
|
|
7529
|
+
const work = [];
|
|
7518
7530
|
for (const location of locations) {
|
|
7519
7531
|
const stagingRoot = `${location.root}/${STAGING_DIR_NAME}`;
|
|
7520
7532
|
let deviceDirs;
|
|
@@ -7524,7 +7536,6 @@ async function recoverAllStagedOrphans(deps) {
|
|
|
7524
7536
|
continue;
|
|
7525
7537
|
}
|
|
7526
7538
|
for (const deviceDir of deviceDirs) {
|
|
7527
|
-
if (aborted) break;
|
|
7528
7539
|
const deviceId = Number(deviceDir);
|
|
7529
7540
|
if (!Number.isInteger(deviceId) || deviceId <= 0) continue;
|
|
7530
7541
|
let profileDirs;
|
|
@@ -7535,37 +7546,52 @@ async function recoverAllStagedOrphans(deps) {
|
|
|
7535
7546
|
}
|
|
7536
7547
|
const segmentSeconds = await deps.segmentSecondsFor(deviceId);
|
|
7537
7548
|
for (const profile of profileDirs) {
|
|
7538
|
-
if (aborted) break;
|
|
7539
7549
|
if (!KNOWN_PROFILES.has(profile)) continue;
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7550
|
+
work.push({
|
|
7551
|
+
location,
|
|
7552
|
+
deviceId,
|
|
7553
|
+
profile,
|
|
7554
|
+
dir: `${stagingRoot}/${deviceDir}/${profile}`,
|
|
7544
7555
|
segmentSeconds
|
|
7545
|
-
}, {
|
|
7546
|
-
listDir: deps.listDir,
|
|
7547
|
-
readPlaylist: deps.readPlaylist,
|
|
7548
|
-
finalize: (orphan, flatAbsPath) => deps.finalize({
|
|
7549
|
-
deviceId,
|
|
7550
|
-
profile,
|
|
7551
|
-
locationId: location.id,
|
|
7552
|
-
locationRoot: location.root,
|
|
7553
|
-
flatAbsPath,
|
|
7554
|
-
startMs: orphan.startMs,
|
|
7555
|
-
durMs: orphan.durMs
|
|
7556
|
-
}),
|
|
7557
|
-
logger: withDeviceTag(deps.logger, deviceId),
|
|
7558
|
-
chunkSize: deps.chunkSize,
|
|
7559
|
-
yieldBetween,
|
|
7560
|
-
shouldStop: deps.shouldStop
|
|
7561
7556
|
});
|
|
7562
|
-
found += report.found;
|
|
7563
|
-
recovered += report.recovered;
|
|
7564
|
-
failed += report.failed;
|
|
7565
|
-
if (report.aborted) aborted = true;
|
|
7566
7557
|
}
|
|
7567
7558
|
}
|
|
7568
7559
|
}
|
|
7560
|
+
const queue = [...work];
|
|
7561
|
+
const lane = async () => {
|
|
7562
|
+
for (;;) {
|
|
7563
|
+
if (aborted || deps.shouldStop?.() === true) return;
|
|
7564
|
+
const item = queue.shift();
|
|
7565
|
+
if (item === void 0) return;
|
|
7566
|
+
dirs += 1;
|
|
7567
|
+
const report = await recoverStagingOrphans(item.dir, {
|
|
7568
|
+
writerStartedMs: deps.bootMs,
|
|
7569
|
+
segmentSeconds: item.segmentSeconds
|
|
7570
|
+
}, {
|
|
7571
|
+
listDir: deps.listDir,
|
|
7572
|
+
readPlaylist: deps.readPlaylist,
|
|
7573
|
+
finalize: (orphan, flatAbsPath) => deps.finalize({
|
|
7574
|
+
deviceId: item.deviceId,
|
|
7575
|
+
profile: item.profile,
|
|
7576
|
+
locationId: item.location.id,
|
|
7577
|
+
locationRoot: item.location.root,
|
|
7578
|
+
flatAbsPath,
|
|
7579
|
+
startMs: orphan.startMs,
|
|
7580
|
+
durMs: orphan.durMs
|
|
7581
|
+
}),
|
|
7582
|
+
logger: withDeviceTag(deps.logger, item.deviceId),
|
|
7583
|
+
chunkSize: deps.chunkSize,
|
|
7584
|
+
yieldBetween,
|
|
7585
|
+
shouldStop: deps.shouldStop
|
|
7586
|
+
});
|
|
7587
|
+
found += report.found;
|
|
7588
|
+
recovered += report.recovered;
|
|
7589
|
+
failed += report.failed;
|
|
7590
|
+
if (report.aborted) aborted = true;
|
|
7591
|
+
}
|
|
7592
|
+
};
|
|
7593
|
+
const lanes = Math.min(STAGING_BOOT_DIR_CONCURRENCY, Math.max(1, queue.length));
|
|
7594
|
+
await Promise.all(Array.from({ length: lanes }, lane));
|
|
7569
7595
|
deps.logger.info("recorder: staging boot reconcile complete", { meta: {
|
|
7570
7596
|
dirs,
|
|
7571
7597
|
found,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_worker_protocol = require("../worker-protocol-
|
|
3
|
-
const require_lazy_sharp = require("../lazy-sharp-
|
|
2
|
+
const require_worker_protocol = require("../worker-protocol-34kViYAj.js");
|
|
3
|
+
const require_lazy_sharp = require("../lazy-sharp-CTNP_35A.js");
|
|
4
4
|
//#region src/session-decode/color-conversion.ts
|
|
5
5
|
/**
|
|
6
6
|
* Explicit YUV→RGB colorspace/range resolution for the session-decode worker.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as formatNativeLeaseKnobs, n as isWorkerRequest, o as resolveNativeLeaseKnobs, r as logLevelForLine } from "../worker-protocol-
|
|
1
|
+
import { i as formatNativeLeaseKnobs, n as isWorkerRequest, o as resolveNativeLeaseKnobs, r as logLevelForLine } from "../worker-protocol-ZYA4xGRg.mjs";
|
|
2
2
|
import { n as setSharpWarnSink, r as hostExternalEntryUrls, t as getSharp } from "../lazy-sharp-6oymT_yf.mjs";
|
|
3
3
|
//#region src/session-decode/color-conversion.ts
|
|
4
4
|
/**
|
|
@@ -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-CYxusT1M.js");
|
|
6
6
|
const require_remote_restream = require("../remote-restream-BYbAsgUf.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
node_crypto = require_dist.__toESM(node_crypto, 1);
|
|
@@ -207,7 +207,9 @@ function formatProbedSummary(declared, snapshot, opts) {
|
|
|
207
207
|
* on our own initiative, and says nothing about waking it because somebody
|
|
208
208
|
* pressed play. That asymmetry is the whole design: brokers stay AVAILABLE
|
|
209
209
|
* (definable, from the durable catalog) without being ACTIVE, and the dial is
|
|
210
|
-
* the only thing that touches the camera.
|
|
210
|
+
* the only thing that touches the camera. Concurrent/retried requests for the
|
|
211
|
+
* same waking device share one transaction; a client retry must not become a
|
|
212
|
+
* second physical wake.
|
|
211
213
|
*
|
|
212
214
|
* ## Honest states
|
|
213
215
|
*
|
|
@@ -243,10 +245,48 @@ var BatteryStreamUnavailableError = class extends Error {
|
|
|
243
245
|
};
|
|
244
246
|
/** Bound on the firmware wake. Matches the cap's own sensible range. */
|
|
245
247
|
var WAKE_FOR_STREAM_TIMEOUT_MS = 8e3;
|
|
246
|
-
/**
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
|
|
248
|
+
/**
|
|
249
|
+
* Bound AFTER firmware acknowledgement for the provider to rebuild/publish
|
|
250
|
+
* stream parameters and the broker to observe them. Field cameras can
|
|
251
|
+
* acknowledge several seconds before their media/catalog plane is usable.
|
|
252
|
+
*/
|
|
253
|
+
var BROKER_SETTLE_TIMEOUT_MS = 2e4;
|
|
254
|
+
/** Reconcile cadence while the acknowledged camera finishes waking. */
|
|
255
|
+
var BROKER_SETTLE_POLL_INTERVAL_MS = 1500;
|
|
256
|
+
function wait(timeoutMs) {
|
|
257
|
+
return new Promise((resolve) => {
|
|
258
|
+
setTimeout(resolve, timeoutMs).unref?.();
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Device-scoped single-flight for wake-on-play. A wake applies to the whole
|
|
263
|
+
* camera, not one profile/brokerId, so concurrent profile requests and client
|
|
264
|
+
* retries all await the same bounded transaction.
|
|
265
|
+
*/
|
|
266
|
+
var BatteryWakeOnPlaySingleFlight = class {
|
|
267
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
268
|
+
async run(deviceId, deps) {
|
|
269
|
+
const existing = this.inFlight.get(deviceId);
|
|
270
|
+
if (existing) {
|
|
271
|
+
await existing;
|
|
272
|
+
if (!deps.hasBroker()) await deps.ensureBroker().catch((err) => {
|
|
273
|
+
deps.logger.debug("wake-on-play: joined demand broker retry failed", {
|
|
274
|
+
tags: { deviceId },
|
|
275
|
+
meta: { error: err instanceof Error ? err.message : String(err) }
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
if (!deps.hasBroker()) throw new BatteryStreamUnavailableError(deviceId, "waking", "the shared wake completed but this stream profile is not available yet — try again");
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const transaction = wakeBatteryDeviceForPlay(deviceId, deps);
|
|
282
|
+
this.inFlight.set(deviceId, transaction);
|
|
283
|
+
try {
|
|
284
|
+
await transaction;
|
|
285
|
+
} finally {
|
|
286
|
+
if (this.inFlight.get(deviceId) === transaction) this.inFlight.delete(deviceId);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
};
|
|
250
290
|
/**
|
|
251
291
|
* Make a broker available for a battery camera that has none, by asking the
|
|
252
292
|
* camera to wake.
|
|
@@ -257,26 +297,25 @@ var STREAM_PARAMS_SETTLE_TIMEOUT_MS = 6e3;
|
|
|
257
297
|
* {@link BatteryStreamUnavailableError} only for a battery camera we could not
|
|
258
298
|
* produce a stream for — with the reason named.
|
|
259
299
|
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
* demand and gets a new wake.
|
|
300
|
+
* After an acknowledged wake, repeatedly reconciles the provider catalog and
|
|
301
|
+
* retries broker resolution within one field-sized bound. It never issues a
|
|
302
|
+
* second wake inside that transaction.
|
|
264
303
|
*/
|
|
265
304
|
async function wakeBatteryDeviceForPlay(deviceId, deps) {
|
|
266
305
|
if (deps.hasBroker()) return;
|
|
267
306
|
if (await deps.isBatteryDevice(deviceId).catch(() => null) !== true) return;
|
|
268
307
|
const facts = await deps.readBatteryFacts(deviceId).catch(() => null);
|
|
269
|
-
const
|
|
308
|
+
const observedAt = (deps.nowMs ?? Date.now)();
|
|
270
309
|
const presence = require_dist.deriveBatteryPresence({
|
|
271
310
|
status: facts,
|
|
272
|
-
nowMs
|
|
311
|
+
nowMs: observedAt
|
|
273
312
|
});
|
|
274
313
|
if (presence === "unreachable") {
|
|
275
314
|
deps.logger.warn("wake-on-play refused — battery camera is unreachable, not asleep", {
|
|
276
315
|
tags: { deviceId },
|
|
277
316
|
meta: {
|
|
278
317
|
lastContactAt: facts?.lastContactAt ?? 0,
|
|
279
|
-
silenceMs:
|
|
318
|
+
silenceMs: observedAt - (facts?.lastContactAt ?? 0)
|
|
280
319
|
}
|
|
281
320
|
});
|
|
282
321
|
throw new BatteryStreamUnavailableError(deviceId, "unreachable", "nothing has been heard from it for hours — check the battery or its network");
|
|
@@ -292,29 +331,46 @@ async function wakeBatteryDeviceForPlay(deviceId, deps) {
|
|
|
292
331
|
awoke: false,
|
|
293
332
|
durationMs: 0
|
|
294
333
|
}));
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
334
|
+
const nowMs = deps.nowMs ?? Date.now;
|
|
335
|
+
const settleStartedAt = nowMs();
|
|
336
|
+
const settleDeadline = settleStartedAt + (wake.awoke ? BROKER_SETTLE_TIMEOUT_MS : 0);
|
|
337
|
+
const maxAttempts = wake.awoke ? Math.ceil(BROKER_SETTLE_TIMEOUT_MS / BROKER_SETTLE_POLL_INTERVAL_MS) + 1 : 1;
|
|
338
|
+
let attempts = 0;
|
|
339
|
+
while (attempts < maxAttempts) {
|
|
340
|
+
attempts += 1;
|
|
341
|
+
await deps.reconcileCatalog(deviceId).catch((err) => {
|
|
342
|
+
deps.logger.debug("wake-on-play: catalog reconcile failed", {
|
|
343
|
+
tags: { deviceId },
|
|
344
|
+
meta: {
|
|
345
|
+
attempt: attempts,
|
|
346
|
+
error: err instanceof Error ? err.message : String(err)
|
|
347
|
+
}
|
|
348
|
+
});
|
|
306
349
|
});
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
350
|
+
await deps.ensureBroker().catch((err) => {
|
|
351
|
+
deps.logger.debug("wake-on-play: broker retry failed", {
|
|
352
|
+
tags: { deviceId },
|
|
353
|
+
meta: {
|
|
354
|
+
attempt: attempts,
|
|
355
|
+
error: err instanceof Error ? err.message : String(err)
|
|
356
|
+
}
|
|
357
|
+
});
|
|
316
358
|
});
|
|
317
|
-
|
|
359
|
+
if (deps.hasBroker()) {
|
|
360
|
+
deps.logger.info("wake-on-play succeeded — broker available after wake", {
|
|
361
|
+
tags: { deviceId },
|
|
362
|
+
meta: {
|
|
363
|
+
awoke: wake.awoke,
|
|
364
|
+
wakeMs: wake.durationMs,
|
|
365
|
+
settleMs: nowMs() - settleStartedAt,
|
|
366
|
+
attempts
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const remainingMs = settleDeadline - nowMs();
|
|
372
|
+
if (remainingMs <= 0 || attempts >= maxAttempts) break;
|
|
373
|
+
await (deps.wait ?? wait)(Math.min(BROKER_SETTLE_POLL_INTERVAL_MS, remainingMs));
|
|
318
374
|
}
|
|
319
375
|
const outcome = wake.awoke ? "waking" : "sleeping";
|
|
320
376
|
deps.logger.warn("wake-on-play exhausted — no stream after the wake", {
|
|
@@ -322,7 +378,8 @@ async function wakeBatteryDeviceForPlay(deviceId, deps) {
|
|
|
322
378
|
meta: {
|
|
323
379
|
awoke: wake.awoke,
|
|
324
380
|
wakeMs: wake.durationMs,
|
|
325
|
-
|
|
381
|
+
settleMs: nowMs() - settleStartedAt,
|
|
382
|
+
attempts,
|
|
326
383
|
outcome
|
|
327
384
|
}
|
|
328
385
|
});
|
|
@@ -14401,6 +14458,13 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
14401
14458
|
*/
|
|
14402
14459
|
brokerEnsures = /* @__PURE__ */ new Map();
|
|
14403
14460
|
/**
|
|
14461
|
+
* Device-scoped wake-on-play transactions. A camera wake is shared by every
|
|
14462
|
+
* profile, so Viewer retries or concurrent sessions must join the existing
|
|
14463
|
+
* sleeping → waking → broker-settle transaction instead of issuing another
|
|
14464
|
+
* `battery.wakeForStream` mutation.
|
|
14465
|
+
*/
|
|
14466
|
+
batteryWakeOnPlay = new BatteryWakeOnPlaySingleFlight();
|
|
14467
|
+
/**
|
|
14404
14468
|
* brokerId → the profile tier a remote-ensured adapter was created for
|
|
14405
14469
|
* (Slice 3b Task 2). `this.assignments` only tracks LOCALLY-owned devices,
|
|
14406
14470
|
* so the `profileTierResolver` closure below always misses for a remote
|
|
@@ -15206,7 +15270,8 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
15206
15270
|
/**
|
|
15207
15271
|
* Wake-on-play (D173). Called by `WebrtcSessionProvider` when the normal
|
|
15208
15272
|
* resolution left no broker: if the device is battery-operated, ask the
|
|
15209
|
-
* camera to wake,
|
|
15273
|
+
* camera to wake, then poll catalog reconciliation + broker resolution
|
|
15274
|
+
* through one bounded settle transaction.
|
|
15210
15275
|
*
|
|
15211
15276
|
* Throws `BatteryStreamUnavailableError` — naming `sleeping` / `waking` /
|
|
15212
15277
|
* `unreachable` — instead of letting `BrokerWebrtcServer` answer a healthy,
|
|
@@ -15219,7 +15284,7 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
15219
15284
|
if (this.disabledDevices.has(deviceId)) return;
|
|
15220
15285
|
const api = this.api;
|
|
15221
15286
|
if (!api) return;
|
|
15222
|
-
await
|
|
15287
|
+
await this.batteryWakeOnPlay.run(deviceId, {
|
|
15223
15288
|
logger: this.logger,
|
|
15224
15289
|
isBatteryDevice: async (id) => {
|
|
15225
15290
|
const dev = await api.deviceManager.getDevice.query({ deviceId: id }).catch(() => null);
|
|
@@ -15242,38 +15307,12 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
15242
15307
|
deviceId: id,
|
|
15243
15308
|
timeoutMs
|
|
15244
15309
|
}),
|
|
15245
|
-
awaitStreamParamsChanged: (id, timeoutMs) => this.awaitStreamParamsChanged(id, timeoutMs),
|
|
15246
15310
|
reconcileCatalog: (id) => this.reconcileDeviceCatalog(id),
|
|
15247
15311
|
ensureBroker: () => this.ensureBrokerForWebrtcSession(deviceId, brokerId, camStreamId),
|
|
15248
15312
|
hasBroker: () => this.hasRegisteredBroker(brokerId)
|
|
15249
15313
|
});
|
|
15250
15314
|
}
|
|
15251
15315
|
/**
|
|
15252
|
-
* Bounded wait for the provider's `StreamParamsChanged` nudge for one
|
|
15253
|
-
* device. Resolves `false` on timeout — a timeout is information, not a
|
|
15254
|
-
* failure: a catalog restored from the durable slice announces nothing, and
|
|
15255
|
-
* the caller reconciles either way.
|
|
15256
|
-
*/
|
|
15257
|
-
awaitStreamParamsChanged(deviceId, timeoutMs) {
|
|
15258
|
-
const bus = this.eventBus;
|
|
15259
|
-
if (!bus) return Promise.resolve(false);
|
|
15260
|
-
return new Promise((resolve) => {
|
|
15261
|
-
let settled = false;
|
|
15262
|
-
const finish = (value) => {
|
|
15263
|
-
if (settled) return;
|
|
15264
|
-
settled = true;
|
|
15265
|
-
clearTimeout(timer);
|
|
15266
|
-
unsubscribe();
|
|
15267
|
-
resolve(value);
|
|
15268
|
-
};
|
|
15269
|
-
const unsubscribe = bus.subscribe({ category: require_dist.EventCategory.StreamParamsChanged }, (event) => {
|
|
15270
|
-
if (event.data.deviceId === deviceId) finish(true);
|
|
15271
|
-
});
|
|
15272
|
-
const timer = setTimeout(() => finish(false), timeoutMs);
|
|
15273
|
-
timer.unref?.();
|
|
15274
|
-
});
|
|
15275
|
-
}
|
|
15276
|
-
/**
|
|
15277
15316
|
* Single-flight body for `ensureBrokerForWebrtcSession`'s remote-adapter
|
|
15278
15317
|
* get-or-create — resolves the ingest owner, and for `remote-adapter` mode
|
|
15279
15318
|
* constructs the `RemoteEncodedSourceBroker`, registers it with the WebRTC
|
|
@@ -35045,9 +35084,9 @@ var StreamBrokerAddon = class extends require_dist.BaseAddon {
|
|
|
35045
35084
|
});
|
|
35046
35085
|
});
|
|
35047
35086
|
};
|
|
35048
|
-
|
|
35087
|
+
this.brokerManager?.reconcileAllCatalogsAtStartup().catch((err) => {
|
|
35049
35088
|
this.ctx.logger.warn("catalog startup reconcile failed", { meta: { error: require_dist.errMsg(err) } });
|
|
35050
|
-
}) ?? Promise.resolve()
|
|
35089
|
+
}) ?? Promise.resolve();
|
|
35051
35090
|
const reconcileMs = Math.max(5, this.config.catalogReconcileIntervalSec) * 1e3;
|
|
35052
35091
|
this.catalogReconcileTimer = setInterval(() => reconcileAll("poll"), reconcileMs);
|
|
35053
35092
|
this.subscribe({ category: require_dist.EventCategory.DeviceRegistered }, (event) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as __toESM, t as __commonJSMin } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { A as createHwAccelCache, At as number, C as RingBuffer, Dt as discriminatedUnion, Et as boolean, Ft as EventCategory, Mt as record, Nt as string, O as batteryCapability, P as deriveBatteryPresence, Pt as union, Q as resolveEgressDecodeHwAccel, R as egressTranscodeSharingKey, T as addonWidgetsSourceCapability, Tt as array, W as maskUrlCredentials, _t as makeProfileBrokerId, at as AUDIO_PRESETS, b as RATE_CONTROL_TIGHT, ct as invocationFromEncodeProfile, dt as CAM_PROFILE_ORDER, ft as DeviceFeature, gt as isEvent, i as BatteryStatusSchema, it as errMsg, jt as object, k as cameraStreamsCapability, kt as literal, lt as isSoftwareDecode, mt as createEvent, ot as Fmp4BoxSplitter, p as EncodeProfileSchema, pt as DeviceType, rt as webrtcSessionCapability, st as buildFfmpegArgs$1, tt as streamBrokerCapability, ut as BaseAddon, vt as makeSourceBrokerId, wt as _enum, xt as parseProfileBrokerId, y as RATE_CONTROL_RELAXED, yt as nodePin, z as egressTransportFromRequest } from "../dist-
|
|
2
|
+
import { A as createHwAccelCache, At as number, C as RingBuffer, Dt as discriminatedUnion, Et as boolean, Ft as EventCategory, Mt as record, Nt as string, O as batteryCapability, P as deriveBatteryPresence, Pt as union, Q as resolveEgressDecodeHwAccel, R as egressTranscodeSharingKey, T as addonWidgetsSourceCapability, Tt as array, W as maskUrlCredentials, _t as makeProfileBrokerId, at as AUDIO_PRESETS, b as RATE_CONTROL_TIGHT, ct as invocationFromEncodeProfile, dt as CAM_PROFILE_ORDER, ft as DeviceFeature, gt as isEvent, i as BatteryStatusSchema, it as errMsg, jt as object, k as cameraStreamsCapability, kt as literal, lt as isSoftwareDecode, mt as createEvent, ot as Fmp4BoxSplitter, p as EncodeProfileSchema, pt as DeviceType, rt as webrtcSessionCapability, st as buildFfmpegArgs$1, tt as streamBrokerCapability, ut as BaseAddon, vt as makeSourceBrokerId, wt as _enum, xt as parseProfileBrokerId, y as RATE_CONTROL_RELAXED, yt as nodePin, z as egressTransportFromRequest } from "../dist-CJI_8GVY.mjs";
|
|
3
3
|
import { n as profileForStreamId, r as parseRestreamPath } from "../remote-restream-Ci7RXNGb.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import * as crypto$1 from "node:crypto";
|
|
@@ -202,7 +202,9 @@ function formatProbedSummary(declared, snapshot, opts) {
|
|
|
202
202
|
* on our own initiative, and says nothing about waking it because somebody
|
|
203
203
|
* pressed play. That asymmetry is the whole design: brokers stay AVAILABLE
|
|
204
204
|
* (definable, from the durable catalog) without being ACTIVE, and the dial is
|
|
205
|
-
* the only thing that touches the camera.
|
|
205
|
+
* the only thing that touches the camera. Concurrent/retried requests for the
|
|
206
|
+
* same waking device share one transaction; a client retry must not become a
|
|
207
|
+
* second physical wake.
|
|
206
208
|
*
|
|
207
209
|
* ## Honest states
|
|
208
210
|
*
|
|
@@ -238,10 +240,48 @@ var BatteryStreamUnavailableError = class extends Error {
|
|
|
238
240
|
};
|
|
239
241
|
/** Bound on the firmware wake. Matches the cap's own sensible range. */
|
|
240
242
|
var WAKE_FOR_STREAM_TIMEOUT_MS = 8e3;
|
|
241
|
-
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
|
|
243
|
+
/**
|
|
244
|
+
* Bound AFTER firmware acknowledgement for the provider to rebuild/publish
|
|
245
|
+
* stream parameters and the broker to observe them. Field cameras can
|
|
246
|
+
* acknowledge several seconds before their media/catalog plane is usable.
|
|
247
|
+
*/
|
|
248
|
+
var BROKER_SETTLE_TIMEOUT_MS = 2e4;
|
|
249
|
+
/** Reconcile cadence while the acknowledged camera finishes waking. */
|
|
250
|
+
var BROKER_SETTLE_POLL_INTERVAL_MS = 1500;
|
|
251
|
+
function wait(timeoutMs) {
|
|
252
|
+
return new Promise((resolve) => {
|
|
253
|
+
setTimeout(resolve, timeoutMs).unref?.();
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Device-scoped single-flight for wake-on-play. A wake applies to the whole
|
|
258
|
+
* camera, not one profile/brokerId, so concurrent profile requests and client
|
|
259
|
+
* retries all await the same bounded transaction.
|
|
260
|
+
*/
|
|
261
|
+
var BatteryWakeOnPlaySingleFlight = class {
|
|
262
|
+
inFlight = /* @__PURE__ */ new Map();
|
|
263
|
+
async run(deviceId, deps) {
|
|
264
|
+
const existing = this.inFlight.get(deviceId);
|
|
265
|
+
if (existing) {
|
|
266
|
+
await existing;
|
|
267
|
+
if (!deps.hasBroker()) await deps.ensureBroker().catch((err) => {
|
|
268
|
+
deps.logger.debug("wake-on-play: joined demand broker retry failed", {
|
|
269
|
+
tags: { deviceId },
|
|
270
|
+
meta: { error: err instanceof Error ? err.message : String(err) }
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
if (!deps.hasBroker()) throw new BatteryStreamUnavailableError(deviceId, "waking", "the shared wake completed but this stream profile is not available yet — try again");
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const transaction = wakeBatteryDeviceForPlay(deviceId, deps);
|
|
277
|
+
this.inFlight.set(deviceId, transaction);
|
|
278
|
+
try {
|
|
279
|
+
await transaction;
|
|
280
|
+
} finally {
|
|
281
|
+
if (this.inFlight.get(deviceId) === transaction) this.inFlight.delete(deviceId);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
};
|
|
245
285
|
/**
|
|
246
286
|
* Make a broker available for a battery camera that has none, by asking the
|
|
247
287
|
* camera to wake.
|
|
@@ -252,26 +292,25 @@ var STREAM_PARAMS_SETTLE_TIMEOUT_MS = 6e3;
|
|
|
252
292
|
* {@link BatteryStreamUnavailableError} only for a battery camera we could not
|
|
253
293
|
* produce a stream for — with the reason named.
|
|
254
294
|
*
|
|
255
|
-
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
* demand and gets a new wake.
|
|
295
|
+
* After an acknowledged wake, repeatedly reconciles the provider catalog and
|
|
296
|
+
* retries broker resolution within one field-sized bound. It never issues a
|
|
297
|
+
* second wake inside that transaction.
|
|
259
298
|
*/
|
|
260
299
|
async function wakeBatteryDeviceForPlay(deviceId, deps) {
|
|
261
300
|
if (deps.hasBroker()) return;
|
|
262
301
|
if (await deps.isBatteryDevice(deviceId).catch(() => null) !== true) return;
|
|
263
302
|
const facts = await deps.readBatteryFacts(deviceId).catch(() => null);
|
|
264
|
-
const
|
|
303
|
+
const observedAt = (deps.nowMs ?? Date.now)();
|
|
265
304
|
const presence = deriveBatteryPresence({
|
|
266
305
|
status: facts,
|
|
267
|
-
nowMs
|
|
306
|
+
nowMs: observedAt
|
|
268
307
|
});
|
|
269
308
|
if (presence === "unreachable") {
|
|
270
309
|
deps.logger.warn("wake-on-play refused — battery camera is unreachable, not asleep", {
|
|
271
310
|
tags: { deviceId },
|
|
272
311
|
meta: {
|
|
273
312
|
lastContactAt: facts?.lastContactAt ?? 0,
|
|
274
|
-
silenceMs:
|
|
313
|
+
silenceMs: observedAt - (facts?.lastContactAt ?? 0)
|
|
275
314
|
}
|
|
276
315
|
});
|
|
277
316
|
throw new BatteryStreamUnavailableError(deviceId, "unreachable", "nothing has been heard from it for hours — check the battery or its network");
|
|
@@ -287,29 +326,46 @@ async function wakeBatteryDeviceForPlay(deviceId, deps) {
|
|
|
287
326
|
awoke: false,
|
|
288
327
|
durationMs: 0
|
|
289
328
|
}));
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
329
|
+
const nowMs = deps.nowMs ?? Date.now;
|
|
330
|
+
const settleStartedAt = nowMs();
|
|
331
|
+
const settleDeadline = settleStartedAt + (wake.awoke ? BROKER_SETTLE_TIMEOUT_MS : 0);
|
|
332
|
+
const maxAttempts = wake.awoke ? Math.ceil(BROKER_SETTLE_TIMEOUT_MS / BROKER_SETTLE_POLL_INTERVAL_MS) + 1 : 1;
|
|
333
|
+
let attempts = 0;
|
|
334
|
+
while (attempts < maxAttempts) {
|
|
335
|
+
attempts += 1;
|
|
336
|
+
await deps.reconcileCatalog(deviceId).catch((err) => {
|
|
337
|
+
deps.logger.debug("wake-on-play: catalog reconcile failed", {
|
|
338
|
+
tags: { deviceId },
|
|
339
|
+
meta: {
|
|
340
|
+
attempt: attempts,
|
|
341
|
+
error: err instanceof Error ? err.message : String(err)
|
|
342
|
+
}
|
|
343
|
+
});
|
|
301
344
|
});
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
}
|
|
345
|
+
await deps.ensureBroker().catch((err) => {
|
|
346
|
+
deps.logger.debug("wake-on-play: broker retry failed", {
|
|
347
|
+
tags: { deviceId },
|
|
348
|
+
meta: {
|
|
349
|
+
attempt: attempts,
|
|
350
|
+
error: err instanceof Error ? err.message : String(err)
|
|
351
|
+
}
|
|
352
|
+
});
|
|
311
353
|
});
|
|
312
|
-
|
|
354
|
+
if (deps.hasBroker()) {
|
|
355
|
+
deps.logger.info("wake-on-play succeeded — broker available after wake", {
|
|
356
|
+
tags: { deviceId },
|
|
357
|
+
meta: {
|
|
358
|
+
awoke: wake.awoke,
|
|
359
|
+
wakeMs: wake.durationMs,
|
|
360
|
+
settleMs: nowMs() - settleStartedAt,
|
|
361
|
+
attempts
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const remainingMs = settleDeadline - nowMs();
|
|
367
|
+
if (remainingMs <= 0 || attempts >= maxAttempts) break;
|
|
368
|
+
await (deps.wait ?? wait)(Math.min(BROKER_SETTLE_POLL_INTERVAL_MS, remainingMs));
|
|
313
369
|
}
|
|
314
370
|
const outcome = wake.awoke ? "waking" : "sleeping";
|
|
315
371
|
deps.logger.warn("wake-on-play exhausted — no stream after the wake", {
|
|
@@ -317,7 +373,8 @@ async function wakeBatteryDeviceForPlay(deviceId, deps) {
|
|
|
317
373
|
meta: {
|
|
318
374
|
awoke: wake.awoke,
|
|
319
375
|
wakeMs: wake.durationMs,
|
|
320
|
-
|
|
376
|
+
settleMs: nowMs() - settleStartedAt,
|
|
377
|
+
attempts,
|
|
321
378
|
outcome
|
|
322
379
|
}
|
|
323
380
|
});
|
|
@@ -14396,6 +14453,13 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
14396
14453
|
*/
|
|
14397
14454
|
brokerEnsures = /* @__PURE__ */ new Map();
|
|
14398
14455
|
/**
|
|
14456
|
+
* Device-scoped wake-on-play transactions. A camera wake is shared by every
|
|
14457
|
+
* profile, so Viewer retries or concurrent sessions must join the existing
|
|
14458
|
+
* sleeping → waking → broker-settle transaction instead of issuing another
|
|
14459
|
+
* `battery.wakeForStream` mutation.
|
|
14460
|
+
*/
|
|
14461
|
+
batteryWakeOnPlay = new BatteryWakeOnPlaySingleFlight();
|
|
14462
|
+
/**
|
|
14399
14463
|
* brokerId → the profile tier a remote-ensured adapter was created for
|
|
14400
14464
|
* (Slice 3b Task 2). `this.assignments` only tracks LOCALLY-owned devices,
|
|
14401
14465
|
* so the `profileTierResolver` closure below always misses for a remote
|
|
@@ -15201,7 +15265,8 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
15201
15265
|
/**
|
|
15202
15266
|
* Wake-on-play (D173). Called by `WebrtcSessionProvider` when the normal
|
|
15203
15267
|
* resolution left no broker: if the device is battery-operated, ask the
|
|
15204
|
-
* camera to wake,
|
|
15268
|
+
* camera to wake, then poll catalog reconciliation + broker resolution
|
|
15269
|
+
* through one bounded settle transaction.
|
|
15205
15270
|
*
|
|
15206
15271
|
* Throws `BatteryStreamUnavailableError` — naming `sleeping` / `waking` /
|
|
15207
15272
|
* `unreachable` — instead of letting `BrokerWebrtcServer` answer a healthy,
|
|
@@ -15214,7 +15279,7 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
15214
15279
|
if (this.disabledDevices.has(deviceId)) return;
|
|
15215
15280
|
const api = this.api;
|
|
15216
15281
|
if (!api) return;
|
|
15217
|
-
await
|
|
15282
|
+
await this.batteryWakeOnPlay.run(deviceId, {
|
|
15218
15283
|
logger: this.logger,
|
|
15219
15284
|
isBatteryDevice: async (id) => {
|
|
15220
15285
|
const dev = await api.deviceManager.getDevice.query({ deviceId: id }).catch(() => null);
|
|
@@ -15237,38 +15302,12 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
15237
15302
|
deviceId: id,
|
|
15238
15303
|
timeoutMs
|
|
15239
15304
|
}),
|
|
15240
|
-
awaitStreamParamsChanged: (id, timeoutMs) => this.awaitStreamParamsChanged(id, timeoutMs),
|
|
15241
15305
|
reconcileCatalog: (id) => this.reconcileDeviceCatalog(id),
|
|
15242
15306
|
ensureBroker: () => this.ensureBrokerForWebrtcSession(deviceId, brokerId, camStreamId),
|
|
15243
15307
|
hasBroker: () => this.hasRegisteredBroker(brokerId)
|
|
15244
15308
|
});
|
|
15245
15309
|
}
|
|
15246
15310
|
/**
|
|
15247
|
-
* Bounded wait for the provider's `StreamParamsChanged` nudge for one
|
|
15248
|
-
* device. Resolves `false` on timeout — a timeout is information, not a
|
|
15249
|
-
* failure: a catalog restored from the durable slice announces nothing, and
|
|
15250
|
-
* the caller reconciles either way.
|
|
15251
|
-
*/
|
|
15252
|
-
awaitStreamParamsChanged(deviceId, timeoutMs) {
|
|
15253
|
-
const bus = this.eventBus;
|
|
15254
|
-
if (!bus) return Promise.resolve(false);
|
|
15255
|
-
return new Promise((resolve) => {
|
|
15256
|
-
let settled = false;
|
|
15257
|
-
const finish = (value) => {
|
|
15258
|
-
if (settled) return;
|
|
15259
|
-
settled = true;
|
|
15260
|
-
clearTimeout(timer);
|
|
15261
|
-
unsubscribe();
|
|
15262
|
-
resolve(value);
|
|
15263
|
-
};
|
|
15264
|
-
const unsubscribe = bus.subscribe({ category: EventCategory.StreamParamsChanged }, (event) => {
|
|
15265
|
-
if (event.data.deviceId === deviceId) finish(true);
|
|
15266
|
-
});
|
|
15267
|
-
const timer = setTimeout(() => finish(false), timeoutMs);
|
|
15268
|
-
timer.unref?.();
|
|
15269
|
-
});
|
|
15270
|
-
}
|
|
15271
|
-
/**
|
|
15272
15311
|
* Single-flight body for `ensureBrokerForWebrtcSession`'s remote-adapter
|
|
15273
15312
|
* get-or-create — resolves the ingest owner, and for `remote-adapter` mode
|
|
15274
15313
|
* constructs the `RemoteEncodedSourceBroker`, registers it with the WebRTC
|
|
@@ -35037,9 +35076,9 @@ var StreamBrokerAddon = class extends BaseAddon {
|
|
|
35037
35076
|
});
|
|
35038
35077
|
});
|
|
35039
35078
|
};
|
|
35040
|
-
|
|
35079
|
+
this.brokerManager?.reconcileAllCatalogsAtStartup().catch((err) => {
|
|
35041
35080
|
this.ctx.logger.warn("catalog startup reconcile failed", { meta: { error: errMsg(err) } });
|
|
35042
|
-
}) ?? Promise.resolve()
|
|
35081
|
+
}) ?? Promise.resolve();
|
|
35043
35082
|
const reconcileMs = Math.max(5, this.config.catalogReconcileIntervalSec) * 1e3;
|
|
35044
35083
|
this.catalogReconcileTimer = setInterval(() => reconcileAll("poll"), reconcileMs);
|
|
35045
35084
|
this.subscribe({ category: EventCategory.DeviceRegistered }, (event) => {
|
|
@@ -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-DKf1PFZt.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as NativeLeaseSettingsSchema, g as NativeLeaseAdmissionSchema, u as DEFAULT_NATIVE_LEASE_SETTINGS } from "./dist-
|
|
1
|
+
import { _ as NativeLeaseSettingsSchema, g as NativeLeaseAdmissionSchema, u as DEFAULT_NATIVE_LEASE_SETTINGS } from "./dist-CJI_8GVY.mjs";
|
|
2
2
|
//#region src/session-decode/native-lease-config.ts
|
|
3
3
|
/**
|
|
4
4
|
* Resolution of the native-frame hold / tile knobs for one decode worker.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-pipeline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.83",
|
|
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",
|