Use webrtc for safari live view (#9839)

* Move safari function

* Use webrtc for safari

* Use taller aspect ratio for tall thumbnails

* Simplify thumbnail sizing

* Use correct aspect ratio on all devices
This commit is contained in:
Nicolas Mowen 2024-02-14 17:19:55 -07:00 committed by GitHub
parent 764736b223
commit 8c4811ed69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 38 additions and 33 deletions

View File

@ -22,30 +22,23 @@ export function AnimatedEventThumbnail({ event }: AnimatedEventThumbnailProps) {
return `${baseUrl}api/events/${event.id}/preview.gif`;
}, [event]);
const aspect = useMemo(() => {
const aspectRatio = useMemo(() => {
if (!config) {
return "";
return 1;
}
const detect = config.cameras[event.camera].detect;
const aspect = detect.width / detect.height;
if (aspect > 2) {
return "aspect-wide";
} else if (aspect < 1) {
return "aspect-tall";
} else {
return "aspect-video";
}
}, [config, event]);
return detect.width / detect.height;
}, [config]);
return (
<Tooltip>
<TooltipTrigger asChild>
<div
className={`relative rounded bg-cover h-24 bg-no-repeat bg-center mr-4 ${aspect}`}
className="h-24 relative rounded bg-cover bg-no-repeat bg-center mr-4"
style={{
backgroundImage: `url(${imageUrl})`,
aspectRatio: aspectRatio,
}}
>
<div className="absolute bottom-0 w-full h-6 bg-gradient-to-t from-slate-900/50 to-transparent rounded">

View File

@ -87,6 +87,7 @@ export default function LivePlayer({
<WebRtcPlayer
className={`rounded-2xl h-full ${liveReady ? "" : "hidden"}`}
camera={cameraConfig.live.stream_name}
playbackEnabled={cameraActive}
onPlaying={() => setLiveReady(true)}
/>
);

View File

@ -2,7 +2,6 @@ import VideoPlayer from "./VideoPlayer";
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
@ -11,6 +10,7 @@ import Player from "video.js/dist/types/player";
import { AspectRatio } from "../ui/aspect-ratio";
import { LuPlayCircle } from "react-icons/lu";
import { isCurrentHour } from "@/utils/dateUtil";
import { isSafari } from "@/utils/browserUtil";
type PreviewPlayerProps = {
camera: string;
@ -38,9 +38,6 @@ export default function PreviewThumbnailPlayer({
onClick,
}: PreviewPlayerProps) {
const playerRef = useRef<Player | null>(null);
const isSafari = useMemo(() => {
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
}, []);
const [visible, setVisible] = useState(false);
const [isInitiallyVisible, setIsInitiallyVisible] = useState(false);
@ -135,7 +132,6 @@ export default function PreviewThumbnailPlayer({
camera={camera}
eventId={eventId}
isMobile={isMobile}
isSafari={isSafari}
onClick={onClick}
/>
</AspectRatio>
@ -151,7 +147,6 @@ type PreviewContentProps = {
isInitiallyVisible: boolean;
startTs: number;
isMobile: boolean;
isSafari: boolean;
onClick?: () => void;
};
function PreviewContent({
@ -163,10 +158,10 @@ function PreviewContent({
isInitiallyVisible,
startTs,
isMobile,
isSafari,
onClick,
}: PreviewContentProps) {
const apiHost = useApiHost();
const slowPlayack = isSafari();
// handle touchstart -> touchend as click
const [touchStart, setTouchStart] = useState(0);
@ -237,7 +232,7 @@ function PreviewContent({
player.pause(); // autoplay + pause is required for iOS
}
player.playbackRate(isSafari ? 2 : 8);
player.playbackRate(slowPlayack ? 2 : 8);
player.currentTime(startTs - relevantPreview.start);
if (isMobile && onClick) {
player.on("touchstart", handleTouchStart);

View File

@ -4,16 +4,21 @@ import { useCallback, useEffect, useRef } from "react";
type WebRtcPlayerProps = {
className?: string;
camera: string;
playbackEnabled?: boolean;
onPlaying?: () => void;
};
export default function WebRtcPlayer({
className,
camera,
playbackEnabled = true,
onPlaying,
}: WebRtcPlayerProps) {
// camera states
const pcRef = useRef<RTCPeerConnection | undefined>();
const videoRef = useRef<HTMLVideoElement | null>(null);
const PeerConnection = useCallback(
async (media: string) => {
if (!videoRef.current) {
@ -129,6 +134,10 @@ export default function WebRtcPlayer({
return;
}
if (!playbackEnabled) {
return;
}
const url = `${baseUrl.replace(
/^http/,
"ws"
@ -143,18 +152,16 @@ export default function WebRtcPlayer({
pcRef.current = undefined;
}
};
}, [camera, connect, PeerConnection, pcRef, videoRef]);
}, [camera, connect, PeerConnection, pcRef, videoRef, playbackEnabled]);
return (
<div>
<video
ref={videoRef}
className={className}
autoPlay
playsInline
muted
onLoadedData={onPlaying}
/>
</div>
<video
ref={videoRef}
className={className}
autoPlay
playsInline
muted
onLoadedData={onPlaying}
/>
);
}

View File

@ -5,6 +5,7 @@ import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import { TooltipProvider } from "@/components/ui/tooltip";
import { Event as FrigateEvent } from "@/types/event";
import { FrigateConfig } from "@/types/frigateConfig";
import { isSafari } from "@/utils/browserUtil";
import { useCallback, useEffect, useMemo, useState } from "react";
import useSWR from "swr";
@ -64,6 +65,7 @@ function Live() {
.sort((aConf, bConf) => aConf.ui.order - bConf.ui.order);
}, [config]);
const safari = isSafari();
const [windowVisible, setWindowVisible] = useState(true);
const visibilityListener = useCallback(() => {
setWindowVisible(document.visibilityState == "visible");
@ -109,7 +111,7 @@ function Live() {
className={`mb-2 md:mb-0 rounded-2xl bg-black ${grow}`}
windowVisible={windowVisible}
cameraConfig={camera}
preferredLiveMode="mse"
preferredLiveMode={safari ? "webrtc" : "mse"}
/>
);
})}

View File

@ -0,0 +1,7 @@
import { useMemo } from "react";
export function isSafari() {
return useMemo(() => {
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
}, []);
}