import { WasmBindings } from "../wasm/bindings"; import { AudioTrack } from "../types"; /** * Browser-agnostic PCM frame. Avoids the WebCodecs AudioData constructor, * which Firefox on Android does not implement. */ export interface PCMFrame { planes: Float32Array[]; numberOfFrames: number; numberOfChannels: number; sampleRate: number; timestamp: number; } export declare class SoftwareAudioDecoder { private bindings; private onData; private onError; private onBroken; private isConfigured; private trackIndex; private _downmix; private consecutiveFailures; private isBroken; private static readonly MAX_CONSECUTIVE_FAILURES; private coalesceTarget; private pending; private pendingSamples; constructor(bindings: WasmBindings); setDownmix(downmix: boolean): void; setOnData(callback: (frame: PCMFrame) => void): void; setOnError(callback: (error: Error) => void): void; /** * Fires once when the failure circuit-breaker trips. Being broken is not * necessarily terminal — the packet stream can be misaligned rather than the * decoder being wrong (a mid-playback rendition swap, a demuxer replaced under * the pump) — and re-aligning the source recovers it, which is exactly what a * manual seek used to do by hand. Without this hook the player had no way to * know it had gone silent, so it stayed silent for the rest of the video. */ setOnBroken(callback: () => void): void; /** Whether the circuit-breaker has tripped (no packets are being decoded). */ isDisabled(): boolean; configure(track: AudioTrack): Promise; flush(): Promise; reset(): void; close(): void; decode(data: Uint8Array, timestamp: number, keyframe: boolean): void; /** * Decode many packets in ONE WASM round-trip. * * decode() above costs ~8 JS→WASM crossings and a typed-array copy per channel * for EVERY packet. TrueHD/MLP emits a 40-sample access unit (~0.8 ms), so a * second of audio is ~1200 packets → ~9600 crossings and ~2400 tiny * allocations. That per-packet overhead — not the decode math — is what leaves * the renderer dry after a seek. Here the whole batch crosses once and the PCM * comes back as one contiguous block: one copy per channel, total. * * Returns the number of packets CONSUMED. If that's less than you passed, the * block ended early at a format change or pts discontinuity — the accumulated * audio has been enqueued; call again with the remaining packets. */ decodeBatch(packets: { data: Uint8Array; pts: number; }[]): number; private processDecodedFrame; /** * Coalesce tiny decoded frames (TrueHD/DTS emit ~40 samples each) into ~30ms * buffers before handing them to the renderer, so its per-frame scheduler * doesn't click on every boundary. Frames already at/above the target (AC-3, * E-AC-3, AAC in software) pass straight through with no added latency. */ private enqueueFrame; private flushPending; private mergePending; get configured(): boolean; } //# sourceMappingURL=SoftwareAudioDecoder.d.ts.map