@camstack/system 1.2.254 → 1.2.255
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/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/autotrack/autotrack-cameras.d.ts +76 -0
- package/dist/builtins/autotrack/autotrack-config.d.ts +89 -0
- package/dist/builtins/autotrack/autotrack-decision.d.ts +99 -0
- package/dist/builtins/autotrack/autotrack-loop.d.ts +75 -0
- package/dist/builtins/autotrack/autotrack.addon.d.ts +71 -0
- package/dist/builtins/autotrack/frame-error.d.ts +50 -0
- package/dist/builtins/autotrack/frame-measurements.d.ts +97 -0
- package/dist/builtins/autotrack/index.d.ts +2 -0
- package/dist/builtins/autotrack/index.js +981 -0
- package/dist/builtins/autotrack/index.mjs +975 -0
- package/dist/builtins/autotrack/ptz-mirror.d.ts +25 -0
- package/dist/builtins/autotrack/target-selection.d.ts +60 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/camera-grid/addon.d.ts +118 -0
- package/dist/builtins/camera-grid/flv-join.d.ts +66 -0
- package/dist/builtins/camera-grid/grid-camera-declarations.d.ts +59 -0
- package/dist/builtins/camera-grid/grid-camera-device.d.ts +32 -0
- package/dist/builtins/camera-grid/grid-child.d.ts +9 -0
- package/dist/builtins/camera-grid/grid-device-settings.d.ts +11 -0
- package/dist/builtins/camera-grid/grid-filter-graph.d.ts +53 -0
- package/dist/builtins/camera-grid/grid-frame-sample.d.ts +27 -0
- package/dist/builtins/camera-grid/grid-instances.d.ts +49 -0
- package/dist/builtins/camera-grid/grid-last-frame-store.d.ts +19 -0
- package/dist/builtins/camera-grid/grid-layout-native-provider.d.ts +8 -0
- package/dist/builtins/camera-grid/grid-plan.d.ts +22 -0
- package/dist/builtins/camera-grid/grid-profiles.d.ts +47 -0
- package/dist/builtins/camera-grid/grid-row-normalization.d.ts +10 -0
- package/dist/builtins/camera-grid/grid-sentry-sources.d.ts +52 -0
- package/dist/builtins/camera-grid/grid-snapshot.d.ts +62 -0
- package/dist/builtins/camera-grid/grid-stream-descriptor.d.ts +24 -0
- package/dist/builtins/camera-grid/grid-stream-invocation.d.ts +29 -0
- package/dist/builtins/camera-grid/grid-stream-relay.d.ts +36 -0
- package/dist/builtins/camera-grid/grid-stream-session.d.ts +113 -0
- package/dist/builtins/camera-grid/grid-wire-format.d.ts +14 -0
- package/dist/builtins/camera-grid/index.d.ts +44 -0
- package/dist/builtins/camera-grid/index.js +2309 -0
- package/dist/builtins/camera-grid/index.mjs +2276 -0
- package/dist/builtins/camera-grid/silence-analysis.d.ts +13 -0
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
- package/dist/builtins/device-manager/device-manager.addon.js +2 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-CnQsUe15.js → dist-BJj6Akye.js} +1319 -0
- package/dist/{dist-BhTy3CUQ.mjs → dist-Ch93tyHB.mjs} +1260 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{retired-settings-keys-DDU-VFTU.js → retired-settings-keys-BRCn6-mt.js} +1 -1
- package/dist/{retired-settings-keys-CMhNYMD9.mjs → retired-settings-keys-uCaSKuwd.mjs} +1 -1
- package/package.json +32 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which URL a grid dials for one source: the live stream, or the SENTRY one.
|
|
3
|
+
*
|
|
4
|
+
* ## What "sentryMuted" turned out to be
|
|
5
|
+
*
|
|
6
|
+
* The operator asked for a stream that *"non esiste ancora"*. It half did.
|
|
7
|
+
* `SENTRY_PATH_SUFFIX` has existed since the sentry shipped, and
|
|
8
|
+
* `parseRestreamPath` already answers `muted: true` for it — the sentry path IS
|
|
9
|
+
* the muted one, by construction, because an `m=audio` nobody fills stalls a
|
|
10
|
+
* consumer for the hours a camera may sit asleep. What did not exist is the
|
|
11
|
+
* WRITER that turns an acquired restream url into that dial, and the broker
|
|
12
|
+
* telling a consumer whether one is on offer. Both are now in
|
|
13
|
+
* `addon-pipeline/src/stream-broker`: `withSentryIntent`, and `sentryUrl` on
|
|
14
|
+
* the `getStreamWithCodec` result.
|
|
15
|
+
*
|
|
16
|
+
* ## The rule, and the fallback it refuses
|
|
17
|
+
*
|
|
18
|
+
* An offered sentry is TAKEN. There is no sleep check and no fallback, and that
|
|
19
|
+
* is deliberate: "use the sentry if the camera is asleep, otherwise the live
|
|
20
|
+
* stream" reads reasonable and is exactly the wake. Whether a battery camera is
|
|
21
|
+
* asleep right now is a fact that changes between the read and the dial, and
|
|
22
|
+
* the dial is what wakes it. The ONE question asked is the one the broker
|
|
23
|
+
* already owns — is this camera offered a sentry at all — and the broker only
|
|
24
|
+
* offers it to a battery camera that declares the signals cap.
|
|
25
|
+
*
|
|
26
|
+
* ## What the operator sees
|
|
27
|
+
*
|
|
28
|
+
* A cell whose source is asleep composes that camera's last picture, held, for
|
|
29
|
+
* as long as it sleeps — visible, legible, and obviously not moving. The two
|
|
30
|
+
* alternatives are the ones D519 and the sentry both exist to refuse: dropping
|
|
31
|
+
* the cell (a hole an operator files as a broken grid) and dialling the camera
|
|
32
|
+
* (eleven seconds of battery for five seconds of video, measured on device 640).
|
|
33
|
+
*/
|
|
34
|
+
/** What `streamBroker.getStreamWithCodec` handed back for one source. */
|
|
35
|
+
export interface GridSourceAcquisition {
|
|
36
|
+
readonly url: string;
|
|
37
|
+
/**
|
|
38
|
+
* The sentry counterpart, when the BROKER offers one. Absent and `null` mean
|
|
39
|
+
* the same thing — this camera has no sentry — and neither is ever resolved
|
|
40
|
+
* into the live url by guessing.
|
|
41
|
+
*/
|
|
42
|
+
readonly sentryUrl?: string | null;
|
|
43
|
+
readonly pipelineKey: string;
|
|
44
|
+
}
|
|
45
|
+
export interface GridSourceDial {
|
|
46
|
+
readonly url: string;
|
|
47
|
+
/** The key the acquisition was issued under — releasing anything else leaks a dial. */
|
|
48
|
+
readonly pipelineKey: string;
|
|
49
|
+
/** What this cell is actually reading. Logged, so a still cell is never a mystery. */
|
|
50
|
+
readonly mode: 'live' | 'sentry';
|
|
51
|
+
}
|
|
52
|
+
export declare function gridSourceDial(acquired: GridSourceAcquisition): GridSourceDial;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { CamProfile } from '@camstack/types';
|
|
2
|
+
import { GridStreamLogger } from './grid-stream-session.js';
|
|
3
|
+
/** Where a grid's last composed frame is kept between compositions. */
|
|
4
|
+
export interface GridLastFrameStore {
|
|
5
|
+
/** The last frame kept for this grid, or `null` — which is a real answer. */
|
|
6
|
+
get(deviceId: number): Promise<Buffer | null>;
|
|
7
|
+
put(deviceId: number, jpeg: Buffer): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
/** Just enough of a session for the snapshot to choose one and read its state. */
|
|
10
|
+
export interface GridSnapshotSession {
|
|
11
|
+
readonly profile: CamProfile;
|
|
12
|
+
isRunning(): boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface GridSnapshotAnswerInput {
|
|
15
|
+
readonly running: boolean;
|
|
16
|
+
readonly hasStoredFrame: boolean;
|
|
17
|
+
}
|
|
18
|
+
export type GridSnapshotAnswer = {
|
|
19
|
+
readonly kind: 'live';
|
|
20
|
+
} | {
|
|
21
|
+
readonly kind: 'stored';
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: 'none';
|
|
24
|
+
readonly reason: 'never-composed';
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Which of the three answers applies. Pure, so the rule can be read — and
|
|
28
|
+
* sabotaged — without a socket, a file or an ffmpeg.
|
|
29
|
+
*/
|
|
30
|
+
export declare function gridSnapshotAnswerFor(input: GridSnapshotAnswerInput): GridSnapshotAnswer;
|
|
31
|
+
export interface GridSnapshotImage {
|
|
32
|
+
readonly base64: string;
|
|
33
|
+
readonly contentType: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generic in the session type so the addon can hand over its OWN session
|
|
37
|
+
* record — the one that also knows the instance and the stream — and get it
|
|
38
|
+
* back in `sampleFrame` without a cast or a second lookup.
|
|
39
|
+
*/
|
|
40
|
+
export interface GridSnapshotDeps<S extends GridSnapshotSession = GridSnapshotSession> {
|
|
41
|
+
readonly logger: GridStreamLogger;
|
|
42
|
+
/**
|
|
43
|
+
* This grid's sessions, one per published profile, in descending quality.
|
|
44
|
+
* EMPTY means this addon does not own the device — never "no picture".
|
|
45
|
+
*/
|
|
46
|
+
readonly sessionsFor: (deviceId: number) => readonly S[];
|
|
47
|
+
/**
|
|
48
|
+
* One JPEG out of a composition that is ALREADY running. `null` when the
|
|
49
|
+
* bytes could not be turned into a frame — which is a miss, not a reason to
|
|
50
|
+
* start anything.
|
|
51
|
+
*/
|
|
52
|
+
readonly sampleFrame: (session: S) => Promise<Buffer | null>;
|
|
53
|
+
readonly store: GridLastFrameStore;
|
|
54
|
+
}
|
|
55
|
+
export declare class GridSnapshotSource<S extends GridSnapshotSession = GridSnapshotSession> {
|
|
56
|
+
private readonly deps;
|
|
57
|
+
constructor(deps: GridSnapshotDeps<S>);
|
|
58
|
+
getSnapshot(deviceId: number): Promise<GridSnapshotImage | null>;
|
|
59
|
+
private sample;
|
|
60
|
+
private readStored;
|
|
61
|
+
private keep;
|
|
62
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CamProfile, CamStreamDescriptor } from '@camstack/types';
|
|
2
|
+
export interface GridStreamDescriptorInput {
|
|
3
|
+
/** Which composition this is. Also the `profileHint` — see below. */
|
|
4
|
+
readonly profile: CamProfile;
|
|
5
|
+
readonly width: number;
|
|
6
|
+
readonly height: number;
|
|
7
|
+
readonly fps: number;
|
|
8
|
+
/** The on-demand endpoint the broker dials. Dialling it IS the demand. */
|
|
9
|
+
readonly url: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* `profileHint` is load-bearing, not decoration.
|
|
13
|
+
*
|
|
14
|
+
* A device publishing a SINGLE stream with no hint is ranked by pixel count,
|
|
15
|
+
* and a single stream ranks into `mid` — the slot `recordings` does not select
|
|
16
|
+
* on its own (`high|mid` picks high), that `recordingsLow` ignores, and that
|
|
17
|
+
* scrub never reads. The Dreame robot's one 720p relay landed exactly there and
|
|
18
|
+
* its footage was written nowhere anything looked.
|
|
19
|
+
*
|
|
20
|
+
* With several compositions published the hint does a second job: it is the
|
|
21
|
+
* only thing that says which slot each one is FOR. Ranked by pixels a grid's
|
|
22
|
+
* `mid` would take the `high` slot on any grid whose `high` was not offered.
|
|
23
|
+
*/
|
|
24
|
+
export declare function gridStreamDescriptor(input: GridStreamDescriptorInput): CamStreamDescriptor;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { FfmpegInvocation, FfmpegVideoEncoderId } from '@camstack/types';
|
|
2
|
+
import { GridLayout } from './grid-filter-graph.js';
|
|
3
|
+
/** One ffmpeg input: the camera it is, and the URL this child will dial. */
|
|
4
|
+
export interface GridStreamSource {
|
|
5
|
+
/** The SOURCE camera. Carried so every log line about it can be tagged. */
|
|
6
|
+
readonly deviceId: number;
|
|
7
|
+
/**
|
|
8
|
+
* A broker restream URL, acquired through `streamBroker.getStreamWithCodec`.
|
|
9
|
+
* That is the single demand-counted entry point: it rides the broker's ONE
|
|
10
|
+
* source dial instead of opening a second connection to the camera.
|
|
11
|
+
*/
|
|
12
|
+
readonly url: string;
|
|
13
|
+
}
|
|
14
|
+
export interface GridStreamInvocationInput {
|
|
15
|
+
readonly layout: GridLayout;
|
|
16
|
+
/** In ffmpeg INPUT ORDINAL order — `sources[n]` is the graph's `[n:v]`. */
|
|
17
|
+
readonly sources: readonly GridStreamSource[];
|
|
18
|
+
readonly decodeHwAccel: string | null;
|
|
19
|
+
readonly encoder: FfmpegVideoEncoderId;
|
|
20
|
+
readonly fps: number;
|
|
21
|
+
readonly bitrateKbps: number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* @throws when the layout addresses an input the sources do not contain, or
|
|
25
|
+
* when there is nothing to compose. Both are plan errors: ffmpeg would refuse
|
|
26
|
+
* them at start-up with a message about a filter pad, which names the graph
|
|
27
|
+
* rather than the configuration that produced it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function gridStreamInvocation(input: GridStreamInvocationInput): FfmpegInvocation;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { CamProfile } from '@camstack/types';
|
|
2
|
+
import { GridStreamLogger, GridStreamSession } from './grid-stream-session.js';
|
|
3
|
+
/**
|
|
4
|
+
* Which grid, and WHICH COMPOSITION of it.
|
|
5
|
+
*
|
|
6
|
+
* The profile is a path segment and not a query string for the reason the
|
|
7
|
+
* restream suffixes are (`restream-intent.ts`): the choice belongs to the URL
|
|
8
|
+
* the consumer was handed, so a broker configured once keeps asking for the
|
|
9
|
+
* same thing. It is also REQUIRED — there is no default composition. A grid
|
|
10
|
+
* publishes one stream per profile it can serve, and a dial that named none
|
|
11
|
+
* would be the broker asking for "whichever", which is how a `low` slot ends
|
|
12
|
+
* up holding a `high` composition.
|
|
13
|
+
*/
|
|
14
|
+
export interface GridStreamRequest {
|
|
15
|
+
readonly instanceId: string;
|
|
16
|
+
readonly profile: CamProfile;
|
|
17
|
+
}
|
|
18
|
+
/** `/grid/<instanceId>/<profile>.flv`, or `null` when it is anything else. */
|
|
19
|
+
export declare function parseGridStreamPath(url: string | undefined): GridStreamRequest | null;
|
|
20
|
+
export interface GridStreamRelayDeps {
|
|
21
|
+
readonly logger: GridStreamLogger;
|
|
22
|
+
/** `null` when no grid serves that instance/profile pair right now. */
|
|
23
|
+
readonly sessionFor: (request: GridStreamRequest) => GridStreamSession | null;
|
|
24
|
+
}
|
|
25
|
+
export declare class GridStreamRelay {
|
|
26
|
+
private readonly deps;
|
|
27
|
+
private server;
|
|
28
|
+
private baseUrl;
|
|
29
|
+
private readonly open;
|
|
30
|
+
constructor(deps: GridStreamRelayDeps);
|
|
31
|
+
start(): Promise<void>;
|
|
32
|
+
/** The URL a grid's catalog descriptor advertises. Empty before {@link start}. */
|
|
33
|
+
streamUrl(request: GridStreamRequest): string;
|
|
34
|
+
private serve;
|
|
35
|
+
dispose(): Promise<void>;
|
|
36
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { FfmpegVideoEncoderId, IScopedLogger } from '@camstack/types';
|
|
2
|
+
import { Readable } from 'node:stream';
|
|
3
|
+
import { GridLayout } from './grid-filter-graph.js';
|
|
4
|
+
/** The logging surface this session needs — a structural subset of the injected logger. */
|
|
5
|
+
export type GridStreamLogger = Pick<IScopedLogger, 'debug' | 'info' | 'warn' | 'error'>;
|
|
6
|
+
/** One acquired broker handle: what to dial, and what to release it by. */
|
|
7
|
+
export interface GridSourceHandle {
|
|
8
|
+
readonly url: string;
|
|
9
|
+
readonly pipelineKey: string;
|
|
10
|
+
}
|
|
11
|
+
/** The spawned ffmpeg, as this session uses it. */
|
|
12
|
+
export interface GridStreamChild {
|
|
13
|
+
readonly stdout: Readable;
|
|
14
|
+
stop(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
/** Everything the composition needs that is not a per-run acquisition. */
|
|
17
|
+
export interface GridStreamPlan {
|
|
18
|
+
readonly layout: GridLayout;
|
|
19
|
+
/** In ffmpeg INPUT ORDINAL order — `sourceDeviceIds[n]` is the graph's `[n:v]`. */
|
|
20
|
+
readonly sourceDeviceIds: readonly number[];
|
|
21
|
+
readonly encoder: FfmpegVideoEncoderId;
|
|
22
|
+
readonly decodeHwAccel: string | null;
|
|
23
|
+
readonly fps: number;
|
|
24
|
+
readonly bitrateKbps: number;
|
|
25
|
+
}
|
|
26
|
+
export interface GridStreamSessionDeps {
|
|
27
|
+
readonly logger: GridStreamLogger;
|
|
28
|
+
readonly acquireSource: (deviceId: number) => Promise<GridSourceHandle>;
|
|
29
|
+
readonly releaseSource: (pipelineKey: string) => Promise<void>;
|
|
30
|
+
readonly startChild: (plan: GridStreamPlan, sources: readonly GridSourceHandle[]) => Promise<GridStreamChild>;
|
|
31
|
+
/** Teardown debounce. `0` ⇒ tear down the moment the last consumer leaves. */
|
|
32
|
+
readonly lingerMs?: number;
|
|
33
|
+
}
|
|
34
|
+
export interface GridStreamConsumer {
|
|
35
|
+
readonly onData: (chunk: Buffer) => void;
|
|
36
|
+
/** Called once, with WHY, when this consumer's stream ends from our side. */
|
|
37
|
+
readonly onClose: (reason: string) => void;
|
|
38
|
+
}
|
|
39
|
+
export interface GridStreamHold {
|
|
40
|
+
close(): void;
|
|
41
|
+
}
|
|
42
|
+
export interface GridStreamSessionOptions {
|
|
43
|
+
/** The COMPOSITE camera's device id — every log line here is tagged with it. */
|
|
44
|
+
readonly deviceId: number;
|
|
45
|
+
readonly deps: GridStreamSessionDeps;
|
|
46
|
+
/**
|
|
47
|
+
* The current composition, re-read on every cold start. `null` ⇒ the grid has
|
|
48
|
+
* no cells yet, which is the normal state of a freshly created grid.
|
|
49
|
+
*/
|
|
50
|
+
readonly resolvePlan: () => GridStreamPlan | null;
|
|
51
|
+
}
|
|
52
|
+
export declare class GridStreamSession {
|
|
53
|
+
private readonly options;
|
|
54
|
+
private readonly consumers;
|
|
55
|
+
/**
|
|
56
|
+
* The FLV stream's describing bytes, and where each reader may start.
|
|
57
|
+
*
|
|
58
|
+
* Rebuilt with every cold start: a new child means a new header and a new
|
|
59
|
+
* sequence header, and handing a reader the previous child's would decode
|
|
60
|
+
* noise. See `flv-join.ts` for why FLV needs this and MPEG-TS did not.
|
|
61
|
+
*/
|
|
62
|
+
private join;
|
|
63
|
+
private running;
|
|
64
|
+
private starting;
|
|
65
|
+
private lingerTimer;
|
|
66
|
+
private teardown;
|
|
67
|
+
private disposed;
|
|
68
|
+
constructor(options: GridStreamSessionOptions);
|
|
69
|
+
private get logTags();
|
|
70
|
+
/** The COMPOSITE camera's device id — what every log line about this grid is tagged with. */
|
|
71
|
+
get deviceId(): number;
|
|
72
|
+
isRunning(): boolean;
|
|
73
|
+
consumerCount(): number;
|
|
74
|
+
/** Resolves once any in-flight start or teardown has finished. For tests and shutdown. */
|
|
75
|
+
settled(): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Attach a consumer, starting the composition if this is the first one.
|
|
78
|
+
*
|
|
79
|
+
* @throws when the grid has nothing to compose, or a source could not be
|
|
80
|
+
* acquired. Both are LOGGED before they are thrown: a branch that accepts a
|
|
81
|
+
* consumer and then produces no media is exactly the branch that reads as
|
|
82
|
+
* "nothing ever happened".
|
|
83
|
+
*/
|
|
84
|
+
open(consumer: GridStreamConsumer): Promise<GridStreamHold>;
|
|
85
|
+
/**
|
|
86
|
+
* Attach to a composition that is ALREADY running, or refuse.
|
|
87
|
+
*
|
|
88
|
+
* The whole difference from {@link open} is the refusal, and the refusal is
|
|
89
|
+
* the feature. A snapshot of a grid is a frame of the composition — which
|
|
90
|
+
* only exists while something is watching it — and the operator's rule is
|
|
91
|
+
* that producing a thumbnail must never be the reason N cameras get dialled.
|
|
92
|
+
* `open()` would start the composition, acquire every source, and on a
|
|
93
|
+
* battery camera that is a wake nobody asked for.
|
|
94
|
+
*
|
|
95
|
+
* `null` is a real answer: "there is no composition to take a frame from",
|
|
96
|
+
* which the caller turns into the stored last frame, or into nothing.
|
|
97
|
+
*/
|
|
98
|
+
openIfRunning(consumer: GridStreamConsumer): GridStreamHold | null;
|
|
99
|
+
/** Forget a consumer AND the reader holding bytes on its behalf. */
|
|
100
|
+
private dropConsumer;
|
|
101
|
+
/**
|
|
102
|
+
* The child ended on its own. Every consumer is told WHY — a stream that
|
|
103
|
+
* simply stops is indistinguishable from a stalled one at the far end.
|
|
104
|
+
*/
|
|
105
|
+
onChildEnded(reason: string): void;
|
|
106
|
+
dispose(): Promise<void>;
|
|
107
|
+
private ensureRunning;
|
|
108
|
+
private startCold;
|
|
109
|
+
private scheduleTeardownIfIdle;
|
|
110
|
+
private cancelLinger;
|
|
111
|
+
private stopNow;
|
|
112
|
+
private releaseAll;
|
|
113
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CamStreamKind } from '@camstack/types';
|
|
2
|
+
/** The ffmpeg muxer the composition writes to stdout. */
|
|
3
|
+
export declare const GRID_WIRE_CONTAINER: "flv";
|
|
4
|
+
/** What the relay answers with, and what the sampler must demux. */
|
|
5
|
+
export declare const GRID_WIRE_CONTENT_TYPE = "video/x-flv";
|
|
6
|
+
/** `/grid/<instanceId>/<profile>.flv`. */
|
|
7
|
+
export declare const GRID_WIRE_PATH_SUFFIX = ".flv";
|
|
8
|
+
/**
|
|
9
|
+
* How the broker must ingest it: `pull-flv` is documented as ALWAYS read
|
|
10
|
+
* through the ffmpeg source reader with `-c copy`. `pull-http` would have been
|
|
11
|
+
* the intuitive choice and means MJPEG in this broker — it answers with
|
|
12
|
+
* `HTTP_MJPEG_H264_OUTPUT_ARGS` and re-encodes an already-encoded H.264.
|
|
13
|
+
*/
|
|
14
|
+
export declare const GRID_WIRE_STREAM_KIND: CamStreamKind;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Camera Grids — composite cameras built from other cameras.
|
|
3
|
+
*
|
|
4
|
+
* The manifest `entry` points at THIS module's build (`./dist/index.js`), and
|
|
5
|
+
* `vite.config.ts` must carry an `entries` key for every module a manifest
|
|
6
|
+
* names — a manifest entry is just a string and nothing resolves it at build
|
|
7
|
+
* time, so a missing key compiles and fails at runtime.
|
|
8
|
+
* `scripts/check-addon-entries.ts` is what catches that.
|
|
9
|
+
*/
|
|
10
|
+
export { CameraGridAddon } from './addon.js';
|
|
11
|
+
export { CameraGridAddon as default } from './addon.js';
|
|
12
|
+
export { buildGridFilterGraph } from './grid-filter-graph.js';
|
|
13
|
+
export type { GridCell, GridFilterGraph, GridLayout, NormalizedRect, } from './grid-filter-graph.js';
|
|
14
|
+
export { buildGridCameraDeclarations, gridCameraReconciliationIndex, newGridCameraStableId, } from './grid-camera-declarations.js';
|
|
15
|
+
export type { ExistingGridCameraRow, GridCameraConfig, GridCameraDeclaration, } from './grid-camera-declarations.js';
|
|
16
|
+
export { GridCameraDevice, installGridCameraRuntime } from './grid-camera-device.js';
|
|
17
|
+
export type { GridCameraRuntime } from './grid-camera-device.js';
|
|
18
|
+
export { readGridInstances } from './grid-instances.js';
|
|
19
|
+
export type { GridCellConfig, GridInstance } from './grid-instances.js';
|
|
20
|
+
export { gridPlanFor } from './grid-plan.js';
|
|
21
|
+
export type { GridPlanEncodeContext } from './grid-plan.js';
|
|
22
|
+
export { normalizeGridRows } from './grid-row-normalization.js';
|
|
23
|
+
export type { NormalizedGridRows } from './grid-row-normalization.js';
|
|
24
|
+
export { gridStreamDescriptor } from './grid-stream-descriptor.js';
|
|
25
|
+
export { GRID_CAM_STREAM_ID, GRID_PROFILES, gridCamStreamId, gridCanvasFor, offeredGridProfiles, } from './grid-profiles.js';
|
|
26
|
+
export type { GridCanvas, GridProfileOffer } from './grid-profiles.js';
|
|
27
|
+
export { gridSourceDial } from './grid-sentry-sources.js';
|
|
28
|
+
export type { GridSourceAcquisition, GridSourceDial } from './grid-sentry-sources.js';
|
|
29
|
+
export { GridSnapshotSource, gridSnapshotAnswerFor } from './grid-snapshot.js';
|
|
30
|
+
export type { GridLastFrameStore, GridSnapshotAnswer, GridSnapshotDeps, GridSnapshotImage, GridSnapshotSession, } from './grid-snapshot.js';
|
|
31
|
+
export { GridLastFrameFileStore } from './grid-last-frame-store.js';
|
|
32
|
+
export { GridFrameSampler } from './grid-frame-sample.js';
|
|
33
|
+
export type { GridFrameSource, GridSpawn } from './grid-frame-sample.js';
|
|
34
|
+
export type { GridStreamDescriptorInput } from './grid-stream-descriptor.js';
|
|
35
|
+
export { gridStreamInvocation } from './grid-stream-invocation.js';
|
|
36
|
+
export type { GridStreamInvocationInput, GridStreamSource } from './grid-stream-invocation.js';
|
|
37
|
+
export { GridStreamRelay, parseGridStreamPath } from './grid-stream-relay.js';
|
|
38
|
+
export type { GridStreamRelayDeps, GridStreamRequest } from './grid-stream-relay.js';
|
|
39
|
+
export { GridStreamSession } from './grid-stream-session.js';
|
|
40
|
+
export type { GridSourceHandle, GridStreamChild, GridStreamConsumer, GridStreamHold, GridStreamLogger, GridStreamPlan, GridStreamSessionDeps, GridStreamSessionOptions, } from './grid-stream-session.js';
|
|
41
|
+
export { startGridChild } from './grid-child.js';
|
|
42
|
+
export type { GridChildContext } from './grid-child.js';
|
|
43
|
+
export { GRID_SILENCED_CAP_NAMES, silenceAnalysisFor } from './silence-analysis.js';
|
|
44
|
+
export type { SilenceAnalysisDeps } from './silence-analysis.js';
|