Ф3
This commit is contained in:
@@ -214,20 +214,41 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
|
||||
// Ensure remote stream is bound to video element when it becomes available
|
||||
useEffect(() => {
|
||||
if (hasRemoteVideo && remoteVideoRef.current && remoteStreamRef.current) {
|
||||
const video = remoteVideoRef.current;
|
||||
if (callState === 'connected' && remoteVideoRef.current && remoteStreamRef.current) {
|
||||
const video = remoteVideoRef.current as any;
|
||||
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);
|
||||
});
|
||||
}
|
||||
const syncAndPlay = async (retryCount = 0) => {
|
||||
if (video._playPromise) return;
|
||||
|
||||
try {
|
||||
if (video.srcObject !== stream) {
|
||||
console.log('[WebRTC] Sync: Binding stream source');
|
||||
video.srcObject = stream;
|
||||
}
|
||||
video.muted = false;
|
||||
|
||||
if (stream.getTracks().length > 0) {
|
||||
video._playPromise = video.play();
|
||||
await video._playPromise;
|
||||
video._playPromise = null;
|
||||
setNeedsInteraction(false);
|
||||
console.log('[WebRTC] Sync: Playback successful');
|
||||
}
|
||||
} catch (e: any) {
|
||||
video._playPromise = null;
|
||||
if (e.name === 'AbortError' && retryCount < 10) {
|
||||
console.log(`[WebRTC] Sync: Aborted, retrying (${retryCount + 1})...`);
|
||||
setTimeout(() => syncAndPlay(retryCount + 1), 200);
|
||||
} else if (e.name === 'NotAllowedError') {
|
||||
setNeedsInteraction(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
syncAndPlay();
|
||||
}
|
||||
}, [hasRemoteVideo]);
|
||||
}, [hasRemoteVideo, callState]);
|
||||
|
||||
// Setup common peer connection event handlers
|
||||
const setupPeerHandlers = useCallback((pc: RTCPeerConnection) => {
|
||||
@@ -246,11 +267,18 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
const streams = event.streams;
|
||||
console.log(`[WebRTC] Received track: ${track.kind} state: ${track.readyState} streams: ${streams.length}`);
|
||||
|
||||
// Ensure we have a stable remote stream object
|
||||
// Ensure we have a stable remote stream object
|
||||
if (!remoteStreamRef.current) {
|
||||
remoteStreamRef.current = streams[0] || new MediaStream([track]);
|
||||
} else if (!remoteStreamRef.current.getTracks().includes(track)) {
|
||||
remoteStreamRef.current = streams[0] || new MediaStream();
|
||||
console.log('[WebRTC] Created new remoteStreamRef.current');
|
||||
}
|
||||
|
||||
if (!remoteStreamRef.current.getTracks().includes(track)) {
|
||||
console.log(`[WebRTC] Adding track ${track.kind} to remoteStreamRef`);
|
||||
remoteStreamRef.current.addTrack(track);
|
||||
} else {
|
||||
console.log(`[WebRTC] Track ${track.kind} already exists in remoteStreamRef`);
|
||||
}
|
||||
|
||||
const stream = remoteStreamRef.current;
|
||||
@@ -289,40 +317,30 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
if (remoteVideoRef.current) {
|
||||
const video = remoteVideoRef.current as any;
|
||||
|
||||
const startPlayback = async () => {
|
||||
// If a play request is already in progress, don't start a new one (as per Chrome docs)
|
||||
const startPlayback = async (retryCount = 0) => {
|
||||
if (video._playPromise) {
|
||||
console.log('[WebRTC] Play is already in progress, waiting...');
|
||||
console.log('[WebRTC] Play in progress, skipping startPlayback call');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Small stabilization delay (100ms)
|
||||
await new Promise(r => setTimeout(r, 100));
|
||||
|
||||
if (video.srcObject !== stream) {
|
||||
console.log('[WebRTC] Binding stream to video element');
|
||||
video.srcObject = stream;
|
||||
}
|
||||
video.muted = false;
|
||||
|
||||
console.log('[WebRTC] Calling video.play()...');
|
||||
console.log('[WebRTC] ontrack: calling play()...');
|
||||
video._playPromise = video.play();
|
||||
|
||||
await video._playPromise;
|
||||
|
||||
console.log('[WebRTC] Playback confirmed');
|
||||
video._playPromise = null;
|
||||
setNeedsInteraction(false);
|
||||
} catch (e: any) {
|
||||
video._playPromise = null;
|
||||
if (e.name === 'NotAllowedError') {
|
||||
console.warn('[WebRTC] Autoplay blocked, showing UI');
|
||||
if (e.name === 'AbortError' && retryCount < 10) {
|
||||
console.log(`[WebRTC] ontrack: Aborted, retrying (${retryCount + 1})...`);
|
||||
setTimeout(() => startPlayback(retryCount + 1), 200);
|
||||
} else if (e.name === 'NotAllowedError') {
|
||||
setNeedsInteraction(true);
|
||||
} else if (e.name === 'AbortError') {
|
||||
console.log('[WebRTC] Play aborted (likely concurrent track), will be retried automatically');
|
||||
} else {
|
||||
console.error('[WebRTC] Fatal playback error:', e);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1339,6 +1357,7 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
const onRenegotiate = async (data: { from: string; offer: RTCSessionDescriptionInit }) => {
|
||||
if (!peerRef.current || data.from !== targetUserIdRef.current) return;
|
||||
try {
|
||||
console.log('[onRenegotiate] Received offer, setting remote description');
|
||||
await peerRef.current.setRemoteDescription(new RTCSessionDescription(data.offer));
|
||||
const answer = await peerRef.current.createAnswer();
|
||||
await peerRef.current.setLocalDescription(answer);
|
||||
@@ -1346,6 +1365,22 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
targetUserId: targetUserIdRef.current,
|
||||
answer: peerRef.current.localDescription,
|
||||
});
|
||||
|
||||
// Nudge video check after renegotiation
|
||||
setTimeout(() => {
|
||||
console.log('[onRenegotiate] Nudging video check');
|
||||
// pc.ontrack should have fired by now, calling checkVideo via setHasRemoteVideo
|
||||
// but we can trigger it manually if we find the stream
|
||||
if (remoteStreamRef.current) {
|
||||
const hasVideo = remoteStreamRef.current.getVideoTracks().some(t => t.readyState === 'live');
|
||||
console.log('[onRenegotiate] Manually found video tracks:', hasVideo);
|
||||
if (hasVideo && !hasRemoteVideoRef.current) {
|
||||
hasRemoteVideoRef.current = true;
|
||||
setHasRemoteVideo(true);
|
||||
setCallType('video');
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
} catch (err) {
|
||||
console.error('Renegotiation error:', err);
|
||||
}
|
||||
@@ -1640,7 +1675,9 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
<span className="text-xl text-white font-medium mb-1">{displayName}</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>
|
||||
<span className="text-sm animate-pulse">
|
||||
{isScreenSharing ? 'Вы транслируете экран...' : 'Ожидание потока...'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user