import { useCallback, useEffect, useRef, useState } from 'react';
// MJPEG
connections can stop delivering frames without firing onError.
// Renew only the camera connection, keeping the overlay and its credentials.
// This also renews healthy connections; it does not measure frame freshness.
const STREAM_RENEWAL_MS = 60_000;
const ERROR_RETRY_MS = 3_000;
export function useOverlayCameraRecovery(enabled: boolean) {
const [imageKey, setImageKey] = useState(Date.now);
const retryTimer = useRef | null>(null);
const renew = useCallback(() => {
if (retryTimer.current !== null) {
clearTimeout(retryTimer.current);
retryTimer.current = null;
}
setImageKey((key) => key + 1);
}, []);
useEffect(() => {
if (!enabled) return;
// Start a fresh deadline after each retry so a newly opened connection
// isn't immediately replaced by the previous connection's renewal timer.
const renewalTimer = setTimeout(renew, STREAM_RENEWAL_MS);
return () => {
clearTimeout(renewalTimer);
if (retryTimer.current !== null) {
clearTimeout(retryTimer.current);
retryTimer.current = null;
}
};
}, [enabled, imageKey, renew]);
const handleStreamError = useCallback(() => {
if (!enabled || retryTimer.current !== null) return;
retryTimer.current = setTimeout(renew, ERROR_RETRY_MS);
}, [enabled, renew]);
return { imageKey, handleStreamError };
}