Skip to content

Events API Documentation ​

MediaFox provides a comprehensive event system that allows you to respond to various player states and user interactions. This document details all available events and their usage.

Event System Overview ​

MediaFox's event system is built on a type-safe EventEmitter that:

  • Supports all standard HTML media events
  • Provides MediaFox-specific events for advanced functionality
  • Includes proper TypeScript typing for all events
  • Implements memory leak protection
  • Supports event listener limits and cleanup

Core Playback Events ​

play ​

Fired when playback starts.

typescript
player.on('play', () => {
  console.log('Playback started');
  updatePlayButton('pause');
});

When fired:

  • When player.play() is called and playback begins
  • After seeking completes and playback resumes
  • After buffering completes and playback continues

pause ​

Fired when playback is paused.

typescript
player.on('pause', () => {
  console.log('Playback paused');
  updatePlayButton('play');
});

When fired:

  • When player.pause() is called
  • When playback is automatically paused due to buffering
  • When an error occurs that stops playback

ended ​

Fired when playback reaches the end of the media.

typescript
player.on('ended', () => {
  console.log('Playback completed');
  showReplayButton();
  trackAnalytics('video_complete');
});

When fired:

  • When currentTime reaches the duration
  • Only fires once per playback session

seeking ​

Fired when a seek operation starts.

typescript
player.on('seeking', () => {
  console.log('Seeking started');
  showSeekingSpinner();
});

When fired:

  • When player.seek(time) is called
  • When user drags the progress bar

seeked ​

Fired when a seek operation completes.

typescript
player.on('seeked', () => {
  console.log('Seek completed');
  hideSeekingSpinner();
});

When fired:

  • When the seek operation finishes and playback can continue
  • After the player has moved to the new position

timeupdate ​

Fired regularly during playback with the current time.

typescript
player.on('timeupdate', (currentTime: number) => {
  updateProgressBar(currentTime, player.duration);
  updateTimeDisplay(currentTime);

  // Check for specific time markers
  if (currentTime > 30 && !hasTrackedEngagement) {
    trackAnalytics('engaged_viewer');
    hasTrackedEngagement = true;
  }
});

Parameters:

  • currentTime (number): Current playback position in seconds

When fired:

  • Approximately every 250ms during playback
  • When seeking to a new position

ratechange ​

Fired when the playback rate changes.

typescript
player.on('ratechange', (rate: number) => {
  console.log(`Playback rate changed to ${rate}x`);
  updatePlaybackRateDisplay(rate);
});

Parameters:

  • rate (number): New playback rate (e.g., 0.5, 1, 1.5, 2)

When fired:

  • When player.playbackRate is modified
  • When user changes playback speed

Loading Events ​

loadstart ​

Fired when loading of the media begins.

typescript
player.on('loadstart', () => {
  console.log('Started loading media');
  showLoadingIndicator();
  resetErrorState();
});

When fired:

  • When player.load() is called
  • When a new source is set

loadedmetadata ​

Fired when media metadata has been loaded.

typescript
player.on('loadedmetadata', () => {
  console.log('Metadata loaded');
  console.log(`Duration: ${player.duration}s`);
  console.log(`Dimensions: ${player.videoWidth}x${player.videoHeight}`);

  initializeProgressBar(player.duration);
  updateVideoInfo(player.videoWidth, player.videoHeight);
});

When fired:

  • When basic media information becomes available
  • Before any actual media data is loaded

loadeddata ​

Fired when the first frame of media has been loaded.

typescript
player.on('loadeddata', () => {
  console.log('First frame loaded');
  hideLoadingIndicator();
  enablePlayButton();
});

When fired:

  • When enough data is available to render the first frame
  • Player is ready for basic interaction

canplay ​

Fired when the player can start playing the media.

typescript
player.on('canplay', () => {
  console.log('Can start playing');
  enableAllControls();

  // Auto-play if enabled
  if (shouldAutoPlay) {
    player.play();
  }
});

When fired:

  • When enough data is buffered to start playback
  • May still require buffering during playback

canplaythrough ​

Fired when the player can play through the entire media without buffering.

typescript
player.on('canplaythrough', () => {
  console.log('Can play through without buffering');
  hideBufferingIndicator();
  setOptimalQuality();
});

When fired:

  • When sufficient data is buffered for smooth playback
  • Indicates good network conditions

progress ​

