mirror of
https://github.com/zoriya/react-native-video.git
synced 2026-08-16 02:56:22 +00:00
319 lines
10 KiB
JavaScript
319 lines
10 KiB
JavaScript
"use strict";
|
|
|
|
import { VideoError } from "../types/VideoError.js";
|
|
export class WebEventEmiter {
|
|
_isBuferring = false;
|
|
_listeners = new Map();
|
|
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);
|
|
}
|
|
_addListener(event, listener) {
|
|
if (!this._listeners.has(event)) {
|
|
this._listeners.set(event, new Set());
|
|
}
|
|
this._listeners.get(event).add(listener);
|
|
return {
|
|
remove: () => {
|
|
this._listeners.get(event)?.delete(listener);
|
|
}
|
|
};
|
|
}
|
|
_emit(event, ...args) {
|
|
this._listeners.get(event)?.forEach(fn => fn(...args));
|
|
}
|
|
addOnAudioBecomingNoisyListener(listener) {
|
|
return this._addListener("onAudioBecomingNoisy", listener);
|
|
}
|
|
addOnAudioFocusChangeListener(listener) {
|
|
return this._addListener("onAudioFocusChange", listener);
|
|
}
|
|
addOnBandwidthUpdateListener(listener) {
|
|
return this._addListener("onBandwidthUpdate", listener);
|
|
}
|
|
addOnBufferListener(listener) {
|
|
return this._addListener("onBuffer", listener);
|
|
}
|
|
addOnControlsVisibleChangeListener(listener) {
|
|
return this._addListener("onControlsVisibleChange", listener);
|
|
}
|
|
addOnEndListener(listener) {
|
|
return this._addListener("onEnd", listener);
|
|
}
|
|
addOnExternalPlaybackChangeListener(listener) {
|
|
return this._addListener("onExternalPlaybackChange", listener);
|
|
}
|
|
addOnLoadListener(listener) {
|
|
return this._addListener("onLoad", listener);
|
|
}
|
|
addOnLoadStartListener(listener) {
|
|
return this._addListener("onLoadStart", listener);
|
|
}
|
|
addOnPlaybackStateChangeListener(listener) {
|
|
return this._addListener("onPlaybackStateChange", listener);
|
|
}
|
|
addOnPlaybackRateChangeListener(listener) {
|
|
return this._addListener("onPlaybackRateChange", listener);
|
|
}
|
|
addOnProgressListener(listener) {
|
|
return this._addListener("onProgress", listener);
|
|
}
|
|
addOnReadyToDisplayListener(listener) {
|
|
return this._addListener("onReadyToDisplay", listener);
|
|
}
|
|
addOnSeekListener(listener) {
|
|
return this._addListener("onSeek", listener);
|
|
}
|
|
addOnStatusChangeListener(listener) {
|
|
return this._addListener("onStatusChange", listener);
|
|
}
|
|
addOnTimedMetadataListener(listener) {
|
|
return this._addListener("onTimedMetadata", listener);
|
|
}
|
|
addOnTextTrackDataChangedListener(listener) {
|
|
return this._addListener("onTextTrackDataChanged", listener);
|
|
}
|
|
addOnTrackChangeListener(listener) {
|
|
return this._addListener("onTrackChange", listener);
|
|
}
|
|
addOnVolumeChangeListener(listener) {
|
|
return this._addListener("onVolumeChange", listener);
|
|
}
|
|
clearAllListeners() {
|
|
this._listeners.clear();
|
|
}
|
|
addOnErrorListener(listener) {
|
|
return this._addListener("onError", listener);
|
|
}
|
|
addOnAudioTrackChangeListener(listener) {
|
|
return this._addListener("onAudioTrackChange", listener);
|
|
}
|
|
addOnVideoTrackChangeListener(listener) {
|
|
return this._addListener("onVideoTrackChange", listener);
|
|
}
|
|
addOnQualityChangeListener(listener) {
|
|
return this._addListener("onQualityChange", listener);
|
|
}
|
|
_onTimeUpdate() {
|
|
this._emit("onProgress", {
|
|
currentTime: this.player.currentTime() ?? 0,
|
|
bufferDuration: this.player.bufferedEnd()
|
|
});
|
|
}
|
|
_onCanPlay() {
|
|
this._isBuferring = false;
|
|
this._emit("onBuffer", false);
|
|
this._emit("onStatusChange", "readyToPlay");
|
|
}
|
|
_onWaiting() {
|
|
this._isBuferring = true;
|
|
this._emit("onBuffer", true);
|
|
this._emit("onStatusChange", "loading");
|
|
}
|
|
_onDurationChange() {
|
|
this._emit("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._emit("onEnd");
|
|
this._emit("onStatusChange", "idle");
|
|
}
|
|
_onLoadStart() {
|
|
this._emit("onLoadStart", {
|
|
sourceType: "network",
|
|
source: {
|
|
uri: this.player.src(undefined),
|
|
config: {
|
|
uri: this.player.src(undefined),
|
|
externalSubtitles: []
|
|
},
|
|
getAssetInformationAsync: async () => {
|
|
return {
|
|
duration: 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._emit("onPlaybackStateChange", {
|
|
isPlaying: true,
|
|
isBuffering: this._isBuferring
|
|
});
|
|
}
|
|
_onPause() {
|
|
this._emit("onPlaybackStateChange", {
|
|
isPlaying: false,
|
|
isBuffering: this._isBuferring
|
|
});
|
|
}
|
|
_onRateChange() {
|
|
this._emit("onPlaybackRateChange", this.player.playbackRate() ?? 1);
|
|
}
|
|
_onLoadedData() {
|
|
this._emit("onReadyToDisplay");
|
|
}
|
|
_onSeeked() {
|
|
this._emit("onSeek", this.player.currentTime() ?? 0);
|
|
}
|
|
_onVolumeChange() {
|
|
this._emit("onVolumeChange", {
|
|
muted: this.player.muted() ?? false,
|
|
volume: this.player.volume() ?? 1
|
|
});
|
|
}
|
|
_onError() {
|
|
this._emit("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._emit("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._emit("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._emit("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._emit("onVideoTrackChange", selected ?? null);
|
|
}
|
|
_onQualityChange() {
|
|
// @ts-expect-error this isn't typed
|
|
const levels = this.player.qualityLevels();
|
|
const quality = levels[levels.selectedIndex];
|
|
this._emit("onQualityChange", {
|
|
id: quality.id,
|
|
width: quality.width,
|
|
height: quality.height,
|
|
bitrate: quality.bitrate,
|
|
selected: true
|
|
});
|
|
}
|
|
}
|
|
//# sourceMappingURL=WebEventEmiter.js.map
|