diff --git a/src/Common/hooks/useHLSPlayer.ts b/src/Common/hooks/useHLSPlayer.ts index 7cb5302e76f..32a52043fe7 100644 --- a/src/Common/hooks/useHLSPlayer.ts +++ b/src/Common/hooks/useHLSPlayer.ts @@ -4,7 +4,7 @@ import { IOptions } from "./useMSEplayer"; export const useHLSPLayer = (ref: ReactPlayer | null) => { const startStream = ({ onSuccess, onError }: IOptions = {}) => { try { - ref && ref.forceUpdate(); + ref?.setState({ url: ref?.props.url + "&t=" + Date.now() }); onSuccess && onSuccess(undefined); } catch (err) { onError && onError(err); diff --git a/src/Components/Facility/Consultations/Feed.tsx b/src/Components/Facility/Consultations/Feed.tsx index 07fd6f31739..84b3e62ef9e 100644 --- a/src/Components/Facility/Consultations/Feed.tsx +++ b/src/Components/Facility/Consultations/Feed.tsx @@ -56,6 +56,7 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => { const [precision, setPrecision] = useState(1); const [cameraState, setCameraState] = useState(null); const [isFullscreen, setFullscreen] = useFullscreen(); + const [videoStartTime, setVideoStartTime] = useState(null); const authUser = useAuthUser(); useEffect(() => { @@ -197,6 +198,16 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => { dispatch, }); + const calculateVideoLiveDelay = () => { + const video = liveFeedPlayerRef.current as HTMLVideoElement; + if (!video || !videoStartTime) return 0; + + const timeDifference = + (new Date().getTime() - videoStartTime.getTime()) / 1000; + + return timeDifference - video.currentTime; + }; + const getBedPresets = async (asset: any) => { if (asset.id && bed) { const bedAssets = await dispatch(listAssetBeds({ asset: asset.id, bed })); @@ -240,7 +251,7 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => { }, []); useEffect(() => { - if (streamStatus === StreamStatus.Playing) { + if (!currentPreset && streamStatus === StreamStatus.Playing) { setLoading(CAMERA_STATES.MOVING.GENERIC); const preset = bedPresets?.find( @@ -296,6 +307,7 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => { }, reset: () => { setStreamStatus(StreamStatus.Loading); + setVideoStartTime(null); startStream({ onSuccess: () => setStreamStatus(StreamStatus.Playing), onError: () => setStreamStatus(StreamStatus.Offline), @@ -437,10 +449,16 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => { playsinline={true} playing={true} muted={true} + onPlay={() => { + setVideoStartTime(() => new Date()); + }} width="100%" height="100%" onBuffer={() => { - setStreamStatus(StreamStatus.Loading); + const delay = calculateVideoLiveDelay(); + if (delay > 5) { + setStreamStatus(StreamStatus.Loading); + } }} onError={(e: any, _: any, hlsInstance: any) => { if (e === "hlsError") { @@ -459,6 +477,15 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => { muted playsInline className="max-h-full max-w-full" + onPlay={() => { + setVideoStartTime(() => new Date()); + }} + onWaiting={() => { + const delay = calculateVideoLiveDelay(); + if (delay > 5) { + setStreamStatus(StreamStatus.Loading); + } + }} ref={liveFeedPlayerRef as any} /> )} @@ -506,7 +533,6 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => {
{["fullScreen", "reset", "updatePreset", "zoomIn", "zoomOut"].map( (button, index) => { - if (isIOS && button === "reset") return null; const option = cameraPTZ.find( (option) => option.action === button ); @@ -531,6 +557,13 @@ export const Feed: React.FC = ({ consultationId, facilityId }) => { clickAction={() => cameraPTZ[4].callback()} />
+ {streamStatus === StreamStatus.Playing && + calculateVideoLiveDelay() > 3 && ( +
+ + Slow Network Detected +
+ )}
{[ false,