diff --git a/frigate/api/app.py b/frigate/api/app.py index 67ad072a7..b387b0a12 100644 --- a/frigate/api/app.py +++ b/frigate/api/app.py @@ -117,6 +117,22 @@ def go2rtc_streams(): return jsonify(stream_data) +@bp.route("/go2rtc/streams/") +def go2rtc_camera_stream(camera_name: str): + r = requests.get(f"http://127.0.0.1:1984/api/streams?src={camera_name}&video=all&audio=allµphone") + if not r.ok: + logger.error("Failed to fetch streams from go2rtc") + return make_response( + jsonify({"success": False, "message": "Error fetching stream data"}), + 500, + ) + stream_data = r.json() + for data in stream_data.values(): + for producer in data.get("producers", []): + producer["url"] = clean_camera_user_pass(producer.get("url", "")) + return jsonify(stream_data) + + @bp.route("/version") def version(): return VERSION diff --git a/web/src/types/live.ts b/web/src/types/live.ts index 34d6b17f6..451e4506c 100644 --- a/web/src/types/live.ts +++ b/web/src/types/live.ts @@ -3,3 +3,30 @@ export type VideoResolutionType = { width: number; height: number; }; + +type LiveProducerMetadata = { + type: string; + url: string; + remote_addr: string; + user_agent: string; + sdp: string; + medias: string[]; + receivers: string[]; + recv: number; +}; + +type LiveConsumerMetadata = { + type: string; + url: string; + remote_addr: string; + user_agent: string; + sdp: string; + medias: string[]; + senders: string[]; + send: number; +}; + +export type LiveStreamMetadata = { + producers: LiveProducerMetadata[]; + consumers: LiveConsumerMetadata[]; +}; diff --git a/web/src/views/live/LiveCameraView.tsx b/web/src/views/live/LiveCameraView.tsx index e3c1801e6..91b032667 100644 --- a/web/src/views/live/LiveCameraView.tsx +++ b/web/src/views/live/LiveCameraView.tsx @@ -20,7 +20,7 @@ import { TooltipProvider } from "@/components/ui/tooltip"; import { useResizeObserver } from "@/hooks/resize-observer"; import useKeyboardListener from "@/hooks/use-keyboard-listener"; import { CameraConfig } from "@/types/frigateConfig"; -import { VideoResolutionType } from "@/types/live"; +import { LiveStreamMetadata, VideoResolutionType } from "@/types/live"; import { CameraPtzInfo } from "@/types/ptz"; import { RecordingStartingPoint } from "@/types/record"; import React, { @@ -82,6 +82,28 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) { const [{ width: windowWidth, height: windowHeight }] = useResizeObserver(window); + // supported features + + const { data: cameraMetadata } = useSWR( + `go2rtc/streams/${camera.live.stream_name}`, + { + revalidateOnFocus: false, + }, + ); + + const supports2WayTalk = useMemo(() => { + if (!window.isSecureContext || !cameraMetadata) { + return false; + } + + return ( + cameraMetadata.producers.find( + (prod) => + prod.medias.find((media) => media.includes("sendonly")) != undefined, + ) != undefined + ); + }, [cameraMetadata]); + // click overlay for ptzs const [clickOverlay, setClickOverlay] = useState(false); @@ -305,7 +327,7 @@ export default function LiveCameraView({ camera }: LiveCameraViewProps) { }} /> )} - {window.isSecureContext && ( + {supports2WayTalk && (