@camstack/addon-pipeline-orchestrator 1.1.26 → 1.1.28
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/_stub.js +2 -2
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_orchestrator_widgets-0vYngRZJ.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_orchestrator_widgets-DaBzEEJK.mjs} +3 -3
- package/dist/_virtual_mf___mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DF4cZqbE.mjs +26 -0
- package/dist/_virtual_mf___mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-ScLTfhI7.mjs +26 -0
- package/dist/{hostInit-CrNnXa-5.mjs → hostInit-CSrBjaSu.mjs} +3 -3
- package/dist/index.js +386 -52
- package/dist/index.mjs +386 -52
- package/dist/remoteEntry.js +1 -1
- package/package.json +1 -1
- package/dist/_virtual_mf___mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DPNDc6_1.mjs +0 -26
- package/dist/_virtual_mf___mfe_internal__addon_pipeline_orchestrator_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BA0gpKU7.mjs +0 -26
package/dist/index.js
CHANGED
|
@@ -4631,7 +4631,7 @@ function _instanceof(cls, params = {}) {
|
|
|
4631
4631
|
return inst;
|
|
4632
4632
|
}
|
|
4633
4633
|
//#endregion
|
|
4634
|
-
//#region ../types/dist/sleep-
|
|
4634
|
+
//#region ../types/dist/sleep-CZDdRBua.mjs
|
|
4635
4635
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4636
4636
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4637
4637
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -7638,7 +7638,16 @@ var DecoderStatsSchema = object({
|
|
|
7638
7638
|
inputFps: number(),
|
|
7639
7639
|
outputFps: number(),
|
|
7640
7640
|
avgDecodeTimeMs: number(),
|
|
7641
|
-
droppedFrames: number()
|
|
7641
|
+
droppedFrames: number(),
|
|
7642
|
+
/**
|
|
7643
|
+
* Pull-mode adaptive-fps telemetry (optional — only pull sessions run the
|
|
7644
|
+
* lag-driven controller; push sessions omit these). `lagMs` is the EWMA of
|
|
7645
|
+
* the decoder's real-time drift (rising = falling behind live); `adaptiveFps`
|
|
7646
|
+
* is the current lag-throttled emit rate (≤ `effectiveFps` ceiling).
|
|
7647
|
+
*/
|
|
7648
|
+
lagMs: number().optional(),
|
|
7649
|
+
effectiveFps: number().optional(),
|
|
7650
|
+
adaptiveFps: number().optional()
|
|
7642
7651
|
});
|
|
7643
7652
|
var DecoderSessionConfigSchema = object({
|
|
7644
7653
|
codec: string(),
|
|
@@ -7679,7 +7688,15 @@ var DecoderSessionConfigSchema = object({
|
|
|
7679
7688
|
* other — `pullFrames` returns nothing for an `'shm'` session and
|
|
7680
7689
|
* `pullHandles` returns nothing for a `'callback'` session.
|
|
7681
7690
|
*/
|
|
7682
|
-
frameSink: _enum(["callback", "shm"]).default("callback")
|
|
7691
|
+
frameSink: _enum(["callback", "shm"]).default("callback"),
|
|
7692
|
+
/**
|
|
7693
|
+
* Per-camera decoder DEBUG facility. When `true`, a pull-mode session emits
|
|
7694
|
+
* a throttled (~1Hz) structured `decoder debug` line (effective/adaptive fps,
|
|
7695
|
+
* real-time lag, dropped-frame delta, avg decode time, hwaccel). Mirrors the
|
|
7696
|
+
* stream-broker's `streamingDebug` gate — off by default so production logs
|
|
7697
|
+
* stay quiet and the emit path pays zero per-frame cost when disabled.
|
|
7698
|
+
*/
|
|
7699
|
+
debug: boolean().optional()
|
|
7683
7700
|
});
|
|
7684
7701
|
var EncodeProfileSchema = object({
|
|
7685
7702
|
video: object({
|
|
@@ -9898,6 +9915,75 @@ DeviceType.Cover, method(object({ deviceId: number().int().nonnegative() }), _vo
|
|
|
9898
9915
|
auth: "admin"
|
|
9899
9916
|
});
|
|
9900
9917
|
/**
|
|
9918
|
+
* Vendor-neutral day/night (IR-cut) control — the per-camera config cap
|
|
9919
|
+
* shared by reolink / hikvision / amcrest. Models the common firmware
|
|
9920
|
+
* surface: the IR-cut switching MODE plus the two knobs that gate it
|
|
9921
|
+
* (photocell `sensitivity` + `switchDelaySec`). Each vendor maps these
|
|
9922
|
+
* onto its own ISAPI / Baichuan / Dahua-CGI fields; the cap standardises
|
|
9923
|
+
* the shape so ONE derived-form renders every camera.
|
|
9924
|
+
*
|
|
9925
|
+
* Follows the D14 `deviceConfig` archetype (see `stream-params.cap.ts`):
|
|
9926
|
+
* `getOptions` advertises per-camera availability, `getStatus` (auto-
|
|
9927
|
+
* injected from `status`) reports the live values, and a single
|
|
9928
|
+
* `setSettings` mutation applies a partial change. No hand-written
|
|
9929
|
+
* settings-contribution methods — the framework derives the UI + save
|
|
9930
|
+
* routing from this surface.
|
|
9931
|
+
*/
|
|
9932
|
+
/** IR-cut switching mode. `schedule` = time-of-day table configured on the camera. */
|
|
9933
|
+
var DayNightModeSchema = _enum([
|
|
9934
|
+
"auto",
|
|
9935
|
+
"day",
|
|
9936
|
+
"night",
|
|
9937
|
+
"schedule"
|
|
9938
|
+
]);
|
|
9939
|
+
/** Normalized numeric range descriptor — `{ min, max, step }` per the
|
|
9940
|
+
* getOptions availability convention. Normalized values are 0–100. */
|
|
9941
|
+
var NormalizedRangeSchema$1 = object({
|
|
9942
|
+
min: number(),
|
|
9943
|
+
max: number(),
|
|
9944
|
+
step: number()
|
|
9945
|
+
});
|
|
9946
|
+
object({
|
|
9947
|
+
mode: DayNightModeSchema,
|
|
9948
|
+
/** IR-cut trigger sensitivity, NORMALIZED 0–100 (higher = switches to night sooner). */
|
|
9949
|
+
sensitivity: number().optional(),
|
|
9950
|
+
/** Delay before the IR-cut filter flips, in seconds. */
|
|
9951
|
+
switchDelaySec: number().optional(),
|
|
9952
|
+
lastFetchedAt: number()
|
|
9953
|
+
});
|
|
9954
|
+
/**
|
|
9955
|
+
* Per-camera availability descriptor — drives which controls the admin UI
|
|
9956
|
+
* renders. Booleans as `supportsX`; numeric ranges as `{ min, max, step }`
|
|
9957
|
+
* (normalized 0–100); the mode choice-set as an array. A provider returns
|
|
9958
|
+
* honest, camera-probed values — never hardcoded.
|
|
9959
|
+
*/
|
|
9960
|
+
var DayNightOptionsSchema = object({
|
|
9961
|
+
/** Modes this camera accepts. Empty → the camera has no configurable day/night mode. */
|
|
9962
|
+
modes: array(DayNightModeSchema),
|
|
9963
|
+
supportsSensitivity: boolean(),
|
|
9964
|
+
/** Present when `supportsSensitivity` — the normalized 0–100 range. */
|
|
9965
|
+
sensitivity: NormalizedRangeSchema$1.optional(),
|
|
9966
|
+
supportsSwitchDelay: boolean(),
|
|
9967
|
+
/** Present when `supportsSwitchDelay` — the allowed delay range in seconds. */
|
|
9968
|
+
switchDelaySec: NormalizedRangeSchema$1.optional()
|
|
9969
|
+
});
|
|
9970
|
+
/**
|
|
9971
|
+
* Partial change to the day/night config — every field optional. A
|
|
9972
|
+
* provider ignores fields it does not support.
|
|
9973
|
+
*/
|
|
9974
|
+
var DayNightSettingsPatchSchema = object({
|
|
9975
|
+
mode: DayNightModeSchema.optional(),
|
|
9976
|
+
sensitivity: number().optional(),
|
|
9977
|
+
switchDelaySec: number().optional()
|
|
9978
|
+
});
|
|
9979
|
+
DeviceType.Camera, method(object({ deviceId: number() }), DayNightOptionsSchema), method(object({
|
|
9980
|
+
deviceId: number(),
|
|
9981
|
+
settings: DayNightSettingsPatchSchema
|
|
9982
|
+
}), _void(), {
|
|
9983
|
+
kind: "mutation",
|
|
9984
|
+
auth: "admin"
|
|
9985
|
+
});
|
|
9986
|
+
/**
|
|
9901
9987
|
* Identity envelope for a device's upstream-system metadata.
|
|
9902
9988
|
*
|
|
9903
9989
|
* Two jobs:
|
|
@@ -10253,6 +10339,130 @@ object({
|
|
|
10253
10339
|
});
|
|
10254
10340
|
DeviceType.Image;
|
|
10255
10341
|
/**
|
|
10342
|
+
* Vendor-neutral image / picture-adjustment cap — the per-camera config
|
|
10343
|
+
* cap shared by reolink / hikvision / amcrest. Models the common ISP
|
|
10344
|
+
* surface: the four picture sliders (brightness / contrast / saturation /
|
|
10345
|
+
* sharpness), orientation (mirror / flip / rotate), white-balance,
|
|
10346
|
+
* exposure and backlight-compensation modes.
|
|
10347
|
+
*
|
|
10348
|
+
* NORMALIZATION: every slider is a normalized int 0–100. Vendors expose
|
|
10349
|
+
* these natively as 0–100 or 0–255 (or other ranges); each provider maps
|
|
10350
|
+
* its native range to/from this normalized 0–100 space so the cap surface
|
|
10351
|
+
* (and the derived form) is identical across cameras. `warmth` (manual
|
|
10352
|
+
* white-balance) is likewise normalized 0–100.
|
|
10353
|
+
*
|
|
10354
|
+
* Follows the D14 `deviceConfig` archetype (see `stream-params.cap.ts`):
|
|
10355
|
+
* `getOptions` advertises per-camera availability, `getStatus` (auto-
|
|
10356
|
+
* injected from `status`) reports the live values, and a single
|
|
10357
|
+
* `setSettings` mutation applies a partial change. No hand-written
|
|
10358
|
+
* settings-contribution methods — the framework derives the UI + save
|
|
10359
|
+
* routing from this surface.
|
|
10360
|
+
*/
|
|
10361
|
+
/** Sensor/image rotation, degrees clockwise. */
|
|
10362
|
+
var ImageRotateSchema = _enum([
|
|
10363
|
+
"0",
|
|
10364
|
+
"90",
|
|
10365
|
+
"180",
|
|
10366
|
+
"270"
|
|
10367
|
+
]);
|
|
10368
|
+
/** White-balance mode. `manual` unlocks the normalized `warmth` knob. */
|
|
10369
|
+
var WhiteBalanceModeSchema = _enum(["auto", "manual"]);
|
|
10370
|
+
/** Exposure mode. */
|
|
10371
|
+
var ExposureModeSchema = _enum(["auto", "manual"]);
|
|
10372
|
+
/**
|
|
10373
|
+
* Backlight-compensation mode:
|
|
10374
|
+
* - `off` — disabled
|
|
10375
|
+
* - `blc` — backlight compensation
|
|
10376
|
+
* - `wdr` — wide dynamic range
|
|
10377
|
+
* - `hlc` — highlight compensation
|
|
10378
|
+
*/
|
|
10379
|
+
var BacklightModeSchema = _enum([
|
|
10380
|
+
"off",
|
|
10381
|
+
"blc",
|
|
10382
|
+
"wdr",
|
|
10383
|
+
"hlc"
|
|
10384
|
+
]);
|
|
10385
|
+
/** Normalized numeric range descriptor — `{ min, max, step }` per the
|
|
10386
|
+
* getOptions availability convention. Slider values are normalized 0–100. */
|
|
10387
|
+
var NormalizedRangeSchema = object({
|
|
10388
|
+
min: number(),
|
|
10389
|
+
max: number(),
|
|
10390
|
+
step: number()
|
|
10391
|
+
});
|
|
10392
|
+
object({
|
|
10393
|
+
/** Normalized 0–100. */
|
|
10394
|
+
brightness: number().optional(),
|
|
10395
|
+
/** Normalized 0–100. */
|
|
10396
|
+
contrast: number().optional(),
|
|
10397
|
+
/** Normalized 0–100. */
|
|
10398
|
+
saturation: number().optional(),
|
|
10399
|
+
/** Normalized 0–100. */
|
|
10400
|
+
sharpness: number().optional(),
|
|
10401
|
+
mirror: boolean().optional(),
|
|
10402
|
+
flip: boolean().optional(),
|
|
10403
|
+
rotate: ImageRotateSchema.optional(),
|
|
10404
|
+
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
10405
|
+
/** Manual white-balance warmth, NORMALIZED 0–100. Meaningful only when `whiteBalance === 'manual'`. */
|
|
10406
|
+
warmth: number().optional(),
|
|
10407
|
+
exposureMode: ExposureModeSchema.optional(),
|
|
10408
|
+
backlightMode: BacklightModeSchema.optional(),
|
|
10409
|
+
lastFetchedAt: number()
|
|
10410
|
+
});
|
|
10411
|
+
/**
|
|
10412
|
+
* Per-camera availability descriptor — drives which controls the admin UI
|
|
10413
|
+
* renders. Booleans as `supportsX`; numeric ranges as `{ min, max, step }`
|
|
10414
|
+
* (the normalized 0–100 range); enums as arrays of supported values (empty
|
|
10415
|
+
* array → control hidden). A provider returns honest, camera-probed values
|
|
10416
|
+
* — never hardcoded.
|
|
10417
|
+
*/
|
|
10418
|
+
var ImageSettingsOptionsSchema = object({
|
|
10419
|
+
supportsBrightness: boolean(),
|
|
10420
|
+
brightness: NormalizedRangeSchema.optional(),
|
|
10421
|
+
supportsContrast: boolean(),
|
|
10422
|
+
contrast: NormalizedRangeSchema.optional(),
|
|
10423
|
+
supportsSaturation: boolean(),
|
|
10424
|
+
saturation: NormalizedRangeSchema.optional(),
|
|
10425
|
+
supportsSharpness: boolean(),
|
|
10426
|
+
sharpness: NormalizedRangeSchema.optional(),
|
|
10427
|
+
supportsMirror: boolean(),
|
|
10428
|
+
supportsFlip: boolean(),
|
|
10429
|
+
/** Supported rotation values. Empty → rotation not configurable. */
|
|
10430
|
+
rotateOptions: array(ImageRotateSchema),
|
|
10431
|
+
/** Supported white-balance modes. Empty → white-balance not configurable. */
|
|
10432
|
+
whiteBalanceModes: array(WhiteBalanceModeSchema),
|
|
10433
|
+
supportsWarmth: boolean(),
|
|
10434
|
+
/** Present when `supportsWarmth` — the normalized 0–100 range. */
|
|
10435
|
+
warmth: NormalizedRangeSchema.optional(),
|
|
10436
|
+
/** Supported exposure modes. Empty → exposure not configurable. */
|
|
10437
|
+
exposureModes: array(ExposureModeSchema),
|
|
10438
|
+
/** Supported backlight modes. Empty → backlight-compensation not configurable. */
|
|
10439
|
+
backlightModes: array(BacklightModeSchema)
|
|
10440
|
+
});
|
|
10441
|
+
/**
|
|
10442
|
+
* Partial change to the image config — every field optional. Slider values
|
|
10443
|
+
* are normalized 0–100. A provider ignores fields it does not support.
|
|
10444
|
+
*/
|
|
10445
|
+
var ImageSettingsPatchSchema = object({
|
|
10446
|
+
brightness: number().optional(),
|
|
10447
|
+
contrast: number().optional(),
|
|
10448
|
+
saturation: number().optional(),
|
|
10449
|
+
sharpness: number().optional(),
|
|
10450
|
+
mirror: boolean().optional(),
|
|
10451
|
+
flip: boolean().optional(),
|
|
10452
|
+
rotate: ImageRotateSchema.optional(),
|
|
10453
|
+
whiteBalance: WhiteBalanceModeSchema.optional(),
|
|
10454
|
+
warmth: number().optional(),
|
|
10455
|
+
exposureMode: ExposureModeSchema.optional(),
|
|
10456
|
+
backlightMode: BacklightModeSchema.optional()
|
|
10457
|
+
});
|
|
10458
|
+
DeviceType.Camera, method(object({ deviceId: number() }), ImageSettingsOptionsSchema), method(object({
|
|
10459
|
+
deviceId: number(),
|
|
10460
|
+
settings: ImageSettingsPatchSchema
|
|
10461
|
+
}), _void(), {
|
|
10462
|
+
kind: "mutation",
|
|
10463
|
+
auth: "admin"
|
|
10464
|
+
});
|
|
10465
|
+
/**
|
|
10256
10466
|
* Robotic lawn-mower cap. Models HA `lawn_mower.*` entities — anything
|
|
10257
10467
|
* with a mowing lifecycle plus a dock action.
|
|
10258
10468
|
*
|
|
@@ -11315,6 +11525,16 @@ var RunnerCameraConfigSchema = object({
|
|
|
11315
11525
|
* this gate is bypassed.
|
|
11316
11526
|
*/
|
|
11317
11527
|
onboardMotionDrivesAnalyzer: boolean().default(true),
|
|
11528
|
+
/**
|
|
11529
|
+
* Master toggle for the occupancy re-check. When `false` (DEFAULT) the runner
|
|
11530
|
+
* never arms the periodic recheck timer, regardless of `occupancyRecheckSec` —
|
|
11531
|
+
* this is off by default because the recheck re-subscribes a detection session
|
|
11532
|
+
* every N seconds while `watching`, a major source of pull-decoder re-dial
|
|
11533
|
+
* churn (each cycle creates+tears a session → RTSP re-dial → latency). The
|
|
11534
|
+
* `occupancyRecheckSec` / `occupancyRecheckFrames` sliders only take effect
|
|
11535
|
+
* (and only render) when this is enabled.
|
|
11536
|
+
*/
|
|
11537
|
+
occupancyRecheckEnabled: boolean().default(false),
|
|
11318
11538
|
occupancyRecheckSec: number().min(occupancyRecheckSecField.min).max(occupancyRecheckSecField.max).default(occupancyRecheckSecField.default),
|
|
11319
11539
|
occupancyRecheckFrames: number().min(occupancyRecheckFramesField.min).max(occupancyRecheckFramesField.max).default(occupancyRecheckFramesField.default),
|
|
11320
11540
|
/**
|
|
@@ -11365,6 +11585,8 @@ var RunnerCameraDeviceUIFields = [
|
|
|
11365
11585
|
default: motionFpsField.default,
|
|
11366
11586
|
showValue: true,
|
|
11367
11587
|
unit: "fps",
|
|
11588
|
+
nullable: true,
|
|
11589
|
+
nullLabel: "Default",
|
|
11368
11590
|
showWhen: {
|
|
11369
11591
|
field: "motionSources",
|
|
11370
11592
|
includes: "analyzer"
|
|
@@ -11379,7 +11601,9 @@ var RunnerCameraDeviceUIFields = [
|
|
|
11379
11601
|
step: detectionFpsField.step,
|
|
11380
11602
|
default: detectionFpsField.default,
|
|
11381
11603
|
showValue: true,
|
|
11382
|
-
unit: "fps"
|
|
11604
|
+
unit: "fps",
|
|
11605
|
+
nullable: true,
|
|
11606
|
+
nullLabel: "Default"
|
|
11383
11607
|
},
|
|
11384
11608
|
{
|
|
11385
11609
|
key: "motionCooldownMs",
|
|
@@ -11392,7 +11616,9 @@ var RunnerCameraDeviceUIFields = [
|
|
|
11392
11616
|
default: motionCooldownMsField.default,
|
|
11393
11617
|
showValue: true,
|
|
11394
11618
|
unit: "s",
|
|
11395
|
-
displayScale: 1e3
|
|
11619
|
+
displayScale: 1e3,
|
|
11620
|
+
nullable: true,
|
|
11621
|
+
nullLabel: "Default"
|
|
11396
11622
|
},
|
|
11397
11623
|
{
|
|
11398
11624
|
key: "onboardMotionDrivesAnalyzer",
|
|
@@ -11405,17 +11631,29 @@ var RunnerCameraDeviceUIFields = [
|
|
|
11405
11631
|
includes: "onboard"
|
|
11406
11632
|
}
|
|
11407
11633
|
},
|
|
11634
|
+
{
|
|
11635
|
+
key: "occupancyRecheckEnabled",
|
|
11636
|
+
type: "boolean",
|
|
11637
|
+
style: "checkbox",
|
|
11638
|
+
label: "Occupancy re-check",
|
|
11639
|
+
description: "Periodically re-sample a few frames during the watching phase to confirm the scene is truly empty (catches stationary objects motion-gating would miss). Off by default — it adds decoder re-dial churn.",
|
|
11640
|
+
default: false
|
|
11641
|
+
},
|
|
11408
11642
|
{
|
|
11409
11643
|
key: "occupancyRecheckSec",
|
|
11410
11644
|
type: "slider",
|
|
11411
11645
|
label: "Occupancy re-check interval",
|
|
11412
|
-
description: "How often (in seconds) the runner re-samples a few frames to confirm the scene is truly empty during the watching phase.
|
|
11646
|
+
description: "How often (in seconds) the runner re-samples a few frames to confirm the scene is truly empty during the watching phase.",
|
|
11413
11647
|
min: occupancyRecheckSecField.min,
|
|
11414
11648
|
max: occupancyRecheckSecField.max,
|
|
11415
11649
|
step: occupancyRecheckSecField.step,
|
|
11416
11650
|
default: occupancyRecheckSecField.default,
|
|
11417
11651
|
showValue: true,
|
|
11418
|
-
unit: "s"
|
|
11652
|
+
unit: "s",
|
|
11653
|
+
showWhen: {
|
|
11654
|
+
field: "occupancyRecheckEnabled",
|
|
11655
|
+
equals: true
|
|
11656
|
+
}
|
|
11419
11657
|
},
|
|
11420
11658
|
{
|
|
11421
11659
|
key: "occupancyRecheckFrames",
|
|
@@ -11426,7 +11664,11 @@ var RunnerCameraDeviceUIFields = [
|
|
|
11426
11664
|
max: occupancyRecheckFramesField.max,
|
|
11427
11665
|
step: occupancyRecheckFramesField.step,
|
|
11428
11666
|
default: occupancyRecheckFramesField.default,
|
|
11429
|
-
showValue: true
|
|
11667
|
+
showValue: true,
|
|
11668
|
+
showWhen: {
|
|
11669
|
+
field: "occupancyRecheckEnabled",
|
|
11670
|
+
equals: true
|
|
11671
|
+
}
|
|
11430
11672
|
}
|
|
11431
11673
|
];
|
|
11432
11674
|
/**
|
|
@@ -20005,6 +20247,18 @@ Object.freeze({
|
|
|
20005
20247
|
addonId: null,
|
|
20006
20248
|
access: "view"
|
|
20007
20249
|
},
|
|
20250
|
+
"dayNight.getOptions": {
|
|
20251
|
+
capName: "day-night",
|
|
20252
|
+
capScope: "device",
|
|
20253
|
+
addonId: null,
|
|
20254
|
+
access: "view"
|
|
20255
|
+
},
|
|
20256
|
+
"dayNight.setSettings": {
|
|
20257
|
+
capName: "day-night",
|
|
20258
|
+
capScope: "device",
|
|
20259
|
+
addonId: null,
|
|
20260
|
+
access: "create"
|
|
20261
|
+
},
|
|
20008
20262
|
"decoder.createSession": {
|
|
20009
20263
|
capName: "decoder",
|
|
20010
20264
|
capScope: "system",
|
|
@@ -20935,6 +21189,18 @@ Object.freeze({
|
|
|
20935
21189
|
addonId: null,
|
|
20936
21190
|
access: "create"
|
|
20937
21191
|
},
|
|
21192
|
+
"imageSettings.getOptions": {
|
|
21193
|
+
capName: "image-settings",
|
|
21194
|
+
capScope: "device",
|
|
21195
|
+
addonId: null,
|
|
21196
|
+
access: "view"
|
|
21197
|
+
},
|
|
21198
|
+
"imageSettings.setSettings": {
|
|
21199
|
+
capName: "image-settings",
|
|
21200
|
+
capScope: "device",
|
|
21201
|
+
addonId: null,
|
|
21202
|
+
access: "create"
|
|
21203
|
+
},
|
|
20938
21204
|
"integrations.create": {
|
|
20939
21205
|
capName: "integrations",
|
|
20940
21206
|
capScope: "system",
|
|
@@ -24514,7 +24780,8 @@ var DEFAULT_WATCHDOG_THRESHOLDS = {
|
|
|
24514
24780
|
audioMs: 9e4,
|
|
24515
24781
|
motionMs: 3e4,
|
|
24516
24782
|
detectionMs: 6e4,
|
|
24517
|
-
maxRecoveryAttempts: 3
|
|
24783
|
+
maxRecoveryAttempts: 3,
|
|
24784
|
+
exhaustedRetryMs: 6e4
|
|
24518
24785
|
};
|
|
24519
24786
|
var STAGE_THRESHOLD_KEY = {
|
|
24520
24787
|
audio: "audioMs",
|
|
@@ -24535,7 +24802,8 @@ var PipelineWatchdog = class {
|
|
|
24535
24802
|
const stages = /* @__PURE__ */ new Map();
|
|
24536
24803
|
for (const [stage] of cam.continuousStages) stages.set(stage, {
|
|
24537
24804
|
lastSeenMs: now,
|
|
24538
|
-
attempts: 0
|
|
24805
|
+
attempts: 0,
|
|
24806
|
+
lastAttemptMs: 0
|
|
24539
24807
|
});
|
|
24540
24808
|
this.state.set(cam.deviceId, stages);
|
|
24541
24809
|
}
|
|
@@ -24558,7 +24826,10 @@ var PipelineWatchdog = class {
|
|
|
24558
24826
|
else this.deps.logger.info(line);
|
|
24559
24827
|
for (const r of recoveries) {
|
|
24560
24828
|
const rt = this.state.get(cam.deviceId)?.get(r.stage);
|
|
24561
|
-
if (rt)
|
|
24829
|
+
if (rt) {
|
|
24830
|
+
if (rt.attempts < this.deps.thresholds.maxRecoveryAttempts) rt.attempts += 1;
|
|
24831
|
+
rt.lastAttemptMs = now;
|
|
24832
|
+
}
|
|
24562
24833
|
this.deps.recover(cam.deviceId, r.stage, r.streamId);
|
|
24563
24834
|
}
|
|
24564
24835
|
}
|
|
@@ -24602,7 +24873,13 @@ var PipelineWatchdog = class {
|
|
|
24602
24873
|
if (staleness <= thresholdMs) parts.push(`${stage}=${stageMode[stage]}@${streamId}(OK ${sSec}s)`);
|
|
24603
24874
|
else if (rt.attempts >= this.deps.thresholds.maxRecoveryAttempts) {
|
|
24604
24875
|
stalled = true;
|
|
24605
|
-
|
|
24876
|
+
if (now - rt.lastAttemptMs >= this.deps.thresholds.exhaustedRetryMs) {
|
|
24877
|
+
recoveries.push({
|
|
24878
|
+
stage,
|
|
24879
|
+
streamId
|
|
24880
|
+
});
|
|
24881
|
+
parts.push(`${stage}=${stageMode[stage]}@${streamId}(STALLED ${sSec}s · exhausted ${rt.attempts} · retrying)`);
|
|
24882
|
+
} else parts.push(`${stage}=${stageMode[stage]}@${streamId}(STALLED ${sSec}s · exhausted ${rt.attempts})`);
|
|
24606
24883
|
} else {
|
|
24607
24884
|
stalled = true;
|
|
24608
24885
|
recoveries.push({
|
|
@@ -24954,6 +25231,24 @@ function isPipelinePhaseMode(v) {
|
|
|
24954
25231
|
var PREFERRED_AGENT_SETTING = "preferredAgent";
|
|
24955
25232
|
/** Key under which the orchestrator stores the per-device audio node pin. */
|
|
24956
25233
|
var AUDIO_NODE_SETTING = "audioNodeId";
|
|
25234
|
+
/**
|
|
25235
|
+
* Target PCM window duration, in ms, for audio classification.
|
|
25236
|
+
*
|
|
25237
|
+
* Sized for the ~1 s inference window the downstream classifiers expect —
|
|
25238
|
+
* YAMNet consumes a 0.975 s frame and Apple SoundAnalysis a ~1 s frame.
|
|
25239
|
+
* The broker's `AudioCodecSession` no longer batches (its 500 ms
|
|
25240
|
+
* accumulator was removed for WebRTC latency), so decoded codec chunks now
|
|
25241
|
+
* arrive at ~21–64 ms each — ~16–48 chunks per second per camera. Feeding
|
|
25242
|
+
* each tiny chunk to the analyzer meant one cross-process `analyseChunk`
|
|
25243
|
+
* RPC + one `PipelineAudioInferenceResult` event PER chunk for a classifier
|
|
25244
|
+
* that (a) throttles to ~2 Hz internally anyway and (b) needs a ~1 s window
|
|
25245
|
+
* for accurate inference. We instead accumulate raw PCM per device and flush
|
|
25246
|
+
* ONE classify + ONE event per ~1 s window: ~1 RPC/event/s/camera and a
|
|
25247
|
+
* correctly-sized inference frame.
|
|
25248
|
+
*/
|
|
25249
|
+
var AUDIO_WINDOW_TARGET_MS = 1e3;
|
|
25250
|
+
/** f32le PCM = 4 bytes per sample. */
|
|
25251
|
+
var F32_BYTES_PER_SAMPLE = 4;
|
|
24957
25252
|
var DEFAULT_BROKER_CALL_TIMEOUT_MS = 5e3;
|
|
24958
25253
|
/** Debounce window for `scheduleReconcile` — coalesces bursts of topology/slot-change signals. */
|
|
24959
25254
|
var RECONCILE_DEBOUNCE_MS = 200;
|
|
@@ -25006,7 +25301,6 @@ var OrchestratorDiagnosticsSchema = object({
|
|
|
25006
25301
|
enabledAudioNodes: array(string()),
|
|
25007
25302
|
clusterRoles: object({
|
|
25008
25303
|
ingestNode: string(),
|
|
25009
|
-
recordingNode: string(),
|
|
25010
25304
|
audioNode: string()
|
|
25011
25305
|
}),
|
|
25012
25306
|
assignedDeviceCount: number().int().min(0),
|
|
@@ -25167,12 +25461,15 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
25167
25461
|
/**
|
|
25168
25462
|
* Cluster-wide singleton role assignments (placement-model §6). Each role
|
|
25169
25463
|
* is the ONE node that serves it for every camera. Driven by the
|
|
25170
|
-
* `ingestNode` / `
|
|
25171
|
-
*
|
|
25464
|
+
* `ingestNode` / `audioNode` node-selects in the addon global schema;
|
|
25465
|
+
* defaults to the hub for both. NOTE: the recording node is NOT a role here
|
|
25466
|
+
* — the `recorder` addon owns it as the single source of truth (its
|
|
25467
|
+
* `recordingNodeId` global setting, obeyed by the recorder's gate). The
|
|
25468
|
+
* Pipeline placement board's "Recording" picker reads/writes that canonical
|
|
25469
|
+
* setting directly via `addonSettings`, not an orchestrator-owned duplicate.
|
|
25172
25470
|
*/
|
|
25173
25471
|
clusterRoles = {
|
|
25174
25472
|
ingestNode: "hub",
|
|
25175
|
-
recordingNode: "hub",
|
|
25176
25473
|
audioNode: "hub"
|
|
25177
25474
|
};
|
|
25178
25475
|
/**
|
|
@@ -28146,32 +28443,21 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
28146
28443
|
title: "Cluster Roles",
|
|
28147
28444
|
tab: "pipeline",
|
|
28148
28445
|
description: "Cluster-wide singleton roles: the single node that serves each role for every camera. Per-node detection/decode/audio CAPABILITIES + weights + camera caps are edited in the per-node capability table (agent settings), not here.",
|
|
28149
|
-
fields: [
|
|
28150
|
-
|
|
28151
|
-
|
|
28152
|
-
|
|
28153
|
-
|
|
28154
|
-
|
|
28155
|
-
|
|
28156
|
-
|
|
28157
|
-
|
|
28158
|
-
|
|
28159
|
-
|
|
28160
|
-
|
|
28161
|
-
|
|
28162
|
-
|
|
28163
|
-
|
|
28164
|
-
showOffline: true
|
|
28165
|
-
},
|
|
28166
|
-
{
|
|
28167
|
-
key: "audioNode",
|
|
28168
|
-
type: "node-select",
|
|
28169
|
-
label: "Audio Node",
|
|
28170
|
-
description: "The node that runs all audio analysis. Defaults to the hub. Must be an audio-capable node.",
|
|
28171
|
-
default: "hub",
|
|
28172
|
-
showOffline: true
|
|
28173
|
-
}
|
|
28174
|
-
]
|
|
28446
|
+
fields: [{
|
|
28447
|
+
key: "ingestNode",
|
|
28448
|
+
type: "node-select",
|
|
28449
|
+
label: "Ingest Node",
|
|
28450
|
+
description: "The node that connects every camera and serves the compressed restream. Defaults to the hub. (Arbitrary ingest ≠ hub is a later phase; kept here so the role is modeled.)",
|
|
28451
|
+
default: "hub",
|
|
28452
|
+
showOffline: true
|
|
28453
|
+
}, {
|
|
28454
|
+
key: "audioNode",
|
|
28455
|
+
type: "node-select",
|
|
28456
|
+
label: "Audio Node",
|
|
28457
|
+
description: "The node that runs all audio analysis. Defaults to the hub. Must be an audio-capable node.",
|
|
28458
|
+
default: "hub",
|
|
28459
|
+
showOffline: true
|
|
28460
|
+
}]
|
|
28175
28461
|
},
|
|
28176
28462
|
{
|
|
28177
28463
|
id: "decoder",
|
|
@@ -28697,7 +28983,6 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
28697
28983
|
};
|
|
28698
28984
|
this.clusterRoles = {
|
|
28699
28985
|
ingestNode: readRole("ingestNode"),
|
|
28700
|
-
recordingNode: readRole("recordingNode"),
|
|
28701
28986
|
audioNode: readRole("audioNode")
|
|
28702
28987
|
};
|
|
28703
28988
|
this.schedulePendingRetry();
|
|
@@ -28872,6 +29157,13 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
28872
29157
|
if (typeof v !== "number") throw new Error(`orchestrator schema missing required number '${key}' for device ${deviceId}`);
|
|
28873
29158
|
return v;
|
|
28874
29159
|
};
|
|
29160
|
+
const numberOrDefault = (key) => {
|
|
29161
|
+
const v = flat[key];
|
|
29162
|
+
if (typeof v === "number") return v;
|
|
29163
|
+
const uiField = RunnerCameraDeviceUIFields.find((f) => f.key === key);
|
|
29164
|
+
const dflt = uiField && "default" in uiField ? uiField.default : void 0;
|
|
29165
|
+
return typeof dflt === "number" ? dflt : 0;
|
|
29166
|
+
};
|
|
28875
29167
|
try {
|
|
28876
29168
|
const features = await this.lookupDeviceFeatures(deviceId);
|
|
28877
29169
|
const profile = resolveDeviceProfile(features);
|
|
@@ -28889,6 +29181,8 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
28889
29181
|
const audioMode = typeof userAudioMode === "string" && isPipelinePhaseMode(userAudioMode) ? userAudioMode : profile?.defaults.audioMode ?? "always-on";
|
|
28890
29182
|
const userOnboardMotionDrivesAnalyzer = raw["onboardMotionDrivesAnalyzer"];
|
|
28891
29183
|
const onboardMotionDrivesAnalyzer = typeof userOnboardMotionDrivesAnalyzer === "boolean" ? userOnboardMotionDrivesAnalyzer : true;
|
|
29184
|
+
const userOccupancyRecheckEnabled = raw["occupancyRecheckEnabled"];
|
|
29185
|
+
const occupancyRecheckEnabled = typeof userOccupancyRecheckEnabled === "boolean" ? userOccupancyRecheckEnabled : false;
|
|
28892
29186
|
const occupancyRecheckSec = mustNumber("occupancyRecheckSec");
|
|
28893
29187
|
const occupancyRecheckFrames = mustNumber("occupancyRecheckFrames");
|
|
28894
29188
|
return {
|
|
@@ -28897,12 +29191,13 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
28897
29191
|
motionSources,
|
|
28898
29192
|
motionStreamProfile: mustString("motionStreamProfile"),
|
|
28899
29193
|
detectionStreamProfile: mustString("detectionStreamProfile"),
|
|
28900
|
-
motionFps:
|
|
28901
|
-
detectionFps:
|
|
28902
|
-
motionCooldownMs:
|
|
29194
|
+
motionFps: numberOrDefault("motionFps"),
|
|
29195
|
+
detectionFps: numberOrDefault("detectionFps"),
|
|
29196
|
+
motionCooldownMs: numberOrDefault("motionCooldownMs"),
|
|
28903
29197
|
detectionMode,
|
|
28904
29198
|
audioMode,
|
|
28905
29199
|
onboardMotionDrivesAnalyzer,
|
|
29200
|
+
occupancyRecheckEnabled,
|
|
28906
29201
|
occupancyRecheckSec,
|
|
28907
29202
|
occupancyRecheckFrames
|
|
28908
29203
|
};
|
|
@@ -29013,6 +29308,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
29013
29308
|
detectionMode: resolved.detectionMode,
|
|
29014
29309
|
audioMode: resolved.audioMode,
|
|
29015
29310
|
onboardMotionDrivesAnalyzer: resolved.onboardMotionDrivesAnalyzer,
|
|
29311
|
+
occupancyRecheckEnabled: resolved.occupancyRecheckEnabled,
|
|
29016
29312
|
occupancyRecheckSec: resolved.occupancyRecheckSec,
|
|
29017
29313
|
occupancyRecheckFrames: resolved.occupancyRecheckFrames
|
|
29018
29314
|
};
|
|
@@ -29047,6 +29343,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
29047
29343
|
detectionMode: config.detectionMode,
|
|
29048
29344
|
audioMode: config.audioMode,
|
|
29049
29345
|
onboardMotionDrivesAnalyzer: config.onboardMotionDrivesAnalyzer,
|
|
29346
|
+
occupancyRecheckEnabled: config.occupancyRecheckEnabled,
|
|
29050
29347
|
occupancyRecheckSec: config.occupancyRecheckSec,
|
|
29051
29348
|
occupancyRecheckFrames: config.occupancyRecheckFrames
|
|
29052
29349
|
};
|
|
@@ -29212,6 +29509,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
29212
29509
|
if (a.motionCooldownMs !== b.motionCooldownMs) return false;
|
|
29213
29510
|
if (a.audioStreamId !== b.audioStreamId) return false;
|
|
29214
29511
|
if (a.onboardMotionDrivesAnalyzer !== b.onboardMotionDrivesAnalyzer) return false;
|
|
29512
|
+
if (a.occupancyRecheckEnabled !== b.occupancyRecheckEnabled) return false;
|
|
29215
29513
|
if (a.occupancyRecheckSec !== b.occupancyRecheckSec) return false;
|
|
29216
29514
|
if (a.occupancyRecheckFrames !== b.occupancyRecheckFrames) return false;
|
|
29217
29515
|
if (a.motionSources.length !== b.motionSources.length) return false;
|
|
@@ -29741,6 +30039,19 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
29741
30039
|
isRemote: isRemoteAudio
|
|
29742
30040
|
}
|
|
29743
30041
|
});
|
|
30042
|
+
let pcmParts = [];
|
|
30043
|
+
let accumulatedBytes = 0;
|
|
30044
|
+
let accumulatedMs = 0;
|
|
30045
|
+
let windowSampleRate = 0;
|
|
30046
|
+
let windowChannels = 0;
|
|
30047
|
+
let windowTimestamp = 0;
|
|
30048
|
+
let windowOpen = false;
|
|
30049
|
+
const resetWindow = () => {
|
|
30050
|
+
pcmParts = [];
|
|
30051
|
+
accumulatedBytes = 0;
|
|
30052
|
+
accumulatedMs = 0;
|
|
30053
|
+
windowOpen = false;
|
|
30054
|
+
};
|
|
29744
30055
|
const teardown = startAudioChunkPoller({
|
|
29745
30056
|
api,
|
|
29746
30057
|
brokerId: audioBrokerId,
|
|
@@ -29750,13 +30061,35 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
29750
30061
|
this.pipelineWatchdog?.noteSignal(deviceId, "audio");
|
|
29751
30062
|
try {
|
|
29752
30063
|
const byteLength = chunk.data.byteLength;
|
|
29753
|
-
const
|
|
29754
|
-
|
|
30064
|
+
const bytes = new Uint8Array(byteLength);
|
|
30065
|
+
bytes.set(new Uint8Array(chunk.data.buffer, chunk.data.byteOffset, byteLength));
|
|
30066
|
+
if (!windowOpen) {
|
|
30067
|
+
windowSampleRate = chunk.sampleRate;
|
|
30068
|
+
windowChannels = chunk.channels;
|
|
30069
|
+
windowTimestamp = chunk.timestamp;
|
|
30070
|
+
windowOpen = true;
|
|
30071
|
+
}
|
|
30072
|
+
pcmParts.push(bytes);
|
|
30073
|
+
accumulatedBytes += byteLength;
|
|
30074
|
+
const channels = chunk.channels > 0 ? chunk.channels : 1;
|
|
30075
|
+
const framesPerChannel = byteLength / F32_BYTES_PER_SAMPLE / channels;
|
|
30076
|
+
accumulatedMs += framesPerChannel / chunk.sampleRate * 1e3;
|
|
30077
|
+
if (accumulatedMs < AUDIO_WINDOW_TARGET_MS) return;
|
|
30078
|
+
const windowData = new Uint8Array(accumulatedBytes);
|
|
30079
|
+
let offset = 0;
|
|
30080
|
+
for (const part of pcmParts) {
|
|
30081
|
+
windowData.set(part, offset);
|
|
30082
|
+
offset += part.byteLength;
|
|
30083
|
+
}
|
|
30084
|
+
const flushSampleRate = windowSampleRate;
|
|
30085
|
+
const flushChannels = windowChannels;
|
|
30086
|
+
const flushTimestamp = windowTimestamp;
|
|
30087
|
+
resetWindow();
|
|
29755
30088
|
const audioChunkInput = {
|
|
29756
|
-
data,
|
|
29757
|
-
sampleRate:
|
|
29758
|
-
channels:
|
|
29759
|
-
timestamp:
|
|
30089
|
+
data: windowData,
|
|
30090
|
+
sampleRate: flushSampleRate,
|
|
30091
|
+
channels: flushChannels,
|
|
30092
|
+
timestamp: flushTimestamp,
|
|
29760
30093
|
deviceId
|
|
29761
30094
|
};
|
|
29762
30095
|
const result = await api.audioAnalyzer.analyseChunk.mutate({
|
|
@@ -29833,6 +30166,7 @@ var PipelineOrchestratorAddon = class PipelineOrchestratorAddon extends BaseAddo
|
|
|
29833
30166
|
this.ctx.logger.info("Audio stream subscribed", { tags: { deviceId } });
|
|
29834
30167
|
return () => {
|
|
29835
30168
|
teardown();
|
|
30169
|
+
resetWindow();
|
|
29836
30170
|
};
|
|
29837
30171
|
}
|
|
29838
30172
|
};
|