@camstack/addon-pipeline 1.2.296 → 1.2.298
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 +571 -305
- package/dist/audio-analyzer/index.mjs +571 -305
- package/dist/{default-detection-model-D1daTtqT.js → default-detection-model-BTJZvSr_.js} +368 -5
- package/dist/{default-detection-model-Co578D8C.mjs → default-detection-model-Bim_g_Ui.mjs} +339 -6
- package/dist/detection-pipeline/index.js +521 -217
- package/dist/detection-pipeline/index.mjs +520 -216
- package/dist/{dist-CCd0Q3nr.mjs → dist-DVz_88D_.mjs} +80 -123
- package/dist/{dist-8up-f2TX.js → dist-L_HlB0At.js} +91 -140
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-lpQgHes9.js → node-CmzZ_-zB.js} +1 -1
- package/dist/{node-DgMSXSWP.mjs → node-Cr8Ch1ZN.mjs} +1 -1
- package/dist/pipeline-runner/index.js +213 -203
- package/dist/pipeline-runner/index.mjs +213 -203
- package/dist/{process-memory-DFC_O5zE.mjs → process-memory-DO7La1yB.mjs} +1 -1
- package/dist/{process-memory-CX_92V_r.js → process-memory-FfRDGu11.js} +1 -1
- package/dist/recorder/index.js +3 -3
- package/dist/recorder/index.mjs +3 -3
- package/dist/{segment-demux-js-FZbBuk3F.mjs → segment-demux-js-BuioTwCh.mjs} +1 -1
- package/dist/{segment-demux-js-DzBx6NN2.js → segment-demux-js-Cd7btWna.js} +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-C_i7oFBl.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CsbrrsyY.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DisouA2F.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-Dti8Ex88.mjs +26 -0
- 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-BPtppL3W.mjs → hostInit-NCsHzij7.mjs} +2 -2
- package/dist/stream-broker/index.js +3 -3
- package/dist/stream-broker/index.mjs +3 -3
- package/dist/stream-broker/remoteEntry.js +1 -1
- 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-DUGQKsKL.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-CkbplMHA.mjs +0 -26
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as MOTION_CLOSE_AFTER_MS, Dn as
|
|
2
|
-
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-
|
|
3
|
-
import {
|
|
1
|
+
import { An as lazy, At as pickDetailCropConvention, D as MOTION_CLOSE_AFTER_MS, Dn as array, En as _enum, In as string, Mn as number, Nn as object, Nt as pipelineRunnerCapability, O as NativeLeaseAdmissionSchema, On as boolean, Rn as EventCategory, en as errMsg, h as DEFAULT_DETAIL_CROP_CONVENTION, hn as defineCustomActions, i as BackgroundRunRegistry, jn as literal, jt as pickNativeLeaseOverride, k as NativeLeaseSettingsSchema, mn as customAction, nt as deriveDetailCropRect, pn as createEvent, pt as failureContributionCapability, sn as BaseAddon, v as DEFAULT_NATIVE_LEASE_SETTINGS, vt as loadContributionCapability, w as FailureCounters, xn as nodePin } from "../dist-DVz_88D_.mjs";
|
|
2
|
+
import { i as NO_COST_CLAIM, t as ChildCostRegistry } from "../node-Cr8Ch1ZN.mjs";
|
|
3
|
+
import { c as macroGateVerdict, d as resolveFrameViewGeometry, g as getStepDefinition, l as rootObjectGate, o as placeDetailStep, r as CustomModelCatalog, s as stepsForElectedPool, u as localFrameRegistry, v as RETIRED_MODEL_IDS } from "../default-detection-model-Bim_g_Ui.mjs";
|
|
4
4
|
import { t as isWorkerReply } from "../worker-protocol-D_NzPcnh.mjs";
|
|
5
5
|
import { t as resolveHubHostname } from "../hub-hostname-cCknRYKj.mjs";
|
|
6
6
|
import { t as getSharp } from "../lazy-sharp-DXsqwpph.mjs";
|
|
@@ -631,6 +631,28 @@ function positiveOrUndefined(value) {
|
|
|
631
631
|
return Number.isFinite(value) && value > 0 ? value : void 0;
|
|
632
632
|
}
|
|
633
633
|
//#endregion
|
|
634
|
+
//#region src/pipeline-runner/retained-reader-hold.ts
|
|
635
|
+
/**
|
|
636
|
+
* Run `read` with `handle`'s parked frame held as a CONSUMER for its whole
|
|
637
|
+
* duration (D656).
|
|
638
|
+
*
|
|
639
|
+
* `getNativeCrop` has two rungs: a native crop, then — on a miss — the retained
|
|
640
|
+
* full-frame fallback. Between them nothing is in flight: the crop's reply
|
|
641
|
+
* settles the worker's last pending request in the same turn, and the fallback's
|
|
642
|
+
* `toBuffer` is only sent on a later microtask. A parked frame does not keep a
|
|
643
|
+
* draining worker alive, so without this hold the drain killed the worker in
|
|
644
|
+
* that gap and the fallback was lost. One rule instead of a timing trick: a
|
|
645
|
+
* read in progress is a consumer.
|
|
646
|
+
*/
|
|
647
|
+
async function withRetainedReader(store, handle, read) {
|
|
648
|
+
const release = store?.holdReader(handle) ?? null;
|
|
649
|
+
try {
|
|
650
|
+
return await read();
|
|
651
|
+
} finally {
|
|
652
|
+
release?.();
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
//#endregion
|
|
634
656
|
//#region src/session-decode/native-crop-lease-age.ts
|
|
635
657
|
/**
|
|
636
658
|
* THE age bound on a native crop lease (ADR-0419).
|
|
@@ -973,6 +995,8 @@ function createRetainedContentFallback(registry, ref) {
|
|
|
973
995
|
timestamp: ref.timestamp,
|
|
974
996
|
...ref.capturedAt !== void 0 ? { capturedAt: ref.capturedAt } : {}
|
|
975
997
|
};
|
|
998
|
+
} catch {
|
|
999
|
+
return null;
|
|
976
1000
|
} finally {
|
|
977
1001
|
lease.release(reason);
|
|
978
1002
|
}
|
|
@@ -1415,6 +1439,14 @@ var RetainedFrameStore = class RetainedFrameStore {
|
|
|
1415
1439
|
if (current) current.hydrating = void 0;
|
|
1416
1440
|
}
|
|
1417
1441
|
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Hold `handle`'s parked frame as a reader until the returned release runs
|
|
1444
|
+
* (D656). `null` when the handle has no un-hydrated fallback — bytes already
|
|
1445
|
+
* in RAM need no worker.
|
|
1446
|
+
*/
|
|
1447
|
+
holdReader(handle) {
|
|
1448
|
+
return this.entries.get(keyOf(handle))?.fallback?.holdReader?.() ?? null;
|
|
1449
|
+
}
|
|
1418
1450
|
/** Drop every retained frame (node/addon shutdown). */
|
|
1419
1451
|
clear() {
|
|
1420
1452
|
for (const entry of this.entries.values()) entry.fallback?.release?.();
|
|
@@ -1581,6 +1613,25 @@ var SESSION_DECODE_DRAIN_BOUND_MS = 1500;
|
|
|
1581
1613
|
*/
|
|
1582
1614
|
var NATIVE_CROP_REFUSED_DRAINING = "session draining — crop requested after teardown";
|
|
1583
1615
|
/**
|
|
1616
|
+
* The refusal for a `toBuffer` asked for once the worker has been told to exit
|
|
1617
|
+
* (D656). A read during a DRAIN is served — that is what the drain is for — but
|
|
1618
|
+
* after the kill no reply can come, and a raw rejection read as a worker fault.
|
|
1619
|
+
*/
|
|
1620
|
+
var TO_BUFFER_REFUSED_KILLED = "session killed — read requested after the worker was told to exit";
|
|
1621
|
+
/** The refusal for a `toBuffer` the worker is no longer there to answer. */
|
|
1622
|
+
var TO_BUFFER_REFUSED_EXITED = "worker already exited";
|
|
1623
|
+
/** A read the session declined to send, by name — never a worker fault. */
|
|
1624
|
+
var SessionDecodeReadRefusedError = class extends Error {
|
|
1625
|
+
reason;
|
|
1626
|
+
frameId;
|
|
1627
|
+
constructor(reason, frameId) {
|
|
1628
|
+
super(`session-decode-coordinator: ${reason} (frameId=${frameId})`);
|
|
1629
|
+
this.reason = reason;
|
|
1630
|
+
this.frameId = frameId;
|
|
1631
|
+
this.name = "SessionDecodeReadRefusedError";
|
|
1632
|
+
}
|
|
1633
|
+
};
|
|
1634
|
+
/**
|
|
1584
1635
|
* How often the cold-start wait REPORTS that it is still waiting. Task 0
|
|
1585
1636
|
* live-measured cold-start (restream dial + hwaccel context + keyframe wait) at
|
|
1586
1637
|
* 5-8s, so this must tolerate a slow-but-healthy start.
|
|
@@ -1664,11 +1715,18 @@ var SessionDecodeSession = class {
|
|
|
1664
1715
|
/** Set when `kill()` is sent, so handleExit can tell an intentional stop from a death. */
|
|
1665
1716
|
killSent = false;
|
|
1666
1717
|
/**
|
|
1667
|
-
* Images yielded
|
|
1668
|
-
*
|
|
1669
|
-
*
|
|
1718
|
+
* Images yielded and not yet closed that a CONSUMER still holds — queued,
|
|
1719
|
+
* in flight, or being read. Each dies with the worker and somebody was going
|
|
1720
|
+
* to read it first. This is what a drain waits on.
|
|
1721
|
+
*/
|
|
1722
|
+
consumerImages = 0;
|
|
1723
|
+
/**
|
|
1724
|
+
* Images yielded and not yet closed that only a RETENTION holder keeps —
|
|
1725
|
+
* parked for a read that may come later (the on-demand JPEG fallback, D656).
|
|
1726
|
+
* They die with the worker too, but nobody reads them inside any bound worth
|
|
1727
|
+
* holding a worker for, so a drain does NOT wait on them.
|
|
1670
1728
|
*/
|
|
1671
|
-
|
|
1729
|
+
retainedImages = 0;
|
|
1672
1730
|
/** Armed while a drain waits; its expiry kills with frames still held. */
|
|
1673
1731
|
drainTimer = null;
|
|
1674
1732
|
sigkillTimer = null;
|
|
@@ -1722,7 +1780,8 @@ var SessionDecodeSession = class {
|
|
|
1722
1780
|
}
|
|
1723
1781
|
/** Send `toBuffer` for `frameId` and resolve with the matching `buffer` reply's bytes. */
|
|
1724
1782
|
requestBuffer(frameId, opts) {
|
|
1725
|
-
if (this.exited) return Promise.reject(
|
|
1783
|
+
if (this.exited) return Promise.reject(new SessionDecodeReadRefusedError(TO_BUFFER_REFUSED_EXITED, frameId));
|
|
1784
|
+
if (this.killSent) return Promise.reject(new SessionDecodeReadRefusedError(TO_BUFFER_REFUSED_KILLED, frameId));
|
|
1726
1785
|
return new Promise((resolve, reject) => {
|
|
1727
1786
|
const waiter = {
|
|
1728
1787
|
resolve,
|
|
@@ -1811,13 +1870,28 @@ var SessionDecodeSession = class {
|
|
|
1811
1870
|
frameId
|
|
1812
1871
|
});
|
|
1813
1872
|
}
|
|
1814
|
-
/** A yielded image the consumer now holds — see {@link
|
|
1873
|
+
/** A yielded image the consumer now holds — see {@link consumerImages}. */
|
|
1815
1874
|
noteImageOpened() {
|
|
1816
|
-
this.
|
|
1875
|
+
this.consumerImages += 1;
|
|
1817
1876
|
}
|
|
1818
|
-
/**
|
|
1819
|
-
|
|
1820
|
-
|
|
1877
|
+
/**
|
|
1878
|
+
* An open image moved between a consumer and a retention-only holder
|
|
1879
|
+
* (D656). Losing its last consumer may complete a waiting drain.
|
|
1880
|
+
*/
|
|
1881
|
+
noteImageHolder(pendingConsumer) {
|
|
1882
|
+
if (pendingConsumer) {
|
|
1883
|
+
this.retainedImages = Math.max(0, this.retainedImages - 1);
|
|
1884
|
+
this.consumerImages += 1;
|
|
1885
|
+
return;
|
|
1886
|
+
}
|
|
1887
|
+
this.consumerImages = Math.max(0, this.consumerImages - 1);
|
|
1888
|
+
this.retainedImages += 1;
|
|
1889
|
+
this.settleDrainIfDone();
|
|
1890
|
+
}
|
|
1891
|
+
/** A yielded image was closed; a waiting drain may now be done. */
|
|
1892
|
+
noteImageClosed(pendingConsumer) {
|
|
1893
|
+
if (pendingConsumer) this.consumerImages = Math.max(0, this.consumerImages - 1);
|
|
1894
|
+
else this.retainedImages = Math.max(0, this.retainedImages - 1);
|
|
1821
1895
|
this.settleDrainIfDone();
|
|
1822
1896
|
}
|
|
1823
1897
|
/**
|
|
@@ -1868,15 +1942,29 @@ var SessionDecodeSession = class {
|
|
|
1868
1942
|
this.tryKill("SIGKILL");
|
|
1869
1943
|
}
|
|
1870
1944
|
/**
|
|
1871
|
-
* Frames
|
|
1945
|
+
* Frames a CONSUMER still holds, reads still waiting on the worker, and
|
|
1872
1946
|
* native crops already REQUESTED. A crop asked for before the teardown
|
|
1873
1947
|
* request is waited for; one asked for after it is refused by name — post-analysis's
|
|
1874
1948
|
* ordinary crop arrives 2.2–9.9 s after the frame, past any bound worth
|
|
1875
1949
|
* holding a worker for, and is served from subject tiles that die with the
|
|
1876
1950
|
* worker either way.
|
|
1951
|
+
*
|
|
1952
|
+
* A frame only PARKED for such a late read ({@link retainedImages}) is not
|
|
1953
|
+
* counted, for the same reason (D656): counting it made nearly every
|
|
1954
|
+
* teardown wait the full bound for frames nobody was going to read. Its read,
|
|
1955
|
+
* once STARTED, is a pending read like any other and is waited for.
|
|
1877
1956
|
*/
|
|
1878
1957
|
unsettledCount() {
|
|
1879
|
-
return this.
|
|
1958
|
+
return this.consumerImages + this.pendingReadCount() + this.pendingNativeCrops.size;
|
|
1959
|
+
}
|
|
1960
|
+
/** What the session still holds, per category — every drain line carries it. */
|
|
1961
|
+
heldCounts() {
|
|
1962
|
+
return {
|
|
1963
|
+
consumerFrames: this.consumerImages,
|
|
1964
|
+
retainedFrames: this.retainedImages,
|
|
1965
|
+
pendingReads: this.pendingReadCount(),
|
|
1966
|
+
pendingCrops: this.pendingNativeCrops.size
|
|
1967
|
+
};
|
|
1880
1968
|
}
|
|
1881
1969
|
pendingReadCount() {
|
|
1882
1970
|
let n = 0;
|
|
@@ -1900,9 +1988,7 @@ var SessionDecodeSession = class {
|
|
|
1900
1988
|
this.logger.warn("session-decode-coordinator: drain bound expired — killing the worker with frames still held", {
|
|
1901
1989
|
tags: { deviceId: this.deviceId },
|
|
1902
1990
|
meta: {
|
|
1903
|
-
|
|
1904
|
-
pendingReads: this.pendingReadCount(),
|
|
1905
|
-
pendingCrops: this.pendingNativeCrops.size,
|
|
1991
|
+
...this.heldCounts(),
|
|
1906
1992
|
boundMs: SESSION_DECODE_DRAIN_BOUND_MS
|
|
1907
1993
|
}
|
|
1908
1994
|
});
|
|
@@ -1924,6 +2010,13 @@ var SessionDecodeSession = class {
|
|
|
1924
2010
|
killNow(mode) {
|
|
1925
2011
|
if (this.killSent) return;
|
|
1926
2012
|
this.killSent = true;
|
|
2013
|
+
if (this.retainedImages > 0) this.logger.debug("session-decode-coordinator: retained frames die with the worker", {
|
|
2014
|
+
tags: { deviceId: this.deviceId },
|
|
2015
|
+
meta: {
|
|
2016
|
+
mode,
|
|
2017
|
+
...this.heldCounts()
|
|
2018
|
+
}
|
|
2019
|
+
});
|
|
1927
2020
|
this.trySend({ kind: "stop" });
|
|
1928
2021
|
if (mode === "immediate") {
|
|
1929
2022
|
this.tryKill("SIGKILL");
|
|
@@ -2025,10 +2118,7 @@ var SessionDecodeSession = class {
|
|
|
2025
2118
|
meta: {
|
|
2026
2119
|
code: info?.code ?? null,
|
|
2027
2120
|
signal: info?.signal ?? null,
|
|
2028
|
-
...this.stopRequested ? {
|
|
2029
|
-
unsettledFrames: this.openImages,
|
|
2030
|
-
pendingReads: this.pendingReadCount()
|
|
2031
|
-
} : {}
|
|
2121
|
+
...this.stopRequested ? this.heldCounts() : {}
|
|
2032
2122
|
}
|
|
2033
2123
|
});
|
|
2034
2124
|
this.exited = true;
|
|
@@ -2226,6 +2316,7 @@ var SessionDecodeSession = class {
|
|
|
2226
2316
|
/** Build the {@link FrameImage} adapter for one `frame` reply. */
|
|
2227
2317
|
function buildFrameImage(session, reply) {
|
|
2228
2318
|
let closed = false;
|
|
2319
|
+
let pendingConsumer = true;
|
|
2229
2320
|
session.noteImageOpened();
|
|
2230
2321
|
return {
|
|
2231
2322
|
width: reply.width,
|
|
@@ -2240,10 +2331,15 @@ function buildFrameImage(session, reply) {
|
|
|
2240
2331
|
cutTiles: (bboxes) => session.cutTiles(reply.frameId, bboxes),
|
|
2241
2332
|
releaseNativeLease: () => session.releaseLease(reply.frameId),
|
|
2242
2333
|
markInferred: () => session.markInferred(reply.frameId),
|
|
2334
|
+
setPendingConsumer: (pending) => {
|
|
2335
|
+
if (closed || pending === pendingConsumer) return;
|
|
2336
|
+
pendingConsumer = pending;
|
|
2337
|
+
session.noteImageHolder(pending);
|
|
2338
|
+
},
|
|
2243
2339
|
close: () => {
|
|
2244
2340
|
if (closed) return;
|
|
2245
2341
|
closed = true;
|
|
2246
|
-
session.noteImageClosed();
|
|
2342
|
+
session.noteImageClosed(pendingConsumer);
|
|
2247
2343
|
}
|
|
2248
2344
|
};
|
|
2249
2345
|
}
|
|
@@ -3919,173 +4015,6 @@ async function runDetailSubtree(deps, input) {
|
|
|
3919
4015
|
return { details };
|
|
3920
4016
|
}
|
|
3921
4017
|
//#endregion
|
|
3922
|
-
//#region src/pipeline-runner/device-jump.ts
|
|
3923
|
-
/**
|
|
3924
|
-
* Step-tree device jump (same-node, phase 1) — the PURE resolution core.
|
|
3925
|
-
*
|
|
3926
|
-
* Given the camera's elected ("effective") inference device and the node's
|
|
3927
|
-
* enabled-device roster, decide which device ONE enrichment step should run on:
|
|
3928
|
-
*
|
|
3929
|
-
* 1. A manual `jumpDeviceKey` override wins when it names a candidate that can
|
|
3930
|
-
* run the step (bypasses the auto choice; operator intent).
|
|
3931
|
-
* 2. Otherwise, if the effective device's format can run the step's model →
|
|
3932
|
-
* NO jump (the step inherits the effective device — the common case).
|
|
3933
|
-
* 3. Otherwise AUTO-jump: among the node's OTHER enabled devices whose format
|
|
3934
|
-
* can run the step (and that are under their `maxSessions` cap), pick the
|
|
3935
|
-
* weighted-least-loaded one — mirroring the balancer's per-device core.
|
|
3936
|
-
* 4. If nothing on the node can run it → `no-candidate` (the caller emits the
|
|
3937
|
-
* loud once-per-(camera,step) warn that replaces today's silent degrade).
|
|
3938
|
-
*
|
|
3939
|
-
* Framework-free + side-effect-free so the whole decision table is unit-testable
|
|
3940
|
-
* without a live runner/catalog. The `canRun(format)` predicate is injected by
|
|
3941
|
-
* the runner (which owns the model catalog); this module never imports it.
|
|
3942
|
-
*/
|
|
3943
|
-
/** The `ModelFormat` of a `<backend>:<device>` key, or `undefined` for an unknown backend. */
|
|
3944
|
-
function formatOf(deviceKey) {
|
|
3945
|
-
const colon = deviceKey.indexOf(":");
|
|
3946
|
-
return DEVICE_BACKEND_TO_FORMAT[colon >= 0 ? deviceKey.slice(0, colon) : deviceKey];
|
|
3947
|
-
}
|
|
3948
|
-
/** True when the step's model has a build for `deviceKey`'s format. */
|
|
3949
|
-
function canRunOn(deviceKey, canRun) {
|
|
3950
|
-
const format = formatOf(deviceKey);
|
|
3951
|
-
return format !== void 0 && canRun(format);
|
|
3952
|
-
}
|
|
3953
|
-
/** Effective weighted load of a device (session count ÷ weight); lower = preferred. */
|
|
3954
|
-
function weightedLoad(d) {
|
|
3955
|
-
return d.attachedCameras / (d.weight > 0 ? d.weight : 1);
|
|
3956
|
-
}
|
|
3957
|
-
/**
|
|
3958
|
-
* Weighted-least-loaded pick with a deterministic `deviceKey` tie-break —
|
|
3959
|
-
* mirrors the node/device balancer's decision core (least `load/weight`, ties
|
|
3960
|
-
* broken stably). `devices` is assumed non-empty.
|
|
3961
|
-
*/
|
|
3962
|
-
function pickWeightedLeastLoaded(devices) {
|
|
3963
|
-
return devices.reduce((best, d) => {
|
|
3964
|
-
const dScore = weightedLoad(d);
|
|
3965
|
-
const bScore = weightedLoad(best);
|
|
3966
|
-
if (dScore < bScore) return d;
|
|
3967
|
-
if (dScore > bScore) return best;
|
|
3968
|
-
return d.deviceKey < best.deviceKey ? d : best;
|
|
3969
|
-
});
|
|
3970
|
-
}
|
|
3971
|
-
/**
|
|
3972
|
-
* Build the `canRun` predicate for ONE enrichment dispatch. The step and its
|
|
3973
|
-
* enabled descendants ride the SAME `runPipeline` call — one pool, one format
|
|
3974
|
-
* (detail-subtree contract: "its inherited children ride the same call → same
|
|
3975
|
-
* device") — so a format can run the dispatch only when EVERY catalog-known
|
|
3976
|
-
* step in the subtree ships a build for it. Gating only the subtree TOP let a
|
|
3977
|
-
* `face-detection` with a tflite build stay on the Coral while its
|
|
3978
|
-
* `face-embedding` child (no tflite build anywhere) doomed the call.
|
|
3979
|
-
* Unknown/custom addonIds (`getStepDef` → null) have no catalog to gate on
|
|
3980
|
-
* and never block. `getStepDef` is injected — this module stays catalog-free.
|
|
3981
|
-
*/
|
|
3982
|
-
function buildSubtreeCanRun(step, getStepDef) {
|
|
3983
|
-
const defs = [];
|
|
3984
|
-
const walk = (s) => {
|
|
3985
|
-
if (s.enabled === false) return;
|
|
3986
|
-
const def = getStepDef(s.addonId);
|
|
3987
|
-
if (def !== null) defs.push(def);
|
|
3988
|
-
for (const child of s.children ?? []) walk(child);
|
|
3989
|
-
};
|
|
3990
|
-
walk(step);
|
|
3991
|
-
return (format) => defs.every((def) => def.models.some((m) => m.formats[format]));
|
|
3992
|
-
}
|
|
3993
|
-
/**
|
|
3994
|
-
* Resolve the device one enrichment step runs on. See the module header for the
|
|
3995
|
-
* decision table. Pure — never throws, no I/O.
|
|
3996
|
-
*/
|
|
3997
|
-
function resolveStepDevice(input) {
|
|
3998
|
-
const { effectiveDeviceKey, manualJumpDeviceKey, canRun } = input;
|
|
3999
|
-
if (manualJumpDeviceKey !== void 0 && manualJumpDeviceKey !== effectiveDeviceKey) {
|
|
4000
|
-
const target = input.devices.find((d) => d.deviceKey === manualJumpDeviceKey);
|
|
4001
|
-
if (target && canRunOn(target.deviceKey, canRun)) return {
|
|
4002
|
-
kind: "jumped",
|
|
4003
|
-
deviceKey: target.deviceKey,
|
|
4004
|
-
reason: "manual"
|
|
4005
|
-
};
|
|
4006
|
-
}
|
|
4007
|
-
if (canRunOn(effectiveDeviceKey, canRun)) return {
|
|
4008
|
-
kind: "no-jump",
|
|
4009
|
-
deviceKey: effectiveDeviceKey
|
|
4010
|
-
};
|
|
4011
|
-
const runnable = input.devices.filter((d) => d.deviceKey !== effectiveDeviceKey && (d.maxSessions === null || d.attachedCameras < d.maxSessions) && canRunOn(d.deviceKey, canRun));
|
|
4012
|
-
if (runnable.length === 0) return {
|
|
4013
|
-
kind: "no-candidate",
|
|
4014
|
-
deviceKey: effectiveDeviceKey
|
|
4015
|
-
};
|
|
4016
|
-
return {
|
|
4017
|
-
kind: "jumped",
|
|
4018
|
-
deviceKey: pickWeightedLeastLoaded(runnable).deviceKey,
|
|
4019
|
-
reason: "auto"
|
|
4020
|
-
};
|
|
4021
|
-
}
|
|
4022
|
-
/**
|
|
4023
|
-
* Re-provision a jumped subtree for its TARGET device (D650): every step's
|
|
4024
|
-
* `modelId` / `settings` are REPLACED by the target's entry — the orchestrator
|
|
4025
|
-
* computed it as what the step would carry had the camera been elected onto
|
|
4026
|
-
* that device (its per-(node,device) base with the camera's override for it).
|
|
4027
|
-
* A step absent from the map runs with neither, i.e. the target format's
|
|
4028
|
-
* default model. The elected device's provisioning never follows a step across:
|
|
4029
|
-
* it was chosen for a format this subtree does not run on.
|
|
4030
|
-
*/
|
|
4031
|
-
function provisionSubtreeForDevice(step, provisioning) {
|
|
4032
|
-
const own = provisioning[step.addonId];
|
|
4033
|
-
const { modelId: _electedModelId, settings: _electedSettings, ...rest } = step;
|
|
4034
|
-
return {
|
|
4035
|
-
...rest,
|
|
4036
|
-
...own?.modelId !== void 0 ? { modelId: own.modelId } : {},
|
|
4037
|
-
...own?.settings !== void 0 ? { settings: own.settings } : {},
|
|
4038
|
-
...step.children !== void 0 ? { children: step.children.map((c) => provisionSubtreeForDevice(c, provisioning)) } : {}
|
|
4039
|
-
};
|
|
4040
|
-
}
|
|
4041
|
-
/**
|
|
4042
|
-
* Place ONE detail subtree (D650): which same-node device runs it
|
|
4043
|
-
* ({@link resolveStepDevice}) and, when it jumps, the provisioning it runs
|
|
4044
|
-
* with there ({@link provisionSubtreeForDevice}). Pure — the caller logs.
|
|
4045
|
-
*
|
|
4046
|
-
* A roster entry without `steps` came from an orchestrator that predates D650:
|
|
4047
|
-
* the step keeps what it was sent with, as it did before.
|
|
4048
|
-
*/
|
|
4049
|
-
function placeDetailStep(input) {
|
|
4050
|
-
const { step, effectiveDeviceKey, roster } = input;
|
|
4051
|
-
if (!effectiveDeviceKey) return {
|
|
4052
|
-
deviceKey: void 0,
|
|
4053
|
-
step,
|
|
4054
|
-
decision: null,
|
|
4055
|
-
provisioned: false
|
|
4056
|
-
};
|
|
4057
|
-
if (!roster || roster.length < 2) return {
|
|
4058
|
-
deviceKey: effectiveDeviceKey,
|
|
4059
|
-
step,
|
|
4060
|
-
decision: null,
|
|
4061
|
-
provisioned: false
|
|
4062
|
-
};
|
|
4063
|
-
const decision = resolveStepDevice({
|
|
4064
|
-
effectiveDeviceKey,
|
|
4065
|
-
devices: roster.map((d) => ({
|
|
4066
|
-
deviceKey: d.deviceKey,
|
|
4067
|
-
weight: d.weight,
|
|
4068
|
-
maxSessions: d.maxSessions,
|
|
4069
|
-
attachedCameras: input.attachedByKey.get(d.deviceKey) ?? 0
|
|
4070
|
-
})),
|
|
4071
|
-
...step.jumpDeviceKey !== void 0 ? { manualJumpDeviceKey: step.jumpDeviceKey } : {},
|
|
4072
|
-
canRun: buildSubtreeCanRun(step, input.getStepDef)
|
|
4073
|
-
});
|
|
4074
|
-
if (decision.kind !== "jumped") return {
|
|
4075
|
-
deviceKey: decision.deviceKey,
|
|
4076
|
-
step,
|
|
4077
|
-
decision,
|
|
4078
|
-
provisioned: false
|
|
4079
|
-
};
|
|
4080
|
-
const provisioning = roster.find((d) => d.deviceKey === decision.deviceKey)?.steps;
|
|
4081
|
-
return {
|
|
4082
|
-
deviceKey: decision.deviceKey,
|
|
4083
|
-
step: provisioning === void 0 ? step : provisionSubtreeForDevice(step, provisioning),
|
|
4084
|
-
decision,
|
|
4085
|
-
provisioned: provisioning !== void 0
|
|
4086
|
-
};
|
|
4087
|
-
}
|
|
4088
|
-
//#endregion
|
|
4089
4018
|
//#region src/pipeline-runner/device-load.ts
|
|
4090
4019
|
/** The backend prefix of a `<backend>:<device>` key (bare `cpu` → `cpu`). */
|
|
4091
4020
|
function backendOf(deviceKey) {
|
|
@@ -5369,7 +5298,7 @@ var ON_DEMAND_JPEG_VIEW = {
|
|
|
5369
5298
|
format: "jpeg"
|
|
5370
5299
|
};
|
|
5371
5300
|
function createOnDemandJpegFallback(registry, ref) {
|
|
5372
|
-
const lease = registry.acquire(ref);
|
|
5301
|
+
const lease = registry.acquire(ref, "retention");
|
|
5373
5302
|
let cached;
|
|
5374
5303
|
let released = false;
|
|
5375
5304
|
const releaseLease = (reason) => {
|
|
@@ -5409,6 +5338,11 @@ function createOnDemandJpegFallback(registry, ref) {
|
|
|
5409
5338
|
},
|
|
5410
5339
|
release() {
|
|
5411
5340
|
releaseLease("eviction");
|
|
5341
|
+
},
|
|
5342
|
+
holdReader() {
|
|
5343
|
+
if (released || cached !== void 0) return null;
|
|
5344
|
+
const reader = registry.acquire(ref);
|
|
5345
|
+
return reader ? () => reader.release("success") : null;
|
|
5412
5346
|
}
|
|
5413
5347
|
};
|
|
5414
5348
|
}
|
|
@@ -7254,11 +7188,14 @@ async function runStatelessStep(deps, input) {
|
|
|
7254
7188
|
return refuse(deps, input, "execution-failed", errorMessage(err));
|
|
7255
7189
|
}
|
|
7256
7190
|
if (result === null) return refuse(deps, input, "execution-failed", "the executor returned no frame result for the crop");
|
|
7191
|
+
const ranModelId = result.rootModelId;
|
|
7192
|
+
if (ranModelId === void 0 || ranModelId === "") return refuse(deps, input, "execution-failed", `the executor result names no model — refusing rather than assuming "${input.modelId}" ran`);
|
|
7193
|
+
if (ranModelId !== input.modelId) return refuse(deps, input, "model-not-servable", `the executor ran "${ranModelId}" for a call pinned to "${input.modelId}" — its output would not be comparable with the pass`);
|
|
7257
7194
|
const details = result.detections.map((detection) => toDetailResult(detection, input.stepId, crop));
|
|
7258
7195
|
return {
|
|
7259
7196
|
kind: "ran",
|
|
7260
7197
|
nodeId: deps.nodeId,
|
|
7261
|
-
modelId:
|
|
7198
|
+
modelId: ranModelId,
|
|
7262
7199
|
details
|
|
7263
7200
|
};
|
|
7264
7201
|
}
|
|
@@ -7667,6 +7604,15 @@ function tryGetStepDefinition(stepId) {
|
|
|
7667
7604
|
}
|
|
7668
7605
|
}
|
|
7669
7606
|
/**
|
|
7607
|
+
* A detail-plane step: its catalog definition consumes a parent class
|
|
7608
|
+
* (`inputClasses` non-null). Unknown/custom addonIds are root-plane — the
|
|
7609
|
+
* same reading as the executor's frame-plane skip and `deriveDetailSteps`.
|
|
7610
|
+
*/
|
|
7611
|
+
function isDetailPlaneStepId(stepId) {
|
|
7612
|
+
const def = tryGetStepDefinition(stepId);
|
|
7613
|
+
return def !== null && def.inputClasses !== null;
|
|
7614
|
+
}
|
|
7615
|
+
/**
|
|
7670
7616
|
* Precomputes the `detailSteps` announce (two-plane design) for a camera's
|
|
7671
7617
|
* configured step tree: every ENABLED step whose catalog definition is a
|
|
7672
7618
|
* detail/child step (`inputClasses !== null` — a root step like
|
|
@@ -8499,14 +8445,16 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
8499
8445
|
height: cached.height,
|
|
8500
8446
|
format: cached.format
|
|
8501
8447
|
}, pin)).frameId;
|
|
8502
|
-
await api.pipelineExecutor.runPipeline.mutate({ ...buildBenchRunPipelineInput({
|
|
8448
|
+
const benchModelId = (await api.pipelineExecutor.runPipeline.mutate({ ...buildBenchRunPipelineInput({
|
|
8503
8449
|
steps: stepsToRun,
|
|
8504
8450
|
frame: sharedFrame
|
|
8505
|
-
}) }, pin);
|
|
8451
|
+
}) }, pin)).rootModelId;
|
|
8452
|
+
if (benchModelId === void 0 || benchModelId === "") throw new Error(`synthetic bench: the warmup of "${rootStep.addonId}" named no model — refusing to time an unnamed variant`);
|
|
8506
8453
|
const warmupCount = input.warmup ?? 1;
|
|
8507
8454
|
for (let w = 0; w < warmupCount; w++) await api.pipelineExecutor.inferCached.mutate({
|
|
8508
8455
|
stepId: rootStep.addonId,
|
|
8509
|
-
frameId: poolFrameId
|
|
8456
|
+
frameId: poolFrameId,
|
|
8457
|
+
modelId: benchModelId
|
|
8510
8458
|
}, pin);
|
|
8511
8459
|
const wallTimings = [];
|
|
8512
8460
|
const inferTimings = [];
|
|
@@ -8524,7 +8472,8 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
8524
8472
|
const t0 = performance.now();
|
|
8525
8473
|
const result = await api.pipelineExecutor.inferCached.mutate({
|
|
8526
8474
|
stepId: rootStep.addonId,
|
|
8527
|
-
frameId: poolFrameId
|
|
8475
|
+
frameId: poolFrameId,
|
|
8476
|
+
modelId: benchModelId
|
|
8528
8477
|
}, pin);
|
|
8529
8478
|
const wallMs = performance.now() - t0;
|
|
8530
8479
|
const r = result;
|
|
@@ -9199,6 +9148,10 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
9199
9148
|
* resolve legitimately want the lower-RES honest frame).
|
|
9200
9149
|
*/
|
|
9201
9150
|
async getNativeCrop(input) {
|
|
9151
|
+
return withRetainedReader(this.retainedFrames, input.handle, () => this.resolveNativeCropBothRungs(input));
|
|
9152
|
+
}
|
|
9153
|
+
/** {@link getNativeCrop}'s two rungs, run under its reader hold. */
|
|
9154
|
+
async resolveNativeCropBothRungs(input) {
|
|
9202
9155
|
const deviceId = this.nativeCropRegistry.deviceIdFor(input.handle) ?? 0;
|
|
9203
9156
|
const isFullFrame = input.bbox.x <= .001 && input.bbox.y <= .001 && input.bbox.w >= .999 && input.bbox.h >= .999;
|
|
9204
9157
|
this.frameLazy.noteOnDemandRequest({
|
|
@@ -9714,6 +9667,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
9714
9667
|
*/
|
|
9715
9668
|
async runDetailSubtree(input) {
|
|
9716
9669
|
const convention = await this.cropConvention.refresh(this.ctxIfReady?.api);
|
|
9670
|
+
await this.customModels.refresh(this.ctxIfReady?.api);
|
|
9717
9671
|
const outcome = await runDetailSubtree({
|
|
9718
9672
|
resolveChildSteps: (deviceId, parentClassName, filter) => this.resolveDetailChildSteps(deviceId, parentClassName, filter),
|
|
9719
9673
|
getNativeCrop: (deviceId, handle, paddedBbox) => this.getNativeCropForDetail(deviceId, handle, paddedBbox),
|
|
@@ -9842,6 +9796,13 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
9842
9796
|
* global settings, NOT from the attach config. See `crop-convention-source.ts`
|
|
9843
9797
|
* for why eleven attach builders make the attach config the wrong carrier.
|
|
9844
9798
|
*/
|
|
9799
|
+
/**
|
|
9800
|
+
* The custom-model registry, merged into the catalog the device jump judges
|
|
9801
|
+
* (D657): a custom model with a tflite build, pinned on a Coral, runs there.
|
|
9802
|
+
* Refreshed on the async boundaries (`runInference`, `runDetailSubtree`),
|
|
9803
|
+
* read synchronously by the placement.
|
|
9804
|
+
*/
|
|
9805
|
+
customModels = new CustomModelCatalog({ warn: (message, extras) => this.ctxIfReady?.logger.warn(message, extras) });
|
|
9845
9806
|
cropConvention = new CropConventionSource({ logger: {
|
|
9846
9807
|
info: (message, extras) => this.ctxIfReady?.logger.info(message, extras),
|
|
9847
9808
|
warn: (message, extras) => this.ctxIfReady?.logger.warn(message, extras)
|
|
@@ -9945,18 +9906,63 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
9945
9906
|
*/
|
|
9946
9907
|
placeDetailStepForCamera(deviceId, step) {
|
|
9947
9908
|
const config = this.attached.get(deviceId)?.config;
|
|
9948
|
-
const placement =
|
|
9949
|
-
step,
|
|
9950
|
-
effectiveDeviceKey: config?.deviceKey,
|
|
9951
|
-
roster: config?.inferenceDevices,
|
|
9952
|
-
attachedByKey: this.perDeviceAttachedCounts(),
|
|
9953
|
-
getStepDef: tryGetStepDefinition
|
|
9954
|
-
});
|
|
9909
|
+
const placement = this.placementOf(config, step, this.perDeviceAttachedCounts());
|
|
9955
9910
|
const decision = placement.decision;
|
|
9956
9911
|
if (decision?.kind === "no-candidate") this.warnStepHasNoRunnableDevice(deviceId, step.addonId, decision.deviceKey);
|
|
9957
9912
|
else if (decision?.kind === "jumped" && config?.deviceKey) this.logStepJumped(deviceId, config.deviceKey, decision, placement);
|
|
9958
9913
|
return placement;
|
|
9959
9914
|
}
|
|
9915
|
+
/**
|
|
9916
|
+
* Where one detail subtree of this camera runs — the ONE decision both the
|
|
9917
|
+
* detail plane (which dispatches it) and the frame plane (which decides what
|
|
9918
|
+
* the elected pool pre-warms, D657) read. Pure: nothing is logged here.
|
|
9919
|
+
*/
|
|
9920
|
+
placementOf(config, step, attachedByKey) {
|
|
9921
|
+
return placeDetailStep({
|
|
9922
|
+
step,
|
|
9923
|
+
effectiveDeviceKey: config?.deviceKey,
|
|
9924
|
+
roster: config?.inferenceDevices,
|
|
9925
|
+
attachedByKey,
|
|
9926
|
+
getStepDef: this.customModels.stepDefinition
|
|
9927
|
+
});
|
|
9928
|
+
}
|
|
9929
|
+
/**
|
|
9930
|
+
* The tree this camera's frame-plane dispatch carries (D657): a detail
|
|
9931
|
+
* subtree the placement sends to another device (or to none) is left out,
|
|
9932
|
+
* so its model is never loaded on the elected pool — it loads on its
|
|
9933
|
+
* target, with the target's provisioning, when the detail plane dispatches
|
|
9934
|
+
* it there. Said once per (camera, elected device, set left out).
|
|
9935
|
+
*/
|
|
9936
|
+
stepsForElectedPoolOf(deviceId, steps) {
|
|
9937
|
+
const config = this.attached.get(deviceId)?.config;
|
|
9938
|
+
if (config?.deviceKey === void 0 || (config.inferenceDevices?.length ?? 0) < 2) {
|
|
9939
|
+
this.noteElectedPoolDelegation(deviceId, void 0, []);
|
|
9940
|
+
return steps;
|
|
9941
|
+
}
|
|
9942
|
+
const attachedByKey = this.perDeviceAttachedCounts();
|
|
9943
|
+
const result = stepsForElectedPool(steps, isDetailPlaneStepId, (step) => this.placementOf(config, step, attachedByKey));
|
|
9944
|
+
this.noteElectedPoolDelegation(deviceId, config.deviceKey, result.delegated);
|
|
9945
|
+
return result.delegated.length === 0 ? steps : result.steps;
|
|
9946
|
+
}
|
|
9947
|
+
/**
|
|
9948
|
+
* Say once per STATE CHANGE which detail steps a camera's elected pool no
|
|
9949
|
+
* longer loads: a camera moving A → B → A says so again on A.
|
|
9950
|
+
*/
|
|
9951
|
+
noteElectedPoolDelegation(deviceId, electedDeviceKey, delegated) {
|
|
9952
|
+
const state = `${electedDeviceKey ?? ""}|${delegated.join(",")}`;
|
|
9953
|
+
if (this.electedPoolDelegationState.get(deviceId) === state) return;
|
|
9954
|
+
this.electedPoolDelegationState.set(deviceId, state);
|
|
9955
|
+
if (delegated.length === 0) return;
|
|
9956
|
+
this.ctx?.logger.info("detail steps not loaded on the elected pool — they run elsewhere", {
|
|
9957
|
+
tags: { deviceId },
|
|
9958
|
+
meta: {
|
|
9959
|
+
electedDeviceKey: electedDeviceKey ?? null,
|
|
9960
|
+
steps: [...delegated]
|
|
9961
|
+
}
|
|
9962
|
+
});
|
|
9963
|
+
}
|
|
9964
|
+
/** Per camera, the last (elected device, steps left out) state that was logged. */
|
|
9965
|
+
electedPoolDelegationState = /* @__PURE__ */ new Map();
|
|
9960
9966
|
/** `${deviceId}:${addonId}:${target}` triples whose jump has been logged. */
|
|
9961
9967
|
loggedStepJumps = /* @__PURE__ */ new Set();
|
|
9962
9968
|
logStepJumped(deviceId, electedDeviceKey, decision, placement) {
|
|
@@ -10193,6 +10199,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
10193
10199
|
const warnPrefix = `${deviceId}:`;
|
|
10194
10200
|
for (const key of this.warnedNoJumpDevice) if (key.startsWith(warnPrefix)) this.warnedNoJumpDevice.delete(key);
|
|
10195
10201
|
this.attached.delete(deviceId);
|
|
10202
|
+
this.electedPoolDelegationState.delete(deviceId);
|
|
10196
10203
|
this.lastMotionAt.delete(deviceId);
|
|
10197
10204
|
this.lastEmittedCameraMetrics.delete(deviceId);
|
|
10198
10205
|
this.retention?.forgetDevice(deviceId);
|
|
@@ -10903,6 +10910,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
10903
10910
|
}
|
|
10904
10911
|
const camConfig = this.attached.get(deviceId)?.config;
|
|
10905
10912
|
const steps = camConfig?.steps;
|
|
10913
|
+
await this.customModels.refresh(api);
|
|
10906
10914
|
if (!steps) {
|
|
10907
10915
|
log.warn("runInference: no steps in attach config — skipping frame (legacy attach?)");
|
|
10908
10916
|
return null;
|
|
@@ -10937,6 +10945,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
10937
10945
|
});
|
|
10938
10946
|
}
|
|
10939
10947
|
}
|
|
10948
|
+
dispatchSteps = this.stepsForElectedPoolOf(deviceId, dispatchSteps);
|
|
10940
10949
|
let image;
|
|
10941
10950
|
const executorCoLocated = this.executorCoLocated();
|
|
10942
10951
|
if (!executorCoLocated) {
|
|
@@ -11066,6 +11075,7 @@ var PipelineRunnerAddon = class PipelineRunnerAddon extends BaseAddon {
|
|
|
11066
11075
|
const cropResult = await api.pipelineExecutor.runPipeline.mutate({
|
|
11067
11076
|
steps: [step],
|
|
11068
11077
|
image: view.jpeg,
|
|
11078
|
+
deviceId,
|
|
11069
11079
|
plane: "frame",
|
|
11070
11080
|
...deviceKey ? { deviceKey } : {}
|
|
11071
11081
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-emK7D4bc.js");
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-L_HlB0At.js");
|
|
3
3
|
let node_fs = require("node:fs");
|
|
4
4
|
node_fs = require_chunk.__toESM(node_fs);
|
|
5
5
|
let node_child_process = require("node:child_process");
|
package/dist/recorder/index.js
CHANGED
|
@@ -3,8 +3,8 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../chunk-emK7D4bc.js");
|
|
6
|
-
const require_dist = require("../dist-
|
|
7
|
-
const require_node = require("../node-
|
|
6
|
+
const require_dist = require("../dist-L_HlB0At.js");
|
|
7
|
+
const require_node = require("../node-CmzZ_-zB.js");
|
|
8
8
|
const require_hub_hostname = require("../hub-hostname-DAJXlOgV.js");
|
|
9
9
|
const require_restream_intent = require("../restream-intent-7uDNqMKs.js");
|
|
10
10
|
const require_retire_root_keys = require("../retire-root-keys-Csb8z2f3.js");
|
|
@@ -14003,7 +14003,7 @@ function bandTriggerSources(band) {
|
|
|
14003
14003
|
* (`packages/types/src/types/detection.ts:448`) and
|
|
14004
14004
|
* `RecordingTriggers.audioThresholdDbfs` are the SAME unit and the SAME
|
|
14005
14005
|
* scale — dBFS, 0 = full scale, more negative = quieter — produced by
|
|
14006
|
-
* `audio-analyzer
|
|
14006
|
+
* `AudioAnalyzerProvider.analyseChunk` in `audio-analyzer/addons/analyzer/index.ts` (`20 * log10(rms)`). No conversion exists
|
|
14007
14007
|
* between them because none is needed: the one other place in this repo that
|
|
14008
14008
|
* compares the two values does the same bare `>=`
|
|
14009
14009
|
* (`notification-center/audio-rule-matcher.ts:221`). Inventing a conversion
|