one
Version:
One is a React framework for web, iOS, and Android apps.
206 lines (203 loc) • 5.92 kB
JavaScript
import { createPlayerEvents } from "./events.mjs";
import { assertCrossOrigin, assertFlag, assertPitchQuality, assertRate, assertSeconds, assertTolerance, assertVolume, normalizeSource, rateError, resolveUpdateInterval } from "./validate.mjs";
var AudioPlayer = class {
element;
playerId;
removed = false;
events;
buffering = false;
finished = false;
failure = null;
constructor(element, id, updateIntervalMs) {
this.element = element;
this.playerId = id;
this.events = createPlayerEvents(() => this.getStatus(), updateIntervalMs);
element.addEventListener("waiting", () => {
this.buffering = true;
});
element.addEventListener("playing", () => {
this.buffering = false;
this.failure = null;
});
element.addEventListener("canplay", () => {
this.buffering = false;
});
element.addEventListener("ended", () => {
this.finished = true;
});
element.addEventListener("error", () => {
this.failure = element.error?.message || "audio playback failed";
});
}
get id() {
return this.playerId;
}
get currentTime() {
this.assertUsable("currentTime");
return this.element.currentTime;
}
get duration() {
this.assertUsable("duration");
const duration = this.element.duration;
return Number.isFinite(duration) ? duration : 0;
}
get playing() {
this.assertUsable("playing");
return !this.element.paused && !this.element.ended;
}
get paused() {
this.assertUsable("paused");
return this.isLoaded && !this.playing;
}
get isLoaded() {
this.assertUsable("isLoaded");
return this.element.readyState >= 2;
}
get isBuffering() {
this.assertUsable("isBuffering");
return this.buffering;
}
get isAudioSamplingSupported() {
return false;
}
get loop() {
this.assertUsable("loop");
return this.element.loop;
}
set loop(value) {
this.assertUsable("loop");
assertFlag(value, "AudioPlayer.loop");
this.element.loop = value;
}
get muted() {
this.assertUsable("muted");
return this.element.muted;
}
set muted(value) {
this.assertUsable("muted");
assertFlag(value, "AudioPlayer.muted");
this.element.muted = value;
}
get volume() {
this.assertUsable("volume");
return this.element.volume;
}
set volume(value) {
this.assertUsable("volume");
assertVolume(value, "AudioPlayer.volume");
this.element.volume = value;
}
get playbackRate() {
this.assertUsable("playbackRate");
return this.element.playbackRate;
}
get shouldCorrectPitch() {
this.assertUsable("shouldCorrectPitch");
return this.element.preservesPitch;
}
set shouldCorrectPitch(value) {
this.assertUsable("shouldCorrectPitch");
assertFlag(value, "AudioPlayer.shouldCorrectPitch");
this.element.preservesPitch = value;
}
play() {
this.assertUsable("play");
this.finished = false;
const started = this.element.play();
if (started && typeof started.catch === "function") {
started.catch((error) => {
this.failure = error instanceof Error ? error.message : "audio playback failed";
});
}
}
pause() {
this.assertUsable("pause");
this.element.pause();
}
seekTo(seconds, toleranceMillisBefore, toleranceMillisAfter) {
this.assertUsable("seekTo");
assertSeconds(seconds, "AudioPlayer.seekTo");
if (toleranceMillisBefore !== void 0) {
assertTolerance(toleranceMillisBefore, "AudioPlayer.seekTo");
}
if (toleranceMillisAfter !== void 0) {
assertTolerance(toleranceMillisAfter, "AudioPlayer.seekTo");
}
this.finished = false;
this.element.currentTime = seconds;
if (!this.element.seeking) return Promise.resolve();
return new Promise((resolve) => {
this.element.addEventListener("seeked", () => resolve(), { once: true });
});
}
replace(source) {
this.assertUsable("replace");
const normalized = normalizeSource(source, "AudioPlayer.replace");
this.finished = false;
this.failure = null;
if (normalized.uri === void 0) {
this.element.removeAttribute("src");
} else {
this.element.src = normalized.uri;
}
this.element.load();
}
remove() {
if (this.removed) return;
this.removed = true;
this.events.removeAll();
this.element.pause();
this.element.removeAttribute("src");
this.element.load();
}
getStatus() {
this.assertUsable("getStatus");
return {
currentTime: this.currentTime,
didJustFinish: this.finished,
duration: this.duration,
error: this.failure,
id: this.playerId,
isBuffering: this.isBuffering,
isLoaded: this.isLoaded,
loop: this.loop,
mute: this.muted,
playbackRate: this.playbackRate,
playing: this.playing,
shouldCorrectPitch: this.shouldCorrectPitch
};
}
setPlaybackRate(rate, pitchCorrectionQuality) {
this.assertUsable("setPlaybackRate");
assertRate(rate, "AudioPlayer.setPlaybackRate");
if (pitchCorrectionQuality !== void 0) {
assertPitchQuality(pitchCorrectionQuality, "AudioPlayer.setPlaybackRate");
}
if (rate < 0 || rate > 2) throw rateError("AudioPlayer.setPlaybackRate");
this.element.playbackRate = rate;
}
addListener(event, listener) {
this.assertUsable("addListener");
return this.events.add(event, listener);
}
removeAllListeners() {
this.events.removeAll();
}
assertUsable(verb) {
if (this.removed) throw new Error(`AudioPlayer.${verb}: the player was removed`);
}
};
function createPlayer(source = null, options = {}) {
const normalized = normalizeSource(source, "Audio.createPlayer");
const updateIntervalMs = resolveUpdateInterval(options, "Audio.createPlayer");
assertCrossOrigin(options.crossOrigin, "Audio.createPlayer");
const element = new Audio();
element.preload = "auto";
if (options.crossOrigin !== void 0) element.crossOrigin = options.crossOrigin;
if (normalized.uri !== void 0) element.src = normalized.uri;
const id = `player-${AudioPlayerId.next++}`;
return new AudioPlayer(element, id, updateIntervalMs);
}
const AudioPlayerId = { next: 1 };
export { AudioPlayer, createPlayer };
//# sourceMappingURL=player.mjs.map