diff --git a/apps/web/src/components/CallModal.tsx b/apps/web/src/components/CallModal.tsx index 3a8f6eb..18e3902 100644 --- a/apps/web/src/components/CallModal.tsx +++ b/apps/web/src/components/CallModal.tsx @@ -262,55 +262,47 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi }; // Force binding to the SINGLE stable video element - if (remoteVideoRef.current) { - if (remoteVideoRef.current.srcObject !== stream) { - console.log('[WebRTC] Binding stream to video element'); - remoteVideoRef.current.srcObject = stream; - // Force load to ensure browser picks up streams properly - remoteVideoRef.current.load(); - } - // Try to play. If fails, it's usually autoplay policy - remoteVideoRef.current.play().catch(() => { - console.warn('[WebRTC] Autoplay blocked, waiting for interaction'); - const retryPlay = () => { - if (!remoteVideoRef.current) return; - remoteVideoRef.current.play().then(() => { - console.log('[WebRTC] Video started after retry'); - }).catch(() => { - // If blocked, ensure it's muted and try again - if (remoteVideoRef.current) remoteVideoRef.current.muted = true; - setTimeout(retryPlay, 2000); - }); - }; - retryPlay(); - }); - } - // Handle remote media via the remoteVideoRef + // Use a custom property on the video element to track the play promise if (remoteVideoRef.current) { - if (remoteVideoRef.current.srcObject !== stream) { - console.log('[WebRTC] Binding stream to video element'); - remoteVideoRef.current.srcObject = stream; - } + const video = remoteVideoRef.current as any; - // Ensure not muted for remote audio - if (remoteVideoRef.current.muted) { - remoteVideoRef.current.muted = false; - } + const startPlayback = async () => { + // If a play promise is already pending, don't start a new one + if (video._playPromise) { + console.log('[WebRTC] Play promise already pending, skipping...'); + return; + } - remoteVideoRef.current.play() - .then(() => { + try { + if (video.srcObject !== stream) { + console.log('[WebRTC] Binding stream to video element'); + video.srcObject = stream; + } + video.muted = false; + + console.log('[WebRTC] Initiating play()...'); + video._playPromise = video.play(); + + await video._playPromise; + console.log('[WebRTC] Playback started successfully'); + video._playPromise = null; setNeedsInteraction(false); - }) - .catch(e => { + } catch (e: any) { + video._playPromise = null; if (e.name === 'NotAllowedError' || e.name === 'NotSupportedError') { console.warn('[WebRTC] Autoplay blocked, waiting for interaction'); setNeedsInteraction(true); + } else if (e.name === 'AbortError') { + console.warn('[WebRTC] Playback interrupted (AbortError), safe to ignore'); } else { - console.warn('[WebRTC] Playback failed (non-autoplay error):', e); + console.error('[WebRTC] Playback failed:', e); } - }); + } + }; + + startPlayback(); } track.onunmute = checkVideo;