From 3690b62e62701dbd454a5eae0321b843f5557e79 Mon Sep 17 00:00:00 2001 From: ryzendigo <48058157+ryzendigo@users.noreply.github.com> Date: Mon, 16 Mar 2026 14:42:46 +0800 Subject: [PATCH] fix: WebSocket connection leaked on WebRTC player cleanup The connect() function creates a WebSocket but never stores the reference. The useEffect cleanup only closes the RTCPeerConnection via pcRef, leaving the WebSocket open. Each time the component re-renders with changed deps (camera switch, playback toggle, microphone toggle), a new WebSocket is created without closing the previous one. This leaks connections until the browser garbage-collects them or the server times out. Store the WebSocket in a ref and close it in the cleanup function. --- web/src/components/player/WebRTCPlayer.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/web/src/components/player/WebRTCPlayer.tsx b/web/src/components/player/WebRTCPlayer.tsx index 147af43ea..d78c7dd80 100644 --- a/web/src/components/player/WebRTCPlayer.tsx +++ b/web/src/components/player/WebRTCPlayer.tsx @@ -52,6 +52,7 @@ export default function WebRtcPlayer({ // camera states const pcRef = useRef(undefined); + const wsRef = useRef(null); const videoRef = useRef(null); const [bufferTimeout, setBufferTimeout] = useState(); const videoLoadTimeoutRef = useRef(undefined); @@ -129,7 +130,8 @@ export default function WebRtcPlayer({ } pcRef.current = await aPc; - const ws = new WebSocket(wsURL); + wsRef.current = new WebSocket(wsURL); + const ws = wsRef.current; ws.addEventListener("open", () => { pcRef.current?.addEventListener("icecandidate", (ev) => { @@ -183,6 +185,10 @@ export default function WebRtcPlayer({ connect(aPc); return () => { + if (wsRef.current) { + wsRef.current.close(); + wsRef.current = null; + } if (pcRef.current) { pcRef.current.close(); pcRef.current = undefined;