mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2026-08-29 16:19:36 +01:00
[MIRROR] ports 516 audio player from cmss (#10259)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
co-authored by
Kashargul
parent
0c363559ee
commit
29263ae8fc
@@ -8,117 +8,93 @@ import { createLogger } from 'tgui/logging';
|
||||
|
||||
const logger = createLogger('AudioPlayer');
|
||||
|
||||
type CustomAudioElement = HTMLAudioElement & { stop: Function };
|
||||
type AudioOptions = {
|
||||
pitch?: number;
|
||||
start?: number;
|
||||
end?: number;
|
||||
};
|
||||
|
||||
export class AudioPlayer {
|
||||
node: CustomAudioElement;
|
||||
playing: boolean;
|
||||
element: HTMLAudioElement | null;
|
||||
options: AudioOptions;
|
||||
volume: number;
|
||||
options: { pitch?: number; start?: number; end?: number };
|
||||
onPlaySubscribers: Function[];
|
||||
onStopSubscribers: Function[];
|
||||
playbackInterval: NodeJS.Timeout;
|
||||
|
||||
onPlaySubscribers: { (): void }[];
|
||||
onStopSubscribers: { (): void }[];
|
||||
|
||||
constructor() {
|
||||
// Set up the HTMLAudioElement node
|
||||
this.node = document.createElement('audio') as CustomAudioElement;
|
||||
this.node.style.setProperty('display', 'none');
|
||||
document.body.appendChild(this.node);
|
||||
// Set up other properties
|
||||
this.playing = false;
|
||||
this.volume = 1;
|
||||
this.options = {};
|
||||
this.element = null;
|
||||
|
||||
this.onPlaySubscribers = [];
|
||||
this.onStopSubscribers = [];
|
||||
// Listen for playback start events
|
||||
this.node.addEventListener('canplaythrough', () => {
|
||||
logger.log('canplaythrough');
|
||||
this.playing = true;
|
||||
this.node.playbackRate = this.options.pitch || 1;
|
||||
this.node.currentTime = this.options.start || 0;
|
||||
this.node.volume = this.volume;
|
||||
this.node.play();
|
||||
for (let subscriber of this.onPlaySubscribers) {
|
||||
subscriber();
|
||||
}
|
||||
});
|
||||
// Listen for playback stop events
|
||||
this.node.addEventListener('ended', () => {
|
||||
logger.log('ended');
|
||||
this.stop();
|
||||
});
|
||||
// Listen for playback errors
|
||||
this.node.addEventListener('error', (e) => {
|
||||
if (this.playing) {
|
||||
logger.log('playback error', e.error);
|
||||
this.stop();
|
||||
}
|
||||
});
|
||||
// Check every second to stop the playback at the right time
|
||||
this.playbackInterval = setInterval(() => {
|
||||
if (!this.playing) {
|
||||
return;
|
||||
}
|
||||
const shouldStop =
|
||||
this.options.end &&
|
||||
this.options.end > 0 &&
|
||||
this.node.currentTime >= this.options.end;
|
||||
if (shouldStop) {
|
||||
this.stop();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (!this.node) {
|
||||
return;
|
||||
}
|
||||
this.node.stop();
|
||||
document.removeChild(this.node);
|
||||
clearInterval(this.playbackInterval);
|
||||
this.element = null;
|
||||
}
|
||||
|
||||
play(url, options = {}) {
|
||||
if (!this.node) {
|
||||
return;
|
||||
play(url: string, options: AudioOptions = {}) {
|
||||
if (this.element) {
|
||||
this.stop();
|
||||
}
|
||||
logger.log('playing', url, options);
|
||||
this.options = options;
|
||||
this.node.src = url;
|
||||
|
||||
const audio = (this.element = new Audio(url));
|
||||
audio.volume = this.volume;
|
||||
audio.playbackRate = this.options.pitch || 1;
|
||||
|
||||
logger.log('playing', url, options);
|
||||
|
||||
audio.addEventListener('ended', () => {
|
||||
logger.log('ended');
|
||||
this.stop();
|
||||
});
|
||||
|
||||
audio.addEventListener('error', (error) => {
|
||||
logger.log('playback error', error);
|
||||
});
|
||||
|
||||
if (this.options.end) {
|
||||
audio.addEventListener('timeupdate', () => {
|
||||
if (
|
||||
this.options.end &&
|
||||
this.options.end > 0 &&
|
||||
audio.currentTime >= this.options.end
|
||||
) {
|
||||
this.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
audio.play();
|
||||
|
||||
this.onPlaySubscribers.forEach((subscriber) => subscriber());
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (!this.node) {
|
||||
return;
|
||||
}
|
||||
if (this.playing) {
|
||||
for (let subscriber of this.onStopSubscribers) {
|
||||
subscriber();
|
||||
}
|
||||
}
|
||||
if (!this.element) return;
|
||||
|
||||
logger.log('stopping');
|
||||
this.playing = false;
|
||||
this.node.src = '';
|
||||
|
||||
this.element.pause();
|
||||
this.element = null;
|
||||
|
||||
this.onStopSubscribers.forEach((subscriber) => subscriber());
|
||||
}
|
||||
|
||||
setVolume(volume) {
|
||||
if (!this.node) {
|
||||
return;
|
||||
}
|
||||
setVolume(volume: number): void {
|
||||
this.volume = volume;
|
||||
this.node.volume = volume;
|
||||
|
||||
if (!this.element) return;
|
||||
|
||||
this.element.volume = volume;
|
||||
}
|
||||
|
||||
onPlay(subscriber) {
|
||||
if (!this.node) {
|
||||
return;
|
||||
}
|
||||
onPlay(subscriber: () => void): void {
|
||||
this.onPlaySubscribers.push(subscriber);
|
||||
}
|
||||
|
||||
onStop(subscriber) {
|
||||
if (!this.node) {
|
||||
return;
|
||||
}
|
||||
onStop(subscriber: () => void): void {
|
||||
this.onStopSubscribers.push(subscriber);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user