Skip to main content

Quick start

import { EvePlayer } from '@admmedia/eveplayer';
import '@admmedia/eveplayer/style.css';

const container = document.getElementById('player-container')!;

const player = new EvePlayer(container, {
widescreen: true,
autoplay: false,
muted: false,
});

player.setSource({
sources: [{ src: 'https://example.com/video.mp4', type: 'video/mp4' }],
poster: 'https://example.com/poster.jpg',
});

player.on('play', () => console.log('Playing'));
player.on('timeupdate', ({ currentTime }) => console.log('Time:', currentTime));
player.on('error', (err) => console.error('Error:', err.category, err.code, err.message));

// When done (e.g. navigating away)
player.dispose();

widescreen: true gives the player a fixed 16:9 frame. Leave it out to let the box follow the video's own aspect ratio: Player sizing explains both.

What you get​

  • One class, EvePlayer, wrapping a single Video.js 8 Player. Consumers never touch Video.js directly (the public surface is the class plus the types re-exported from the package entry point).
  • A typed event bus: on / off / once over PlayerEventMap.
  • HLS / DASH / CMAF via @videojs/http-streaming with a custom "Auto" quality selector.

Loading streams​

// HLS
player.setSource({
sources: [{ src: 'https://example.com/master.m3u8', type: 'application/x-mpegURL' }],
});

// MPEG-DASH
player.setSource({
sources: [{ src: 'https://example.com/manifest.mpd', type: 'application/dash+xml' }],
});

// Poster-only / no video yet
player.setSource({ sources: [], poster: 'https://example.com/poster.jpg' });

setSource() is safe to call at any time; an empty sources array skips .src() entirely instead of raising a "source not supported" error.

Swapping to a different source​

Reloading a variant of what is already playing is just another setSource(). When the new source is a genuinely different stream, though (a pre-live placeholder handing over to the live stream, say, or a switch from progressive MP4 to HLS), call reset() first:

player.reset();
player.setSource({
sources: [{ src: 'https://example.com/live.m3u8', type: 'application/x-mpegURL' }],
});

Safari keeps a single playback engine across an in-place swap, and its native-to-VHS hand-off can race the segment loaders, leaving the player frozen on the last frame of the previous source. reset() clears the engine back to a sourceless state (without disposing the player) so the next setSource() loads from scratch. The viewer's volume and mute state are carried across.

MPEG-DASH on Safari (macOS): known to be unreliable, see Format support before relying on DASH there. Prefer an HLS source for Safari when both are available.

See Text tracks & captions for side-loading WebVTT subtitle or chapter files that are not embedded in the manifest.

Autoplay and muting​

Browsers only allow unattended playback when the video starts muted, so the usual pairing is autoplay: true with muted: true plus an unmute control of your own:

const player = new EvePlayer(container, { autoplay: true, muted: true });

// Your own "tap for sound" button
unmuteButton.addEventListener('click', () => {
player.muted = false;
});

muted is the initial state, not a standing instruction. Once the player is unmuted (through your control, through the control bar's own mute toggle, or by setting player.muted = false), it stays unmuted: loading another source, swapping a pre-live placeholder for the live stream, or otherwise rebuilding the underlying playback engine never silently restores the muted option the player was constructed with. The volume is preserved the same way as long as engine rebuilds go through reset().

Listen for volumechange to keep your own UI in step with either route:

player.on('volumechange', ({ volume, muted }) => updateUnmuteButton(muted, volume));

Cleanup​

Always call dispose() when the player leaves the page. It tears down Video.js, removes the DOM nodes it created, and clears every listener. It is safe to call more than once.