import type { EventKind, SessionEvent } from "@a4anthony/proctorkit-types"; /** * Shared core behind `playAudioFile()` and `playVideoFile()`. Everything * here operates on `HTMLMediaElement` — playback lifecycle, terminal-state * tracking, audio output (sink) routing with devicechange monitoring, and * privacy-safe payloads. The thin `AudioFilePlayer` / `VideoFilePlayer` * subclasses pin down the element type, the emitted event-kind prefix, and * user-facing error wording. */ export type MediaPlaybackKindPrefix = "audio-playback" | "video-playback"; export interface MediaFilePlaybackOptions { /** URL of the media file to play. Query strings are omitted from emitted events. */ url: string | URL; /** Optional reviewer-friendly label, for example "Question 5 listening audio". */ label?: string; /** * Optional existing media element. Pass this when your app renders native * controls and wants the SDK helper to attach telemetry to that element. */ element?: TElement; /** Start playback immediately. Default: true. */ autoplay?: boolean; loop?: boolean; volume?: number; playbackRate?: number; /** * Optional audio output device id. When supported, the helper calls * HTMLMediaElement.setSinkId() before playback so prompts route * through the candidate's selected speaker/headphones. */ sinkId?: string; onStarted?: (payload: SessionEvent["payload"]) => void; onPaused?: (payload: SessionEvent["payload"]) => void; onEnded?: (payload: SessionEvent["payload"]) => void; onStopped?: (payload: SessionEvent["payload"]) => void; onError?: (error: Error, payload: SessionEvent["payload"]) => void; } export interface MediaFilePlaybackHandle { readonly url: string; readonly element: TElement; play(): Promise; pause(): void; stop(): void; seek(seconds: number): void; setSinkId(sinkId?: string | null): Promise; dispose(): void; } /** Client-internal hooks threaded in by ProctoringClient. */ export interface MediaFilePlayerHooks { emit?: (kind: EventKind, payload: SessionEvent["payload"]) => void; onDisposed?: (player: MediaFilePlaybackHandle) => void; } export interface MediaFilePlayerConfig { kindPrefix: MediaPlaybackKindPrefix; mediaNoun: "Audio" | "Video"; createElement: () => TElement; } export declare class MediaFilePlayer implements MediaFilePlaybackHandle { readonly url: string; readonly element: TElement; private readonly kindPrefix; private readonly mediaNoun; private readonly safeUrl; private readonly label; private readonly createdElement; private readonly emit; private readonly onStarted; private readonly onPaused; private readonly onEnded; private readonly onStopped; private readonly onError; private readonly onDisposed; private sinkId; private sinkReady; private monitoringDeviceChanges; private deviceChangeCheck; private disposed; private suppressNextPause; private terminalState; private hasStarted; constructor(options: MediaFilePlaybackOptions & MediaFilePlayerHooks, config: MediaFilePlayerConfig); play(): Promise; pause(): void; stop(): void; seek(seconds: number): void; setSinkId(sinkId?: string | null): Promise; dispose(): void; private assertActive; private readonly handlePlay; private readonly handlePause; private readonly handleEnded; private readonly handleElementError; private emitError; private ensureSinkReady; private setAudioSink; private syncDeviceChangeMonitor; private stopDeviceChangeMonitor; private readonly handleDeviceChange; private checkSelectedSinkAvailability; private payload; } //# sourceMappingURL=media-file-player.d.ts.map