UNPKG

icecast-metadata-player

Version:

Simple to use Javascript class that plays an Icecast stream with real-time metadata updates

115 lines (89 loc) 2.63 kB
import { state, event, fireEvent, NOT_SYNCED } from "../global.js"; import Player from "./Player.js"; export default class HTML5Player extends Player { constructor(icecast, endpoint) { super(icecast, endpoint); this._audioElement.crossOrigin = "anonymous"; this._audioElement.preload = "none"; this._icecast.addEventListener(event.STREAM_START, () => { if (!this._playReady) this.end(); }); this._init(); } static canPlayType(mimeType) { if (!HTML5Player.isSupported) return ""; return super.canPlayType((type) => new Audio().canPlayType(type), mimeType); } static get isSupported() { return Boolean(window.Audio); } static get name() { return "html5"; } get isAudioPlayer() { return true; } get metadataTimestamp() { return this._frame ? (this._frame.totalDuration + this._metadataTimestampOffset) / 1000 : 0; } get currentTime() { return ( this._audioLoadedTimestamp && (performance.now() - this._audioLoadedTimestamp) / 1000 ); } get waiting() { return new Promise((resolve) => { this._audioElement.addEventListener("waiting", resolve, { once: true }); }); } async _init() { super._init(); this._frame = null; this._audioLoadedTimestamp = 0; this._metadataTimestampOffset = 0; this._playReady = false; } async start(metadataOffset) { const playing = super.start(metadataOffset); this._metadataLoadedTimestamp = performance.now(); this._audioElement.loop = false; this._audioElement.src = null; this._audioElement.srcObject = null; this._audioElement.src = this._endpoint; if ( this._icecast.state !== state.STOPPING && this._icecast.state !== state.STOPPED ) { this._audioElement.addEventListener( "playing", () => { this._audioLoadedTimestamp = performance.now(); this._metadataTimestampOffset = performance.now() - this._metadataLoadedTimestamp; this._startMetadataQueues(); this._icecast[fireEvent](event.PLAY); }, { once: true }, ); this._icecast[fireEvent](event.PLAY_READY); this._playReady = true; } await playing; } async end() { super.end(); this._audioElement.src = null; this._audioElement.srcObject = null; this._init(); } onStream(frames) { this._frame = frames[frames.length - 1] || this._frame; if (this.syncState === NOT_SYNCED) { // syncing not implemented in html5 playback method this.syncState = NOT_SYNCED; } } }