CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-native-video

A comprehensive React Native video player component with streaming, DRM, and Picture-in-Picture support

Pending
Overview
Eval results
Files

event-handling.mddocs/

Event Handling

Comprehensive event system covering playback events, state changes, track information, buffering, error handling, and platform-specific events for complete video playback monitoring and control.

Capabilities

ReactVideoEvents Interface

Main interface defining all available event handlers for the Video component.

/**
 * Complete event handling interface for video playback monitoring
 * All events are optional and provide detailed information about video state
 */
interface ReactVideoEvents {
  // Core Playback Events
  onLoad?: (e: OnLoadData) => void;
  onLoadStart?: (e: OnLoadStartData) => void;
  onProgress?: (e: OnProgressData) => void;
  onEnd?: () => void;
  onError?: (e: OnVideoErrorData) => void;
  onSeek?: (e: OnSeekData) => void;
  
  // State Change Events
  onPlaybackStateChanged?: (e: OnPlaybackStateChangedData) => void;
  onPlaybackRateChange?: (e: OnPlaybackRateChangeData) => void;
  onVolumeChange?: (e: OnVolumeChangeData) => void;
  onBuffer?: (e: OnBufferData) => void;
  onReadyForDisplay?: () => void;
  
  // Track Events
  onAudioTracks?: (e: OnAudioTracksData) => void;
  onTextTracks?: (e: OnTextTracksData) => void;
  onVideoTracks?: (e: OnVideoTracksData) => void;
  onTextTrackDataChanged?: (e: OnTextTrackDataChangedData) => void;
  onAspectRatio?: (e: OnVideoAspectRatioData) => void;
  
  // UI & Interaction Events
  onFullscreenPlayerWillPresent?: () => void;
  onFullscreenPlayerDidPresent?: () => void;
  onFullscreenPlayerWillDismiss?: () => void;
  onFullscreenPlayerDidDismiss?: () => void;
  onControlsVisibilityChange?: (e: OnControlsVisibilityChange) => void;
  
  // Picture-in-Picture Events
  onPictureInPictureStatusChanged?: (e: OnPictureInPictureStatusChangedData) => void;
  onRestoreUserInterfaceForPictureInPictureStop?: () => void;
  
  // Platform-Specific Events
  onAudioBecomingNoisy?: () => void;
  onAudioFocusChanged?: (e: OnAudioFocusChangedData) => void;
  onIdle?: () => void;
  onExternalPlaybackChange?: (e: OnExternalPlaybackChangeData) => void;
  onBandwidthUpdate?: (e: OnBandwidthUpdateData) => void;
  onTimedMetadata?: (e: OnTimedMetadataData) => void;
  onReceiveAdEvent?: (e: OnReceiveAdEventData) => void;
}

Usage Examples:

<Video
  source={{ uri: "https://example.com/video.mp4" }}
  onLoad={(data) => {
    console.log("Video loaded:", {
      duration: data.duration,
      naturalSize: data.naturalSize,
      audioTracks: data.audioTracks.length,
      textTracks: data.textTracks.length
    });
  }}
  onProgress={(data) => {
    console.log(`Progress: ${data.currentTime}/${data.seekableDuration}`);
  }}
  onError={(error) => {
    console.error("Video error:", error.error.errorString);
  }}
  onEnd={() => {
    console.log("Video playback completed");
  }}
/>

Core Playback Events

Events related to video loading, progress, and basic playback state.

/**
 * Fired when video metadata and tracks are loaded
 */
interface OnLoadData {
  currentTime: number;
  duration: number;
  naturalSize: {
    width: number;
    height: number;
    orientation: "landscape" | "portrait";
  };
  audioTracks: AudioTrack[];
  textTracks: TextTrack[];
  videoTracks: VideoTrack[];
}

/**
 * Fired when video loading begins
 */
interface OnLoadStartData {
  isNetwork: boolean;
  type: string;
  uri: string;
}

/**
 * Fired periodically during playback with current progress
 */
interface OnProgressData {
  currentTime: number;
  playableDuration: number;
  seekableDuration: number;
}

/**
 * Fired when seek operation completes
 */
interface OnSeekData {
  currentTime: number;
  seekTime: number;
}

/**
 * Fired when video playback error occurs
 */
interface OnVideoErrorData {
  error: {
    errorString: string;
    errorException: string;
    errorStackTrace: string;
    errorCode: string;
    domain?: string;
  };
}

Usage Examples:

