37 lines
961 B
TypeScript
37 lines
961 B
TypeScript
const MAX_INTERPOLATION_SECONDS = 0.25;
|
|
|
|
export class ProgressClock {
|
|
#rafId: number | null = null;
|
|
#time = 0;
|
|
#stamp = 0;
|
|
|
|
constructor(
|
|
private getAudio: () => HTMLAudioElement | null,
|
|
private onProgress: (seconds: number) => void
|
|
) {}
|
|
|
|
#tick = (now: number) => {
|
|
const audio = this.getAudio();
|
|
if (!audio) return;
|
|
if (audio.currentTime !== this.#time) {
|
|
this.#time = audio.currentTime;
|
|
this.#stamp = now;
|
|
}
|
|
const elapsed = Math.min(MAX_INTERPOLATION_SECONDS, (now - this.#stamp) / 1000);
|
|
const smooth = this.#time + (audio.paused ? 0 : elapsed * audio.playbackRate);
|
|
this.onProgress(Math.min(smooth, Number.isFinite(audio.duration) ? audio.duration : smooth));
|
|
this.#rafId = requestAnimationFrame(this.#tick);
|
|
};
|
|
|
|
start() {
|
|
if (this.#rafId !== null) return;
|
|
this.#rafId = requestAnimationFrame(this.#tick);
|
|
}
|
|
|
|
stop() {
|
|
if (this.#rafId === null) return;
|
|
cancelAnimationFrame(this.#rafId);
|
|
this.#rafId = null;
|
|
}
|
|
}
|