import { z } from 'zod';
import type { FrameFormat } from '../types/io.js';
export declare const DecoderStatsSchema: z.ZodObject<{
    inputFps: z.ZodNumber;
    outputFps: z.ZodNumber;
    avgDecodeTimeMs: z.ZodNumber;
    droppedFrames: z.ZodNumber;
}, z.core.$strip>;
export declare const DecoderSessionConfigSchema: z.ZodObject<{
    codec: z.ZodString;
    maxFps: z.ZodDefault<z.ZodNumber>;
    outputFormat: z.ZodDefault<z.ZodEnum<{
        jpeg: "jpeg";
        rgb: "rgb";
        bgr: "bgr";
        yuv420: "yuv420";
        gray: "gray";
    }>>;
    scale: z.ZodDefault<z.ZodNumber>;
    width: z.ZodOptional<z.ZodNumber>;
    height: z.ZodOptional<z.ZodNumber>;
    deviceId: z.ZodOptional<z.ZodNumber>;
    tag: z.ZodOptional<z.ZodString>;
}, z.core.$strip>;
export type Unsubscribe = () => void;
/**
 * Discriminator for `StreamSource.type`. Values that the broker
 * understands today:
 *
 * - `'rtsp'`     — pull mode. Broker connects to a `rtsp://` URL,
 *                   demuxes RTP, exposes raw RTP via `onVideoRtp`.
 * - `'rtmp'`     — pull mode. Broker connects to a `rtmp://` URL,
 *                   demuxes flv into AnnexB packets. No source RTP
 *                   available (RTMP carries no RTP), so the WebRTC
 *                   path falls back to AnnexB → writeVideoNals.
 *                   Reserved — implementation pending.
 * - `'push'`     — push mode. Provider addon delivers AnnexB packets
 *                   via `pushEncodedPacket()` (Reolink Baichuan,
 *                   Frigate event streams, etc.).
 * - `'push-rtp'` — push mode with raw RTP packets. Provider addon
 *                   delivers source RTP via `pushVideoRtp()` AND
 *                   AnnexB-equivalents via `pushEncodedPacket()` so
 *                   downstream consumers (decoder, restreamer) keep
 *                   working. Lets the WebRTC path use the H.265
 *                   repacketizer for push-mode H.265 streams. Reserved
 *                   — implementation pending.
 * - `'placeholder'` — silent black-image placeholder reader.
 *
 * String type instead of a literal union so addons remain free to
 * add new source types — the broker's switch statement falls through
 * to "data is pushed externally" for unknown values.
 */
export type StreamSourceType = 'rtsp' | 'rtmp' | 'push' | 'push-rtp' | 'rfc4571' | 'placeholder' | (string & {});
export interface StreamSource {
    readonly type: StreamSourceType;
    /** Stream URL — required for pull-based sources (rtsp, rtmp). Not used for push sources. */
    readonly url: string;
    readonly videoCodec?: string;
    readonly audioCodec?: string;
    readonly metadata?: Readonly<Record<string, unknown>>;
    /**
     * Push-source flag — when true, a stall in the input stream is
     * treated as a valid suspension (battery cameras intentionally go
     * silent between motion events) rather than an error. The broker
     * stops emitting the black-image placeholder and pauses the watchdog
     * until the next packet arrives. Default: false (legacy behaviour —
     * stall is an error).
     */
    readonly allowStall?: boolean;
}
export interface StreamSourceOption {
    readonly id: string;
    readonly label: string;
    readonly source: StreamSource;
    readonly resolution?: {
        readonly width: number;
        readonly height: number;
    };
    readonly primary?: boolean;
}
export interface EncodedPacket {
    readonly type: 'video' | 'audio';
    readonly data: Buffer;
    readonly pts: number;
    readonly dts: number;
    readonly keyframe: boolean;
    readonly codec: string;
    /**
     * `true` when the packet was synthesized by the broker's placeholder
     * pump (state-aware "RECONNECTING" / "SLEEPING" / etc. keyframes
     * pushed at 1Hz while no real RTP is flowing). Consumers that
     * accumulate per-stream codec state (sticky SPS/PPS, decoder config)
     * MUST treat these as throwaway: the placeholder is a different
     * resolution and parameter set than the live camera, so caching its
     * SPS/PPS and prepending them to real keyframes silently corrupts
     * the decoder state and freezes the WebRTC viewer on the last
     * placeholder until the consumer is re-created. Absent on packets
     * produced from real source data.
     */
    readonly isPlaceholder?: boolean;
}
/**
 * Audio metadata declared by push-source providers before they emit the
 * first audio `EncodedPacket`. Mirrors the slice of an SDP audio track
 * the broker actually consumes — `codec` is canonical lowercase
 * ('aac' | 'opus' | 'pcmu' | 'pcma' | ...).
 *
 * `extraData` carries codec-specific config bytes (e.g. AAC
 * AudioSpecificConfig) when the codec needs them at decoder-init time.
 */
