Live video on the AT Protocol
at next 88 lines 2.4 kB view raw
1import { useEffect, useRef, useState } from "react"; 2import { useLivestreamStore } from "../livestream-store"; 3 4export type ConnectionQuality = "good" | "degraded" | "poor"; 5 6function getLiveConnectionQuality( 7 timeBetweenSegments: number | null, 8 range: number | null, 9 numOfSegments: number = 1, 10): ConnectionQuality { 11 if (timeBetweenSegments === null || range === null) return "poor"; 12 13 if (timeBetweenSegments <= 1500 && range <= (1500 * 60) / numOfSegments) { 14 return "good"; 15 } 16 if (timeBetweenSegments <= 3000 && range <= (3000 * 60) / numOfSegments) { 17 return "degraded"; 18 } 19 return "poor"; 20} 21 22export function useSegmentTiming() { 23 const latestSegment = useLivestreamStore((x) => x.segment); 24 const [segmentDeltas, setSegmentDeltas] = useState<number[]>([]); 25 const prevSegmentRef = useRef<any>(); 26 const prevTimestampRef = useRef<number | null>(null); 27 28 // Dummy state to force update every second 29 const [, setNow] = useState(Date.now()); 30 31 useEffect(() => { 32 const interval = setInterval(() => { 33 setNow(Date.now()); 34 }, 1000); 35 return () => clearInterval(interval); 36 }, []); 37 38 useEffect(() => { 39 if (latestSegment && prevSegmentRef.current !== latestSegment) { 40 const now = Date.now(); 41 if (prevTimestampRef.current !== null) { 42 const delta = now - prevTimestampRef.current; 43 // Only store the last 25 deltas 44 setSegmentDeltas((prev) => [...prev, delta].slice(-25)); 45 } 46 prevTimestampRef.current = now; 47 prevSegmentRef.current = latestSegment; 48 } 49 }, [latestSegment]); 50 51 // The most recent time between segments 52 const timeBetweenSegments = 53 segmentDeltas.length > 0 54 ? segmentDeltas[segmentDeltas.length - 1] 55 : prevTimestampRef.current 56 ? Date.now() - prevTimestampRef.current 57 : null; 58 59 // Calculate mean and range of deltas 60 const mean = 61 segmentDeltas.length > 0 62 ? Math.round( 63 segmentDeltas.reduce((acc, curr) => acc + curr, 0) / 64 segmentDeltas.length, 65 ) 66 : null; 67 68 const range = 69 segmentDeltas.length > 0 70 ? Math.max(...segmentDeltas) - Math.min(...segmentDeltas) 71 : null; 72 73 let to_ret = { 74 segmentDeltas, 75 timeBetweenSegments, 76 mean, 77 range, 78 connectionQuality: "poor", 79 }; 80 81 to_ret.connectionQuality = getLiveConnectionQuality( 82 timeBetweenSegments, 83 range, 84 segmentDeltas.length, 85 ); 86 87 return to_ret; 88}