import { isIOSorMacintoshTouchDevice } from "../utils"; import { Howl } from "howler"; export class ReadyEvent extends Event { constructor() { super("ready"); } } export class EndEvent extends Event { constructor() { super("end"); } } export class NothingEvent extends Event { readonly path: string; constructor(path: string) { super("nothing"); this.path = path; } } export class HowlAudioSource { readonly audio: Howl; readonly path: string; readyState: "init" | "loading" | "ready" | "destroyed"; isNothing: boolean; onReady?: () => void; onError?: (error: ErrorEvent) => void; onEnded?: () => void; onNothing?: () => void; constructor(path: string, extensions: string[]) { this.path = path; this.readyState = "init"; this.isNothing = false; this.onEnded = undefined; this.onError = undefined; this.onReady = undefined; this.onNothing = undefined; this.audio = new Howl({ src: extensions.map((extension) => `${path}${extension}`), html5: isIOSorMacintoshTouchDevice() ? false : true, // html5: false, preload: true, onload: (id) => { console.log("onload", id, path); this.readyState = "ready"; if (this.onReady != null) this.onReady(); }, onloaderror: (id, error) => { console.log("onloaderror", id, error, this.onError != null); this.isNothing = true; if (this.onNothing != null) this.onNothing(); }, onplayerror: (id, error) => { console.log("onplayerror", id, error, this.onError != null); if (this.onError != null) this.onError(error as ErrorEvent); }, onend: () => { if (this.onEnded != null) this.onEnded(); }, }); this.readyState = "loading"; } load() { // if (this.readyState !== "init") { // throw new Error(`duplicate load audio: ${this.path}`); // } if (this.audio.state() === "loaded") { this.readyState = "ready"; if (this.onReady != null) this.onReady(); return; } // this.audio.load(); } reset() { this.audio.stop(); this.audio.seek(0); } destroy() { this.readyState = "destroyed"; this.audio.unload(); } preparePlay() { this.audio.stop(); } }