import { Lock, LockOpen } from "lucide-react"; import { openCallPage, useCall } from "../store"; import { Button, Card, CardContent, CardHeader, Tooltip, TooltipContent, TooltipTrigger, useIsMobile, } from "@tensamin/ui"; import ScreenshareButton from "./buttons/screenshare"; import MuteButton from "./buttons/mute"; import DeafButton from "./buttons/deaf"; import { Room, Track } from "livekit-client"; import { useEffect, useState } from "react"; import { AreaChart, Area } from "recharts"; import LeaveButton from "./buttons/leave"; export default function SidebarBox() { const state = useCall((store) => store.state); const isMobile = useIsMobile(); return state === "closed" ? null : ( ); } function ConnectionBar() { const state = useCall((store) => store.state); const isEncrypted = useCall((store) => store.isEncrypted); const callId = useCall((store) => store.callId); return ( openCallPage(callId || "")} size="lg" variant={ state === "open" && isEncrypted ? "subtleDefault" : "destructive" } className="flex justify-between items-center" > {state === "encrypting" && "Encrypting..."} {state === "connecting" && "Connecting..."} {state === "open" && "Connected"} {state === "closed" && "Closed"} {state === "closing" && "Closing"} {isEncrypted ? ( ) : ( )} } /> Click to open call page ); } export function TinyPingGraph() { const room = useCall((store) => store.room); const [mapData, setMapData] = useState>(() => new Map()); const data = Array.from(mapData, ([time, ping]) => ({ time, ping })); useEffect(() => { const interval = setInterval(async () => { const now = Date.now(); const ping = await getPing(room); const cutoff = now - 10_000; setMapData((prev) => { const next = new Map(prev); if (ping != null && ping > 0) { next.set(now, ping); } for (const time of next.keys()) { if (time < cutoff) next.delete(time); } return next; }); }, 2_000); return () => clearInterval(interval); }, [room]); return ( {data.length > 1 && ( )} } /> {data.length > 0 ? `${data.at(-1)?.ping} ms` : "Measuring ping..."} ); } async function getPing(room: Room): Promise { const report = await room.localParticipant .getTrackPublication(Track.Source.Microphone) ?.track?.getRTCStatsReport(); if (!report) return; let bestRtt: number | undefined; report.forEach((stat) => { if ( stat.type === "candidate-pair" && stat.state === "succeeded" && stat.currentRoundTripTime != null ) { bestRtt = stat.currentRoundTripTime * 1000; } if (stat.type === "remote-inbound-rtp" && stat.roundTripTime != null) { bestRtt = stat.roundTripTime * 1000; } }); if (bestRtt == null || bestRtt <= 0) return; const roundedRtt = Math.round(bestRtt); if (roundedRtt <= 0) return; return roundedRtt; }