This commit is contained in:
Халимов Рустам
2026-03-11 17:15:23 +03:00
parent 3cf56b62ca
commit 8c7ca3b869
+27 -2
View File
@@ -114,6 +114,7 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
const [isVideoOff, setIsVideoOff] = useState(false); const [isVideoOff, setIsVideoOff] = useState(false);
const [isScreenSharing, setIsScreenSharing] = useState(false); const [isScreenSharing, setIsScreenSharing] = useState(false);
const [hasRemoteVideo, setHasRemoteVideo] = useState(false); const [hasRemoteVideo, setHasRemoteVideo] = useState(false);
const hasRemoteVideoRef = useRef(false);
const [isFullscreen, setIsFullscreen] = useState(false); const [isFullscreen, setIsFullscreen] = useState(false);
const [isMinimized, setIsMinimized] = useState(false); const [isMinimized, setIsMinimized] = useState(false);
const [duration, setDuration] = useState(0); const [duration, setDuration] = useState(0);
@@ -211,6 +212,23 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
scheduleClose(); scheduleClose();
}, [cleanup, scheduleClose]); }, [cleanup, scheduleClose]);
// Ensure remote stream is bound to video element when it becomes available
useEffect(() => {
if (hasRemoteVideo && remoteVideoRef.current && remoteStreamRef.current) {
const video = remoteVideoRef.current;
const stream = remoteStreamRef.current;
if (video.srcObject !== stream) {
console.log('[WebRTC] Effect: Binding stream to video element');
video.srcObject = stream;
video.muted = false;
video.play().catch(e => {
if (e.name === 'NotAllowedError') setNeedsInteraction(true);
});
}
}
}, [hasRemoteVideo]);
// Setup common peer connection event handlers // Setup common peer connection event handlers
const setupPeerHandlers = useCallback((pc: RTCPeerConnection) => { const setupPeerHandlers = useCallback((pc: RTCPeerConnection) => {
pc.onicecandidate = (e) => { pc.onicecandidate = (e) => {
@@ -255,7 +273,11 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
`${t.label} state=${t.readyState} enabled=${t.enabled} muted=${t.muted}` `${t.label} state=${t.readyState} enabled=${t.enabled} muted=${t.muted}`
), '→ hasRemoteVideo:', hasVideo); ), '→ hasRemoteVideo:', hasVideo);
if (hasVideo !== hasRemoteVideoRef.current) {
hasRemoteVideoRef.current = hasVideo;
setHasRemoteVideo(hasVideo); setHasRemoteVideo(hasVideo);
}
if (hasVideo && callType !== 'video') { if (hasVideo && callType !== 'video') {
setCallType('video'); setCallType('video');
} }
@@ -1597,7 +1619,7 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
ref={remoteVideoRef} ref={remoteVideoRef}
autoPlay autoPlay
playsInline playsInline
className="w-full h-full object-contain" className={`w-full h-full object-contain transition-opacity duration-300 ${hasRemoteVideo ? 'opacity-100' : 'opacity-0'}`}
onContextMenu={(e) => { e.preventDefault(); setShowVolumeSlider(true); }} onContextMenu={(e) => { e.preventDefault(); setShowVolumeSlider(true); }}
/> />
@@ -1616,7 +1638,10 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
</div> </div>
<VideoOff size={48} className="text-zinc-500 mb-2" /> <VideoOff size={48} className="text-zinc-500 mb-2" />
<span className="text-xl text-white font-medium mb-1">{displayName}</span> <span className="text-xl text-white font-medium mb-1">{displayName}</span>
<span className="text-sm text-zinc-500 animate-pulse">Соединение...</span> <div className="flex items-center gap-2 text-zinc-500">
<div className="w-2 h-2 rounded-full bg-vortex-500 animate-pulse" />
<span className="text-sm animate-pulse">Ожидание потока...</span>
</div>
</div> </div>
)} )}