@camstack/types 1.2.225 → 1.2.226

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.
@@ -378,6 +378,28 @@ export interface FfmpegFilterGraph {
378
378
  */
379
379
  readonly audioOutLabel?: string | null;
380
380
  }
381
+ /**
382
+ * The hardware device an ENCODER runs on — a different question from
383
+ * {@link FfmpegInvocation.decodeHwAccel}, and the reason both exist.
384
+ *
385
+ * A software decode can feed a hardware encoder: ffmpeg pushes the frames to
386
+ * the GPU with `hwupload`, and the encode — which is where the CPU actually
387
+ * goes — never touches a core. Tying the two together is what kept this hub on
388
+ * `libx264` while its iGPU sat idle: the node's DECODE preference is `copy`
389
+ * for a good reason (hardware decode hard-fails on a fragile HEVC source) and
390
+ * that preference was deciding the ENCODER too.
391
+ *
392
+ * Declaring it is all-or-nothing by construction: the device option, the
393
+ * upload filter and the encoder are emitted together or not at all, because
394
+ * any two of the three without the third is a child that dies at start-up
395
+ * ("No device available for encoder", "Impossible to convert between the
396
+ * formats").
397
+ */
398
+ export interface FfmpegHwEncodeDevice {
399
+ readonly kind: 'vaapi';
400
+ /** DRM render node, e.g. `/dev/dri/renderD128`. */
401
+ readonly renderNode: string;
402
+ }
381
403
  export interface FfmpegInvocation {
382
404
  readonly logLevel: 'error' | 'warning' | 'info';
383
405
  /**
@@ -387,6 +409,12 @@ export interface FfmpegInvocation {
387
409
  * DECODER ADDON's ranking, never the raw kernel resolver's.
388
410
  */
389
411
  readonly decodeHwAccel: string | null;
412
+ /**
413
+ * The device the hardware ENCODER runs on. Absent ⇒ nothing changes: no
414
+ * device option, no upload filter, argv unchanged for every software
415
+ * encode and for every call site that predates this field.
416
+ */
417
+ readonly hwEncodeDevice?: FfmpegHwEncodeDevice;
390
418
  readonly input: FfmpegInputPlan;
391
419
  /**
392
420
  * Inputs 1..N-1, emitted after {@link input} in this order, each with its own
@@ -464,32 +492,14 @@ export type FfmpegStreamSelection = Pick<FfmpegInvocation, 'extraInputs' | 'filt
464
492
  */
465
493
  export declare function resolveStreamMaps(selection: FfmpegStreamSelection): FfmpegStreamMaps;
466
494
  /** The whole video block (`-vf` … `-c:v` … knobs), after `-i`. */
467
- export declare function buildVideoArgs(video: FfmpegVideoPlan, outputArgs: readonly string[], filterGraph?: FfmpegFilterGraph | null): string[];
495
+ export declare function buildVideoArgs(video: FfmpegVideoPlan, outputArgs: readonly string[], filterGraph?: FfmpegFilterGraph | null,
496
+ /** Set when the encoder runs on a GPU — see {@link FfmpegHwEncodeDevice}. */
497
+ hwEncode?: {
498
+ readonly device: FfmpegHwEncodeDevice;
499
+ readonly decodeHwAccel: string | null;
500
+ }): string[];
468
501
  /** The whole audio block, after `-i`. */
469
502
  export declare function buildAudioArgs(audio: FfmpegAudioPlan): string[];
470
- /**
471
- * Assemble the full ffmpeg argument list. Layout:
472
- *
473
- * -hide_banner -loglevel <level>
474
- * [-hwaccel <backend|auto>] ─┐ INPUT options — strictly before -i.
475
- * [<input.extraArgs>] │
476
- * [-fflags <flag>…] │
477
- * [-rtsp_transport tcp] │
478
- * -i <url> ─┘ …repeated per extraInput
479
- * [-filter_complex <graph>] ─ global, after the LAST -i
480
- * [-map <video>] <video block> <threads> ─┐ OUTPUT options.
481
- * [-map <audio>] <audio block> │
482
- * <consumer outputArgs verbatim> │
483
- * <sink> ─┘ terminal
484
- *
485
- * The `-map`s are DERIVED (see {@link resolveStreamMaps}), never constants:
486
- * one input with no graph emits none at all, which is why the argv of every
487
- * call site that predates the N-input extension is unchanged to the byte.
488
- *
489
- * {@link FfmpegInvocation.audioSidecar} is the one map that stays literal
490
- * (`0:a:0?`): the sidecar is defined as the SOURCE's microphone on its own RTP
491
- * output, not as whatever the main output happens to carry.
492
- */
493
503
  export declare function buildFfmpegArgs(inv: FfmpegInvocation): string[];
494
504
  /**
495
505
  * The hardware encoder for a target codec on `backend`, or the software one.
@@ -9206,6 +9206,13 @@ export type AppRouter = TrpcCoreRouter<{
9206
9206
  output: z.infer<typeof webrtcSessionCapability.methods.getSessionState.output>;
9207
9207
  meta: object;
9208
9208
  }>;
9209
+ getSessionDebug: TRPCQueryProcedure<{
9210
+ input: {
9211
+ [x: string]: unknown;
9212
+ } & z.input<typeof webrtcSessionCapability.methods.getSessionDebug.input>;
9213
+ output: z.infer<typeof webrtcSessionCapability.methods.getSessionDebug.output>;
9214
+ meta: object;
9215
+ }>;
9209
9216
  }>>;
9210
9217
  zoneAnalytics: TRPCBuiltRouter<{
9211
9218
  ctx: TrpcContext;
@@ -6,7 +6,7 @@
6
6
  * scope+access check inside `protectedProcedure` (see
7
7
  * `server/backend/src/api/trpc/trpc.middleware.ts`).
8
8
  *
9
- * Coverage: 1055 method paths across 131 capabilities.
9
+ * Coverage: 1056 method paths across 131 capabilities.
10
10
  */
11
11
  import type { CapabilityMethodAccess } from '../capabilities/capability-definition.js';
12
12
  export interface MethodAccessRecord {
@@ -6,7 +6,7 @@
6
6
  * system-scope cap that takes a deviceId was previously never device-filtered
7
7
  * — see the generator header).
8
8
  *
9
- * Coverage: 387 methods carry a device reference, of which
9
+ * Coverage: 388 methods carry a device reference, of which
10
10
  * 141 are on SYSTEM-scope caps.
11
11
  *
12
12
  * Top-level fields, number arrays, and one-level arrays of objects carrying
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sleep = require("./sleep-VlZxDyXq.js");
2
+ const require_sleep = require("./sleep-D7DPSeiv.js");
3
3
  const require_event_category = require("./event-category-BVfsrBYA.js");
4
- const require_canonical_hash = require("./canonical-hash-DYsYm8is.js");
4
+ const require_canonical_hash = require("./canonical-hash-CSE4ioRi.js");
5
5
  const require_enums = require("./enums.js");
6
6
  const require_err_msg = require("./err-msg-COpsHMw2.js");
7
7
  let zod = require("zod");
@@ -20819,6 +20819,7 @@ var MediaFileKindEnum = zod.z.enum([
20819
20819
  "keyFrameSmall",
20820
20820
  "thumbnailSmall",
20821
20821
  "confirmationCrop",
20822
+ "debugCrop",
20822
20823
  "sceneFrame"
20823
20824
  ]);
20824
20825
  /**
@@ -23196,6 +23197,18 @@ var RunnerCameraConfigSchema = zod.z.object({
23196
23197
  motionStreamId: zod.z.string(),
23197
23198
  detectionStreamId: zod.z.string(),
23198
23199
  /**
23200
+ * Which rung this camera's audio analysis listens on — `auto` (the lowest
23201
+ * AVAILABLE native rung) or an explicit one.
23202
+ *
23203
+ * Not consumed by the runner: carried here so it travels with the camera's
23204
+ * config the way `audioMotionWindowMs` does, and so the orchestrator's
23205
+ * watchdog resolves the same stream the audio subscription did. OPTIONAL
23206
+ * with no default — absent means `auto`, which is what every camera written
23207
+ * before this field had, and an absent optional adds nothing to the
23208
+ * generated cap-input defaults (D537).
23209
+ */
23210
+ audioStreamPick: require_sleep.AudioStreamPickSchema.optional(),
23211
+ /**
23199
23212
  * Motion sources that can activate the pipeline. At least one must
23200
23213
  * be present. Multiple sources OR-ed: any one firing arms the
23201
23214
  * cooldown timer and transitions watching → active. The same
@@ -27132,6 +27145,104 @@ var WebrtcStreamChoiceSchema = zod.z.object({
27132
27145
  bitrateKbps: zod.z.number().nullable()
27133
27146
  });
27134
27147
  /**
27148
+ * The last move the adaptive ladder made on this session, and the numbers it
27149
+ * rested on. Mirrors `LadderDecision` in the stream-broker's
27150
+ * `adaptive-controller.ts` — the log line's evidence, made readable.
27151
+ *
27152
+ * Nullability is load-bearing: `lossRatio: null` means the loss tracker had
27153
+ * no window to report, which is NOT a link with zero loss.
27154
+ */
27155
+ var WebrtcLadderDecisionSchema = zod.z.object({
27156
+ /** `loss` — RTCP / client-reported packet loss; `stall` — the picture
27157
+ * stopped moving; `healthy` — a promotion. */
27158
+ cause: zod.z.enum([
27159
+ "loss",
27160
+ "stall",
27161
+ "healthy"
27162
+ ]),
27163
+ /** The rung the ladder moved TO. Null for a move that changed no rung
27164
+ * (an MTU reduction, a forced transcode-down at the bottom). */
27165
+ tier: require_sleep.CamProfileSchema.nullable(),
27166
+ /** Whether that move forced the egress transcode-down rung. */
27167
+ forcedTranscodeDown: zod.z.boolean(),
27168
+ /** Loss ratio over the tracker's window at the moment of the decision. */
27169
+ lossRatio: zod.z.number().nullable(),
27170
+ /** The client's reported downlink at that moment, in kbps. */
27171
+ clientKbps: zod.z.number().nullable(),
27172
+ /** How long the stall detector had been seeing nothing arrive. */
27173
+ stalledForMs: zod.z.number().nullable(),
27174
+ /** Whether the broker WAS sending while that was measured — the half that
27175
+ * separates "the camera stopped" from "the link stopped". */
27176
+ serverSending: zod.z.boolean().nullable(),
27177
+ /** Epoch ms. The overlay prints its age; a decision from 40 minutes ago
27178
+ * must not read like one from this second. */
27179
+ at: zod.z.number()
27180
+ });
27181
+ /** Per-tier count of MEASURED downgrades this viewer session has suffered. */
27182
+ var WebrtcTierFailureSchema = zod.z.object({
27183
+ tier: require_sleep.CamProfileSchema,
27184
+ failures: zod.z.number().int().nonnegative()
27185
+ });
27186
+ /**
27187
+ * What the SERVER decided for one WebRTC session — the half the client cannot
27188
+ * measure. See `getSessionDebug`.
27189
+ */
27190
+ var WebrtcSessionDebugSchema = zod.z.object({
27191
+ sessionId: zod.z.string(),
27192
+ /** Whether the session still exists here. Everything below is null when
27193
+ * it does not — a dead session has no measurements, not zero ones. */
27194
+ alive: zod.z.boolean(),
27195
+ /** Epoch ms this snapshot was taken, so the overlay can show its age. */
27196
+ observedAt: zod.z.number(),
27197
+ /** The broker actually feeding this session (`<deviceId>/<camStreamId>`). */
27198
+ brokerId: zod.z.string().nullable(),
27199
+ camStreamId: zod.z.string().nullable(),
27200
+ /** `derived` = this hub BUILT the rung being served (a transcode/scale of
27201
+ * another stream); `native` = the camera's own encode. */
27202
+ sourceKind: zod.z.enum([
27203
+ "native",
27204
+ "derived",
27205
+ "unknown"
27206
+ ]),
27207
+ /** Whether the ladder is running at all (an `adaptive` target). */
27208
+ adaptive: zod.z.boolean(),
27209
+ /** The rung `auto` ACTUALLY resolved to right now. Null when the broker
27210
+ * is bound to no profile slot (a manually-activated stream). */
27211
+ servedTier: require_sleep.CamProfileSchema.nullable(),
27212
+ /** Which node ingests the source. Null when unresolved. */
27213
+ ingestNodeId: zod.z.string().nullable(),
27214
+ /** Whether that node is a remote one (the media crosses a node boundary
27215
+ * before it reaches this session). Null when unresolved. */
27216
+ ingestIsRemote: zod.z.boolean().nullable(),
27217
+ /** Codec off the source, and the one negotiated with this client. */
27218
+ sourceCodec: zod.z.string().nullable(),
27219
+ negotiatedCodec: zod.z.string().nullable(),
27220
+ /** Whether the EGRESS leg re-encodes for this client or forwards the
27221
+ * source bytes untouched. */
27222
+ egressLeg: zod.z.enum([
27223
+ "copy",
27224
+ "transcode",
27225
+ "unknown"
27226
+ ]),
27227
+ /** What the broker itself reports about the rung it is serving. */
27228
+ brokerStatus: zod.z.string().nullable(),
27229
+ brokerCodec: zod.z.string().nullable(),
27230
+ brokerBitrateKbps: zod.z.number().nullable(),
27231
+ brokerInputFps: zod.z.number().nullable(),
27232
+ brokerUptimeMs: zod.z.number().nullable(),
27233
+ /** RTP packets this session has sent — the server's own "am I sending?". */
27234
+ rtpPacketsSent: zod.z.number().nullable(),
27235
+ /** D42: the track may be carrying the recorded feeder, not live. The ladder
27236
+ * is suspended there, so a frozen picture in `recorded` mode means
27237
+ * something entirely different. */
27238
+ trackMode: zod.z.enum(["live", "recorded"]).nullable(),
27239
+ lastDecision: WebrtcLadderDecisionSchema.nullable(),
27240
+ tierFailures: zod.z.array(WebrtcTierFailureSchema),
27241
+ /** Successful promotions in this viewer session (drives the progressive
27242
+ * healthy timer). Null when no ladder is running. */
27243
+ upgradeCount: zod.z.number().nullable()
27244
+ });
27245
+ /**
27135
27246
  * WebRTC session — device-scoped facade over the system `webrtc` cap.
27136
27247
  *
27137
27248
  * Exposes per-device signaling (`createSession`, `handleAnswer`,
@@ -27371,7 +27482,27 @@ var webrtcSessionCapability = {
27371
27482
  * the same answer as "it ended": either way nothing is holding it up.
27372
27483
  */
27373
27484
  alive: zod.z.boolean()
27374
- }))
27485
+ })),
27486
+ /**
27487
+ * The SERVER's half of the stream-debug overlay, for one live session.
27488
+ *
27489
+ * The client can measure its own transport (`getStats()`); it cannot see
27490
+ * which rung `auto` actually resolved to, why the ladder last moved, or
27491
+ * whether the rung it is being served is the camera's own encode or
27492
+ * something this hub built. That asymmetry is why "quality is stuck on
27493
+ * low" reports have historically been unanswerable from the viewer alone.
27494
+ *
27495
+ * EVERY measurement here is nullable and `null` means UNKNOWN, never zero
27496
+ * (D393): a session whose ladder has never moved reports
27497
+ * `lastDecision: null`, which is a different fact from a ladder that moved
27498
+ * for `healthy` with a 0 loss ratio.
27499
+ *
27500
+ * Read-only, ~1 Hz, polled by the overlay only while it is visible.
27501
+ */
27502
+ getSessionDebug: require_sleep.method(zod.z.object({
27503
+ deviceId: zod.z.number().int().nonnegative(),
27504
+ sessionId: zod.z.string()
27505
+ }), WebrtcSessionDebugSchema, { kind: "query" })
27375
27506
  },
