@camstack/addon-pipeline 1.2.366 → 1.2.368
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 +3 -3
- package/dist/audio-analyzer/index.mjs +3 -3
- package/dist/{custom-model-catalog-C34VqcPo.js → custom-model-catalog-BY-aEI2s.js} +2 -2
- package/dist/{custom-model-catalog-CtpK3FKL.mjs → custom-model-catalog-Bnel86hH.mjs} +2 -2
- package/dist/detection-pipeline/index.js +4 -4
- package/dist/detection-pipeline/index.mjs +4 -4
- package/dist/{dist-BshC0NZR.mjs → dist-5AhGOWWu.mjs} +20270 -1345
- package/dist/{dist-i4kS_3O7.js → dist-DDXsZaRH.js} +20270 -1345
- package/dist/{model-catalogs-Cy7mZRWh.js → model-catalogs-DJN58c_U.js} +1 -1
- package/dist/{model-catalogs-DNx5ATgm.mjs → model-catalogs-DWR9EsGI.mjs} +1 -1
- package/dist/motion-wasm/index.js +1 -1
- package/dist/motion-wasm/index.mjs +1 -1
- package/dist/{node-TzgGsCvW.js → node-CiciZWts.js} +1 -1
- package/dist/{node-Dqmrb990.mjs → node-DqZJFOzR.mjs} +1 -1
- package/dist/pipeline-runner/index.js +3 -3
- package/dist/pipeline-runner/index.mjs +3 -3
- package/dist/{process-memory-DLCPFTGC.js → process-memory-BRu19Dgr.js} +1 -1
- package/dist/{process-memory-DyfrbFY4.mjs → process-memory-Batknjjt.mjs} +1 -1
- package/dist/recorder/index.js +3 -2
- package/dist/recorder/index.mjs +3 -2
- package/dist/{segment-demux-js-C9AYdKkD.js → segment-demux-js-0CRf7GAb.js} +2 -2
- package/dist/{segment-demux-js-COoPqx93.mjs → segment-demux-js-dlhO3Q8W.mjs} +2 -2
- package/dist/stream-broker/_stub.js +83 -83
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-DVgnss_e.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CSajlHKC.mjs} +2 -2
- package/dist/stream-broker/_virtual_mf___mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BfVREmhg.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-5KL24-a_.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-ZvA7Cl_1.mjs → hostInit-KJ1eka58.mjs} +2 -2
- package/dist/stream-broker/index.js +240 -65
- package/dist/stream-broker/index.mjs +240 -65
- 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-DWI1BCfa.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-BUBmyDde.mjs +0 -26
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { r as __toESM } from "../chunk-DnnnRqeS.mjs";
|
|
2
|
-
import { $n as discriminatedUnion, An as BaseAddon, D as G711_SCALE_CORRECTION_DB, Dn as DeviceType, Dt as gifDeriveSpeed, En as DeviceFeature, Gn as maskUrlCredentials, Hn as isEvent, I as RATE_CONTROL_RELAXED, In as createEvent, J as addonWidgetsSourceCapability, Kn as nodePin, L as RATE_CONTROL_TIGHT, Mn as CamProfileSchema, Nt as loadContributionCapability, On as errMsg, Ot as gifFromMp4Args, Pt as logChannelsCapability, Qn as boolean, Rt as memoizePinnedFfmpeg, Sn as buildFfmpegArgs, Tn as isSoftwareDecode, Tt as ffmpegRate, Un as makeProfileBrokerId, W as RingBuffer, Wn as makeSourceBrokerId, Xn as _enum, Xt as rankStreams, Zn as array, _t as egressTranscodeSharingKey, ar as record, at as clipExportFailureOf, c as CLIP_STILL_REASON_CODE_HEADER, cr as EventCategory, ct as createHwAccelCache, et as batteryCapability, ft as deriveBatteryPresence, jn as CAM_PROFILE_ORDER, kn as BOOT_RECOVERY_BACKOFF_MS, lt as createLogChannelsProvider, mn as streamBrokerCapability, nr as number, o as BatteryStatusSchema, or as string, qn as parseProfileBrokerId, rn as resolveEgressDecodeHwAccel, rr as object, rt as cameraStreamsCapability, s as CLIP_BROKER_PACED_RATES, sr as union, tr as literal, ut as declareLogChannel, vn as webrtcSessionCapability, vt as egressTransportFromRequest, w as EncodeProfileSchema, wn as invocationFromEncodeProfile, yn as AUDIO_PRESETS, zn as expandAudioChunkToF32le } from "../dist-
|
|
3
|
-
import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, o as probeFfmpegBinary, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-
|
|
2
|
+
import { $n as discriminatedUnion, An as BaseAddon, D as G711_SCALE_CORRECTION_DB, Dn as DeviceType, Dt as gifDeriveSpeed, En as DeviceFeature, Gn as maskUrlCredentials, Hn as isEvent, I as RATE_CONTROL_RELAXED, In as createEvent, J as addonWidgetsSourceCapability, Kn as nodePin, L as RATE_CONTROL_TIGHT, Mn as CamProfileSchema, Nt as loadContributionCapability, On as errMsg, Ot as gifFromMp4Args, Pt as logChannelsCapability, Qn as boolean, Rt as memoizePinnedFfmpeg, Sn as buildFfmpegArgs, Tn as isSoftwareDecode, Tt as ffmpegRate, Un as makeProfileBrokerId, W as RingBuffer, Wn as makeSourceBrokerId, Xn as _enum, Xt as rankStreams, Zn as array, _t as egressTranscodeSharingKey, ar as record, at as clipExportFailureOf, c as CLIP_STILL_REASON_CODE_HEADER, cr as EventCategory, ct as createHwAccelCache, et as batteryCapability, ft as deriveBatteryPresence, jn as CAM_PROFILE_ORDER, kn as BOOT_RECOVERY_BACKOFF_MS, lt as createLogChannelsProvider, mn as streamBrokerCapability, nr as number, o as BatteryStatusSchema, or as string, qn as parseProfileBrokerId, rn as resolveEgressDecodeHwAccel, rr as object, rt as cameraStreamsCapability, s as CLIP_BROKER_PACED_RATES, sr as union, tr as literal, ut as declareLogChannel, vn as webrtcSessionCapability, vt as egressTransportFromRequest, w as EncodeProfileSchema, wn as invocationFromEncodeProfile, yn as AUDIO_PRESETS, zn as expandAudioChunkToF32le } from "../dist-5AhGOWWu.mjs";
|
|
3
|
+
import { i as NO_COST_CLAIM, n as Fmp4FragmentChild, o as probeFfmpegBinary, r as Fmp4FragmentPlane, t as ChildCostRegistry } from "../node-DqZJFOzR.mjs";
|
|
4
4
|
import { a as parseRestreamPath, d as PREBUFFER_MAX_MS, f as capPreRollRequestMs, i as isLiveEdgeOnlyDial, m as resolvePrebuffer, n as NO_DECLARATION, p as prebufferRetentionMs, s as sdpVariantFor, u as withSentryIntent } from "../restream-intent-DyGmLAU9.mjs";
|
|
5
5
|
import { n as profileForStreamId } from "../remote-restream-BeHi78PZ.mjs";
|
|
6
6
|
import { n as RowMapStore, t as retireRootKeys } from "../retire-root-keys-DZvlso2l.mjs";
|
|
7
|
-
import { a as require_mp4box_all, c as parseNalLengthSize, i as runFfmpegOnce, n as demuxSegmentPreferJs, o as avccSampleToAnnexB, r as FfmpegFallbackRefusedError, s as buildKeyframeAnnexB, t as demuxSegmentFullJs } from "../segment-demux-js-
|
|
7
|
+
import { a as require_mp4box_all, c as parseNalLengthSize, i as runFfmpegOnce, n as demuxSegmentPreferJs, o as avccSampleToAnnexB, r as FfmpegFallbackRefusedError, s as buildKeyframeAnnexB, t as demuxSegmentFullJs } from "../segment-demux-js-dlhO3Q8W.mjs";
|
|
8
8
|
import { createRequire } from "node:module";
|
|
9
9
|
import * as os$1 from "node:os";
|
|
10
10
|
import { networkInterfaces, tmpdir } from "node:os";
|
|
@@ -18,6 +18,7 @@ import { spawn } from "node:child_process";
|
|
|
18
18
|
import { readFile } from "node:fs/promises";
|
|
19
19
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
20
20
|
import { renderCourtesyJpeg, renderCourtesyOverlayJpeg } from "@camstack/system/addon-utils";
|
|
21
|
+
import { getHeapSpaceStatistics, getHeapStatistics } from "node:v8";
|
|
21
22
|
import * as net$1 from "node:net";
|
|
22
23
|
import net from "node:net";
|
|
23
24
|
import { createSocket } from "node:dgram";
|
|
@@ -3082,6 +3083,25 @@ var RtpPacketizer = class {
|
|
|
3082
3083
|
};
|
|
3083
3084
|
//#endregion
|
|
3084
3085
|
//#region src/stream-broker/stream-broker/broker-mem-probe.ts
|
|
3086
|
+
/**
|
|
3087
|
+
* broker-mem-probe — what owns the broker runner's NATIVE memory.
|
|
3088
|
+
*
|
|
3089
|
+
* The runner's `[mem]` heartbeat (`kernel/heap-watch.ts`) says how big the
|
|
3090
|
+
* process is; it cannot say who holds it. On the hub, `stream-broker` grew
|
|
3091
|
+
* 250 -> 1015 MB in steps while `heapUsed` stayed at ~90 MB and `arrayBuffers`
|
|
3092
|
+
* at ~150 MB, so ~600 MB sat outside everything the heartbeat reports. This
|
|
3093
|
+
* module is the attribution half: one `[broker-mem]` line every five minutes
|
|
3094
|
+
* carrying the kernel's view of the process (RssAnon / RssFile, the `[heap]`
|
|
3095
|
+
* brk mapping, the count of anonymous mappings) NEXT TO the broker's own
|
|
3096
|
+
* structures (rings, write queues, consumers by kind, egress children), so a
|
|
3097
|
+
* step in RSS can be laid against what changed.
|
|
3098
|
+
*
|
|
3099
|
+
* It is a probe, not a fix: no caps, no allocator tuning, no snapshot. Cost is
|
|
3100
|
+
* O(brokers + sessions) per line and O(1) per packet (two integer adds in
|
|
3101
|
+
* `copyOwned`). Everything here is a pure function over plain data so the
|
|
3102
|
+
* aggregation and the `/proc` parsers are testable on fixture text.
|
|
3103
|
+
*/
|
|
3104
|
+
var MB = 1024 * 1024;
|
|
3085
3105
|
/** Cadence of the `[broker-mem]` line — aligned with the runner's `[mem]`. */
|
|
3086
3106
|
var BROKER_MEM_INTERVAL_MS = 5 * 6e4;
|
|
3087
3107
|
var copiedPackets = 0;
|
|
@@ -3120,6 +3140,7 @@ function parseProcMaps(text) {
|
|
|
3120
3140
|
let heapBytes = 0;
|
|
3121
3141
|
let anonMappings = 0;
|
|
3122
3142
|
let anonBytes = 0;
|
|
3143
|
+
let v8PageMaps = 0;
|
|
3123
3144
|
let from = 0;
|
|
3124
3145
|
while (from < text.length) {
|
|
3125
3146
|
let to = text.indexOf("\n", from);
|
|
@@ -3135,14 +3156,50 @@ function parseProcMaps(text) {
|
|
|
3135
3156
|
if (path === void 0 || path === "") {
|
|
3136
3157
|
anonMappings += 1;
|
|
3137
3158
|
anonBytes += size;
|
|
3159
|
+
if (size === 262144) v8PageMaps += 1;
|
|
3138
3160
|
} else if (path === "[heap]") heapBytes += size;
|
|
3139
3161
|
}
|
|
3140
3162
|
return {
|
|
3141
3163
|
heapBytes,
|
|
3142
3164
|
anonMappings,
|
|
3143
|
-
anonBytes
|
|
3165
|
+
anonBytes,
|
|
3166
|
+
v8PageMaps
|
|
3144
3167
|
};
|
|
3145
3168
|
}
|
|
3169
|
+
/** Read the main isolate. Probe tick only: `getHeapSpaceStatistics` walks the spaces. */
|
|
3170
|
+
function readV8Heap() {
|
|
3171
|
+
const h = getHeapStatistics();
|
|
3172
|
+
return {
|
|
3173
|
+
totalHeapBytes: h.total_heap_size,
|
|
3174
|
+
physicalBytes: h.total_physical_size,
|
|
3175
|
+
mallocedBytes: h.malloced_memory,
|
|
3176
|
+
peakMallocedBytes: h.peak_malloced_memory,
|
|
3177
|
+
externalBytes: h.external_memory,
|
|
3178
|
+
spaces: getHeapSpaceStatistics().map((x) => ({
|
|
3179
|
+
name: x.space_name,
|
|
3180
|
+
committedBytes: x.space_size
|
|
3181
|
+
}))
|
|
3182
|
+
};
|
|
3183
|
+
}
|
|
3184
|
+
var SPACE_ABBREVIATIONS = {
|
|
3185
|
+
read_only_space: "ro",
|
|
3186
|
+
old_space: "old",
|
|
3187
|
+
new_space: "new",
|
|
3188
|
+
large_object_space: "lo",
|
|
3189
|
+
new_large_object_space: "nlo",
|
|
3190
|
+
code_space: "code",
|
|
3191
|
+
code_large_object_space: "clo",
|
|
3192
|
+
map_space: "map",
|
|
3193
|
+
shared_space: "shared",
|
|
3194
|
+
shared_large_object_space: "slo",
|
|
3195
|
+
trusted_space: "trusted",
|
|
3196
|
+
trusted_large_object_space: "tlo"
|
|
3197
|
+
};
|
|
3198
|
+
/** `old:120,new:24,lo:8` — committed MB per space, empty spaces left out. */
|
|
3199
|
+
function formatHeapSpaces(spaces) {
|
|
3200
|
+
const parts = spaces.filter((x) => x.committedBytes > 0).map((x) => `${SPACE_ABBREVIATIONS[x.name] ?? x.name}:${Math.round(x.committedBytes / MB)}`);
|
|
3201
|
+
return parts.length === 0 ? "none" : parts.join(",");
|
|
3202
|
+
}
|
|
3146
3203
|
/** Opened/closed consumers since the last reading; `drain()` resets. */
|
|
3147
3204
|
var ConsumerChurn = class {
|
|
3148
3205
|
opened = 0;
|
|
@@ -3220,7 +3277,6 @@ function reportConsumerEvent(logger, event, kind, deviceId, total, now = Date.no
|
|
|
3220
3277
|
const suppressed = verdict.suppressedBefore > 0 ? ` suppressedBefore=${verdict.suppressedBefore}` : "";
|
|
3221
3278
|
logger.info(`consumer ${event} kind=${kind} total=${total}${suppressed}`, { ...deviceId !== void 0 ? { tags: { deviceId } } : {} });
|
|
3222
3279
|
}
|
|
3223
|
-
var MB = 1024 * 1024;
|
|
3224
3280
|
function ringBytesOf(s) {
|
|
3225
3281
|
return s.preBufferBytes + s.clipBytes + s.rtpRingBytes + s.keyframeCacheBytes;
|
|
3226
3282
|
}
|
|
@@ -3263,7 +3319,11 @@ function formatBrokerMem(input) {
|
|
|
3263
3319
|
const top = [...samples].filter((s) => s.deviceId !== void 0).sort((a, b) => ringBytesOf(b) - ringBytesOf(a)).slice(0, 5).map((s) => `${s.deviceId}:${mb(ringBytesOf(s))}`).join(",");
|
|
3264
3320
|
const parts = ["[broker-mem]"];
|
|
3265
3321
|
if (proc.status !== null) parts.push(`rssAnonMb=${(proc.status.rssAnonKb / 1024).toFixed(0)}`, `rssFileMb=${(proc.status.rssFileKb / 1024).toFixed(0)}`);
|
|
3266
|
-
if (proc.maps !== null) parts.push(`heapMapMb=${mb(proc.maps.heapBytes)}`, `anonMaps=${proc.maps.anonMappings}`, `anonMapsMb=${mb(proc.maps.anonBytes)}`);
|
|
3322
|
+
if (proc.maps !== null) parts.push(`heapMapMb=${mb(proc.maps.heapBytes)}`, `anonMaps=${proc.maps.anonMappings}`, `anonMapsMb=${mb(proc.maps.anonBytes)}`, `v8PageMaps=${proc.maps.v8PageMaps}`);
|
|
3323
|
+
const v8 = input.v8;
|
|
3324
|
+
if (v8 !== void 0 && v8 !== null) parts.push(`v8TotalHeapMb=${mb(v8.totalHeapBytes)}`, `v8PhysicalMb=${mb(v8.physicalBytes)}`, `v8MallocedMb=${mb(v8.mallocedBytes)}`, `v8PeakMallocedMb=${mb(v8.peakMallocedBytes)}`, `v8ExternalMb=${mb(v8.externalBytes)}`, `spaces=${formatHeapSpaces(v8.spaces)}`);
|
|
3325
|
+
const w = input.worker;
|
|
3326
|
+
if (w !== void 0 && w !== null) parts.push(`workers=${w.workers}`, `workerHeapMb=${mb(w.heapBytes)}`, `workerPhysicalMb=${mb(w.physicalBytes)}`, `workerUsedMb=${mb(w.usedBytes)}`, `workerAgeS=${Math.round(w.maxAgeMs / 1e3)}`, `workerIdleExit=${w.idleTerminates ? "yes" : "never"}`);
|
|
3267
3327
|
parts.push(`brokers=${samples.length}`, `ingesting=${ingesting}`, `annexBPlanes=${planes}`, `rtsp=${rtsp}`, `webrtc=${input.webrtcSessions}`, `encoded=${kindList(consumers)}`, `audioSubs=${audio}`, `pipeClients=${pipe}`, `egress=${input.egressTranscodes}`, `children=${input.childProcesses}`, `opened=${churn.opened}`, `closed=${churn.closed}`, `openedKinds=${kindList(churn.openedByKind)}`, `closedKinds=${kindList(churn.closedByKind)}`, `preBufferMb=${mb(pre)}`, `clipMb=${mb(clip)}`, `rtpRingMb=${mb(rtp)}`, `keyframeMb=${mb(kf)}`, `writeQueueSumMb=${mb(qSum)}`, `writeQueueMaxMb=${mb(qMax)}`, `copiedPackets=${copied.packets}`, `copiedMb=${mb(copied.bytes)}`, `topRingMb=${top === "" ? "none" : top}`);
|
|
3268
3328
|
return parts.join(" ");
|
|
3269
3329
|
}
|
|
@@ -5083,6 +5143,17 @@ var RtspSession = class {
|
|
|
5083
5143
|
//#endregion
|
|
5084
5144
|
//#region src/stream-broker/rtsp/rtsp-listen-server.ts
|
|
5085
5145
|
/**
|
|
5146
|
+
* Attribution of the synthetic consumer a {@link BrokerWarmUp} subscribes:
|
|
5147
|
+
* the RTSP listen server holding a cold broker open for a DESCRIBE. Named
|
|
5148
|
+
* after that real consumer — it used to subscribe with no attribution and
|
|
5149
|
+
* surfaced as `unknown` (45 attach/detach pairs per 5 min on the hub).
|
|
5150
|
+
*/
|
|
5151
|
+
var RTSP_DESCRIBE_WARMUP_ATTRIBUTION = {
|
|
5152
|
+
kind: "rtsp-listen",
|
|
5153
|
+
label: "describe-warmup",
|
|
5154
|
+
media: "both"
|
|
5155
|
+
};
|
|
5156
|
+
/**
|
|
5086
5157
|
* Single TCP server for all RTSP restream connections.
|
|
5087
5158
|
* Routes clients to the correct RtspRestreamer by a random token path
|
|
5088
5159
|
* (not the predictable brokerId) for security.
|
|
@@ -19929,7 +20000,7 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
19929
20000
|
const sourceBroker = this.brokers.get(sourceBrokerId);
|
|
19930
20001
|
if (!sourceBroker) continue;
|
|
19931
20002
|
const existingToken = this.persistedTokens.get(profileBrokerId);
|
|
19932
|
-
const warmUp = () => sourceBroker.onEncodedData(() => {});
|
|
20003
|
+
const warmUp = () => sourceBroker.onEncodedData(() => {}, RTSP_DESCRIBE_WARMUP_ATTRIBUTION);
|
|
19933
20004
|
const openPrestreamWindow = () => sourceBroker.openPrestreamWindow();
|
|
19934
20005
|
this.rtspServer.registerRestreamer(profileBrokerId, sourceBroker.getRtspRestreamer(), warmUp, existingToken, openPrestreamWindow);
|
|
19935
20006
|
this.profileRestreamerBindings.set(profileBrokerId, sourceBrokerId);
|
|
@@ -21588,7 +21659,7 @@ var StreamBrokerManager = class StreamBrokerManager {
|
|
|
21588
21659
|
this.brokers.set(brokerId, broker);
|
|
21589
21660
|
this.applyClipRetention(deviceId);
|
|
21590
21661
|
const existingToken = this.persistedTokens.get(brokerId);
|
|
21591
|
-
const warmUp = () => broker.onEncodedData(() => {});
|
|
21662
|
+
const warmUp = () => broker.onEncodedData(() => {}, RTSP_DESCRIBE_WARMUP_ATTRIBUTION);
|
|
21592
21663
|
const openPrestreamWindow = () => broker.openPrestreamWindow();
|
|
21593
21664
|
this.rtspServer.registerRestreamer(brokerId, broker.getRtspRestreamer(), warmUp, existingToken, openPrestreamWindow);
|
|
21594
21665
|
if (!existingToken) this.rtspProvider.persistTokens();
|
|
@@ -33866,23 +33937,37 @@ function createHttpClipStreamOpener(options = {}) {
|
|
|
33866
33937
|
req.end();
|
|
33867
33938
|
});
|
|
33868
33939
|
}
|
|
33869
|
-
//#endregion
|
|
33870
|
-
//#region src/stream-broker/recorded/demux-off-thread.ts
|
|
33871
33940
|
/**
|
|
33872
|
-
*
|
|
33873
|
-
*
|
|
33874
|
-
*
|
|
33875
|
-
*
|
|
33876
|
-
*
|
|
33877
|
-
*
|
|
33878
|
-
*
|
|
33879
|
-
*
|
|
33880
|
-
*
|
|
33881
|
-
*
|
|
33882
|
-
*
|
|
33883
|
-
*
|
|
33884
|
-
*
|
|
33885
|
-
|
|
33941
|
+
* Heap shaping for the demux isolate. The runner's process-wide V8 flags
|
|
33942
|
+
* (`--initial-old-space-size=512`, `--max-semi-space-size=8`, from the
|
|
33943
|
+
* stream-broker manifest) are sized for the MAIN isolate and leak into every
|
|
33944
|
+
* Worker: with a 512 MB initial old space the worker grew to 144 MB of
|
|
33945
|
+
* garbage without a single major GC. Explicit `resourceLimits` replace the
|
|
33946
|
+
* inherited sizing (measured under those flags with the same allocation
|
|
33947
|
+
* churn: worker heap 474 MB without limits, 88 MB with them; see
|
|
33948
|
+
* docs/history/sessions.md).
|
|
33949
|
+
*
|
|
33950
|
+
* 128 MB old generation: parsing a recorded fragment retains about 1 MB
|
|
33951
|
+
* after GC for an 86 KB input (fixture bench), so even a 10 MB fragment (a
|
|
33952
|
+
* long 4K segment) holds well under 30 MB live; 128 MB is more than 4x that.
|
|
33953
|
+
* A parse that still exceeds it fails the worker cleanly
|
|
33954
|
+
* (`ERR_WORKER_OUT_OF_MEMORY`): in-flight parses resolve null (ffmpeg
|
|
33955
|
+
* fallback) and the next parse spawns a fresh worker.
|
|
33956
|
+
*/
|
|
33957
|
+
var DEMUX_WORKER_RESOURCE_LIMITS = {
|
|
33958
|
+
maxOldGenerationSizeMb: 128,
|
|
33959
|
+
maxYoungGenerationSizeMb: 16
|
|
33960
|
+
};
|
|
33961
|
+
var defaultTimers = {
|
|
33962
|
+
set: (fn, ms) => {
|
|
33963
|
+
const t = setTimeout(fn, ms);
|
|
33964
|
+
t.unref();
|
|
33965
|
+
return t;
|
|
33966
|
+
},
|
|
33967
|
+
clear: (handle) => {
|
|
33968
|
+
if (handle !== void 0) clearTimeout(handle);
|
|
33969
|
+
}
|
|
33970
|
+
};
|
|
33886
33971
|
function isCodec(value) {
|
|
33887
33972
|
return value === "H264" || value === "H265";
|
|
33888
33973
|
}
|
|
@@ -33917,55 +34002,93 @@ function parseWorkerMessage(message) {
|
|
|
33917
34002
|
function defaultWorkerFilename() {
|
|
33918
34003
|
return fileURLToPath(new URL("./demux-worker-child.js", import.meta.url));
|
|
33919
34004
|
}
|
|
33920
|
-
/**
|
|
33921
|
-
|
|
33922
|
-
* callers are matched by request id; the worker's own event loop serializes
|
|
33923
|
-
* mp4box. Live RTP on the parent thread is not waiting on box parsing.
|
|
33924
|
-
*/
|
|
33925
|
-
function createOffThreadJsParse(deps) {
|
|
34005
|
+
/** {@link createOffThreadJsParse} plus the heap accessor the memory probe reads. */
|
|
34006
|
+
function createOffThreadDemuxClient(deps) {
|
|
33926
34007
|
const Ctor = deps.WorkerCtor;
|
|
33927
|
-
|
|
34008
|
+
const idleMs = deps.idleMs ?? 6e4;
|
|
34009
|
+
const timers = deps.timers ?? defaultTimers;
|
|
34010
|
+
const now = deps.now ?? Date.now;
|
|
34011
|
+
let current = null;
|
|
33928
34012
|
let nextId = 1;
|
|
33929
|
-
const
|
|
33930
|
-
|
|
33931
|
-
|
|
33932
|
-
|
|
33933
|
-
|
|
34013
|
+
const failAll = (slot, why) => {
|
|
34014
|
+
const waiting = [...slot.pending.values()];
|
|
34015
|
+
slot.pending.clear();
|
|
34016
|
+
if (waiting.length > 0 && deps.logger) for (const deviceId of new Set(waiting.map((p) => p.deviceId))) deps.logger.warn(`demux worker lost with parses in flight (${why}) — ffmpeg fallback`, {
|
|
34017
|
+
...deviceId !== void 0 ? { tags: { deviceId } } : {},
|
|
34018
|
+
meta: { inFlight: waiting.length }
|
|
34019
|
+
});
|
|
34020
|
+
for (const p of waiting) p.resolve(null);
|
|
34021
|
+
};
|
|
34022
|
+
const retire = (slot) => {
|
|
34023
|
+
timers.clear(slot.idleTimer);
|
|
34024
|
+
slot.idleTimer = void 0;
|
|
34025
|
+
if (current === slot) current = null;
|
|
34026
|
+
};
|
|
34027
|
+
const onIdle = async (slot) => {
|
|
34028
|
+
slot.idleTimer = void 0;
|
|
34029
|
+
if (current !== slot || slot.pending.size > 0) return;
|
|
34030
|
+
current = null;
|
|
34031
|
+
const heapBytes = (await slot.worker.getHeapStatistics?.().catch(() => null))?.total_heap_size ?? slot.lastHeapBytes;
|
|
34032
|
+
deps.logger?.info("demux worker idle — terminating", { meta: {
|
|
34033
|
+
ageMs: Math.max(0, now() - slot.spawnedAt),
|
|
34034
|
+
idleMs,
|
|
34035
|
+
lastHeapMb: Math.round(heapBytes / 1048576)
|
|
34036
|
+
} });
|
|
34037
|
+
slot.worker.terminate();
|
|
34038
|
+
};
|
|
34039
|
+
const armIdle = (slot) => {
|
|
34040
|
+
timers.clear(slot.idleTimer);
|
|
34041
|
+
slot.idleTimer = timers.set(() => void onIdle(slot), idleMs);
|
|
33934
34042
|
};
|
|
33935
|
-
const attach = (
|
|
34043
|
+
const attach = (slot) => {
|
|
34044
|
+
const w = slot.worker;
|
|
33936
34045
|
w.on("message", (message) => {
|
|
33937
34046
|
const parsed = parseWorkerMessage(message);
|
|
33938
34047
|
if (!parsed) return;
|
|
33939
|
-
const
|
|
33940
|
-
if (!
|
|
33941
|
-
pending.delete(parsed.id);
|
|
33942
|
-
resolve(parsed.aus);
|
|
34048
|
+
const pending = slot.pending.get(parsed.id);
|
|
34049
|
+
if (!pending) return;
|
|
34050
|
+
slot.pending.delete(parsed.id);
|
|
34051
|
+
pending.resolve(parsed.aus);
|
|
34052
|
+
if (slot.pending.size === 0 && current === slot) armIdle(slot);
|
|
33943
34053
|
});
|
|
33944
|
-
w.on("error", () => {
|
|
33945
|
-
|
|
33946
|
-
failAll();
|
|
34054
|
+
w.on("error", (err) => {
|
|
34055
|
+
retire(slot);
|
|
34056
|
+
failAll(slot, String(err));
|
|
33947
34057
|
});
|
|
33948
34058
|
w.on("exit", () => {
|
|
33949
|
-
|
|
33950
|
-
failAll();
|
|
34059
|
+
retire(slot);
|
|
34060
|
+
failAll(slot, "exit");
|
|
33951
34061
|
});
|
|
33952
34062
|
};
|
|
33953
34063
|
const ensureWorker = () => {
|
|
33954
|
-
if (
|
|
34064
|
+
if (current) return current;
|
|
33955
34065
|
if (!Ctor) return null;
|
|
33956
34066
|
try {
|
|
33957
|
-
const
|
|
33958
|
-
|
|
33959
|
-
|
|
33960
|
-
|
|
33961
|
-
|
|
34067
|
+
const slot = {
|
|
34068
|
+
worker: new Ctor(deps.workerFilename, { resourceLimits: DEMUX_WORKER_RESOURCE_LIMITS }),
|
|
34069
|
+
pending: /* @__PURE__ */ new Map(),
|
|
34070
|
+
spawnedAt: now(),
|
|
34071
|
+
idleTimer: void 0,
|
|
34072
|
+
lastHeapBytes: 0
|
|
34073
|
+
};
|
|
34074
|
+
attach(slot);
|
|
34075
|
+
current = slot;
|
|
34076
|
+
deps.logger?.info("demux worker spawned", { meta: {
|
|
34077
|
+
resourceLimits: DEMUX_WORKER_RESOURCE_LIMITS,
|
|
34078
|
+
idleMs
|
|
34079
|
+
} });
|
|
34080
|
+
return slot;
|
|
34081
|
+
} catch (err) {
|
|
34082
|
+
deps.logger?.warn(`demux worker spawn failed: ${String(err)} — parsing in-process`);
|
|
33962
34083
|
return null;
|
|
33963
34084
|
}
|
|
33964
34085
|
};
|
|
33965
|
-
|
|
34086
|
+
const parse = async (bytes, ctx) => {
|
|
33966
34087
|
if (!deps.existsSync(deps.workerFilename)) return deps.parseInProcess(bytes);
|
|
33967
|
-
const
|
|
33968
|
-
if (!
|
|
34088
|
+
const slot = ensureWorker();
|
|
34089
|
+
if (!slot) return deps.parseInProcess(bytes);
|
|
34090
|
+
timers.clear(slot.idleTimer);
|
|
34091
|
+
slot.idleTimer = void 0;
|
|
33969
34092
|
const id = nextId;
|
|
33970
34093
|
nextId += 1;
|
|
33971
34094
|
const copy = new Uint8Array(bytes);
|
|
@@ -33974,25 +34097,73 @@ function createOffThreadJsParse(deps) {
|
|
|
33974
34097
|
bytes: copy
|
|
33975
34098
|
};
|
|
33976
34099
|
return new Promise((resolve) => {
|
|
33977
|
-
pending.set(id,
|
|
33978
|
-
|
|
34100
|
+
slot.pending.set(id, {
|
|
34101
|
+
resolve,
|
|
34102
|
+
deviceId: ctx?.deviceId
|
|
34103
|
+
});
|
|
34104
|
+
slot.worker.postMessage(request, [copy.buffer]);
|
|
33979
34105
|
});
|
|
33980
34106
|
};
|
|
34107
|
+
const readHeaps = async (at = Date.now()) => {
|
|
34108
|
+
const live = current;
|
|
34109
|
+
const empty = {
|
|
34110
|
+
workers: 0,
|
|
34111
|
+
heapBytes: 0,
|
|
34112
|
+
physicalBytes: 0,
|
|
34113
|
+
usedBytes: 0,
|
|
34114
|
+
maxAgeMs: 0,
|
|
34115
|
+
idleTerminates: true
|
|
34116
|
+
};
|
|
34117
|
+
if (live === null) return empty;
|
|
34118
|
+
const stats = await live.worker.getHeapStatistics?.().catch(() => null);
|
|
34119
|
+
if (stats) live.lastHeapBytes = stats.total_heap_size;
|
|
34120
|
+
return {
|
|
34121
|
+
...empty,
|
|
34122
|
+
workers: 1,
|
|
34123
|
+
maxAgeMs: Math.max(0, at - live.spawnedAt),
|
|
34124
|
+
...stats ? {
|
|
34125
|
+
heapBytes: stats.total_heap_size,
|
|
34126
|
+
physicalBytes: stats.total_physical_size,
|
|
34127
|
+
usedBytes: stats.used_heap_size
|
|
34128
|
+
} : {}
|
|
34129
|
+
};
|
|
34130
|
+
};
|
|
34131
|
+
return {
|
|
34132
|
+
parse,
|
|
34133
|
+
readHeaps
|
|
34134
|
+
};
|
|
33981
34135
|
}
|
|
33982
|
-
function
|
|
33983
|
-
return
|
|
34136
|
+
function defaultOffThreadClient() {
|
|
34137
|
+
return createOffThreadDemuxClient({
|
|
33984
34138
|
workerFilename: defaultWorkerFilename(),
|
|
33985
34139
|
existsSync,
|
|
33986
34140
|
parseInProcess: demuxSegmentFullJs,
|
|
33987
|
-
WorkerCtor: Worker
|
|
34141
|
+
WorkerCtor: Worker,
|
|
34142
|
+
...sharedLogger ? { logger: sharedLogger } : {}
|
|
33988
34143
|
});
|
|
33989
34144
|
}
|
|
33990
34145
|
var shared;
|
|
33991
34146
|
/** Process-wide JS parse: one Worker, shared by every WebRTC session. */
|
|
33992
|
-
var offThreadJsParse = (bytes) => {
|
|
33993
|
-
shared ??=
|
|
33994
|
-
return shared(bytes);
|
|
34147
|
+
var offThreadJsParse = (bytes, ctx) => {
|
|
34148
|
+
shared ??= defaultOffThreadClient();
|
|
34149
|
+
return shared.parse(bytes, ctx);
|
|
33995
34150
|
};
|
|
34151
|
+
var sharedLogger;
|
|
34152
|
+
/** Give the process-wide client a logger; call before the first parse. */
|
|
34153
|
+
function setDemuxWorkerLogger(logger) {
|
|
34154
|
+
sharedLogger = logger;
|
|
34155
|
+
}
|
|
34156
|
+
/** Heap of the shared demux worker, for the `[broker-mem]` probe (tick only). */
|
|
34157
|
+
async function readDemuxWorkerHeaps(now) {
|
|
34158
|
+
return shared ? shared.readHeaps(now) : {
|
|
34159
|
+
workers: 0,
|
|
34160
|
+
heapBytes: 0,
|
|
34161
|
+
physicalBytes: 0,
|
|
34162
|
+
usedBytes: 0,
|
|
34163
|
+
maxAgeMs: 0,
|
|
34164
|
+
idleTerminates: true
|
|
34165
|
+
};
|
|
34166
|
+
}
|
|
33996
34167
|
/**
|
|
33997
34168
|
* Drop-in for the session `demuxVideo` hook: JS parse off the live loop,
|
|
33998
34169
|
* ffmpeg subprocess fallback unchanged.
|
|
@@ -34893,6 +35064,7 @@ var BrokerWebrtcServer = class {
|
|
|
34893
35064
|
stopped = false;
|
|
34894
35065
|
constructor(options) {
|
|
34895
35066
|
this.logger = options.logger;
|
|
35067
|
+
setDemuxWorkerLogger(options.logger.child("demux-worker"));
|
|
34896
35068
|
this.getIceServersFn = options.getIceServers;
|
|
34897
35069
|
this.staticIceServers = options.iceServers;
|
|
34898
35070
|
this.icePortRange = options.icePortRange;
|
|
@@ -35558,6 +35730,7 @@ var BrokerWebrtcServer = class {
|
|
|
35558
35730
|
if (locateRecorded && readRecorded) {
|
|
35559
35731
|
const demuxVideo = (b) => demuxSegmentPreferJsOffThread(b, {
|
|
35560
35732
|
ffmpegPath: resolveFfmpeg(),
|
|
35733
|
+
deviceId,
|
|
35561
35734
|
onDemuxPath: (outcome) => {
|
|
35562
35735
|
const report = demuxTally.record(outcome, Date.now());
|
|
35563
35736
|
if (!report) return;
|
|
@@ -37490,7 +37663,7 @@ async function readProc() {
|
|
|
37490
37663
|
}
|
|
37491
37664
|
async function emitOnce(deps) {
|
|
37492
37665
|
const now = Date.now();
|
|
37493
|
-
const proc = await readProc();
|
|
37666
|
+
const [proc, worker] = await Promise.all([readProc(), readDemuxWorkerHeaps(now)]);
|
|
37494
37667
|
const resources = process.getActiveResourcesInfo();
|
|
37495
37668
|
const line = formatBrokerMem({
|
|
37496
37669
|
samples: deps.manager.getBrokerInstances().map((b) => b.getMemSample(now)),
|
|
@@ -37499,7 +37672,9 @@ async function emitOnce(deps) {
|
|
|
37499
37672
|
childProcesses: countActiveResources(resources, "ProcessWrap"),
|
|
37500
37673
|
proc,
|
|
37501
37674
|
churn: consumerChurn.drain(),
|
|
37502
|
-
copied: readCopyOwnedTotals()
|
|
37675
|
+
copied: readCopyOwnedTotals(),
|
|
37676
|
+
v8: readV8Heap(),
|
|
37677
|
+
worker
|
|
37503
37678
|
});
|
|
37504
37679
|
deps.logger.info(line);
|
|
37505
37680
|
}
|
|
@@ -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-CSajlHKC.mjs")).catch((e) => {
|
|
34
34
|
throw l = void 0, e;
|
|
35
35
|
}), l;
|
|
36
36
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-pipeline",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.368",
|
|
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",
|