mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-09-27 18:08:58 +03:00
* allow users to select live streaming technology * fix webrtc being downgraded to mse on load `useUserPersistence` seeds state with the default and loads asynchronously, so the first render always used `mse` instead of the saved choice, and `useWebRTCGloballyAvailable` reports `checking` until the probe settles and re-enters that state on every consumer mount, so a saved `webrtc` was rewritten to `mse` even after the probe had already passed. On Safari the MSE player then timed out and latched the jsmpeg fallback. A pending probe now counts as available, the player waits on `autoLive` until the stored preferences load, and `handleError` gates on the mode in use since the fallback flag no longer implies webrtc is untried. A rejected IndexedDB read also resolves `loaded` now, so a blocked store can't leave the player waiting forever. * add support for configurable ICE servers in WebRTC player * add mic error state, fix dialog overwriting saved choice and dashboard ignoring stream * tweaks
95 lines
3.2 KiB
TypeScript
95 lines
3.2 KiB
TypeScript
import { cn } from "@/lib/utils";
|
|
import { PlayerStatsType } from "@/types/live";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
type PlayerStatsProps = {
|
|
stats: PlayerStatsType;
|
|
minimal: boolean;
|
|
};
|
|
|
|
export function PlayerStats({ stats, minimal }: PlayerStatsProps) {
|
|
const { t } = useTranslation(["components/player", "views/live"]);
|
|
const streamTypeLabel = t(
|
|
`stream.technology.name.${stats.streamType.toLowerCase()}`,
|
|
{ ns: "views/live", defaultValue: stats.streamType },
|
|
);
|
|
const fullStatsContent = (
|
|
<>
|
|
<p>
|
|
<span className="text-white/70">{t("stats.streamType.title")}</span>{" "}
|
|
<span className="text-white">{streamTypeLabel}</span>
|
|
</p>
|
|
<p>
|
|
<span className="text-white/70">{t("stats.bandwidth.title")}</span>{" "}
|
|
<span className="text-white">{stats.bandwidth.toFixed(2)} kBps</span>
|
|
</p>
|
|
<p>
|
|
<span className="text-white/70">{t("stats.totalFrames")}</span>{" "}
|
|
<span className="text-white">{stats.totalFrames}</span>
|
|
</p>
|
|
{stats.droppedFrames != undefined && (
|
|
<p>
|
|
<span className="text-white/70">
|
|
{t("stats.droppedFrames.title")}
|
|
</span>{" "}
|
|
<span className="text-white">{stats.droppedFrames}</span>
|
|
</p>
|
|
)}
|
|
{stats.decodedFrames != undefined && (
|
|
<p>
|
|
<span className="text-white/70">{t("stats.decodedFrames")}</span>{" "}
|
|
<span className="text-white">{stats.decodedFrames}</span>
|
|
</p>
|
|
)}
|
|
{stats.droppedFrameRate != undefined && (
|
|
<p>
|
|
<span className="text-white/70">{t("stats.droppedFrameRate")}</span>{" "}
|
|
<span className="text-white">
|
|
{stats.droppedFrameRate.toFixed(2)}%
|
|
</span>
|
|
</p>
|
|
)}
|
|
</>
|
|
);
|
|
|
|
const minimalStatsContent = (
|
|
<div className="flex flex-row items-center justify-center gap-4">
|
|
<div className="flex flex-col items-center justify-start gap-1">
|
|
<span className="text-white/70">{t("stats.streamType.short")}</span>
|
|
<span className="text-white">{streamTypeLabel}</span>
|
|
</div>
|
|
<div className="flex flex-col items-center gap-1">
|
|
<span className="text-white/70">{t("stats.bandwidth.short")}</span>{" "}
|
|
<span className="text-white">{stats.bandwidth.toFixed(2)} kBps</span>
|
|
</div>
|
|
{stats.droppedFrames != undefined && (
|
|
<div className="flex flex-col items-center justify-end gap-1">
|
|
<span className="text-white/70">
|
|
{t("stats.droppedFrames.short.title")}
|
|
</span>
|
|
<span className="text-white">
|
|
{t("stats.droppedFrames.short.value", {
|
|
droppedFrames: stats.droppedFrames,
|
|
})}
|
|
</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<div
|
|
className={cn(
|
|
minimal
|
|
? "absolute bottom-0 left-0 max-h-[50%] w-full overflow-y-auto rounded-b-lg p-1 md:rounded-b-xl md:p-3"
|
|
: "absolute bottom-2 right-2 min-w-52 rounded-2xl p-4",
|
|
"z-50 flex flex-col gap-1 bg-black/70 text-[9px] duration-300 animate-in fade-in md:text-xs",
|
|
)}
|
|
>
|
|
{minimal ? minimalStatsContent : fullStatsContent}
|
|
</div>
|
|
</>
|
|
);
|
|
}
|