add descriptive console errors when falling back to jsmpeg

This commit is contained in:
Josh Hawkins 2025-09-22 19:35:44 -05:00
parent cd519ed1ad
commit a525dd0ff7
2 changed files with 40 additions and 13 deletions

View File

@ -84,6 +84,17 @@ function MSEPlayer({
return `${baseUrl.replace(/^http/, "ws")}live/mse/api/ws?src=${camera}`; return `${baseUrl.replace(/^http/, "ws")}live/mse/api/ws?src=${camera}`;
}, [camera]); }, [camera]);
const handleError = useCallback(
(error: LivePlayerError, description: string = "Unknown error") => {
// eslint-disable-next-line no-console
console.error(
`${camera} - MSE error '${error}': ${description} See the documentation: https://docs.frigate.video/configuration/live`,
);
onError?.(error);
},
[camera, onError],
);
const handleLoadedMetadata = useCallback(() => { const handleLoadedMetadata = useCallback(() => {
if (videoRef.current && setFullResolution) { if (videoRef.current && setFullResolution) {
setFullResolution({ setFullResolution({
@ -237,9 +248,9 @@ function MSEPlayer({
onDisconnect(); onDisconnect();
} }
if (isIOS || isSafari) { if (isIOS || isSafari) {
onError?.("mse-decode"); handleError("mse-decode", "Safari cannot open MediaSource.");
} else { } else {
onError?.("startup"); handleError("startup", "Error opening MediaSource.");
} }
}); });
}, },
@ -267,9 +278,9 @@ function MSEPlayer({
onDisconnect(); onDisconnect();
} }
if (isIOS || isSafari) { if (isIOS || isSafari) {
onError?.("mse-decode"); handleError("mse-decode", "Safari cannot open MediaSource.");
} else { } else {
onError?.("startup"); handleError("startup", "Error opening MediaSource.");
} }
}); });
}, },
@ -297,7 +308,7 @@ function MSEPlayer({
if (wsRef.current) { if (wsRef.current) {
onDisconnect(); onDisconnect();
} }
onError?.("mse-decode"); handleError("mse-decode", "Safari reported InvalidStateError.");
return; return;
} else { } else {
throw e; // Re-throw if it's not the error we're handling throw e; // Re-throw if it's not the error we're handling
@ -424,7 +435,10 @@ function MSEPlayer({
(bufferThreshold > 10 || bufferTime > 10) (bufferThreshold > 10 || bufferTime > 10)
) { ) {
onDisconnect(); onDisconnect();
onError?.("stalled"); handleError(
"stalled",
"Buffer time (10 seconds) exceeded, browser may not be playing media correctly.",
);
} }
const playbackRate = calculateAdaptivePlaybackRate( const playbackRate = calculateAdaptivePlaybackRate(
@ -470,7 +484,7 @@ function MSEPlayer({
videoRef.current videoRef.current
) { ) {
onDisconnect(); onDisconnect();
onError("stalled"); handleError("stalled", "Media playback has stalled.");
} }
}, timeoutDuration), }, timeoutDuration),
); );
@ -479,6 +493,7 @@ function MSEPlayer({
bufferTimeout, bufferTimeout,
isPlaying, isPlaying,
onDisconnect, onDisconnect,
handleError,
onError, onError,
onPlaying, onPlaying,
playbackEnabled, playbackEnabled,
@ -663,7 +678,7 @@ function MSEPlayer({
if (wsRef.current) { if (wsRef.current) {
onDisconnect(); onDisconnect();
} }
onError?.("startup"); handleError("startup", "Browser reported a network error.");
} }
if ( if (
@ -674,7 +689,7 @@ function MSEPlayer({
if (wsRef.current) { if (wsRef.current) {
onDisconnect(); onDisconnect();
} }
onError?.("mse-decode"); handleError("mse-decode", "Safari reported decoding errors.");
} }
setErrorCount((prevCount) => prevCount + 1); setErrorCount((prevCount) => prevCount + 1);
@ -683,7 +698,7 @@ function MSEPlayer({
onDisconnect(); onDisconnect();
if (errorCount >= 3) { if (errorCount >= 3) {
// too many mse errors, try jsmpeg // too many mse errors, try jsmpeg
onError?.("startup"); handleError("startup", `Max error count ${errorCount} exceeded.`);
} else { } else {
reconnect(5000); reconnect(5000);
} }

View File

@ -37,6 +37,18 @@ export default function WebRtcPlayer({
return `${baseUrl.replace(/^http/, "ws")}live/webrtc/api/ws?src=${camera}`; return `${baseUrl.replace(/^http/, "ws")}live/webrtc/api/ws?src=${camera}`;
}, [camera]); }, [camera]);
// error handler
const handleError = useCallback(
(error: LivePlayerError, description: string = "Unknown error") => {
// eslint-disable-next-line no-console
console.error(
`${camera} - WebRTC error '${error}': ${description} See the documentation: https://docs.frigate.video/configuration/live`,
);
onError?.(error);
},
[camera, onError],
);
// camera states // camera states
const pcRef = useRef<RTCPeerConnection | undefined>(); const pcRef = useRef<RTCPeerConnection | undefined>();
@ -212,7 +224,7 @@ export default function WebRtcPlayer({
useEffect(() => { useEffect(() => {
videoLoadTimeoutRef.current = setTimeout(() => { videoLoadTimeoutRef.current = setTimeout(() => {
onError?.("stalled"); handleError("stalled", "WebRTC connection timed out.");
}, 5000); }, 5000);
return () => { return () => {
@ -327,7 +339,7 @@ export default function WebRtcPlayer({
document.visibilityState === "visible" && document.visibilityState === "visible" &&
pcRef.current != undefined pcRef.current != undefined
) { ) {
onError("stalled"); handleError("stalled", "WebRTC connection stalled.");
} }
}, 3000), }, 3000),
); );
@ -344,7 +356,7 @@ export default function WebRtcPlayer({
// @ts-expect-error code does exist // @ts-expect-error code does exist
e.target.error.code == MediaError.MEDIA_ERR_NETWORK e.target.error.code == MediaError.MEDIA_ERR_NETWORK
) { ) {
onError?.("startup"); handleError("startup", "Browser reported a network error.");
} }
}} }}
/> />