/**
 * AudioBridge — the audio leg of a single call.
 *
 * Joins three things for one `callSid`:
 *   1. the microphone (`getUserMedia`),
 *   2. an `AudioWorklet` that does the μ-law 8 kHz transcoding + resampling
 *      (see `audio-worklet.ts`), and
 *   3. the audio WebSocket to the Audin service.
 *
 * Data flow:
 *   mic → AudioContext source → worklet → (μ-law bytes) → WS binary frame
 *   WS binary frame → (μ-law bytes) → worklet → AudioContext destination → 🔊
 *
 * Control (mute / DTMF / hangup) is sent as JSON text frames on the same WS.
 *
 * The bridge owns the lifecycle of everything it creates and tears it ALL
 * down on `close()` (mic tracks stopped, worklet disconnected, context closed,
 * socket closed) so a call leak can't keep the microphone hot.
 *
 * No provider names appear anywhere here — it is just "audio over a WebSocket".
 */
import type { OperatorLogger } from "./types.js";
/** Reason strings the bridge reports to its `onClosed` callback. */
export type BridgeCloseReason = "local_hangup" | "remote_close" | "ws_error" | "mic_error" | "teardown";
export interface AudioBridgeOptions {
    /** `wss://…/operator-audio/ws/:callSid?token=…` — already fully formed. */
    audioWsUrl: string;
    /** Microphone constraints for `getUserMedia`. */
    audioConstraints: MediaTrackConstraints;
    logger: OperatorLogger;
    /** Called once when the bridge finishes tearing down (any reason). */
    onClosed: (reason: BridgeCloseReason) => void;
}
export declare class AudioBridge {
    private readonly opts;
    private ws;
    private audioContext;
    private micStream;
    private sourceNode;
    private workletNode;
    private blobUrl;
    private closed;
    private muted;
    constructor(opts: AudioBridgeOptions);
    /**
     * Open the WS, capture the mic, load the worklet and wire the graph. Resolves
     * once audio is flowing both ways (or throws on a fatal setup error, having
     * already torn down whatever was partially created).
     */
    start(): Promise<void>;
    /** Mute / unmute the operator microphone toward the far end. */
    setMuted(on: boolean): void;
    get isMuted(): boolean;
    /**
     * Send a DTMF digit as a control message.
     *
     * Note: not yet honored end-to-end — the server does not currently forward
     * the tones onto the telephone network, so this is a functional no-op for
     * the far end today (the control message itself stays valid for the future).
     */
    sendDtmf(digit: string): void;
    /** Tell the server to hang up, then tear down locally. */
    hangup(): void;
    /**
     * Tear down everything this bridge created. Idempotent. Fires `onClosed`
     * exactly once with the FIRST reason it was closed with.
     */
    close(reason: BridgeCloseReason): void;
    private openSocket;
    private onWsMessage;
    private setupAudioGraph;
    private sendAudio;
    private sendControl;
}