Fired periodically as the media downloads.

typescript
player.on('progress', (buffered: TimeRanges) => {
  updateBufferIndicator(buffered);

  // Calculate download progress
  if (buffered.length > 0) {
    const bufferedEnd = buffered.end(buffered.length - 1);
    const progress = (bufferedEnd / player.duration) * 100;
    console.log(`Downloaded: ${progress.toFixed(1)}%`);
  }
});

Parameters:

  • buffered (TimeRanges): Buffered time ranges

When fired:

  • As media data downloads
  • When buffer state changes

waiting ​

Fired when playback stops due to lack of data.

typescript
player.on('waiting', () => {
  console.log('Waiting for data');
  showBufferingSpinner();
  pauseAnalyticsTracking();
});

When fired:

  • When playback pauses due to buffering
  • When network is slow or interrupted

stalled ​

Fired when the download has stalled.

typescript
player.on('stalled', () => {
  console.log('Download stalled');
  showNetworkIssueWarning();

  // Retry or switch quality
  handleNetworkIssue();
});

When fired:

  • When download progress stops unexpectedly
  • May indicate network issues

Audio Events ​

volumechange ​

Fired when volume or muted state changes.

typescript
player.on('volumechange', (volume: number, muted: boolean) => {
  console.log(`Volume: ${Math.round(volume * 100)}%, Muted: ${muted}`);

  updateVolumeSlider(volume);
  updateMuteButton(muted);
  saveVolumePreference(volume, muted);
});

Parameters:

  • volume (number): Volume level (0-1)
  • muted (boolean): Whether audio is muted

When fired:

  • When player.volume is changed
  • When player.muted is toggled

Error Events ​

error ​

Fired when an error occurs.

typescript
player.on('error', (error: Error) => {
  console.error('Player error:', error);

  showErrorMessage(error.message);
  hideLoadingIndicator();

  // Handle different error types
  if (error instanceof MediaError) {
    handleMediaError(error);
  } else if (error.message.includes('network')) {
    handleNetworkError(error);
  } else {
    handleGenericError(error);
  }
});

Parameters:

  • error (Error): Error object with details

When fired:

  • When media loading fails
  • When decoding errors occur
  • When network errors happen
  • When invalid operations are attempted

Track Events ​

tracksChanged ​

Fired when available tracks change.

typescript
player.on('tracksChanged', (tracks: TrackList) => {
  console.log('Tracks updated:', tracks);

  updateVideoQualitySelector(tracks.video);
  updateAudioTrackSelector(tracks.audio);

  // Auto-select preferred tracks
  selectPreferredTracks(tracks);
});

Parameters:

  • tracks (TrackList): Object containing video and audio track arrays

When fired:

  • When media is loaded and tracks are discovered
  • When tracks are added or removed dynamically

trackChanged ​

Fired when the active track changes.

typescript
player.on('trackChanged', (type: 'video' | 'audio', trackIndex: number) => {
  console.log(`${type} track changed to index: ${trackIndex}`);

  if (type === 'video') {
    const track = player.tracks.video[trackIndex];
    updateQualityIndicator(track.width, track.height);
  } else {
    const track = player.tracks.audio[trackIndex];
    updateLanguageIndicator(track.language);
  }
});

Parameters:

  • type ('video' | 'audio'): Type of track that changed
  • trackIndex (number): Index of the new active track

When fired:

  • When player.selectVideoTrack() or player.selectAudioTrack() is called
  • When automatic track switching occurs

trackSwitching ​

Fired when a track switch operation begins.

typescript
player.on('trackSwitching', (type: 'video' | 'audio') => {
  console.log(`Switching ${type} track...`);
  showTrackSwitchingIndicator(type);
});

Parameters:

  • type ('video' | 'audio'): Type of track being switched

trackSwitched ​

Fired when a track switch operation completes.

typescript
player.on('trackSwitched', (type: 'video' | 'audio', trackIndex: number) => {
  console.log(`${type} track switched successfully`);
  hideTrackSwitchingIndicator(type);
});

Parameters:

  • type ('video' | 'audio'): Type of track that was switched
  • trackIndex (number): Index of the new active track

Source Events ​

sourceChanged ​

Fired when the media source changes.

typescript
player.on('sourceChanged', (source: string) => {
  console.log('Source changed to:', source);

  resetPlayerState();
  updateMediaInfo(source);
  saveRecentlyPlayed(source);
});