<Video
  source={{ uri: "https://example.com/video.mp4" }}
  onLoadStart={(data) => {
    console.log("Loading started:", data.uri, "Network:", data.isNetwork);
  }}
  onLoad={(data) => {
    console.log("Video loaded:", {
      duration: Math.round(data.duration),
      resolution: `${data.naturalSize.width}x${data.naturalSize.height}`,
      orientation: data.naturalSize.orientation,
      tracks: {
        audio: data.audioTracks.length,
        text: data.textTracks.length,
        video: data.videoTracks.length
      }
    });
  }}
  onProgress={(data) => {
    const progress = (data.currentTime / data.seekableDuration) * 100;
    console.log(`Progress: ${progress.toFixed(1)}%`);
  }}
  onSeek={(data) => {
    console.log(`Seek completed: ${data.currentTime}s (target: ${data.seekTime}s)`);
  }}
  onError={(error) => {
    console.error("Playback error:", {
      code: error.error.errorCode,
      message: error.error.errorString,
      domain: error.error.domain
    });
  }}
/>

State Change Events

Events for monitoring playback state, rate, and volume changes.

/**
 * Fired when playback state changes (play/pause/buffering/idle)
 */
interface OnPlaybackStateChangedData {
  isPlaying: boolean;
}

/**
 * Fired when playback rate changes
 */
interface OnPlaybackRateChangeData {
  playbackRate: number;
}

/**
 * Fired when volume changes
 */
interface OnVolumeChangeData {
  volume: number;
}

/**
 * Fired during buffering events
 */
interface OnBufferData {
  isBuffering: boolean;
}

Usage Examples:

<Video
  source={{ uri: "https://example.com/video.mp4" }}
  onPlaybackStateChanged={(data) => {
    console.log("Playback state:", data.isPlaying ? "Playing" : "Paused");
  }}
  onPlaybackRateChange={(data) => {
    console.log("Playback rate changed to:", data.playbackRate);
  }}
  onVolumeChange={(data) => {
    console.log("Volume changed to:", Math.round(data.volume * 100) + "%");
  }}
  onBuffer={(data) => {
    console.log("Buffering:", data.isBuffering ? "Started" : "Finished");
  }}
  onReadyForDisplay={() => {
    console.log("Video is ready for display");
  }}
/>

Track Information Events

Events providing information about available and selected tracks.

/**
 * Audio track information
 */
interface AudioTrack {
  index: number;
  title?: string;
  language?: string;
  bitrate?: number;
  type?: string;
  selected?: boolean;
}

/**
 * Text track information
 */
interface TextTrack {
  index: number;
  title?: string;
  language?: string;
  type?: "srt" | "ttml" | "vtt";
  selected?: boolean;
}

/**
 * Video track information
 */
interface VideoTrack {
  index: number;
  tracksID?: string;
  codecs?: string;
  width?: number;
  height?: number;
  bitrate?: number;
  selected?: boolean;
}

/**
 * Fired when audio tracks are available
 */
interface OnAudioTracksData {
  audioTracks: AudioTrack[];
}

/**
 * Fired when text tracks are available
 */
interface OnTextTracksData {
  textTracks: TextTrack[];
}

/**
 * Fired when video tracks are available
 */
interface OnVideoTracksData {
  videoTracks: VideoTrack[];
}

/**
 * Fired when text track data changes (iOS)
 */
interface OnTextTrackDataChangedData {
  subtitleTracks: TextTrack[];
}

/**
 * Fired when video aspect ratio changes
 */
interface OnVideoAspectRatioData {
  aspectRatio: number;
}

Usage Examples:

<Video
  source={{ uri: "https://example.com/video.mp4" }}
  onAudioTracks={(data) => {
    console.log("Audio tracks available:");
    data.audioTracks.forEach(track => {
      console.log(`- ${track.title || 'Track ' + track.index}: ${track.language} (${track.bitrate}bps)`);
    });
  }}
  onTextTracks={(data) => {
    console.log("Text tracks available:");
    data.textTracks.forEach(track => {
      console.log(`- ${track.title || 'Track ' + track.index}: ${track.language} (${track.type})`);
    });
  }}
  onVideoTracks={(data) => {
    console.log("Video tracks available:");
    data.videoTracks.forEach(track => {
      console.log(`- Track ${track.index}: ${track.width}x${track.height} (${track.bitrate}bps)`);
    });
  }}
  onAspectRatio={(data) => {
    console.log("Aspect ratio changed to:", data.aspectRatio);
  }}
/>

UI & Fullscreen Events

Events related to user interface changes and fullscreen transitions.

/**
 * Fired when controls visibility changes
 */
interface OnControlsVisibilityChange {
  isVisible: boolean;
}

Usage Examples:

<Video
  source={{ uri: "https://example.com/video.mp4" }}
  controls={true}
  onFullscreenPlayerWillPresent={() => {
    console.log("Fullscreen presentation will start");
  }}
  onFullscreenPlayerDidPresent={() => {
    console.log("Fullscreen presentation completed");
  }}
  onFullscreenPlayerWillDismiss={() => {
    console.log("Fullscreen dismissal will start");
  }}
  onFullscreenPlayerDidDismiss={() => {
    console.log("Fullscreen dismissal completed");
  }}
  onControlsVisibilityChange={(data) => {
    console.log("Controls are now:", data.isVisible ? "visible" : "hidden");
  }}
