From 1309cb0d7f44a440afbdc8da1da37f261d5d3195 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Fri, 20 Dec 2024 09:42:55 -0600 Subject: [PATCH] add ability to continue playing stream in background --- web/src/components/player/LivePlayer.tsx | 3 +++ web/src/components/player/MsePlayer.tsx | 18 ++++++++++++--- web/src/views/live/LiveCameraView.tsx | 28 ++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/web/src/components/player/LivePlayer.tsx b/web/src/components/player/LivePlayer.tsx index 858aa9c6f..2f71293b6 100644 --- a/web/src/components/player/LivePlayer.tsx +++ b/web/src/components/player/LivePlayer.tsx @@ -32,6 +32,7 @@ type LivePlayerProps = { useWebGL: boolean; windowVisible?: boolean; playAudio?: boolean; + playInBackground: boolean; micEnabled?: boolean; // only webrtc supports mic iOSCompatFullScreen?: boolean; pip?: boolean; @@ -53,6 +54,7 @@ export default function LivePlayer({ useWebGL = false, windowVisible = true, playAudio = false, + playInBackground = false, micEnabled = false, iOSCompatFullScreen = false, pip, @@ -202,6 +204,7 @@ export default function LivePlayer({ camera={streamName} playbackEnabled={cameraActive || liveReady} audioEnabled={playAudio} + playInBackground={playInBackground} onPlaying={playerIsPlaying} pip={pip} setFullResolution={setFullResolution} diff --git a/web/src/components/player/MsePlayer.tsx b/web/src/components/player/MsePlayer.tsx index 52cf8f99c..e3d431b82 100644 --- a/web/src/components/player/MsePlayer.tsx +++ b/web/src/components/player/MsePlayer.tsx @@ -15,6 +15,7 @@ type MSEPlayerProps = { className?: string; playbackEnabled?: boolean; audioEnabled?: boolean; + playInBackground?: boolean; pip?: boolean; onPlaying?: () => void; setFullResolution?: React.Dispatch>; @@ -26,6 +27,7 @@ function MSEPlayer({ className, playbackEnabled = true, audioEnabled = false, + playInBackground = false, pip = false, onPlaying, setFullResolution, @@ -508,12 +510,22 @@ function MSEPlayer({ } }; - document.addEventListener("visibilitychange", listener); + if (!playInBackground) { + document.addEventListener("visibilitychange", listener); + } return () => { - document.removeEventListener("visibilitychange", listener); + if (!playInBackground) { + document.removeEventListener("visibilitychange", listener); + } }; - }, [playbackEnabled, visibilityCheck, onConnect, onDisconnect]); + }, [ + playbackEnabled, + visibilityCheck, + playInBackground, + onConnect, + onDisconnect, + ]); // control pip diff --git a/web/src/views/live/LiveCameraView.tsx b/web/src/views/live/LiveCameraView.tsx index 6bd187c14..7b9f2f98a 100644 --- a/web/src/views/live/LiveCameraView.tsx +++ b/web/src/views/live/LiveCameraView.tsx @@ -55,6 +55,7 @@ import { FaMicrophone, FaMicrophoneSlash, } from "react-icons/fa"; +import { CiStreamOff, CiStreamOn } from "react-icons/ci"; import { GiSpeaker, GiSpeakerOff } from "react-icons/gi"; import { TbViewfinder, TbViewfinderOff } from "react-icons/tb"; import { IoIosWarning, IoMdArrowRoundBack } from "react-icons/io"; @@ -220,6 +221,11 @@ export default function LiveCameraView({ const [pip, setPip] = useState(false); const [lowBandwidth, setLowBandwidth] = useState(false); + const [playInBackground, setPlayInBackground] = usePersistence( + `${camera.name}-background-play`, + false, + ); + const [fullResolution, setFullResolution] = useState({ width: 0, height: 0, @@ -481,6 +487,8 @@ export default function LiveCameraView({ streamName={streamName ?? ""} setStreamName={setStreamName} preferredLiveMode={preferredLiveMode} + playInBackground={playInBackground ?? false} + setPlayInBackground={setPlayInBackground} /> @@ -513,6 +521,7 @@ export default function LiveCameraView({ showStillWithoutActivity={false} cameraConfig={camera} playAudio={audio} + playInBackground={playInBackground ?? false} micEnabled={mic} iOSCompatFullScreen={isIOS} preferredLiveMode={preferredLiveMode} @@ -779,6 +788,8 @@ type FrigateCameraFeaturesProps = { streamName: string; setStreamName?: (value: string | undefined) => void; preferredLiveMode: string; + playInBackground: boolean; + setPlayInBackground: (value: boolean | undefined) => void; }; function FrigateCameraFeatures({ camera, @@ -789,6 +800,8 @@ function FrigateCameraFeatures({ streamName, setStreamName, preferredLiveMode, + playInBackground, + setPlayInBackground, }: FrigateCameraFeaturesProps) { const { payload: detectState, send: sendDetect } = useDetectState( camera.name, @@ -853,6 +866,14 @@ function FrigateCameraFeatures({ } /> )} + setPlayInBackground(!playInBackground)} + /> {Object.values(camera.live.streams).length > 1 && (