import { StreamingWord, TurnEvent } from "../../types/streaming";
import { Channel, VadFrame } from "../../types/streaming/dual-channel";
export type LabelMapperParams = {
    /** Per-word energy ratio above which a channel is declared dominant. */
    dominanceRatio: number;
};
/**
 * Append-only ring buffer of VAD frames in stream-relative ms order.
 * `pushFrame` is O(1) amortized; `framesInWindow` is O(n) over kept frames,
 * which is fine for the per-word lookups we do (a 30 s window at 50 frames/s
 * per channel × 2 channels = 3000 entries, scanned once per word).
 *
 * Runtime-agnostic — no DOM or Web Audio dependencies.
 */
export declare class VadTimeline {
    private readonly windowMs;
    private frames;
    private head;
    constructor(windowMs: number);
    pushFrame(frame: VadFrame): void;
    framesInWindow(startMs: number, endMs: number): VadFrame[];
    clear(): void;
}
/**
 * Decide which channel was dominant during a word's `[start, end]` window.
 *
 * - If no channel has any active VAD energy → `"unknown"`.
 * - If the top channel beats the runner-up by at least `dominanceRatio` → top channel.
 * - Else: top channel wins on absolute score; exact ties → `"unknown"`.
 */
export declare function attributeWord(word: StreamingWord, timeline: VadTimeline, params: LabelMapperParams): Channel;
/**
 * Duration-weighted majority of word channels. `"unknown"` if there are no
 * words, every word resolved to `"unknown"`, or two channels tie exactly.
 */
export declare function rollUpTurnChannel(words: StreamingWord[]): Channel;
/**
 * Mutate `turn` in place: write `turn.words[i].channel` for every word and set
 * `turn.channel` to the duration-weighted rollup.
 *
 * Returns `void` because the transcriber owns the `TurnEvent` ref and forwards
 * the same object to the customer listener — no need to allocate a copy.
 */
export declare function attributeTurn(turn: TurnEvent, timeline: VadTimeline, params: LabelMapperParams): void;
