111 lines
2.7 KiB
TypeScript
111 lines
2.7 KiB
TypeScript
import { ConnectionData } from "../connection-data.ts";
|
|
import { FRAME_DURATION } from "../sample-consts.ts";
|
|
import { Player } from "./types.ts";
|
|
import { setDriftlessInterval, clearDriftless } from "npm:driftless";
|
|
import { PlayerEventSource, RawEventTypes, PlayerListener } from "./events.ts";
|
|
|
|
import { errorMessageCallback } from "../../../utils.ts";
|
|
|
|
export class RawPlayer implements Player<AsyncIterableIterator<Uint8Array>> {
|
|
#audio?: AsyncIterableIterator<Uint8Array>;
|
|
#interrupt?: AsyncIterableIterator<Uint8Array>;
|
|
playing = false;
|
|
conn: ConnectionData;
|
|
#events = new PlayerEventSource<
|
|
AsyncIterableIterator<Uint8Array>,
|
|
RawEventTypes
|
|
>();
|
|
|
|
constructor(conn: ConnectionData) {
|
|
this.conn = conn;
|
|
}
|
|
|
|
play() {
|
|
try {
|
|
if (this.playing) {
|
|
return;
|
|
}
|
|
this.playing = true;
|
|
|
|
const inter = setDriftlessInterval(async () => {
|
|
if (this.playing === false) {
|
|
clearDriftless(inter);
|
|
return;
|
|
}
|
|
const frame = await this.#getFrame();
|
|
if (frame === undefined) {
|
|
return;
|
|
}
|
|
this.conn.audio.trigger(frame);
|
|
}, FRAME_DURATION);
|
|
} catch(err) {
|
|
errorMessageCallback(this.conn.guildId, `The player broke for some reason: ${err}`);
|
|
console.log("error while playing!!");
|
|
console.error(err);
|
|
}
|
|
}
|
|
|
|
pause() {
|
|
this.playing = false;
|
|
}
|
|
|
|
stop() {
|
|
this.clear();
|
|
this.pause();
|
|
}
|
|
|
|
clear() {
|
|
if (this.#audio) {
|
|
this.#events.trigger("done", this.#audio);
|
|
}
|
|
this.#interrupt = undefined;
|
|
}
|
|
|
|
setAudio(audio: AsyncIterableIterator<Uint8Array>) {
|
|
this.#audio = audio;
|
|
this.#events.trigger("next", audio);
|
|
this.play();
|
|
}
|
|
|
|
interrupt(audio?: AsyncIterableIterator<Uint8Array>) {
|
|
this.#interrupt = audio;
|
|
if (!this.playing) {
|
|
this.play();
|
|
}
|
|
}
|
|
|
|
on<J extends RawEventTypes>(
|
|
event: J,
|
|
listener: PlayerListener<AsyncIterableIterator<Uint8Array>, J>
|
|
) {
|
|
return this.#events.on(event, listener);
|
|
}
|
|
|
|
async #getFrame() {
|
|
const interrupt = await this.#getNextFrame(this.#interrupt);
|
|
if (interrupt !== undefined) {
|
|
return interrupt;
|
|
}
|
|
const audio = await this.#getNextFrame(this.#audio);
|
|
if (audio === undefined) {
|
|
this.#handleAudioStopped();
|
|
}
|
|
return audio;
|
|
}
|
|
|
|
async #getNextFrame(source: AsyncIterableIterator<Uint8Array> | undefined) {
|
|
const nextResult = await source?.next();
|
|
return nextResult !== undefined && !nextResult?.done
|
|
? nextResult.value
|
|
: undefined;
|
|
}
|
|
|
|
#handleAudioStopped() {
|
|
if (this.#audio !== undefined) {
|
|
this.#events.trigger("done", this.#audio);
|
|
}
|
|
this.#audio = undefined;
|
|
this.playing = false;
|
|
}
|
|
}
|