@camstack/addon-pipeline 1.2.130 → 1.2.131
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-DH78p79i.js → addon-utils-DCQ5AP_v.js} +1 -1
- package/dist/audio-analyzer/index.js +3 -3
- package/dist/audio-analyzer/index.mjs +2 -2
- package/dist/detection-pipeline/index.js +332 -20
- package/dist/detection-pipeline/index.mjs +330 -18
- package/dist/{dist-DOw-izoI.js → dist-CqoMNE1e.js} +1817 -1712
- package/dist/{dist-Wt81pN5Y.mjs → dist-DO0UVhOk.mjs} +1817 -1712
- package/dist/{event-loop-stall-monitor-CtQCOZqm.mjs → event-loop-stall-monitor-D0Juf7Dn.mjs} +1 -1
- package/dist/{event-loop-stall-monitor-Bld7jNCb.js → event-loop-stall-monitor-eM7_yYfn.js} +1 -1
- package/dist/{lazy-sharp-BbNI2ZD-.js → lazy-sharp-BGrpS8yi.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/{process-memory-1_D3EZT9.mjs → process-memory-Bac3FuG6.mjs} +1 -1
- package/dist/{process-memory-D9H5qjDl.js → process-memory-xAPjvSw9.js} +1 -1
- package/dist/recorder/index.js +95 -4
- package/dist/recorder/index.mjs +94 -3
- package/dist/{segment-demux-js-C2jBBqGW.js → segment-demux-js-Cu0oDMUL.js} +1 -1
- package/dist/{segment-demux-js-BW-Q-j2A.mjs → segment-demux-js-skhsAZx6.mjs} +1 -1
- package/dist/session-decode/decode-worker-child.js +2 -2
- package/dist/session-decode/decode-worker-child.mjs +1 -1
- package/dist/stream-broker/_stub.js +1 -1
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-Dw-iwP4y.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DGQkDEYw.mjs} +3 -3
- package/dist/stream-broker/{_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-D36MoVV1.mjs → _virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CQKwHIHI.mjs} +1 -1
- package/dist/stream-broker/demux-worker-child.js +1 -1
- package/dist/stream-broker/demux-worker-child.mjs +1 -1
- package/dist/stream-broker/{hostInit-DEVCEYgu.mjs → hostInit-D7FwwZgj.mjs} +3 -3
- package/dist/stream-broker/index.js +2 -2
- package/dist/stream-broker/index.mjs +2 -2
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/dist/{worker-protocol-nAZl_Rsv.js → worker-protocol-G3HXTY8z.js} +1 -1
- package/dist/{worker-protocol-rpnr7Ldd.mjs → worker-protocol-_Ujvj1hl.mjs} +1 -1
- package/package.json +1 -1
package/dist/{event-loop-stall-monitor-CtQCOZqm.mjs → event-loop-stall-monitor-D0Juf7Dn.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { K as hfModelUrl, a as COCO_80_LABELS, j as audioKindId, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-
|
|
1
|
+
import { K as hfModelUrl, a as COCO_80_LABELS, j as audioKindId, o as COCO_TO_MACRO, r as AUDIO_MACRO_LABELS } from "./dist-DO0UVhOk.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { PerformanceObserver } from "node:perf_hooks";
|
|
4
4
|
//#region src/detection-pipeline/registry/model-catalogs.ts
|
|
@@ -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-CqoMNE1e.js");
|
|
6
|
+
const require_lazy_sharp = require("../lazy-sharp-BGrpS8yi.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 { Dt as hydrateSchema, G as evaluateZoneRules, St as BaseAddon, Tt as DeviceType, X as motionDetectionCapability } from "../dist-
|
|
1
|
+
import { Dt as hydrateSchema, G as evaluateZoneRules, St as BaseAddon, Tt as DeviceType, X as motionDetectionCapability } from "../dist-DO0UVhOk.mjs";
|
|
2
2
|
import { t as getSharp } from "../lazy-sharp-BtT5x-qP.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-CqoMNE1e.js");
|
|
6
|
+
const require_event_loop_stall_monitor = require("../event-loop-stall-monitor-eM7_yYfn.js");
|
|
7
|
+
const require_worker_protocol = require("../worker-protocol-G3HXTY8z.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-BGrpS8yi.js");
|
|
10
10
|
const require_restream_intent = require("../restream-intent-Cv9x3jmu.js");
|
|
11
11
|
const require_remote_restream = require("../remote-restream-CO36Sr30.js");
|
|
12
12
|
let sharp = require("sharp");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Bt as lazy, Et as createEvent, F as customAction, Gt as string, Ht as number, It as _enum, L as defineCustomActions, Lt as array, Rt as boolean, St as BaseAddon, Ut as object, Vt as literal, f as DEFAULT_NATIVE_LEASE_SETTINGS, gt as errMsg, it as pipelineRunnerCapability, jt as nodePin, nt as pickNativeLeaseOverride, p as DEVICE_BACKEND_TO_FORMAT, qt as EventCategory, tt as pickDetailCropConvention, u as DEFAULT_DETAIL_CROP_CONVENTION, z as deriveDetailCropRect } from "../dist-
|
|
2
|
-
import { i as resolveFrameViewGeometry, r as localFrameRegistry, t as attributeStall, u as getStepDefinition } from "../event-loop-stall-monitor-
|
|
3
|
-
import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-
|
|
1
|
+
import { Bt as lazy, Et as createEvent, F as customAction, Gt as string, Ht as number, It as _enum, L as defineCustomActions, Lt as array, Rt as boolean, St as BaseAddon, Ut as object, Vt as literal, f as DEFAULT_NATIVE_LEASE_SETTINGS, gt as errMsg, it as pipelineRunnerCapability, jt as nodePin, nt as pickNativeLeaseOverride, p as DEVICE_BACKEND_TO_FORMAT, qt as EventCategory, tt as pickDetailCropConvention, u as DEFAULT_DETAIL_CROP_CONVENTION, z as deriveDetailCropRect } from "../dist-DO0UVhOk.mjs";
|
|
2
|
+
import { i as resolveFrameViewGeometry, r as localFrameRegistry, t as attributeStall, u as getStepDefinition } from "../event-loop-stall-monitor-D0Juf7Dn.mjs";
|
|
3
|
+
import { a as nativeLeaseSettingEnv, t as isWorkerReply } from "../worker-protocol-_Ujvj1hl.mjs";
|
|
4
4
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
5
5
|
import { t as getSharp } from "../lazy-sharp-BtT5x-qP.mjs";
|
|
6
6
|
import { n as withDetectionIntent } from "../restream-intent-B4BXZra7.mjs";
|
package/dist/recorder/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const require_dist = require("../dist-
|
|
1
|
+
const require_dist = require("../dist-CqoMNE1e.js");
|
|
2
2
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
3
3
|
const require_restream_intent = require("../restream-intent-Cv9x3jmu.js");
|
|
4
|
-
const require_addon_utils = require("../addon-utils-
|
|
4
|
+
const require_addon_utils = require("../addon-utils-DCQ5AP_v.js");
|
|
5
5
|
const require_retire_root_keys = require("../retire-root-keys-KE6D6Xh_.js");
|
|
6
6
|
let node_crypto = require("node:crypto");
|
|
7
7
|
let node_child_process = require("node:child_process");
|
|
@@ -7522,7 +7522,46 @@ function resolveBandBufferMs(band) {
|
|
|
7522
7522
|
*/
|
|
7523
7523
|
function eventsBandCanEverDemand(band) {
|
|
7524
7524
|
if (band.mode !== "events") return true;
|
|
7525
|
-
return (band.
|
|
7525
|
+
return bandTriggerSources(band).length > 0 && resolveBandBufferMs(band).postMs > 0;
|
|
7526
|
+
}
|
|
7527
|
+
/**
|
|
7528
|
+
* LE sorgenti che questa banda ascolta — l'unico posto dove i `triggers` di
|
|
7529
|
+
* una banda diventano `TriggerSource[]`. `eventsBandCanEverDemand` e
|
|
7530
|
+
* `RecordingController.reportUnrecordable` lo leggono invece di ripetere
|
|
7531
|
+
* l'if-ladder motion/audio a mano.
|
|
7532
|
+
*/
|
|
7533
|
+
function bandTriggerSources(band) {
|
|
7534
|
+
const t = band.triggers;
|
|
7535
|
+
if (t === void 0) return [];
|
|
7536
|
+
const sources = [];
|
|
7537
|
+
if (t.motion === true) sources.push("motion");
|
|
7538
|
+
if (t.audioThresholdDbfs !== void 0) sources.push("audio");
|
|
7539
|
+
return sources;
|
|
7540
|
+
}
|
|
7541
|
+
/**
|
|
7542
|
+
* Does this audio window's level clear the ACTIVE band's configured
|
|
7543
|
+
* threshold?
|
|
7544
|
+
*
|
|
7545
|
+
* `PipelineAudioInferenceResultPayload.frame.level.dbfs`
|
|
7546
|
+
* (`packages/types/src/types/detection.ts:448`) and
|
|
7547
|
+
* `RecordingTriggers.audioThresholdDbfs` are the SAME unit and the SAME
|
|
7548
|
+
* scale — dBFS, 0 = full scale, more negative = quieter — produced by
|
|
7549
|
+
* `audio-analyzer-provider.ts:77` (`20 * log10(rms)`). No conversion exists
|
|
7550
|
+
* between them because none is needed: the one other place in this repo that
|
|
7551
|
+
* compares the two values does the same bare `>=`
|
|
7552
|
+
* (`notification-center/audio-rule-matcher.ts:221`). Inventing a conversion
|
|
7553
|
+
* here would recreate the exact defect this track exists to close, only
|
|
7554
|
+
* harder to see because a wrong scale still fires occasionally.
|
|
7555
|
+
*
|
|
7556
|
+
* `band` must be the band ACTIVE AT the audio window's own timestamp — a
|
|
7557
|
+
* device can carry several bands with different thresholds (day/night), and
|
|
7558
|
+
* only one is ever "the" threshold at a given instant. The caller
|
|
7559
|
+
* (`RecordingController.onAudioLevel`) resolves it the same way
|
|
7560
|
+
* `postBufferMsFor` resolves the post-buffer.
|
|
7561
|
+
*/
|
|
7562
|
+
function audioLevelQualifies(band, dbfs) {
|
|
7563
|
+
const threshold = band?.triggers?.audioThresholdDbfs;
|
|
7564
|
+
return threshold !== void 0 && dbfs >= threshold;
|
|
7526
7565
|
}
|
|
7527
7566
|
/** No trigger has been seen for this device yet. */
|
|
7528
7567
|
var EMPTY_TRIGGER_STATE = {
|
|
@@ -9385,6 +9424,43 @@ var RecordingController = class {
|
|
|
9385
9424
|
}
|
|
9386
9425
|
}
|
|
9387
9426
|
/**
|
|
9427
|
+
* Feed one audio window's LEVEL into the trigger pipeline — the counterpart
|
|
9428
|
+
* of `onTrigger('motion', …)` for the `audioThresholdDbfs` source, and the
|
|
9429
|
+
* feed that source was missing until 2026-08-26 (D62: authorized by the UI,
|
|
9430
|
+
* read by every pure function in `band-decision.ts`, alimented by nobody).
|
|
9431
|
+
*
|
|
9432
|
+
* Qualification happens HERE, not upstream like motion's `data.detected`,
|
|
9433
|
+
* because it depends on a PER-BAND threshold: `audioThresholdDbfs` is
|
|
9434
|
+
* authored per band, not once per device, so it needs the same config read
|
|
9435
|
+
* {@link postBufferMsFor} already does to resolve which band is active at
|
|
9436
|
+
* `atMs` before it can know which threshold applies.
|
|
9437
|
+
*
|
|
9438
|
+
* Fed from the event bus (telemetry, may be dropped — D8/D11), so a
|
|
9439
|
+
* config-read failure here drops only THIS window's qualification test
|
|
9440
|
+
* rather than guessing a threshold — logged, never silent, and never fatal:
|
|
9441
|
+
* the device's recordability does not depend on any single audio sample,
|
|
9442
|
+
* the next window (or motion) can still open the band.
|
|
9443
|
+
*/
|
|
9444
|
+
async onAudioLevel(deviceId, dbfs, atMs) {
|
|
9445
|
+
if (this.stopped) return;
|
|
9446
|
+
let band;
|
|
9447
|
+
try {
|
|
9448
|
+
band = activeBandAt({ bands: (await this.deps.loadConfig(deviceId)).bands ?? [] }, new Date(atMs));
|
|
9449
|
+
} catch (err) {
|
|
9450
|
+
this.deps.logger.warn("recorder: audio trigger qualification skipped — config read failed", {
|
|
9451
|
+
tags: { deviceId },
|
|
9452
|
+
meta: {
|
|
9453
|
+
atMs,
|
|
9454
|
+
dbfs,
|
|
9455
|
+
error: require_dist.errMsg(err)
|
|
9456
|
+
}
|
|
9457
|
+
});
|
|
9458
|
+
return;
|
|
9459
|
+
}
|
|
9460
|
+
if (!audioLevelQualifies(band, dbfs)) return;
|
|
9461
|
+
await this.onTrigger(deviceId, "audio", atMs);
|
|
9462
|
+
}
|
|
9463
|
+
/**
|
|
9388
9464
|
* The post-buffer that governs this device's trigger history right now: it is
|
|
9389
9465
|
* both the MERGE GAP (a trigger landing inside the open live window belongs to
|
|
9390
9466
|
* the running episode) and the retention horizon. Falls back to the shipped
|
|
@@ -9499,7 +9575,7 @@ var RecordingController = class {
|
|
|
9499
9575
|
meta: {
|
|
9500
9576
|
postBufferSec: band.postBufferSec,
|
|
9501
9577
|
triggers: band.triggers,
|
|
9502
|
-
reason: band.
|
|
9578
|
+
reason: bandTriggerSources(band).length > 0 ? "postBufferSec is 0" : "no trigger configured"
|
|
9503
9579
|
}
|
|
9504
9580
|
});
|
|
9505
9581
|
}
|
|
@@ -11553,6 +11629,14 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
|
|
|
11553
11629
|
eventMap = new EventMap();
|
|
11554
11630
|
/** Unsubscribe handle for the EventCapture motion subscription. */
|
|
11555
11631
|
eventUnsub = null;
|
|
11632
|
+
/**
|
|
11633
|
+
* Unsubscribe handle for the `PipelineAudioInferenceResult` audio-level
|
|
11634
|
+
* subscription — the feed `audioThresholdDbfs` was missing (D62, Traccia 0
|
|
11635
|
+
* of `docs/design/plans/2026-08-26-trigger-detection-e-sensori.md`). Kept
|
|
11636
|
+
* separate from `eventUnsub` (a distinct bus category) but guarded and torn
|
|
11637
|
+
* down the same way, idempotent re-entry included.
|
|
11638
|
+
*/
|
|
11639
|
+
audioTriggerUnsub = null;
|
|
11556
11640
|
/** Resolved recordings locations (id + root). Refreshed on boot + rescan.
|
|
11557
11641
|
* Already ALIAS-GUARDED: a writable same-type duplicate of another
|
|
11558
11642
|
* location's physical root arrives here demoted to read-only. */
|
|
@@ -12024,6 +12108,8 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
|
|
|
12024
12108
|
async onShutdown() {
|
|
12025
12109
|
this.eventUnsub?.();
|
|
12026
12110
|
this.eventUnsub = null;
|
|
12111
|
+
this.audioTriggerUnsub?.();
|
|
12112
|
+
this.audioTriggerUnsub = null;
|
|
12027
12113
|
await this.controller?.stop();
|
|
12028
12114
|
this.controller = null;
|
|
12029
12115
|
this.segmentStore = null;
|
|
@@ -12098,6 +12184,11 @@ var RecorderV2Addon = class extends require_dist.BaseAddon {
|
|
|
12098
12184
|
this.controller?.onTrigger(deviceId, "motion", atMs);
|
|
12099
12185
|
}
|
|
12100
12186
|
});
|
|
12187
|
+
if (this.audioTriggerUnsub === null) this.audioTriggerUnsub = this.ctx.eventBus.subscribe({ category: require_dist.EventCategory.PipelineAudioInferenceResult }, (event) => {
|
|
12188
|
+
const dbfs = event.data.frame.level?.dbfs;
|
|
12189
|
+
if (dbfs === void 0) return;
|
|
12190
|
+
this.controller?.onAudioLevel(event.data.deviceId, dbfs, event.data.frame.timestamp);
|
|
12191
|
+
});
|
|
12101
12192
|
try {
|
|
12102
12193
|
await this.segmentHours?.load();
|
|
12103
12194
|
this.segmentHours?.hydrateIndex(this.index);
|
package/dist/recorder/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as deriveRecordingMode, Dt as hydrateSchema, F as customAction, Gt as string, Ht as number, L as defineCustomActions, Lt as array, M as batteryCapability, Pt as selectAssignedProfileSlots, R as deriveBatteryPresence, Rt as boolean, St as BaseAddon, T as RecordingConfigSchema, Tt as DeviceType, Ut as object, Wt as record, at as recordingCapability, b as OpsLogEntrySchema, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, ft as storageEvictableCapability, g as ExportRecordSchema, gt as errMsg, i as BatteryStatusSchema, jt as nodePin, m as EVENT_PAD_MS, ot as recordingExportCapability, qt as EventCategory, ut as resolveRecordingProfiles, w as RECORDING_EXPORT_MAX_READ_BYTES, wt as DeviceFeature } from "../dist-
|
|
1
|
+
import { B as deriveRecordingMode, Dt as hydrateSchema, F as customAction, Gt as string, Ht as number, L as defineCustomActions, Lt as array, M as batteryCapability, Pt as selectAssignedProfileSlots, R as deriveBatteryPresence, Rt as boolean, St as BaseAddon, T as RecordingConfigSchema, Tt as DeviceType, Ut as object, Wt as record, at as recordingCapability, b as OpsLogEntrySchema, d as DEFAULT_EVENTS_BAND_BUFFER_SEC, ft as storageEvictableCapability, g as ExportRecordSchema, gt as errMsg, i as BatteryStatusSchema, jt as nodePin, m as EVENT_PAD_MS, ot as recordingExportCapability, qt as EventCategory, ut as resolveRecordingProfiles, w as RECORDING_EXPORT_MAX_READ_BYTES, wt as DeviceFeature } from "../dist-DO0UVhOk.mjs";
|
|
2
2
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
3
3
|
import { r as withRecordingIntent } from "../restream-intent-B4BXZra7.mjs";
|
|
4
4
|
import { n as createFileDataPlaneHandler, s as parseRangeHeader, t as contentTypeFor } from "../addon-utils-CgBCF-mE.mjs";
|
|
@@ -7520,7 +7520,46 @@ function resolveBandBufferMs(band) {
|
|
|
7520
7520
|
*/
|
|
7521
7521
|
function eventsBandCanEverDemand(band) {
|
|
7522
7522
|
if (band.mode !== "events") return true;
|
|
7523
|
-
return (band.
|
|
7523
|
+
return bandTriggerSources(band).length > 0 && resolveBandBufferMs(band).postMs > 0;
|
|
7524
|
+
}
|
|
7525
|
+
/**
|
|
7526
|
+
* LE sorgenti che questa banda ascolta — l'unico posto dove i `triggers` di
|
|
7527
|
+
* una banda diventano `TriggerSource[]`. `eventsBandCanEverDemand` e
|
|
7528
|
+
* `RecordingController.reportUnrecordable` lo leggono invece di ripetere
|
|
7529
|
+
* l'if-ladder motion/audio a mano.
|
|
7530
|
+
*/
|
|
7531
|
+
function bandTriggerSources(band) {
|
|
7532
|
+
const t = band.triggers;
|
|
7533
|
+
if (t === void 0) return [];
|
|
7534
|
+
const sources = [];
|
|
7535
|
+
if (t.motion === true) sources.push("motion");
|
|
7536
|
+
if (t.audioThresholdDbfs !== void 0) sources.push("audio");
|
|
7537
|
+
return sources;
|
|
7538
|
+
}
|
|
7539
|
+
/**
|
|
7540
|
+
* Does this audio window's level clear the ACTIVE band's configured
|
|
7541
|
+
* threshold?
|
|
7542
|
+
*
|
|
7543
|
+
* `PipelineAudioInferenceResultPayload.frame.level.dbfs`
|
|
7544
|
+
* (`packages/types/src/types/detection.ts:448`) and
|
|
7545
|
+
* `RecordingTriggers.audioThresholdDbfs` are the SAME unit and the SAME
|
|
7546
|
+
* scale — dBFS, 0 = full scale, more negative = quieter — produced by
|
|
7547
|
+
* `audio-analyzer-provider.ts:77` (`20 * log10(rms)`). No conversion exists
|
|
7548
|
+
* between them because none is needed: the one other place in this repo that
|
|
7549
|
+
* compares the two values does the same bare `>=`
|
|
7550
|
+
* (`notification-center/audio-rule-matcher.ts:221`). Inventing a conversion
|
|
7551
|
+
* here would recreate the exact defect this track exists to close, only
|
|
7552
|
+
* harder to see because a wrong scale still fires occasionally.
|
|
7553
|
+
*
|
|
7554
|
+
* `band` must be the band ACTIVE AT the audio window's own timestamp — a
|
|
7555
|
+
* device can carry several bands with different thresholds (day/night), and
|
|
7556
|
+
* only one is ever "the" threshold at a given instant. The caller
|
|
7557
|
+
* (`RecordingController.onAudioLevel`) resolves it the same way
|
|
7558
|
+
* `postBufferMsFor` resolves the post-buffer.
|
|
7559
|
+
*/
|
|
7560
|
+
function audioLevelQualifies(band, dbfs) {
|
|
7561
|
+
const threshold = band?.triggers?.audioThresholdDbfs;
|
|
7562
|
+
return threshold !== void 0 && dbfs >= threshold;
|
|
7524
7563
|
}
|
|
7525
7564
|
/** No trigger has been seen for this device yet. */
|
|
7526
7565
|
var EMPTY_TRIGGER_STATE = {
|
|
@@ -9383,6 +9422,43 @@ var RecordingController = class {
|
|
|
9383
9422
|
}
|
|
9384
9423
|
}
|
|
9385
9424
|
/**
|
|
9425
|
+
* Feed one audio window's LEVEL into the trigger pipeline — the counterpart
|
|
9426
|
+
* of `onTrigger('motion', …)` for the `audioThresholdDbfs` source, and the
|
|
9427
|
+
* feed that source was missing until 2026-08-26 (D62: authorized by the UI,
|
|
9428
|
+
* read by every pure function in `band-decision.ts`, alimented by nobody).
|
|
9429
|
+
*
|
|
9430
|
+
* Qualification happens HERE, not upstream like motion's `data.detected`,
|
|
9431
|
+
* because it depends on a PER-BAND threshold: `audioThresholdDbfs` is
|
|
9432
|
+
* authored per band, not once per device, so it needs the same config read
|
|
9433
|
+
* {@link postBufferMsFor} already does to resolve which band is active at
|
|
9434
|
+
* `atMs` before it can know which threshold applies.
|
|
9435
|
+
*
|
|
9436
|
+
* Fed from the event bus (telemetry, may be dropped — D8/D11), so a
|
|
9437
|
+
* config-read failure here drops only THIS window's qualification test
|
|
9438
|
+
* rather than guessing a threshold — logged, never silent, and never fatal:
|
|
9439
|
+
* the device's recordability does not depend on any single audio sample,
|
|
9440
|
+
* the next window (or motion) can still open the band.
|
|
9441
|
+
*/
|
|
9442
|
+
async onAudioLevel(deviceId, dbfs, atMs) {
|
|
9443
|
+
if (this.stopped) return;
|
|
9444
|
+
let band;
|
|
9445
|
+
try {
|
|
9446
|
+
band = activeBandAt({ bands: (await this.deps.loadConfig(deviceId)).bands ?? [] }, new Date(atMs));
|
|
9447
|
+
} catch (err) {
|
|
9448
|
+
this.deps.logger.warn("recorder: audio trigger qualification skipped — config read failed", {
|
|
9449
|
+
tags: { deviceId },
|
|
9450
|
+
meta: {
|
|
9451
|
+
atMs,
|
|
9452
|
+
dbfs,
|
|
9453
|
+
error: errMsg(err)
|
|
9454
|
+
}
|
|
9455
|
+
});
|
|
9456
|
+
return;
|
|
9457
|
+
}
|
|
9458
|
+
if (!audioLevelQualifies(band, dbfs)) return;
|
|
9459
|
+
await this.onTrigger(deviceId, "audio", atMs);
|
|
9460
|
+
}
|
|
9461
|
+
/**
|
|
9386
9462
|
* The post-buffer that governs this device's trigger history right now: it is
|
|
9387
9463
|
* both the MERGE GAP (a trigger landing inside the open live window belongs to
|
|
9388
9464
|
* the running episode) and the retention horizon. Falls back to the shipped
|
|
@@ -9497,7 +9573,7 @@ var RecordingController = class {
|
|
|
9497
9573
|
meta: {
|
|
9498
9574
|
postBufferSec: band.postBufferSec,
|
|
9499
9575
|
triggers: band.triggers,
|
|
9500
|
-
reason: band.
|
|
9576
|
+
reason: bandTriggerSources(band).length > 0 ? "postBufferSec is 0" : "no trigger configured"
|
|
9501
9577
|
}
|
|
9502
9578
|
});
|
|
9503
9579
|
}
|
|
@@ -11551,6 +11627,14 @@ var RecorderV2Addon = class extends BaseAddon {
|
|
|
11551
11627
|
eventMap = new EventMap();
|
|
11552
11628
|
/** Unsubscribe handle for the EventCapture motion subscription. */
|
|
11553
11629
|
eventUnsub = null;
|
|
11630
|
+
/**
|
|
11631
|
+
* Unsubscribe handle for the `PipelineAudioInferenceResult` audio-level
|
|
11632
|
+
* subscription — the feed `audioThresholdDbfs` was missing (D62, Traccia 0
|
|
11633
|
+
* of `docs/design/plans/2026-08-26-trigger-detection-e-sensori.md`). Kept
|
|
11634
|
+
* separate from `eventUnsub` (a distinct bus category) but guarded and torn
|
|
11635
|
+
* down the same way, idempotent re-entry included.
|
|
11636
|
+
*/
|
|
11637
|
+
audioTriggerUnsub = null;
|
|
11554
11638
|
/** Resolved recordings locations (id + root). Refreshed on boot + rescan.
|
|
11555
11639
|
* Already ALIAS-GUARDED: a writable same-type duplicate of another
|
|
11556
11640
|
* location's physical root arrives here demoted to read-only. */
|
|
@@ -12022,6 +12106,8 @@ var RecorderV2Addon = class extends BaseAddon {
|
|
|
12022
12106
|
async onShutdown() {
|
|
12023
12107
|
this.eventUnsub?.();
|
|
12024
12108
|
this.eventUnsub = null;
|
|
12109
|
+
this.audioTriggerUnsub?.();
|
|
12110
|
+
this.audioTriggerUnsub = null;
|
|
12025
12111
|
await this.controller?.stop();
|
|
12026
12112
|
this.controller = null;
|
|
12027
12113
|
this.segmentStore = null;
|
|
@@ -12096,6 +12182,11 @@ var RecorderV2Addon = class extends BaseAddon {
|
|
|
12096
12182
|
this.controller?.onTrigger(deviceId, "motion", atMs);
|
|
12097
12183
|
}
|
|
12098
12184
|
});
|
|
12185
|
+
if (this.audioTriggerUnsub === null) this.audioTriggerUnsub = this.ctx.eventBus.subscribe({ category: EventCategory.PipelineAudioInferenceResult }, (event) => {
|
|
12186
|
+
const dbfs = event.data.frame.level?.dbfs;
|
|
12187
|
+
if (dbfs === void 0) return;
|
|
12188
|
+
this.controller?.onAudioLevel(event.data.deviceId, dbfs, event.data.frame.timestamp);
|
|
12189
|
+
});
|
|
12099
12190
|
try {
|
|
12100
12191
|
await this.segmentHours?.load();
|
|
12101
12192
|
this.segmentHours?.hydrateIndex(this.index);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_dist = require("./dist-
|
|
1
|
+
const require_dist = require("./dist-CqoMNE1e.js");
|
|
2
2
|
let node_child_process = require("node:child_process");
|
|
3
3
|
//#region ../../node_modules/mp4box/dist/mp4box.all.js
|
|
4
4
|
var require_mp4box_all = /* @__PURE__ */ require_dist.__commonJSMin(((exports) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as __toESM, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { gt as errMsg } from "./dist-
|
|
2
|
+
import { gt as errMsg } from "./dist-DO0UVhOk.mjs";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
//#region ../../node_modules/mp4box/dist/mp4box.all.js
|
|
5
5
|
var require_mp4box_all = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
@@ -1,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-G3HXTY8z.js");
|
|
3
|
+
const require_lazy_sharp = require("../lazy-sharp-BGrpS8yi.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-_Ujvj1hl.mjs";
|
|
2
2
|
import { n as setSharpWarnSink, r as hostExternalEntryUrls, t as getSharp } from "../lazy-sharp-BtT5x-qP.mjs";
|
|
3
3
|
//#region src/session-decode/color-conversion.ts
|
|
4
4
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, p as c, r as l, s as u, t as d, u as f } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-
|
|
1
|
+
import { a as e, c as t, d as n, f as r, i, l as a, n as o, o as s, p as c, r as l, s as u, t as d, u as f } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-CQKwHIHI.mjs";
|
|
2
2
|
import { a as p, i as m, n as h, o as g, r as _, t as v } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.js-C9j-2lBe.mjs";
|
|
3
3
|
import { n as y, r as b, t as x } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-XO0-Pyu6.mjs";
|
|
4
4
|
import { t as S } from "./_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-Bme2OZQp.mjs";
|
|
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
|
|
|
3
3
|
var e = {
|
|
4
4
|
"@camstack/sdk": {
|
|
5
5
|
name: "@camstack/sdk",
|
|
6
|
-
version: "1.2.
|
|
6
|
+
version: "1.2.33",
|
|
7
7
|
scope: ["default"],
|
|
8
8
|
loaded: !1,
|
|
9
9
|
from: "addon_stream_broker_widgets",
|
|
@@ -18,7 +18,7 @@ var e = {
|
|
|
18
18
|
},
|
|
19
19
|
"@camstack/types": {
|
|
20
20
|
name: "@camstack/types",
|
|
21
|
-
version: "1.2.
|
|
21
|
+
version: "1.2.111",
|
|
22
22
|
scope: ["default"],
|
|
23
23
|
loaded: !1,
|
|
24
24
|
from: "addon_stream_broker_widgets",
|
|
@@ -33,7 +33,7 @@ var e = {
|
|
|
33
33
|
},
|
|
34
34
|
"@camstack/ui-library": {
|
|
35
35
|
name: "@camstack/ui-library",
|
|
36
|
-
version: "1.2.
|
|
36
|
+
version: "1.2.74",
|
|
37
37
|
scope: ["default"],
|
|
38
38
|
loaded: !1,
|
|
39
39
|
from: "addon_stream_broker_widgets",
|