export interface PushAudioInfo {
    readonly codec: string;
    readonly sampleRate: number;
    readonly channels: number;
    readonly extraData?: Uint8Array;
}
export interface DecodedFrame {
    readonly data: Buffer;
    readonly width: number;
    readonly height: number;
    readonly format: FrameFormat;
    readonly timestamp: number;
}
export interface DecodedAudioChunk {
    readonly data: Buffer;
    readonly sampleRate: number;
    readonly channels: number;
    readonly timestamp: number;
}
export interface DecodeOptions {
    readonly maxFps?: number;
    readonly format?: FrameFormat;
    readonly scale?: number;
    /**
     * Caller identity tag (Phase 10). Surfaced by `listClients` so
     * operators can tell who's holding the broker open. Short and stable:
     * `motion`, `detection`, `snapshot`, `webrtc:<sessionId>`,
     * `benchmark`. Missing tag → recorded as `'unknown'` with a broker-
     * side warn log.
     */
    readonly tag?: string;
}
export interface AudioSubscribeOptions {
    /** Caller identity tag. See DecodeOptions.tag. */
    readonly tag?: string;
}
export type BrokerStatus = 'idle' | 'connecting' | 'streaming' | 'error' | 'stopped';
export interface BrokerStats {
    readonly status: BrokerStatus;
    readonly inputFps: number;
    readonly decodeFps: number;
    readonly encodedSubscribers: number;
    readonly decodedSubscribers: number;
    readonly uptimeMs: number;
    /** Measured bitrate in kbps (averaged over 2s window) */
    readonly bitrateKbps: number;
    /** Time between last two keyframes in ms (IDR interval) */
    readonly idrIntervalMs: number;
    /** Detected video codec (h264, h265) */
    readonly codec?: string;
    /** Total bytes received since broker start */
    readonly totalBytes: number;
    /** Total encoded packets received since broker start */
    readonly packetCount: number;
    /** Number of connected RTSP restream clients */
    readonly rtspClients: number;
    /** Number of connected TCP pipe clients */
    readonly pipeClients: number;
    /** Pre-buffer configured duration in seconds */
    readonly preBufferSec: number;
    /** Pre-buffer actual buffered duration in ms */
    readonly preBufferMs: number;
    /** Pre-buffer packet count */
    readonly preBufferPackets: number;
    /**
     * Moleculer node id of the decoder provider currently servicing this
     * stream's decoded subscribers. `null` until the deferred decoder is
     * created (no decoded clients yet, or codec not detected).
     */
    readonly decoderNodeId: string | null;
    /**
     * Detected audio track parameters from the RTSP DESCRIBE / SDP. Null
     * when the stream has no audio track or the broker is still in cold
     * start. `supported` reflects whether the local native + ffmpeg-based
     * decoder pipeline can produce PCM chunks for downstream consumers
     * (audio-analyzer). When `false`, the codec is detected but skipped.
     */
    readonly audio?: {
        readonly codec: string;
        readonly sampleRate: number;
        readonly channels: number;
        readonly supported: boolean;
    } | null;
}
export interface IStreamBroker {
    readonly deviceId: string;
    readonly status: BrokerStatus;
    readonly suspended: boolean;
    start(source: StreamSource): Promise<void>;
    stop(): Promise<void>;
    /**
     * Push an encoded packet into the broker from an external source.
     *
     * Used by camera provider addons that deliver media data directly
     * (e.g. Reolink Baichuan protocol, Frigate event streams) instead
     * of exposing an RTSP URL for the broker to pull from.
     *
     * The broker fans out the packet to all consumers: pre-buffer, RTSP
     * restreamer, TCP pipe, decoder sessions, and encoded subscribers.
     */
    pushEncodedPacket(packet: EncodedPacket): void;
    /**
     * Push-source audio metadata. Push providers (Reolink Baichuan,
     * Frigate, etc.) call this BEFORE the first audio EncodedPacket so
     * the broker can wire the audio-codec capability — RTSP sources get
     * the same data from the SDP audio track. Repeat calls update the
     * declared codec; calling with `null` retracts (broker tears down
     * any audio decode session).
     *
     * Typical Reolink Baichuan audio: AAC-LC 16 kHz mono. Cameras that
     * push G.711 should still call this so the broker can bypass the
     * codec cap for the supported native codecs.
     */
    pushAudioInfo?(info: PushAudioInfo | null): void;
    /**
     * Push a raw video RTP packet from an external source (used by
     * `'push-rtp'`-typed sources, e.g. Reolink Baichuan adapter that
     * synthesizes RTP from its packetizer-friendly access units). The
     * broker fans out to `onVideoRtp` subscribers, including the
     * WebRTC server's H.265 repacketizer path.
     *
     * Sources that don't carry per-packet RTP MAY ignore this entirely
     * and call only `pushEncodedPacket`. Implementations are free to
     * be a no-op when no RTP subscribers exist.
     */
    pushVideoRtp?(rtpData: Buffer): void;
    onEncodedData(callback: (packet: EncodedPacket) => void): Unsubscribe;
    /**
     * Subscribe to source video RTP packets (raw on-wire bytes, before
     * depacketization). Used by the WebRTC server's H.265 path to feed
     * a packet-level repacketizer that preserves the original RTP header
     * layout — Chrome's HEVC depacketizer is sensitive to it.
     *
     * Sources that don't have an underlying RTP wire (e.g. Frigate event
     * streams that call `pushEncodedPacket`) MAY register zero callbacks
     * and emit nothing.
     */
    onVideoRtp(callback: (rtpData: Buffer) => void): Unsubscribe;
    /**
     * Codec parameter sets harvested from the camera's SDP (sprop-vps /
     * sprop-sps / sprop-pps). Cameras like Reolink high-profile streams
     * publish VPS/SPS/PPS only via SDP — Chrome's HEVC decoder needs them
     * to initialise. Returns null when the broker hasn't connected yet
     * or the camera ships param sets in-band.
     */
    getSdpParameterSets(): ReadonlyArray<Buffer> | null;
    /**
     * Subscribe to SDP-derived VPS/SPS/PPS deliveries. Fires once
     * synchronously if the broker already has them (late-subscriber
     * shape), and again every time `onVideoTrack` repopulates them on a
     * reader rebuild. Used by the WebRTC server's H.265 path so a
     * session created during the wake-up window — when
     * `getSdpParameterSets()` still returns null — can seed its
     * `H265Repacketizer` once the camera's first RTP+SDP arrive.
     */
    onSdpParameterSets(callback: (ps: ReadonlyArray<Buffer>) => void): Unsubscribe;
    /**
     * Source type as configured at `start()` — see `StreamSourceType`
     * for the supported values. `null` before `start()` resolves.
     */
    getSourceType(): StreamSourceType | null;
    /**
     * True when the broker can emit source RTP packets via
     * `onVideoRtp` — i.e. the source is RTSP (pull) or push-rtp.
     * RTMP and bare push (AnnexB-only) sources return false.
     * Routing decisions in the WebRTC server (e.g. "use the H.265
     * repacketizer") should consult this rather than string-comparing
     * the source type.
     */
    isRtpSource(): boolean;
    /**
     * Subscribe to decoded frames. Phase 10 added `options.tag` — a short
     * caller-identity string (`motion`, `detection`, `snapshot`,
     * `webrtc:<sessionId>`, `benchmark`) used by `listClients` so
     * operators can see who is holding the broker open. Omitted tag
     * yields a `'unknown'` entry with a warn log — not silently accepted.
     */
    onDecodedFrame(callback: (frame: DecodedFrame) => void, options?: DecodeOptions): Unsubscribe;
    /** Subscribe to decoded audio chunks. `options.tag` mirrors `onDecodedFrame`. */
    onDecodedAudioChunk(callback: (chunk: DecodedAudioChunk) => void, options?: AudioSubscribeOptions): Unsubscribe;
    getStats(): BrokerStats;
    getLocalStreamUrl(): string;
    /** Get the pre-buffer: recent encoded packets starting from last keyframe. */
    getPreBuffer(): readonly EncodedPacket[];
    /** Set the pre-buffer duration in seconds (0 to disable, max 30). */
    setPreBufferDuration(seconds: number): void;
    /** Get the current pre-buffer duration in seconds. */
    getPreBufferDuration(): number;
    setPreBufferEnabled(enabled: boolean): void;
}
/**
 * Manager for stream brokers — the server interacts with this interface,
 * while the concrete implementation lives in the addon-stream-broker package.
 */
