diff --git a/apps/web/src/components/CallModal.tsx b/apps/web/src/components/CallModal.tsx
index 9a986ac..032a8bd 100644
--- a/apps/web/src/components/CallModal.tsx
+++ b/apps/web/src/components/CallModal.tsx
@@ -249,42 +249,41 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
}
};
- // Always merge tracks into a single remote stream
+ // Ensure we have a stream object (even if browser didn't provide one)
if (!remoteStreamRef.current) {
remoteStreamRef.current = streams[0] || new MediaStream([track]);
- } else if (streams[0]) {
- streams[0].getTracks().forEach(t => {
- if (!remoteStreamRef.current?.getTracks().includes(t)) {
- remoteStreamRef.current?.addTrack(t);
- }
- });
} else if (!remoteStreamRef.current.getTracks().includes(track)) {
remoteStreamRef.current.addTrack(track);
}
const stream = remoteStreamRef.current;
- // Bind to DOM elements
- if (track.kind === 'video' && remoteVideoRef.current) {
- remoteVideoRef.current.srcObject = stream;
- remoteVideoRef.current.play().catch(err => console.warn('[WebRTC] video play failed:', err));
- checkVideo();
- } else if (track.kind === 'audio') {
- if (remoteAudioRef?.current) {
- remoteAudioRef.current.srcObject = stream;
- remoteAudioRef.current.play().catch(err => console.warn('[WebRTC] audio play failed:', err));
- } else if (remoteVideoRef.current) {
- remoteVideoRef.current.srcObject = stream;
+ // Link to DOM elements immediately
+ if (remoteVideoRef.current) {
+ // IMPORTANT: If srcObject is the same, some browsers won't refresh the view.
+ // We set it to the stream and call play() explicitly.
+ if (remoteVideoRef.current.srcObject !== stream) {
+ remoteVideoRef.current.srcObject = stream;
}
+ remoteVideoRef.current.play().catch(err => {
+ console.warn('[WebRTC] Video play failed (retrying):', err);
+ // Retry play on next tick if failed
+ setTimeout(() => remoteVideoRef.current?.play().catch(() => {}), 500);
+ });
+ }
+
+ if (track.kind === 'audio' && remoteAudioRef?.current) {
+ remoteAudioRef.current.srcObject = stream;
+ remoteAudioRef.current.play().catch(() => {});
}
track.onunmute = checkVideo;
track.onmute = checkVideo;
track.onended = checkVideo;
- // Extra checks for slow browsers
+ checkVideo();
setTimeout(checkVideo, 500);
- setTimeout(checkVideo, 1500);
+ setTimeout(checkVideo, 2000);
};
pc.onconnectionstatechange = () => {
@@ -1549,7 +1548,6 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
ref={remoteVideoRef}
autoPlay
playsInline
- muted
className={`absolute inset-0 w-full h-full object-contain bg-black transition-opacity duration-300 ${hasRemoteVideo ? 'opacity-100' : 'opacity-0'}`}
onContextMenu={(e) => { e.preventDefault(); setShowVolumeSlider(true); }}
/>
@@ -1669,7 +1667,7 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
)}
{/* Hidden remote video element */}
-
+
)}