Files
react-native-video/lib/module/core/web/WebEventEmiter.js
2025-10-24 12:31:06 +02:00

256 lines
8.3 KiB
JavaScript

"use strict";
import { VideoError } from "../types/VideoError.js";
export class WebEventEmiter {
_isBuferring = false;
constructor(player) {
this.player = player;
// TODO: add `onBandwithUpdate`
// on buffer
this._onCanPlay = this._onCanPlay.bind(this);
this._onWaiting = this._onWaiting.bind(this);
this.player.on("canplay", this._onCanPlay);
this.player.on("waiting", this._onWaiting);
// on end
this._onEnded = this._onEnded.bind(this);
this.player.on("ended", this._onEnded);
// on load
this._onDurationChange = this._onDurationChange.bind(this);
this.player.on("durationchange", this._onDurationChange);
// on load start
this._onLoadStart = this._onLoadStart.bind(this);
this.player.on("loadstart", this._onLoadStart);
// on playback state change
this._onPlay = this._onPlay.bind(this);
this._onPause = this._onPause.bind(this);
this.player.on("play", this._onPlay);
this.player.on("pause", this._onPause);
// on playback rate change
this._onRateChange = this._onRateChange.bind(this);
this.player.on("ratechange", this._onRateChange);
// on progress
this._onTimeUpdate = this._onTimeUpdate.bind(this);
this.player.on("timeupdate", this._onTimeUpdate);
// on ready to play
this._onLoadedData = this._onLoadedData.bind(this);
this.player.on("loadeddata", this._onLoadedData);
// on seek
this._onSeeked = this._onSeeked.bind(this);
this.player.on("seeked", this._onSeeked);
// on volume change
this._onVolumeChange = this._onVolumeChange.bind(this);
this.player.on("volumechange", this._onVolumeChange);
// on status change
this._onError = this._onError.bind(this);
this.player.on("error", this._onError);
this._onTextTrackChange = this._onTextTrackChange.bind(this);
this.player.textTracks().on("change", this._onTextTrackChange);
this._onAudioTrackChange = this._onAudioTrackChange.bind(this);
this.player.audioTracks().on("change", this._onAudioTrackChange);
this._onVideoTrackChange = this._onVideoTrackChange.bind(this);
this.player.videoTracks().on("change", this._onVideoTrackChange);
this._onQualityChange = this._onQualityChange.bind(this);
// @ts-expect-error this isn't typed
this.player.qualityLevels().on("change", this._onQualityChange);
}
destroy() {
this.player.off("canplay", this._onCanPlay);
this.player.off("waiting", this._onWaiting);
this.player.off("ended", this._onEnded);
this.player.off("durationchange", this._onDurationChange);
this.player.off("play", this._onPlay);
this.player.off("pause", this._onPause);
this.player.off("ratechange", this._onRateChange);
this.player.off("timeupdate", this._onTimeUpdate);
this.player.off("loadeddata", this._onLoadedData);
this.player.off("seeked", this._onSeeked);
this.player.off("volumechange", this._onVolumeChange);
this.player.off("error", this._onError);
this.player.textTracks().off("change", this._onTextTrackChange);
this.player.audioTracks().off("change", this._onAudioTrackChange);
this.player.videoTracks().off("change", this._onVideoTrackChange);
this._onQualityChange = this._onQualityChange.bind(this);
// @ts-expect-error this isn't typed
this.player.qualityLevels().off("change", this._onQualityChange);
}
_onTimeUpdate() {
this.onProgress({
currentTime: this.player.currentTime() ?? 0,
bufferDuration: this.player.bufferedEnd()
});
}
_onCanPlay() {
this._isBuferring = false;
this.onBuffer(false);
this.onStatusChange("readyToPlay");
}
_onWaiting() {
this._isBuferring = true;
this.onBuffer(true);
this.onStatusChange("loading");
}
_onDurationChange() {
this.onLoad({
currentTime: this.player.currentTime() ?? 0,
duration: this.player.duration() ?? NaN,
width: this.player.width() ?? NaN,
height: this.player.height() ?? NaN,
orientation: "unknown"
});
}
_onEnded() {
this.onEnd();
this.onStatusChange("idle");
}
_onLoadStart() {
this.onLoadStart({
sourceType: "network",
source: {
uri: this.player.src(undefined),
config: {
uri: this.player.src(undefined),
externalSubtitles: []
},
getAssetInformationAsync: async () => {
return {
duration: BigInt(this.player.duration() ?? NaN),
height: this.player.height() ?? NaN,
width: this.player.width() ?? NaN,
orientation: "unknown",
bitrate: NaN,
fileSize: BigInt(NaN),
isHDR: false,
isLive: false
};
}
}
});
}
_onPlay() {
this.onPlaybackStateChange({
isPlaying: true,
isBuffering: this._isBuferring
});
}
_onPause() {
this.onPlaybackStateChange({
isPlaying: false,
isBuffering: this._isBuferring
});
}
_onRateChange() {
this.onPlaybackRateChange(this.player.playbackRate() ?? 1);
}
_onLoadedData() {
this.onReadyToDisplay();
}
_onSeeked() {
this.onSeek(this.player.currentTime() ?? 0);
}
_onVolumeChange() {
this.onVolumeChange({
muted: this.player.muted() ?? false,
volume: this.player.volume() ?? 1
});
}
_onError() {
this.onStatusChange("error");
const err = this.player.error();
if (!err) {
console.error("Unknown error occured in player");
return;
}
const codeMap = {
// @ts-expect-error Code added to html5 MediaError by videojs
[MediaError.MEDIA_ERR_CUSTOM]: "unknown/unknown",
[MediaError.MEDIA_ERR_ABORTED]: "player/asset-not-initialized",
[MediaError.MEDIA_ERR_NETWORK]: "player/network",
[MediaError.MEDIA_ERR_DECODE]: "player/invalid-source",
[MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED]: "source/unsupported-content-type",
// @ts-expect-error Code added to html5 MediaError by videojs
[MediaError.MEDIA_ERR_ENCRYPTED]: "source/failed-to-initialize-asset"
};
this.onError(new VideoError(codeMap[err.code], err.message));
}
_onTextTrackChange() {
// @ts-expect-error they define length & index properties via prototype
const tracks = this.player.textTracks();
const selected = [...Array(tracks.length)].map((_, i) => ({
id: tracks[i].id,
label: tracks[i].label,
language: tracks[i].language,
selected: tracks[i].mode === "showing"
})).find(x => x.selected);
this.onTrackChange(selected ?? null);
}
_onAudioTrackChange() {
// @ts-expect-error they define length & index properties via prototype
const tracks = this.player.audioTracks();
const selected = [...Array(tracks.length)].map((_, i) => ({
id: tracks[i].id,
label: tracks[i].label,
language: tracks[i].language,
selected: tracks[i].enabled
})).find(x => x.selected);
this.onAudioTrackChange(selected ?? null);
}
_onVideoTrackChange() {
// @ts-expect-error they define length & index properties via prototype
const tracks = this.player.videoTracks();
const selected = [...Array(tracks.length)].map((_, i) => ({
id: tracks[i].id,
label: tracks[i].label,
language: tracks[i].language,
selected: tracks[i].enabled
})).find(x => x.selected);
this.onVideoTrackChange(selected ?? null);
}
_onQualityChange() {
// @ts-expect-error this isn't typed
const levels = this.player.qualityLevels();
const quality = levels[levels.selectedIndex];
this.onQualityChange({
id: quality.id,
width: quality.width,
height: quality.height,
bitrate: quality.bitrate,
selected: true
});
}
NOOP = () => {};
onError = this.NOOP;
onAudioBecomingNoisy = this.NOOP;
onAudioFocusChange = this.NOOP;
onAudioTrackChange = this.NOOP;
onBandwidthUpdate = this.NOOP;
onBuffer = this.NOOP;
onControlsVisibleChange = this.NOOP;
onEnd = this.NOOP;
onExternalPlaybackChange = this.NOOP;
onLoad = this.NOOP;
onLoadStart = this.NOOP;
onPlaybackStateChange = this.NOOP;
onPlaybackRateChange = this.NOOP;
onProgress = this.NOOP;
onReadyToDisplay = this.NOOP;
onSeek = this.NOOP;
onTimedMetadata = this.NOOP;
onTextTrackDataChanged = this.NOOP;
onTrackChange = this.NOOP;
onVolumeChange = this.NOOP;
onStatusChange = this.NOOP;
onVideoTrackChange = this.NOOP;
onQualityChange = this.NOOP;
}
//# sourceMappingURL=WebEventEmiter.js.map