/** Per-broker RTSP restream entry (absorbed from the former rtsp-restream capability). */
export interface RtspRestreamEntry {
    readonly brokerId: string;
    readonly url: string;
    readonly mutedUrl: string;
    readonly enabled: boolean;
}
/** Flat cap-shaped broker record returned by `listBrokers()`. */
export interface BrokerListEntry {
    readonly brokerId: string;
    readonly status: string;
    readonly inputFps: number;
    readonly decodeFps: number;
    readonly encodedSubscribers: number;
    readonly decodedSubscribers: number;
    readonly uptimeMs: number;
    readonly bitrateKbps: number;
    readonly idrIntervalMs: number;
    readonly codec?: string;
    readonly totalBytes: number;
    readonly packetCount: number;
    readonly rtspClients: number;
    readonly pipeClients: number;
    readonly preBufferSec: number;
    readonly preBufferMs: number;
    readonly preBufferPackets: number;
}
/**
 * Phase the runner's per-camera state machine occupies. `'idle'` is the
 * `detectionMode === 'disabled'` resting state — runner registered the
 * camera but never subscribed to detection frames. The other 4 are the
 * historical motion-gated states; their transitions are now driven by
 * `detectionMode` ('always-on' starts in 'active', 'on-motion' starts
 * in 'watching').
 */
export type CameraPhase = 'idle' | 'watching' | 'active' | 'paused' | 'load-shed';
export interface CameraDetectionConfig {
    readonly enabled: boolean;
    readonly pipelineEnabled: boolean;
    /** Motion sources that activate this camera's pipeline. At least one. */
    readonly motionSources: import('./pipeline-orchestrator-capability.js').OrchestrationMotionSources;
    readonly motionStreamId: string;
    readonly detectionStreamId: string;
    readonly motionFps: number;
    readonly detectionFps: number;
    readonly motionCooldownMs: number;
    readonly audioStreamId?: string;
    /**
     * Operator-facing scheduling modes. Forwarded to `RunnerCameraConfig`;
     * the runner uses these to gate its substream subscribers + phase
     * machine. See `PipelinePhaseMode` for the semantics.
     */
    readonly detectionMode: import('../device/device-profile.js').PipelinePhaseMode;
    readonly audioMode: import('../device/device-profile.js').PipelinePhaseMode;
}
//# sourceMappingURL=stream-broker.d.ts.map