From 91bf0b0d089bfcdd483ac91ad1489edbf442f4ee Mon Sep 17 00:00:00 2001 From: Babaev Makhmoud Date: Tue, 23 Sep 2025 00:24:49 +0300 Subject: [PATCH] Guard remote video stream attachments --- .../call/components/CallParticipantsGrid.tsx | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/frontend/src/features/call/components/CallParticipantsGrid.tsx b/frontend/src/features/call/components/CallParticipantsGrid.tsx index b614dfb..a964c77 100644 --- a/frontend/src/features/call/components/CallParticipantsGrid.tsx +++ b/frontend/src/features/call/components/CallParticipantsGrid.tsx @@ -18,24 +18,39 @@ export const CallParticipantsGrid = ({ containerRef, isFullscreen, }: CallParticipantsGridProps) => { - const handleLocalVideoRef = useCallback( - (element: HTMLVideoElement | null) => { - localVideoRef.current = element; + const attachStreamToElement = useCallback( + (element: HTMLVideoElement | null, stream: MediaStream | null | undefined) => { if (!element) { return; } - const stream = localStreamRef.current; - if (stream && element.srcObject !== stream) { + const currentStream = element.srcObject as MediaStream | null; + let streamAttached = false; + + if (stream && currentStream !== stream) { element.srcObject = stream; + streamAttached = true; } - element.muted = true; - if (element.srcObject) { + if ((streamAttached || element.paused) && element.srcObject) { element.play().catch(() => undefined); } }, - [localStreamRef, localVideoRef], + [], + ); + + const handleLocalVideoRef = useCallback( + (element: HTMLVideoElement | null) => { + localVideoRef.current = element; + if (!element) { + return; + } + + const stream = localStreamRef.current; + element.muted = true; + attachStreamToElement(element, stream); + }, + [attachStreamToElement, localStreamRef, localVideoRef], ); if (isFullscreen && remoteParticipants.length > 0) { @@ -48,10 +63,7 @@ export const CallParticipantsGrid = ({ autoPlay playsInline ref={(element) => { - if (element) { - element.srcObject = primaryParticipant.stream; - element.play().catch(() => undefined); - } + attachStreamToElement(element, primaryParticipant.stream); }} className="video-stage__primary-video" /> @@ -77,10 +89,7 @@ export const CallParticipantsGrid = ({ autoPlay playsInline ref={(element) => { - if (element) { - element.srcObject = participant.stream; - element.play().catch(() => undefined); - } + attachStreamToElement(element, participant.stream); }} className="video-stage__thumbnail-video" /> @@ -105,10 +114,7 @@ export const CallParticipantsGrid = ({ autoPlay playsInline ref={(element) => { - if (element) { - element.srcObject = participant.stream; - element.play().catch(() => undefined); - } + attachStreamToElement(element, participant.stream); }} /> {participant.id.slice(0, 6)}