Parameters:

  • source (string): New source URL or identifier

When fired:

  • When player.load() is called with a new source
  • When source is changed programmatically

Player Lifecycle Events ​

ready ​

Fired when the player is fully initialized and ready.

typescript
player.on('ready', () => {
  console.log('Player is ready');

  enablePlayerControls();
  loadUserPreferences();
  initializePlugins();
});

When fired:

  • After player initialization is complete
  • Before any media is loaded

destroy ​

Fired when the player is being destroyed.

typescript
player.on('destroy', () => {
  console.log('Player is being destroyed');

  savePlayerState();
  cleanupEventListeners();
  destroyPlugins();
});

When fired:

  • When player.destroy() is called
  • Before cleanup operations begin

Advanced Events ​

frameChanged ​

Fired when a new video frame is available.

typescript
player.on('frameChanged', (frame: VideoFrame) => {
  // Process frame for custom effects
  processVideoFrame(frame);

  // Update frame counter
  frameCount++;
});

Parameters:

  • frame (VideoFrame): New video frame object

When fired:

  • When a new video frame is decoded and ready
  • During active playback

frameRendered ​

Fired when a frame is rendered to the canvas.

typescript
player.on('frameRendered', (timestamp: number) => {
  // Track rendering performance
  trackFrameRate(timestamp);

  // Update custom overlays
  updateOverlays(timestamp);
});

Parameters:

  • timestamp (number): Render timestamp in milliseconds

When fired:

  • After each frame is drawn to the canvas
  • Used for performance monitoring

memoryUsage ​

Fired when memory usage information is available.

typescript
player.on('memoryUsage', (bytes: number) => {
  console.log(`Memory usage: ${(bytes / 1024 / 1024).toFixed(2)} MB`);

  if (bytes > 100 * 1024 * 1024) { // 100MB
    optimizeMemoryUsage();
  }
});

Parameters:

  • bytes (number): Current memory usage in bytes

When fired:

  • Periodically during playback
  • When memory usage changes significantly

Event Listener Management ​

Adding Listeners ​

typescript
// Basic listener
player.on('play', handlePlay);

// Listener with context
player.on('timeupdate', function(time) {
  this.updateUI(time);
}.bind(uiController));

// One-time listener
player.once('canplay', () => {
  console.log('Ready to play - this will only fire once');
});

// Multiple events with same handler
['play', 'pause'].forEach(event => {
  player.on(event, updatePlayState);
});

Removing Listeners ​

typescript
// Remove specific listener
player.off('play', handlePlay);

// Remove all listeners for an event
player.off('timeupdate');

// Remove all listeners
player.removeAllListeners();

Listener Limits ​

typescript
// Set maximum listeners for memory protection
player.setMaxListeners(50);

// Check current listener count
const count = player.listenerCount('timeupdate');
console.log(`timeupdate has ${count} listeners`);

// Get all event names with listeners
const events = player.eventNames();
console.log('Events with listeners:', events);

Error Handling ​

typescript
// Comprehensive error handling
player.on('error', (error) => {
  console.error('Player error:', {
    message: error.message,
    code: error.code,
    timestamp: Date.now(),
    playerState: player.store.getState()
  });

  // Report to error tracking service
  errorTracker.report(error, {
    player: 'mediafox',
    version: '1.0.0',
    userAgent: navigator.userAgent
  });
});

// Handle specific error types
player.on('error', (error) => {
  if (error instanceof MediaError) {
    switch (error.code) {
      case MediaError.MEDIA_ERR_NETWORK:
        showRetryDialog();
        break;
      case MediaError.MEDIA_ERR_DECODE:
        showFormatError();
        break;
      case MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:
        showUnsupportedError();
        break;
    }
  }
});

Best Practices ​

  1. Always Clean Up: Remove event listeners when components unmount
  2. Use Specific Events: Subscribe to the most specific event for your needs
  3. Throttle Frequent Events: Use throttling for high-frequency events like timeupdate
  4. Handle Errors Gracefully: Always listen for error events
  5. Monitor Performance: Use frame and memory events for optimization
  6. Type Safety: Leverage TypeScript types for event parameters
  7. Avoid Memory Leaks: Set reasonable listener limits and clean up properly

The event system in MediaFox provides comprehensive coverage of all player states and interactions, enabling you to build responsive and feature-rich video applications.

MIT License