/>

Picture-in-Picture Events

Events for Picture-in-Picture mode changes and state restoration.

/**
 * Fired when Picture-in-Picture status changes
 */
interface OnPictureInPictureStatusChangedData {
  isActive: boolean;
}

Usage Examples:

<Video
  source={{ uri: "https://example.com/video.mp4" }}
  onPictureInPictureStatusChanged={(data) => {
    console.log("Picture-in-Picture:", data.isActive ? "Active" : "Inactive");
  }}
  onRestoreUserInterfaceForPictureInPictureStop={() => {
    console.log("Restore UI for PiP stop requested");
    // Restore your app's UI here
  }}
/>

Platform-Specific Events

Events that are specific to certain platforms or provide platform-specific information.

/**
 * Audio focus change event (Android)
 */
interface OnAudioFocusChangedData {
  hasAudioFocus: boolean;
}

/**
 * External playback change event (iOS)
 */
interface OnExternalPlaybackChangeData {
  isExternalPlaybackActive: boolean;
}

/**
 * Bandwidth update event (Android)
 */
interface OnBandwidthUpdateData {
  bitrate: number;
}

/**
 * Timed metadata event (Android, iOS)
 */
interface OnTimedMetadataData {
  metadata: {
    identifier: string;
    value: string;
  }[];
}

Usage Examples:

<Video
  source={{ uri: "https://example.com/video.mp4" }}
  // Android events
  onAudioFocusChanged={(data) => {
    console.log("Audio focus:", data.hasAudioFocus ? "gained" : "lost");
  }}
  onBandwidthUpdate={(data) => {
    console.log("Current bitrate:", Math.round(data.bitrate / 1000) + " kbps");
  }}
  onIdle={() => {
    console.log("Player entered idle state");
  }}
  
  // iOS events
  onExternalPlaybackChange={(data) => {
    console.log("AirPlay:", data.isExternalPlaybackActive ? "active" : "inactive");
  }}
  
  // Cross-platform events
  onAudioBecomingNoisy={() => {
    console.log("Audio becoming noisy (headphones unplugged?)");
    // Pause playback
  }}
  onTimedMetadata={(data) => {
    console.log("Timed metadata received:");
    data.metadata.forEach(item => {
      console.log(`- ${item.identifier}: ${item.value}`);
    });
  }}
/>

Advertisement Events

Events related to advertisement playback and interaction.

/**
 * Advertisement event data
 */
interface OnReceiveAdEventData {
  event: AdEvent;
  data?: object;
}

Usage Examples:

<Video
  source={{
    uri: "https://example.com/video.mp4",
    ad: {
      adTagUrl: "https://pubads.g.doubleclick.net/gampad/ads?...",
      adLanguage: "en"
    }
  }}
  onReceiveAdEvent={(data) => {
    console.log("Ad event:", data.event);
    
    switch (data.event) {
      case "LOADED":
        console.log("Ad loaded and ready to play");
        break;
      case "STARTED":
        console.log("Ad playback started");
        break;
      case "COMPLETED":
        console.log("Ad playback completed");
        break;
      case "ERROR":
        console.error("Ad error:", data.data);
        break;
      case "CLICK":
        console.log("Ad was clicked");
        break;
    }
  }}
/>

Event Usage Patterns

Progress Tracking with State Management

import React, { useState } from "react";
import Video from "react-native-video";

function VideoPlayerWithProgress() {
  const [progress, setProgress] = useState({ currentTime: 0, duration: 0 });
  const [isBuffering, setIsBuffering] = useState(false);

  return (
    <Video
      source={{ uri: "https://example.com/video.mp4" }}
      onLoad={(data) => {
        setProgress(prev => ({ ...prev, duration: data.duration }));
      }}
      onProgress={(data) => {
        setProgress(prev => ({ ...prev, currentTime: data.currentTime }));
      }}
      onBuffer={(data) => {
        setIsBuffering(data.isBuffering);
      }}
    />
  );
}

Error Handling and Recovery

function VideoPlayerWithErrorHandling() {
  const [error, setError] = useState<string | null>(null);
  const [retryCount, setRetryCount] = useState(0);

  const handleError = (errorData: OnVideoErrorData) => {
    console.error("Video error:", errorData.error);
    setError(errorData.error.errorString);
    
    // Implement retry logic
    if (retryCount < 3) {
      setTimeout(() => {
        setRetryCount(prev => prev + 1);
        setError(null);
      }, 2000);
    }
  };

  return (
    <Video
      source={{ uri: "https://example.com/video.mp4" }}
      onError={handleError}
      onLoad={() => {
        setError(null);
        setRetryCount(0);
      }}
    />
  );
}

Install with Tessl CLI

npx tessl i tessl/npm-react-native-video

docs

event-handling.md

expo-configuration.md

index.md

platform-features.md

video-component.md

video-ref-methods.md

video-sources.md

tile.json