From 84fcc56fefbf46626dc82bd8c9967b178a2abe16 Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Sun, 22 Dec 2024 12:25:07 -0600 Subject: [PATCH] add capabilities to live mode hook --- web/src/hooks/use-camera-live-mode.ts | 87 +++++++++++++++++++++------ 1 file changed, 68 insertions(+), 19 deletions(-) diff --git a/web/src/hooks/use-camera-live-mode.ts b/web/src/hooks/use-camera-live-mode.ts index eabc23aba..238ac70cc 100644 --- a/web/src/hooks/use-camera-live-mode.ts +++ b/web/src/hooks/use-camera-live-mode.ts @@ -1,16 +1,29 @@ import { CameraConfig, FrigateConfig } from "@/types/frigateConfig"; import { useCallback, useEffect, useState } from "react"; import useSWR from "swr"; -import { LivePlayerMode } from "@/types/live"; +import { LivePlayerMode, LiveStreamMetadata } from "@/types/live"; export default function useCameraLiveMode( cameras: CameraConfig[], windowVisible: boolean, ) { const { data: config } = useSWR("config"); + const { data: allStreamMetadata } = useSWR<{ + [key: string]: LiveStreamMetadata; + }>(config ? "go2rtc/streams" : null, { revalidateOnFocus: false }); + const [preferredLiveModes, setPreferredLiveModes] = useState<{ [key: string]: LivePlayerMode; }>({}); + const [isRestreamedStates, setIsRestreamedStates] = useState<{ + [key: string]: boolean; + }>({}); + const [supportsAudioOutputStates, setSupportsAudioOutputStates] = useState<{ + [key: string]: { + supportsAudio: boolean; + cameraName: string; + }; + }>({}); useEffect(() => { if (!cameras) return; @@ -18,26 +31,56 @@ export default function useCameraLiveMode( const mseSupported = "MediaSource" in window || "ManagedMediaSource" in window; - const newPreferredLiveModes = cameras.reduce( - (acc, camera) => { - const isRestreamed = - config && - Object.keys(config.go2rtc.streams || {}).includes( - Object.values(camera.live.streams)[0], - ); + const newPreferredLiveModes: { [key: string]: LivePlayerMode } = {}; + const newIsRestreamedStates: { [key: string]: boolean } = {}; + const newSupportsAudioOutputStates: { + [key: string]: { supportsAudio: boolean; cameraName: string }; + } = {}; - if (!mseSupported) { - acc[camera.name] = isRestreamed ? "webrtc" : "jsmpeg"; - } else { - acc[camera.name] = isRestreamed ? "mse" : "jsmpeg"; - } - return acc; - }, - {} as { [key: string]: LivePlayerMode }, - ); + cameras.forEach((camera) => { + const isRestreamed = + config && + Object.keys(config.go2rtc.streams || {}).includes( + Object.values(camera.live.streams)[0], + ); + + newIsRestreamedStates[camera.name] = isRestreamed ?? false; + + if (!mseSupported) { + newPreferredLiveModes[camera.name] = isRestreamed ? "webrtc" : "jsmpeg"; + } else { + newPreferredLiveModes[camera.name] = isRestreamed ? "mse" : "jsmpeg"; + } + + // check each stream for audio support + if (isRestreamed) { + Object.values(camera.live.streams).forEach((streamName) => { + const metadata = allStreamMetadata?.[streamName]; + newSupportsAudioOutputStates[streamName] = { + supportsAudio: metadata + ? metadata.producers.find( + (prod) => + prod.medias && + prod.medias.find((media) => + media.includes("audio, recvonly"), + ) !== undefined, + ) !== undefined + : false, + cameraName: camera.name, + }; + }); + } else { + newSupportsAudioOutputStates[camera.name] = { + supportsAudio: false, + cameraName: camera.name, + }; + } + }); setPreferredLiveModes(newPreferredLiveModes); - }, [cameras, config, windowVisible]); + setIsRestreamedStates(newIsRestreamedStates); + setSupportsAudioOutputStates(newSupportsAudioOutputStates); + }, [cameras, config, windowVisible, allStreamMetadata]); const resetPreferredLiveMode = useCallback( (cameraName: string) => { @@ -61,5 +104,11 @@ export default function useCameraLiveMode( [config], ); - return { preferredLiveModes, setPreferredLiveModes, resetPreferredLiveMode }; + return { + preferredLiveModes, + setPreferredLiveModes, + resetPreferredLiveMode, + isRestreamedStates, + supportsAudioOutputStates, + }; }