import { EventEmitter } from "events"; import { type AudioStreamDemuxer, type AudioStreamDemuxerFactory } from "./audio-stream/demuxer.js"; import { type AudioStats } from "./zig-structs.js"; export interface AudioSetupOptions { autoStart?: boolean; sampleRate?: number; playbackChannels?: number; startOptions?: AudioStartOptions; } export interface AudioStartOptions { periodSizeInFrames?: number; periodSizeInMilliseconds?: number; periods?: number; performanceProfile?: number; shareMode?: number; noPreSilencedOutputBuffer?: boolean; noClip?: boolean; noDisableDenormals?: boolean; noFixedSizedCallback?: boolean; wasapiNoAutoConvertSrc?: boolean; wasapiNoDefaultQualitySrc?: boolean; alsaNoMMap?: boolean; alsaNoAutoFormat?: boolean; alsaNoAutoChannels?: boolean; alsaNoAutoResample?: boolean; } export interface AudioPlayOptions { volume?: number; pan?: number; loop?: boolean; groupId?: number; } export type AudioStreamBody = ReadableStream | AsyncIterable; export type AudioStreamFormat = "mp3" | "flac" | "pcm"; export interface AudioStreamContentTypeContext { readonly format: AudioStreamFormat; readonly contentType: string | null; readonly status: number; readonly url: string; } export type AudioStreamContentTypePolicy = "validate" | "ignore" | ((context: AudioStreamContentTypeContext) => boolean); export interface AudioStreamConnectContext { readonly signal: AbortSignal; readonly attempt: number; } export interface AudioStreamConnection { readonly body: AudioStreamBody; readonly info: I; close?(): void | Promise; } export type AudioStreamRetryPhase = "connect" | "read"; export interface AudioStreamRetryContext { readonly attempt: number; readonly maxRetries: number; readonly phase: AudioStreamRetryPhase; } export type AudioStreamRetryDecision = false | { readonly delayMs?: number; }; export interface AudioStreamConnector { connect(context: AudioStreamConnectContext): Promise>; } export interface AudioStreamBufferOptions { capacityMs?: number; startupMs?: number; resumeMs?: number; } export interface AudioStreamReconnectOptions { maxRetries?: number; initialDelayMs?: number; maxDelayMs?: number; backoffFactor?: number; retryOnEnd?: boolean; retry?(error: AudioStreamError, context: AudioStreamRetryContext): AudioStreamRetryDecision; } export interface AudioStreamOptions { format?: AudioStreamFormat; /** Required for raw PCM. Input consists of interleaved little-endian float32 samples. */ sampleFormat?: "f32le"; sampleRate?: number; channels?: 1 | 2; volume?: number; pan?: number; groupId?: number; maxProbeBytes?: number; buffer?: AudioStreamBufferOptions; signal?: AbortSignal; } export interface AudioStreamBodyOptions extends AudioStreamOptions { demuxer?: AudioStreamDemuxerFactory; contentTypePolicy?: never; request?: never; reconnect?: never; metadataEncoding?: never; } export interface AudioStreamSourceOptions extends AudioStreamOptions { demuxer?: (info: I) => AudioStreamDemuxer | null; reconnect?: AudioStreamReconnectOptions; contentTypePolicy?: never; request?: never; metadataEncoding?: never; } export interface AudioStreamUrlOptions extends AudioStreamOptions { request?: Omit; reconnect?: AudioStreamReconnectOptions; metadataEncoding?: string; contentTypePolicy?: AudioStreamContentTypePolicy; demuxer?: never; } export type AudioStreamState = "initializing" | "buffering" | "playing" | "reconnecting" | "ended" | "errored" | "disposed"; export interface AudioStreamStats { state: AudioStreamState; sampleRate: number; channels: number; bufferedFrames: number; capacityFrames: number; bufferedDurationMs: number; bytesReceived: bigint; framesDecoded: bigint; framesPlayed: bigint; underruns: number; reconnectAttempts: number; } export type AudioStreamMetadataFormat = "icy"; export interface AudioStreamMetadata { readonly format: AudioStreamMetadataFormat; readonly headers: Readonly>; readonly fields: Readonly>; } export type AudioStreamAction = "fetch" | "response" | "source" | "demuxer" | "create" | "write" | "end" | "restart" | "stats" | "decoder" | "destroy" | "setVolume" | "setPan" | "setGroup"; export interface AudioStreamErrorContext { action: AudioStreamAction; status?: number; errorCode?: number; attempt?: number; } export interface AudioStreamReconnectEvent { attempt: number; delayMs: number; maxRetries: number; error: AudioStreamError; } export interface AudioStreamEvents { metadata: [metadata: M | null]; reconnecting: [event: AudioStreamReconnectEvent]; ended: []; error: [error: Error, context: AudioStreamErrorContext]; disposed: []; } export type AudioGroup = number; export type AudioVoice = number; export type AudioSound = number; export interface AudioPlaybackDevice { index: number; name: string; isDefault: boolean; } export interface AudioCaptureDevice { index: number; name: string; isDefault: boolean; } export interface AudioCaptureOptions { channels?: number; capacityFrames?: number; startOptions?: AudioStartOptions; } export interface AudioCaptureStreamOptions extends AudioCaptureOptions { chunkFrames?: number; signal?: AbortSignal; } export type AudioCaptureStreamState = "initializing" | "capturing" | "stopping" | "stopped" | "errored" | "disposed"; export type AudioCaptureStreamAction = "start" | "read" | "stop" | "stats" | "destroy"; export interface AudioCaptureStreamErrorContext { action: AudioCaptureStreamAction; status?: number; } export interface AudioCaptureStreamEvents { stopped: []; error: [error: AudioCaptureStreamError, context: AudioCaptureStreamErrorContext]; disposed: []; } export interface AudioCaptureStats { sampleRate: number; channels: number; capacityFrames: number; bufferedFrames: number; framesReceived: bigint; framesRead: bigint; framesDropped: bigint; } export interface AudioCaptureStreamStats extends AudioCaptureStats { state: AudioCaptureStreamState; bufferedDurationMs: number; } export interface AudioCaptureReadResult { frames: Float32Array; framesRead: number; } export type AudioRecordToFileOptions = AudioCaptureStreamOptions; export type AudioRecorderState = "initializing" | "recording" | "stopping" | "stopped" | "errored" | "disposed"; export type AudioRecorderAction = "open" | "start" | "read" | "write" | "stop" | "finalize" | "publish" | "stats" | "destroy"; export interface AudioRecorderErrorContext { action: AudioRecorderAction; status?: number; } export interface AudioRecorderEvents { stopped: []; error: [error: AudioRecorderError, context: AudioRecorderErrorContext]; disposed: []; } export interface AudioRecorderStats extends AudioCaptureStats { state: AudioRecorderState; bufferedDurationMs: number; framesWritten: bigint; dataBytesWritten: bigint; durationMs: number; } export type AudioAction = "createAudioEngine" | "start" | "startMixer" | "stop" | "loadSound" | "loadSoundFile" | "unloadSound" | "group" | "play" | "stopVoice" | "setVoiceGroup" | "setGroupVolume" | "setMasterVolume" | "mixFrames" | "enableTap" | "readTapFrames" | "listPlaybackDevices" | "selectPlaybackDevice" | "clearPlaybackDeviceSelection" | "listCaptureDevices" | "selectCaptureDevice" | "clearCaptureDeviceSelection" | "startCapture" | "readCaptureFrames" | "getCaptureStats" | "stopCapture" | "getStats"; export interface AudioErrorContext { action: AudioAction; status?: number; } export interface AudioEvents { error: [error: Error, context: AudioErrorContext]; started: []; mixerStarted: []; captureStarted: []; captureStopped: []; stopped: []; disposed: []; } export type AudioInitializationAction = "resolveRenderLib" | "createAudioEngine" | "start"; export declare class AudioInitializationError extends Error { readonly action: AudioInitializationAction; readonly status?: number; constructor(action: AudioInitializationAction, message: string, status?: number, cause?: unknown); } export declare class AudioCaptureStreamError extends Error { readonly context: AudioCaptureStreamErrorContext; constructor(message: string, context: AudioCaptureStreamErrorContext, cause?: unknown); } export declare class AudioRecorderError extends Error { readonly context: AudioRecorderErrorContext; constructor(message: string, context: AudioRecorderErrorContext, cause?: unknown); } export declare class AudioStreamError extends Error { readonly context: AudioStreamErrorContext; constructor(message: string, context: AudioStreamErrorContext, cause?: unknown); } export declare class AudioStream extends EventEmitter> { readonly closed: Promise; readonly format: AudioStreamFormat; private readonly lib; private readonly engine; private readonly connector; private readonly demuxerFactory?; private readonly readAction; private readonly options; private readonly removeFromOwner; private readonly lifecycleController; private nativeStreamId; private nativeStats; private readyGeneration; private activeAttempt; private pendingCleanup; private reconnectAttempts; private consecutiveReconnectAttempts; private disposed; private exposed; private terminalError; private metadata; private pendingMetadataEvent; private metadataEventScheduled; private terminalEventScheduled; private setupResolve; private setupReject; private closedResolve; private readonly setupPromise; private readonly overallAbortListener; private constructor(); get state(): AudioStreamState; private open; getStats(): AudioStreamStats; getMetadata(): M | null; setVolume(volume: number): boolean; setPan(pan: number): boolean; setGroup(groupId: number): boolean; private control; dispose(): void; private runLifecycle; private createNativeStream; private consumeSource; private pumpSource; private processDemuxOutput; private writeStreamChunk; private resolveConnection; private beginResourceAcquisition; private cleanupAttempt; private performAttemptCleanup; private runBoundedAttemptCleanup; private retry; private awaitReady; private observeReady; private awaitEnded; private pollNativeSnapshot; private snapshotError; private finish; private publishMetadata; private emitMetadata; private emitAsync; private emitTerminal; private isAttemptActive; private stopSource; private closeNativeStream; private readNativeStats; private toPublicStats; private removeOwner; } export declare class AudioCaptureStream extends EventEmitter { readonly readable: ReadableStream; readonly sampleRate: number; readonly channels: number; readonly chunkFrames: number; readonly closed: Promise; private readonly init; private readonly lifecycleController; private streamController; private nativeStats; private currentState; private pendingFrames; private readonly pendingSamples; private producerStopAttempted; private producerStopped; private producerMayBeRunning; private ownerRemoved; private exposed; private terminal; private discardRequested; private discardDecisionScheduled; private pumpPromise; private producerCleanupPromise; private lastCleanupFailure; private terminalCompletionPromise; private closedResolve; private readonly signalAbortListener; private constructor(); get state(): AudioCaptureStreamState; private open; getStats(): AudioCaptureStreamStats; stop(): void; dispose(): void; private disposeInternal; private pull; private pump; private pumpSource; private discardNativeRing; private requestDiscardDrain; private scheduleDiscardIfIdle; private refreshStats; private observeProducer; private stopProducer; private finishStopped; private fail; private operationError; private cleanupProducer; private retryTerminalCleanup; private publicStats; private refreshFinalStats; private removeOwner; private emitTerminal; } export declare class AudioRecorder extends EventEmitter { private static readonly fileSystem; readonly filePath: string; readonly format: "wav"; readonly sampleRate: number; readonly channels: number; readonly closed: Promise; private readonly init; private currentState; private capture; private reader; private fileHandle; private tempPath; private captureStats; private framesWritten; private dataBytesWritten; private stopRequested; private terminal; private terminationRequest; private publicationStarted; private exposed; private ownerRemoved; private cleanupPromise; private resourceCleanupPromise; private retainedCleanupScheduled; private lifecyclePromise; private closedResolve; private readonly signalAbortListener; private readonly captureErrorListener; private constructor(); get state(): AudioRecorderState; private open; getStats(): AudioRecorderStats; stop(): void; dispose(): void; private consume; private writeSamples; private readWithStats; private complete; private publish; private fail; private requestTermination; private finishCleanup; private cleanupOwnedResources; private retryRetainedCleanup; private scheduleRetainedCleanup; private hasRetainedResources; private openTemporaryFile; private writeFully; private ensureOpening; private fromCaptureError; private removeOwner; private emitTerminal; } export declare class Audio extends EventEmitter { static create(options?: AudioSetupOptions): Audio; readonly sampleRate: number; private readonly lib; private readonly defaultStartOptions; private engine; private readonly groups; private readonly streams; private playbackStarted; private mixerStarted; private captureStarted; private captureDeviceOpen; private captureBufferAvailable; private captureChannels; private captureCapacityFrames; private captureOwner; private captureStream; private disposing; private constructor(); private throwAfterInitializationCleanup; private emitError; start(options?: AudioStartOptions): boolean; startMixer(): boolean; stop(): boolean; isStarted(): boolean; isMixerStarted(): boolean; loadSound(data: Uint8Array | ArrayBuffer): AudioSound | null; loadSoundFile(filePath: string): Promise; unloadSound(sound: AudioSound): boolean; group(name: string): AudioGroup | null; play(sound: AudioSound, options?: AudioPlayOptions): AudioVoice | null; playStream(source: AudioStreamBody, options?: AudioStreamBodyOptions): Promise>; playStreamUrl(source: string | URL, options?: AudioStreamUrlOptions): Promise>; playStreamSource(connector: AudioStreamConnector, options?: AudioStreamSourceOptions): Promise>; private openStream; stopVoice(voice: AudioVoice): boolean; setVoiceGroup(voice: AudioVoice, group: AudioGroup): boolean; setGroupVolume(group: AudioGroup, volume: number): boolean; setMasterVolume(volume: number): boolean; mixFrames(frameCount: number, channels?: number): Float32Array | null; enableTap(capacityFrames?: number): boolean; disableTap(): boolean; readTapFrames(frameCount: number, channels?: number): { frames: Float32Array; framesRead: number; } | null; listPlaybackDevices(): AudioPlaybackDevice[] | null; selectPlaybackDevice(index: number): boolean; clearPlaybackDeviceSelection(): void; openCapture(options?: AudioCaptureStreamOptions): Promise; recordToFile(filePath: string, options?: AudioRecordToFileOptions): Promise; listCaptureDevices(): AudioCaptureDevice[] | null; selectCaptureDevice(index: number): boolean; clearCaptureDeviceSelection(): void; startCapture(options?: AudioCaptureOptions): boolean; isCapturing(): boolean; private isCapturingInternal; readCaptureFrames(frameCount: number): AudioCaptureReadResult | null; getCaptureStats(): AudioCaptureStats | null; stopCapture(): boolean; private emitCaptureOwnershipError; private startCaptureInternal; private readCaptureInternal; private getCaptureStatsInternal; private stopCaptureInternal; getStats(): AudioStats | null; dispose(): void; } export declare function setupAudio(options?: AudioSetupOptions): Audio;