Spaces:
Build error
Build error
| type AudioQueueEvent = 'stop' | 'empty-queue' | 'id-change'; | |
| interface AudioQueueStopDetail { | |
| event: AudioQueueEvent; | |
| id: string | null; | |
| } | |
| export type OnStoppedCallback = (detail: AudioQueueStopDetail) => void; | |
| export class AudioQueue { | |
| private audio: HTMLAudioElement; | |
| private queue: string[] = []; | |
| private current: string | null = null; | |
| private readonly _onEnded = () => this.next(); | |
| id: string | null = null; | |
| onStopped: OnStoppedCallback | null = null; | |
| constructor(audioElement: HTMLAudioElement) { | |
| this.audio = audioElement; | |
| this.audio.addEventListener('ended', this._onEnded); | |
| } | |
| setId(newId: string) { | |
| if (this.id === newId) return; | |
| this.#halt(); | |
| this.id = newId; | |
| this.onStopped?.({ event: 'id-change', id: newId }); | |
| } | |
| setPlaybackRate(rate: number) { | |
| this.audio.playbackRate = rate; | |
| } | |
| enqueue(url: string) { | |
| this.queue.push(url); | |
| // Auto-play if nothing is currently playing or loaded | |
| if (this.audio.paused && !this.current) { | |
| this.next(); | |
| } | |
| } | |
| play() { | |
| if (!this.current && this.queue.length > 0) { | |
| this.next(); | |
| } else { | |
| this.audio.play(); | |
| } | |
| } | |
| next() { | |
| this.current = this.queue.shift() ?? null; | |
| if (this.current) { | |
| this.audio.src = this.current; | |
| this.audio.play(); | |
| } else { | |
| this.#halt(); | |
| this.onStopped?.({ event: 'empty-queue', id: this.id }); | |
| } | |
| } | |
| stop() { | |
| this.#halt(); | |
| this.onStopped?.({ event: 'stop', id: this.id }); | |
| } | |
| destroy() { | |
| this.audio.removeEventListener('ended', this._onEnded); | |
| this.#halt(); | |
| this.onStopped = null; | |
| } | |
| /** | |
| * Pause audio and clear queue without firing onStopped. | |
| * Callers that need the callback should invoke it themselves. | |
| */ | |
| #halt() { | |
| this.audio.pause(); | |
| this.audio.currentTime = 0; | |
| this.audio.src = ''; | |
| this.queue = []; | |
| this.current = null; | |
| } | |
| } | |