import type { AudioFrame } from '@livekit/rtc-node';
import type { TypedEventEmitter as TypedEmitter } from '@livekit/typed-emitter';
import type { ReadableStream, ReadableStreamDefaultReader, WritableStreamDefaultWriter } from 'node:stream/web';
import type { VADMetrics } from './metrics/base.js';
import { DeferredReadableStream } from './stream/deferred_stream.js';
import { IdentityTransform } from './stream/identity_transform.js';
export declare enum VADEventType {
    START_OF_SPEECH = 0,
    INFERENCE_DONE = 1,
    END_OF_SPEECH = 2,
    METRICS_COLLECTED = 3
}
export interface VADEvent {
    /** Type of the VAD event (e.g., start of speech, end of speech, inference done). */
    type: VADEventType;
    /**
     * Index of the audio sample where the event occurred, relative to the inference sample rate.
     */
    samplesIndex: number;
    /** Timestamp (milliseconds since epoch) when the event was fired. */
    timestamp: number;
    /** Duration of the speech segment in milliseconds. */
    speechDuration: number;
    /** Duration of the silence segment in milliseconds. */
    silenceDuration: number;
    /**
     * List of audio frames associated with the speech.
     *
     * @remarks
     * - For `start_of_speech` events, this contains the audio chunks that triggered the detection.
     * - For `inference_done` events, this contains the audio chunks that were processed.
     * - For `end_of_speech` events, this contains the complete user speech.
     */
    frames: AudioFrame[];
    /** Probability that speech is present (only for `INFERENCE_DONE` events). */
    probability: number;
    /** Time taken to perform the inference, in milliseconds (only for `INFERENCE_DONE` events). */
    inferenceDuration: number;
    /** Indicates whether speech was detected in the frames. */
    speaking: boolean;
    /** Threshold used to detect silence. */
    rawAccumulatedSilence: number;
    /** Threshold used to detect speech. */
    rawAccumulatedSpeech: number;
}
export interface VADCapabilities {
    /** Duration of each VAD inference window in milliseconds. Used to batch metrics emissions to roughly once per second. */
    updateInterval: number;
}
export type VADCallbacks = {
    ['metrics_collected']: (metrics: VADMetrics) => void;
};
declare const VAD_base: new () => TypedEmitter<VADCallbacks>;
export declare abstract class VAD extends VAD_base {
    #private;
    abstract label: string;
    constructor(capabilities: VADCapabilities);
    get capabilities(): VADCapabilities;
    /**
     * Current `minSilenceDuration` floor in milliseconds, or `null` if the
     * VAD does not expose this knob.
     *
     * Consumed by `AudioRecognition` when a `TurnDetector` is active —
     * the EOT detector needs a wider silence window than typical VAD
     * defaults, so the floor is validated against this knob. Implementations
     * that don't support introspection should leave the default `null` return.
     */
    get minSilenceDuration(): number | null;
    /**
     * Returns a {@link VADStream} that can be used to push audio frames and receive VAD events.
     */
    abstract stream(): VADStream;
    close(): Promise<void>;
}
export declare abstract class VADStream implements AsyncIterableIterator<VADEvent> {
    protected static readonly FLUSH_SENTINEL: unique symbol;
    protected input: IdentityTransform<AudioFrame | typeof VADStream.FLUSH_SENTINEL>;
    protected output: IdentityTransform<VADEvent>;
    protected inputWriter: WritableStreamDefaultWriter<AudioFrame | typeof VADStream.FLUSH_SENTINEL>;
    protected inputReader: ReadableStreamDefaultReader<AudioFrame | typeof VADStream.FLUSH_SENTINEL>;
    protected outputWriter: WritableStreamDefaultWriter<VADEvent>;
    protected outputReader: ReadableStreamDefaultReader<VADEvent>;
    protected closed: boolean;
    protected inputClosed: boolean;
    protected vad: VAD;
    protected lastActivityTime: bigint;
    protected logger: import("pino").Logger;
    protected deferredInputStream: DeferredReadableStream<AudioFrame>;
    private metricsStream;
    constructor(vad: VAD);
    /**
     * Reads from the deferred input stream and forwards chunks to the input writer.
     *
     * Note: we can't just do this.deferredInputStream.stream.pipeTo(this.input.writable)
     * because the inputWriter locks the this.input.writable stream. All writes must go through
     * the inputWriter.
     */
    private pumpDeferredStream;
    protected monitorMetrics(): Promise<void>;
    /**
     * Safely send a VAD event to the output stream, handling writer release errors during shutdown.
     * @returns true if the event was sent, false if the stream is closing
     * @throws Error if an unexpected error occurs
     */
    protected sendVADEvent(event: VADEvent): boolean;
    updateInputStream(audioStream: ReadableStream<AudioFrame>): void;
    detachInputStream(): void;
    /** @deprecated Use `updateInputStream` instead */
    pushFrame(frame: AudioFrame): void;
    /**
     * Mark the end of the current segment.
     *
     * Implementations must treat this as a hard segment boundary: drop any accumulated
     * speech/silence state so the next pushed frame starts a fresh segment.
     */
    flush(): void;
    endInput(): void;
    next(): Promise<IteratorResult<VADEvent>>;
    close(): void;
    [Symbol.asyncIterator](): VADStream;
}
export {};
//# sourceMappingURL=vad.d.ts.map