27376
27507
  /** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
27377
27508
  mount: { kind: "server-provided" }
@@ -50470,6 +50601,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
50470
50601
  addonId: null,
50471
50602
  access: "view"
50472
50603
  },
50604
+ "webrtcSession.getSessionDebug": {
50605
+ capName: "webrtc-session",
50606
+ capScope: "device",
50607
+ addonId: null,
50608
+ access: "view"
50609
+ },
50473
50610
  "webrtcSession.getSessionState": {
50474
50611
  capName: "webrtc-session",
50475
50612
  capScope: "device",
@@ -52726,6 +52863,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
52726
52863
  form: "single",
52727
52864
  optional: false
52728
52865
  }],
52866
+ "webrtcSession.getSessionDebug": [{
52867
+ name: "deviceId",
52868
+ form: "single",
52869
+ optional: false
52870
+ }],
52729
52871
  "webrtcSession.getSessionState": [{
52730
52872
  name: "deviceId",
52731
52873
  form: "single",
@@ -58233,6 +58375,7 @@ exports.AudioMetricsHistoryPointSchema = AudioMetricsHistoryPointSchema;
58233
58375
  exports.AudioMetricsHistorySchema = AudioMetricsHistorySchema;
58234
58376
  exports.AudioMetricsSnapshotSchema = AudioMetricsSnapshotSchema;
58235
58377
  exports.AudioPcmChunkSchema = AudioPcmChunkSchema;
58378
+ exports.AudioStreamPickSchema = require_sleep.AudioStreamPickSchema;
58236
58379
  exports.AuthResultSchema = AuthResultSchema;
58237
58380
  exports.AutoUpdateSettingsSchema = AutoUpdateSettingsSchema;
58238
58381
  exports.AutomationActionSchema = AutomationActionSchema;
@@ -59266,8 +59409,11 @@ exports.WELL_KNOWN_TABS = require_sleep.WELL_KNOWN_TABS;
59266
59409
  exports.WELL_KNOWN_TAB_MAP = require_sleep.WELL_KNOWN_TAB_MAP;
59267
59410
  exports.WaterHeaterStatusSchema = WaterHeaterStatusSchema;
59268
59411
  exports.WeatherStatusSchema = WeatherStatusSchema;
59412
+ exports.WebrtcLadderDecisionSchema = WebrtcLadderDecisionSchema;
59413
+ exports.WebrtcSessionDebugSchema = WebrtcSessionDebugSchema;
59269
59414
  exports.WebrtcStreamChoiceSchema = WebrtcStreamChoiceSchema;
59270
59415
  exports.WebrtcStreamTargetSchema = WebrtcStreamTargetSchema;
59416
+ exports.WebrtcTierFailureSchema = WebrtcTierFailureSchema;
59271
59417
  exports.WhiteBalanceModeSchema = WhiteBalanceModeSchema;
59272
59418
  exports.WidgetHostEnum = WidgetHostEnum;
59273
59419
  exports.WidgetLoginMethodSchema = WidgetLoginMethodSchema;