Check websocket readyState for disconnect and fix firefox pip (#12216)

This commit is contained in:
Josh Hawkins 2024-06-30 07:04:45 -05:00 committed by GitHub
parent f0159bf41e
commit f9e1ad253f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 32 deletions

View File

@ -128,12 +128,12 @@ function MSEPlayer({
setSafariPlaying(false); setSafariPlaying(false);
} }
if (wsRef.current && wsState != WebSocket.CLOSED) { if (wsRef.current) {
setWsState(WebSocket.CLOSED); setWsState(WebSocket.CLOSED);
wsRef.current.close(); wsRef.current.close();
wsRef.current = null; wsRef.current = null;
} }
}, [wsState, bufferTimeout, safariPlaying]); }, [bufferTimeout, safariPlaying]);
const onOpen = () => { const onOpen = () => {
setWsState(WebSocket.OPEN); setWsState(WebSocket.OPEN);
@ -359,7 +359,7 @@ function MSEPlayer({
// ensure we disconnect for slower connections // ensure we disconnect for slower connections
useEffect(() => { useEffect(() => {
if (wsState === WebSocket.OPEN && !playbackEnabled) { if (wsRef.current?.readyState === WebSocket.OPEN && !playbackEnabled) {
if (bufferTimeout) { if (bufferTimeout) {
clearTimeout(bufferTimeout); clearTimeout(bufferTimeout);
setBufferTimeout(undefined); setBufferTimeout(undefined);

View File

@ -21,7 +21,11 @@ import { TooltipProvider } from "@/components/ui/tooltip";
import { useResizeObserver } from "@/hooks/resize-observer"; import { useResizeObserver } from "@/hooks/resize-observer";
import useKeyboardListener from "@/hooks/use-keyboard-listener"; import useKeyboardListener from "@/hooks/use-keyboard-listener";
import { CameraConfig, FrigateConfig } from "@/types/frigateConfig"; import { CameraConfig, FrigateConfig } from "@/types/frigateConfig";
import { LiveStreamMetadata, VideoResolutionType } from "@/types/live"; import {
LivePlayerError,
LiveStreamMetadata,
VideoResolutionType,
} from "@/types/live";
import { CameraPtzInfo } from "@/types/ptz"; import { CameraPtzInfo } from "@/types/ptz";
import { RecordingStartingPoint } from "@/types/record"; import { RecordingStartingPoint } from "@/types/record";
import React, { import React, {
@ -33,6 +37,7 @@ import React, {
} from "react"; } from "react";
import { import {
isDesktop, isDesktop,
isFirefox,
isIOS, isIOS,
isMobile, isMobile,
isTablet, isTablet,
@ -275,6 +280,15 @@ export default function LiveCameraView({
} }
}, [fullscreen, isPortrait, cameraAspectRatio, containerAspectRatio]); }, [fullscreen, isPortrait, cameraAspectRatio, containerAspectRatio]);
const handleError = useCallback((e: LivePlayerError) => {
if (e == "mse-decode") {
setWebRTC(true);
} else {
setWebRTC(false);
setLowBandwidth(true);
}
}, []);
return ( return (
<TransformWrapper minScale={1.0}> <TransformWrapper minScale={1.0}>
<div <div
@ -353,7 +367,7 @@ export default function LiveCameraView({
onClick={toggleFullscreen} onClick={toggleFullscreen}
/> />
)} )}
{!isIOS && ( {!isIOS && !isFirefox && (
<CameraFeatureToggle <CameraFeatureToggle
className="p-2 md:p-0" className="p-2 md:p-0"
variant={fullscreen ? "overlay" : "primary"} variant={fullscreen ? "overlay" : "primary"}
@ -435,26 +449,21 @@ export default function LiveCameraView({
pip={pip} pip={pip}
setFullResolution={setFullResolution} setFullResolution={setFullResolution}
containerRef={containerRef} containerRef={containerRef}
onError={(e) => { onError={handleError}
if (e == "mse-decode") {
setWebRTC(true);
} else {
setWebRTC(false);
setLowBandwidth(true);
}
}}
/> />
</div> </div>
{camera.onvif.host != "" && (
<PtzControlPanel
camera={camera.name}
clickOverlay={clickOverlay}
setClickOverlay={setClickOverlay}
/>
)}
</TransformComponent> </TransformComponent>
</div> </div>
</div> </div>
{camera.onvif.host != "" && (
<div className="flex flex-col items-center justify-center">
<PtzControlPanel
camera={camera.name}
clickOverlay={clickOverlay}
setClickOverlay={setClickOverlay}
/>
</div>
)}
</TransformWrapper> </TransformWrapper>
); );
} }

View File

@ -23,7 +23,7 @@ import DraggableGridLayout from "./DraggableGridLayout";
import { IoClose } from "react-icons/io5"; import { IoClose } from "react-icons/io5";
import { LuLayoutDashboard } from "react-icons/lu"; import { LuLayoutDashboard } from "react-icons/lu";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { LivePlayerMode } from "@/types/live"; import { LivePlayerError, LivePlayerMode } from "@/types/live";
type LiveDashboardViewProps = { type LiveDashboardViewProps = {
cameras: CameraConfig[]; cameras: CameraConfig[];
@ -184,6 +184,21 @@ export default function LiveDashboardView({
const birdseyeConfig = useMemo(() => config?.birdseye, [config]); const birdseyeConfig = useMemo(() => config?.birdseye, [config]);
const handleError = useCallback(
(cameraName: string, error: LivePlayerError) => {
setPreferredLiveModes((prevModes) => {
const newModes = { ...prevModes };
if (error === "mse-decode") {
newModes[cameraName] = "webrtc";
} else {
newModes[cameraName] = "jsmpeg";
}
return newModes;
});
},
[setPreferredLiveModes],
);
return ( return (
<div <div
className="scrollbar-container size-full overflow-y-auto px-1 pt-2 md:p-2" className="scrollbar-container size-full overflow-y-auto px-1 pt-2 md:p-2"
@ -315,17 +330,7 @@ export default function LiveDashboardView({
preferredLiveMode={preferredLiveModes[camera.name] ?? "mse"} preferredLiveMode={preferredLiveModes[camera.name] ?? "mse"}
autoLive={autoLiveView} autoLive={autoLiveView}
onClick={() => onSelectCamera(camera.name)} onClick={() => onSelectCamera(camera.name)}
onError={(e) => { onError={(e) => handleError(camera.name, e)}
setPreferredLiveModes((prevModes) => {
const newModes = { ...prevModes };
if (e === "mse-decode") {
newModes[camera.name] = "webrtc";
} else {
newModes[camera.name] = "jsmpeg";
}
return newModes;
});
}}
/> />
); );
})} })}