import type { ProtectLogging } from "../logging.ts"; import type { ProtectWritableWebSocket } from "./ws.ts"; /** * The deterministic lifecycle of a talkback session. The transitions are: construction begins connecting (`connecting`); WebSocket `open` advances to `live` (and the * static `connect()`'s promise resolves); an error, the caller's abort, or an explicit `close()` requests a graceful close and moves to `closing`; the socket fully * closing and the owned agent being destroyed is `closed`, which a peer-initiated close reaches directly without passing through `closing`. There is no `handshaking` * arm - talkback has no init segment. * * @category Transport */ export type TalkbackState = "closed" | "closing" | "connecting" | "live"; /** * Construction options for {@link TalkbackSession}. * * - `cameraId` is the camera whose speaker receives the audio - the only negotiation param. * - `resolveUrl` is the negotiation hook, identical in type to {@link LivestreamSession}'s: given the request params it returns the controller-minted, host-rewritten * WebSocket URL. The composition root wires it to a transport-backed GET (see `talkbackUrlResolver`); tests pass a one-line fake. * - `webSocket` is the injected I/O dependency - the write-direction `ProtectWritableWebSocket`, distinct from the receive-direction interface {@link EventStream} / * {@link LivestreamSession} share; omit it for the default undici-backed factory, inject it in tests. * - `signal` cancels the connect attempt and, once live, the session - if it aborts, the session tears down and an in-flight `send` rejects. * - `verifyTls` opts the owned agent into strict TLS certificate verification; it defaults to `false` for the controller's self-signed certificate. An injected * `webSocket` factory builds no agent here, so the option is inert alongside one. * * @category Transport */ export interface TalkbackSessionOptions { cameraId: string; log?: ProtectLogging; resolveUrl: (params: URLSearchParams, opts: { signal?: AbortSignal; }) => Promise; signal?: AbortSignal; verifyTls?: boolean; webSocket?: (url: string) => ProtectWritableWebSocket; } /** * One talkback WebSocket, write-only. Constructed atomically via the static `connect()` (the constructor is private): it negotiates the URL, opens the socket, and * resolves to a live session or throws a typed `ProtectError` - there is no half-open session. Feed it audio with {@link TalkbackSession.send} and dispose it (or abort * its signal) to close. * * @category Transport */ export declare class TalkbackSession implements AsyncDisposable { #private; private constructor(); /** * Open a talkback session and wait for it to connect. Atomic: it negotiates the WebSocket URL, opens the socket, and returns a live session, or throws a typed * `ProtectError` - there is no half-open session a caller must clean up. * * @param options - The session options. * * @returns A connected {@link TalkbackSession}. * * @throws {@link ProtectUnsupportedError} is not thrown here (the capability guard lives on `Camera.talkback`); negotiation surfaces the classified `FatalError` on a * non-2xx (typically {@link ProtectRequestError}), a {@link ProtectNetworkError} when the socket fails to open, and {@link ProtectAbortedError} when the caller's * signal aborts the connect. */ static connect(options: TalkbackSessionOptions): Promise; /** The session's current lifecycle state, for diagnostics and tests. */ get state(): TalkbackState; /** * Drain a consumer-supplied audio source to the camera speaker. The single write entry: it sends each `Uint8Array` and pulls the next as fast as the source yields it, * so a real-time, producer-paced source streams at its own rate with no buffer growth. Resolves when the source is * exhausted; rejects with a typed {@link ProtectError} if the socket errors or closes mid-drain, if the caller's `signal` aborts, or if the socket's send buffer * crosses the `PROTECT_TALKBACK_MAX_BUFFERED_BYTES` safety ceiling (a non-real-time source the wire cannot keep up with). The bytes are opaque - whatever audio * format the camera expects (read `camera.config.talkbackSettings`); the library neither inspects nor transcodes them. * * @param source - The audio source to drain. A Node `Readable` (e.g. `ffmpeg.stdout`) is an `AsyncIterable` and feeds in directly. * @param opts - An optional abort signal that ends this drain. * * @returns A promise that resolves when the source is exhausted. * * @throws {@link ProtectNetworkError} on a socket failure mid-drain, a buffer-ceiling overrun, or a call made while the session is not live (never * connected, or already closed/faulted); {@link ProtectAbortedError} when the per-send `opts.signal` aborts, the session's own caller signal aborts * mid-drain, or when send() is called after an earlier caller-signal abort already tore the session down; any error the source itself raises * propagates unwrapped. */ send(source: AsyncIterable, opts?: { signal?: AbortSignal; }): Promise; /** * Close the session: request the WebSocket close, detach every listener, and destroy the owned agent. Safe to call more than once, and awaitable. An in-flight {@link * TalkbackSession.send} rejects. */ close(): Promise; /** * Dispose the session. Delegates to {@link TalkbackSession.close} so `await using session = ...` tears the socket down cleanly. */ [Symbol.asyncDispose](): Promise; } //# sourceMappingURL=talkback-session.d.ts.map