2015-12-06 22:25:18 -08:00
|
|
|
'use strict';
|
|
|
|
|
2024-07-15 23:29:23 +02:00
|
|
|
import React, {type FC, useCallback, useRef, useState} from 'react';
|
2016-04-22 00:01:44 -04:00
|
|
|
|
2024-07-15 23:29:23 +02:00
|
|
|
import {Platform, TouchableOpacity, View} from 'react-native';
|
2016-02-10 11:39:54 +00:00
|
|
|
|
2023-10-26 08:46:04 +02:00
|
|
|
import Video, {
|
|
|
|
VideoRef,
|
2024-05-22 14:01:55 +02:00
|
|
|
SelectedVideoTrackType,
|
2024-05-11 22:02:04 +02:00
|
|
|
BufferingStrategyType,
|
2024-06-28 13:03:10 +03:30
|
|
|
SelectedTrackType,
|
2024-07-08 11:24:32 +03:30
|
|
|
ResizeMode,
|
2024-07-15 23:29:23 +02:00
|
|
|
type AudioTrack,
|
|
|
|
type OnAudioTracksData,
|
|
|
|
type OnLoadData,
|
|
|
|
type OnProgressData,
|
|
|
|
type OnTextTracksData,
|
|
|
|
type OnVideoAspectRatioData,
|
|
|
|
type TextTrack,
|
|
|
|
type OnBufferData,
|
|
|
|
type OnAudioFocusChangedData,
|
|
|
|
type OnVideoErrorData,
|
|
|
|
type OnTextTrackDataChangedData,
|
|
|
|
type OnSeekData,
|
|
|
|
type OnPlaybackStateChangedData,
|
|
|
|
type OnPlaybackRateChangeData,
|
|
|
|
type OnVideoTracksData,
|
|
|
|
type ReactVideoSource,
|
|
|
|
type VideoTrack,
|
|
|
|
type SelectedTrack,
|
|
|
|
type SelectedVideoTrack,
|
|
|
|
type EnumValues,
|
2023-10-26 08:46:04 +02:00
|
|
|
} from 'react-native-video';
|
2024-05-22 14:01:55 +02:00
|
|
|
import styles from './styles';
|
2024-07-15 23:29:23 +02:00
|
|
|
import {type AdditionalSourceInfo} from './types';
|
2024-07-08 11:24:32 +03:30
|
|
|
import {bufferConfig, srcList, textTracksSelectionBy} from './constants';
|
2024-06-28 13:03:10 +03:30
|
|
|
import {Overlay, toast} from './components';
|
|
|
|
|
|
|
|
type Props = NonNullable<unknown>;
|
|
|
|
|
|
|
|
const VideoPlayer: FC<Props> = ({}) => {
|
2024-07-08 11:24:32 +03:30
|
|
|
const [rate, setRate] = useState(1);
|
|
|
|
const [volume, setVolume] = useState(1);
|
|
|
|
const [muted, setMuted] = useState(false);
|
2024-07-12 15:12:36 +03:30
|
|
|
const [resizeMode, setResizeMode] = useState<EnumValues<ResizeMode>>(
|
|
|
|
ResizeMode.CONTAIN,
|
|
|
|
);
|
2024-07-08 11:24:32 +03:30
|
|
|
const [duration, setDuration] = useState(0);
|
|
|
|
const [currentTime, setCurrentTime] = useState(0);
|
|
|
|
const [_, setVideoSize] = useState({videoWidth: 0, videoHeight: 0});
|
|
|
|
const [paused, setPaused] = useState(false);
|
|
|
|
const [fullscreen, setFullscreen] = useState(true);
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
const [audioTracks, setAudioTracks] = useState<AudioTrack[]>([]);
|
|
|
|
const [textTracks, setTextTracks] = useState<TextTrack[]>([]);
|
|
|
|
const [videoTracks, setVideoTracks] = useState<VideoTrack[]>([]);
|
|
|
|
const [selectedAudioTrack, setSelectedAudioTrack] = useState<
|
|
|
|
SelectedTrack | undefined
|
|
|
|
>(undefined);
|
|
|
|
const [selectedTextTrack, setSelectedTextTrack] = useState<
|
|
|
|
SelectedTrack | undefined
|
|
|
|
>(undefined);
|
|
|
|
const [selectedVideoTrack, setSelectedVideoTrack] =
|
|
|
|
useState<SelectedVideoTrack>({
|
|
|
|
type: SelectedVideoTrackType.AUTO,
|
|
|
|
});
|
|
|
|
const [srcListId, setSrcListId] = useState(0);
|
|
|
|
const [repeat, setRepeat] = useState(false);
|
|
|
|
const [controls, setControls] = useState(false);
|
|
|
|
const [useCache, setUseCache] = useState(false);
|
|
|
|
const [poster, setPoster] = useState<string | undefined>(undefined);
|
|
|
|
const [showNotificationControls, setShowNotificationControls] =
|
|
|
|
useState(false);
|
|
|
|
const [isSeeking, setIsSeeking] = useState(false);
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const videoRef = useRef<VideoRef>(null);
|
2024-07-08 11:24:32 +03:30
|
|
|
const viewStyle = fullscreen ? styles.fullScreen : styles.halfScreen;
|
|
|
|
const currentSrc = srcList[srcListId];
|
2024-06-28 13:03:10 +03:30
|
|
|
const additional = currentSrc as AdditionalSourceInfo;
|
|
|
|
|
2024-07-15 23:29:23 +02:00
|
|
|
const goToChannel = useCallback((channel: number) => {
|
|
|
|
setSrcListId(channel);
|
|
|
|
setDuration(0);
|
|
|
|
setCurrentTime(0);
|
|
|
|
setVideoSize({videoWidth: 0, videoHeight: 0});
|
|
|
|
setIsLoading(false);
|
|
|
|
setAudioTracks([]);
|
|
|
|
setTextTracks([]);
|
|
|
|
setSelectedAudioTrack(undefined);
|
|
|
|
setSelectedTextTrack(undefined);
|
|
|
|
setSelectedVideoTrack({
|
|
|
|
type: SelectedVideoTrackType.AUTO,
|
|
|
|
});
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const channelUp = useCallback(() => {
|
|
|
|
console.log('channel up');
|
|
|
|
goToChannel((srcListId + 1) % srcList.length);
|
|
|
|
}, [goToChannel, srcListId]);
|
|
|
|
|
|
|
|
const channelDown = useCallback(() => {
|
|
|
|
console.log('channel down');
|
|
|
|
goToChannel((srcListId + srcList.length - 1) % srcList.length);
|
|
|
|
}, [goToChannel, srcListId]);
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onAudioTracks = (data: OnAudioTracksData) => {
|
2023-10-26 08:46:04 +02:00
|
|
|
const selectedTrack = data.audioTracks?.find((x: AudioTrack) => {
|
2023-10-07 23:14:09 +02:00
|
|
|
return x.selected;
|
|
|
|
});
|
2024-05-22 14:01:55 +02:00
|
|
|
if (selectedTrack?.index) {
|
2024-07-08 11:24:32 +03:30
|
|
|
setAudioTracks(data.audioTracks);
|
|
|
|
setSelectedAudioTrack({
|
|
|
|
type: SelectedTrackType.INDEX,
|
|
|
|
value: selectedTrack.index,
|
2023-10-07 23:14:09 +02:00
|
|
|
});
|
2024-03-22 07:58:09 +01:00
|
|
|
} else {
|
2024-07-08 11:24:32 +03:30
|
|
|
setAudioTracks(data.audioTracks);
|
2022-04-26 22:59:04 +02:00
|
|
|
}
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onVideoTracks = (data: OnVideoTracksData) => {
|
2024-05-22 14:01:55 +02:00
|
|
|
console.log('onVideoTracks', data.videoTracks);
|
2024-07-08 11:24:32 +03:30
|
|
|
setVideoTracks(data.videoTracks);
|
2024-05-22 14:01:55 +02:00
|
|
|
};
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onTextTracks = (data: OnTextTracksData) => {
|
2023-10-26 08:46:04 +02:00
|
|
|
const selectedTrack = data.textTracks?.find((x: TextTrack) => {
|
2024-02-29 22:41:04 +09:00
|
|
|
return x?.selected;
|
2023-10-07 23:14:09 +02:00
|
|
|
});
|
2022-04-26 22:59:04 +02:00
|
|
|
|
|
|
|
if (selectedTrack?.language) {
|
2024-07-08 11:24:32 +03:30
|
|
|
setTextTracks(data.textTracks);
|
|
|
|
if (textTracksSelectionBy === 'index') {
|
|
|
|
setSelectedTextTrack({
|
|
|
|
type: SelectedTrackType.INDEX,
|
|
|
|
value: selectedTrack?.index,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
setSelectedTextTrack({
|
|
|
|
type: SelectedTrackType.LANGUAGE,
|
|
|
|
value: selectedTrack?.language,
|
|
|
|
});
|
|
|
|
}
|
2024-03-22 07:58:09 +01:00
|
|
|
} else {
|
2024-07-08 11:24:32 +03:30
|
|
|
setTextTracks(data.textTracks);
|
2022-04-26 22:59:04 +02:00
|
|
|
}
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onLoad = (data: OnLoadData) => {
|
2024-07-08 11:24:32 +03:30
|
|
|
setDuration(data.duration);
|
2024-06-28 13:03:10 +03:30
|
|
|
onAudioTracks(data);
|
|
|
|
onTextTracks(data);
|
|
|
|
onVideoTracks(data);
|
|
|
|
};
|
|
|
|
|
|
|
|
const onProgress = (data: OnProgressData) => {
|
2024-07-08 11:24:32 +03:30
|
|
|
setCurrentTime(data.currentTime);
|
2024-06-28 13:03:10 +03:30
|
|
|
};
|
|
|
|
|
|
|
|
const onSeek = (data: OnSeekData) => {
|
2024-07-08 11:24:32 +03:30
|
|
|
setCurrentTime(data.currentTime);
|
|
|
|
setIsSeeking(false);
|
2024-06-28 13:03:10 +03:30
|
|
|
};
|
|
|
|
|
|
|
|
const onVideoLoadStart = () => {
|
|
|
|
console.log('onVideoLoadStart');
|
2024-07-08 11:24:32 +03:30
|
|
|
setIsLoading(true);
|
2024-06-28 13:03:10 +03:30
|
|
|
};
|
|
|
|
|
|
|
|
const onTextTrackDataChanged = (data: OnTextTrackDataChangedData) => {
|
2024-02-29 22:41:04 +09:00
|
|
|
console.log(`Subtitles: ${JSON.stringify(data, null, 2)}`);
|
|
|
|
};
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onAspectRatio = (data: OnVideoAspectRatioData) => {
|
2023-10-07 23:14:09 +02:00
|
|
|
console.log('onAspectRadio called ' + JSON.stringify(data));
|
2024-07-08 11:24:32 +03:30
|
|
|
setVideoSize({videoWidth: data.width, videoHeight: data.height});
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onVideoBuffer = (param: OnBufferData) => {
|
2023-10-07 23:14:09 +02:00
|
|
|
console.log('onVideoBuffer');
|
2024-07-08 11:24:32 +03:30
|
|
|
setIsLoading(param.isBuffering);
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onReadyForDisplay = () => {
|
2023-10-07 23:14:09 +02:00
|
|
|
console.log('onReadyForDisplay');
|
2024-07-08 11:24:32 +03:30
|
|
|
setIsLoading(false);
|
2017-01-11 12:51:45 +00:00
|
|
|
};
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onAudioBecomingNoisy = () => {
|
2024-07-08 11:24:32 +03:30
|
|
|
setPaused(true);
|
2017-01-11 12:51:45 +00:00
|
|
|
};
|
2015-12-06 22:25:18 -08:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onAudioFocusChanged = (event: OnAudioFocusChangedData) => {
|
2024-07-08 11:24:32 +03:30
|
|
|
setPaused(!event.hasAudioFocus);
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onError = (err: OnVideoErrorData) => {
|
2023-10-26 08:46:04 +02:00
|
|
|
console.log(JSON.stringify(err));
|
2024-06-28 13:03:10 +03:30
|
|
|
toast(true, 'error: ' + JSON.stringify(err));
|
2023-10-07 23:14:09 +02:00
|
|
|
};
|
2022-04-26 22:59:04 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onEnd = () => {
|
2024-07-08 11:24:32 +03:30
|
|
|
if (!repeat) {
|
2024-06-28 13:03:10 +03:30
|
|
|
channelUp();
|
2024-04-26 09:42:21 +02:00
|
|
|
}
|
2022-04-26 22:59:04 +02:00
|
|
|
};
|
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onPlaybackRateChange = (data: OnPlaybackRateChangeData) => {
|
2024-04-04 14:45:39 +02:00
|
|
|
console.log('onPlaybackRateChange', data);
|
2024-04-19 22:38:52 +02:00
|
|
|
};
|
2024-04-04 14:45:39 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
const onPlaybackStateChanged = (data: OnPlaybackStateChangedData) => {
|
2024-04-04 14:45:39 +02:00
|
|
|
console.log('onPlaybackStateChanged', data);
|
2024-04-19 22:38:52 +02:00
|
|
|
};
|
2024-04-04 14:45:39 +02:00
|
|
|
|
2024-07-15 23:29:23 +02:00
|
|
|
const onFullScreenExit = () => {
|
|
|
|
// iOS pauses video on exit from full screen
|
|
|
|
Platform.OS === 'ios' && setPaused(true);
|
2023-11-22 15:03:57 +01:00
|
|
|
};
|
2022-09-11 17:01:53 +02:00
|
|
|
|
2024-06-28 13:03:10 +03:30
|
|
|
return (
|
|
|
|
<View style={styles.container}>
|
2024-07-08 11:24:32 +03:30
|
|
|
{(srcList[srcListId] as AdditionalSourceInfo)?.noView ? null : (
|
2024-06-28 13:03:10 +03:30
|
|
|
<TouchableOpacity style={viewStyle}>
|
|
|
|
<Video
|
2024-07-08 11:24:32 +03:30
|
|
|
showNotificationControls={showNotificationControls}
|
2024-06-28 13:03:10 +03:30
|
|
|
ref={videoRef}
|
|
|
|
source={currentSrc as ReactVideoSource}
|
|
|
|
textTracks={additional?.textTracks}
|
|
|
|
adTagUrl={additional?.adTagUrl}
|
|
|
|
drm={additional?.drm}
|
|
|
|
style={viewStyle}
|
2024-07-08 11:24:32 +03:30
|
|
|
rate={rate}
|
|
|
|
paused={paused}
|
|
|
|
volume={volume}
|
|
|
|
muted={muted}
|
|
|
|
fullscreen={fullscreen}
|
|
|
|
controls={controls}
|
|
|
|
resizeMode={resizeMode}
|
2024-07-15 23:29:23 +02:00
|
|
|
onFullscreenPlayerWillDismiss={onFullScreenExit}
|
2024-06-28 13:03:10 +03:30
|
|
|
onLoad={onLoad}
|
|
|
|
onAudioTracks={onAudioTracks}
|
|
|
|
onTextTracks={onTextTracks}
|
|
|
|
onVideoTracks={onVideoTracks}
|
|
|
|
onTextTrackDataChanged={onTextTrackDataChanged}
|
|
|
|
onProgress={onProgress}
|
|
|
|
onEnd={onEnd}
|
|
|
|
progressUpdateInterval={1000}
|
|
|
|
onError={onError}
|
|
|
|
onAudioBecomingNoisy={onAudioBecomingNoisy}
|
|
|
|
onAudioFocusChanged={onAudioFocusChanged}
|
|
|
|
onLoadStart={onVideoLoadStart}
|
|
|
|
onAspectRatio={onAspectRatio}
|
|
|
|
onReadyForDisplay={onReadyForDisplay}
|
|
|
|
onBuffer={onVideoBuffer}
|
|
|
|
onSeek={onSeek}
|
2024-07-08 11:24:32 +03:30
|
|
|
repeat={repeat}
|
|
|
|
selectedTextTrack={selectedTextTrack}
|
|
|
|
selectedAudioTrack={selectedAudioTrack}
|
|
|
|
selectedVideoTrack={selectedVideoTrack}
|
2024-06-28 13:03:10 +03:30
|
|
|
playInBackground={false}
|
|
|
|
bufferConfig={{
|
|
|
|
...bufferConfig,
|
2024-07-08 11:24:32 +03:30
|
|
|
cacheSizeMB: useCache ? 200 : 0,
|
2024-06-28 13:03:10 +03:30
|
|
|
}}
|
|
|
|
preventsDisplaySleepDuringVideoPlayback={true}
|
2024-07-08 11:24:32 +03:30
|
|
|
poster={poster}
|
2024-06-28 13:03:10 +03:30
|
|
|
onPlaybackRateChange={onPlaybackRateChange}
|
|
|
|
onPlaybackStateChanged={onPlaybackStateChanged}
|
|
|
|
bufferingStrategy={BufferingStrategyType.DEFAULT}
|
|
|
|
debug={{enable: true, thread: true}}
|
|
|
|
/>
|
|
|
|
</TouchableOpacity>
|
|
|
|
)}
|
|
|
|
<Overlay
|
|
|
|
channelDown={channelDown}
|
|
|
|
channelUp={channelUp}
|
|
|
|
ref={videoRef}
|
2024-07-08 11:24:32 +03:30
|
|
|
videoTracks={videoTracks}
|
|
|
|
selectedVideoTrack={selectedVideoTrack}
|
|
|
|
setSelectedTextTrack={setSelectedTextTrack}
|
|
|
|
audioTracks={audioTracks}
|
|
|
|
controls={controls}
|
|
|
|
resizeMode={resizeMode}
|
|
|
|
textTracks={textTracks}
|
|
|
|
selectedTextTrack={selectedTextTrack}
|
|
|
|
selectedAudioTrack={selectedAudioTrack}
|
|
|
|
setSelectedAudioTrack={setSelectedAudioTrack}
|
|
|
|
setSelectedVideoTrack={setSelectedVideoTrack}
|
|
|
|
currentTime={currentTime}
|
|
|
|
setMuted={setMuted}
|
|
|
|
muted={muted}
|
|
|
|
duration={duration}
|
|
|
|
paused={paused}
|
|
|
|
volume={volume}
|
|
|
|
setControls={setControls}
|
|
|
|
poster={poster}
|
|
|
|
rate={rate}
|
|
|
|
setFullscreen={setFullscreen}
|
|
|
|
setPaused={setPaused}
|
|
|
|
isLoading={isLoading}
|
|
|
|
isSeeking={isSeeking}
|
|
|
|
setIsSeeking={setIsSeeking}
|
|
|
|
repeat={repeat}
|
|
|
|
setRepeat={setRepeat}
|
|
|
|
setPoster={setPoster}
|
|
|
|
setRate={setRate}
|
|
|
|
setResizeMode={setResizeMode}
|
|
|
|
setShowNotificationControls={setShowNotificationControls}
|
|
|
|
showNotificationControls={showNotificationControls}
|
|
|
|
setUseCache={setUseCache}
|
|
|
|
setVolume={setVolume}
|
|
|
|
useCache={useCache}
|
|
|
|
srcListId={srcListId}
|
2024-06-28 13:03:10 +03:30
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
);
|
|
|
|
};
|
2023-10-07 23:14:09 +02:00
|
|
|
export default VideoPlayer;
|