.net10 сервер с рабочими звонками и файлами
This commit is contained in:
@@ -302,12 +302,19 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
), '→ hasRemoteVideo:', hasVideo);
|
||||
|
||||
if (hasVideo !== hasRemoteVideoRef.current) {
|
||||
console.log(`[checkVideo] hasRemoteVideo changed: ${hasRemoteVideoRef.current} -> ${hasVideo}`);
|
||||
hasRemoteVideoRef.current = hasVideo;
|
||||
setHasRemoteVideo(hasVideo);
|
||||
}
|
||||
|
||||
if (hasVideo && callType !== 'video') {
|
||||
// Auto-switch UI mode if remote starts sending video or STOPS sending it
|
||||
if (hasVideo && callType === 'voice') {
|
||||
console.log('[checkVideo] Remote started video, switching UI to video mode');
|
||||
setCallType('video');
|
||||
} else if (!hasVideo && callType === 'video') {
|
||||
// If we were in video mode but tracks are gone, revert to voice
|
||||
console.log('[checkVideo] Remote stopped video, reverting UI to voice mode');
|
||||
setCallType('voice');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1401,13 +1408,17 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
setCallType(data.callType);
|
||||
|
||||
// If remote switched to video, nudge the video element
|
||||
if (data.callType === 'video') {
|
||||
if (data.callType === 'video' || data.callType === 'voice') {
|
||||
setTimeout(() => {
|
||||
if (remoteVideoRef.current && remoteStreamRef.current) {
|
||||
console.log(`[onCallTypeChanged] Nudging playback for ${data.callType}`);
|
||||
remoteVideoRef.current.srcObject = remoteStreamRef.current;
|
||||
remoteVideoRef.current.play().catch(() => {});
|
||||
remoteVideoRef.current.play().catch(e => {
|
||||
if (e.name === 'NotAllowedError') setNeedsInteraction(true);
|
||||
console.warn('Auto-play failed:', e);
|
||||
});
|
||||
}
|
||||
}, 500);
|
||||
}, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1456,15 +1467,46 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
}
|
||||
});
|
||||
|
||||
// Sync remote video ref with remote stream (only when srcObject actually changes)
|
||||
// Sync remote video/audio ref with remote stream
|
||||
useEffect(() => {
|
||||
if (!remoteVideoRef.current || !remoteStreamRef.current) return;
|
||||
if (remoteVideoRef.current.srcObject !== remoteStreamRef.current) {
|
||||
console.log('[useEffect] Syncing remote video srcObject');
|
||||
remoteVideoRef.current.srcObject = remoteStreamRef.current;
|
||||
remoteVideoRef.current.play().catch(() => { });
|
||||
}
|
||||
}, [hasRemoteVideo, callType]);
|
||||
if (!remoteStreamRef.current) return;
|
||||
|
||||
const stream = remoteStreamRef.current;
|
||||
|
||||
const bindAndPlay = async () => {
|
||||
// 1) Bind to video element (primary for video, also handles audio)
|
||||
if (remoteVideoRef.current) {
|
||||
const video = remoteVideoRef.current as any;
|
||||
if (video.srcObject !== stream) {
|
||||
console.log('[useEffect] Binding stream to remoteVideoRef');
|
||||
video.srcObject = stream;
|
||||
}
|
||||
video.muted = false;
|
||||
video.volume = remoteVolume;
|
||||
if (stream.getTracks().length > 0) {
|
||||
video.play().catch((e: any) => {
|
||||
if (e.name === 'NotAllowedError') setNeedsInteraction(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Bind to audio element (dedicated fallback for sound, especially in voice calls)
|
||||
if (remoteAudioRef.current) {
|
||||
const audio = remoteAudioRef.current;
|
||||
if (audio.srcObject !== stream) {
|
||||
console.log('[useEffect] Binding stream to remoteAudioRef');
|
||||
audio.srcObject = stream;
|
||||
}
|
||||
audio.muted = false;
|
||||
audio.volume = remoteVolume;
|
||||
if (stream.getAudioTracks().length > 0) {
|
||||
audio.play().catch(() => {});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bindAndPlay();
|
||||
}, [hasRemoteVideo, callType, callState, remoteVolume]);
|
||||
|
||||
// Cleanup on unmount
|
||||
useEffect(() => {
|
||||
@@ -1804,6 +1846,9 @@ export default function CallModal({ isOpen, onClose, targetUser, callType: initi
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Dedicated hidden audio element to ensure sound in ALL cases once connected */}
|
||||
<audio ref={remoteAudioRef} autoPlay style={{ display: 'none' }} />
|
||||
</div>
|
||||
|
||||
{/* === Controls === */}
|
||||
|
||||
@@ -266,14 +266,25 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
|
||||
}, [chatMessages.length, isLoadingMessages]);
|
||||
|
||||
// Scroll detection
|
||||
const handleScroll = () => {
|
||||
const checkScrollPosition = useCallback(() => {
|
||||
const container = messagesContainerRef.current;
|
||||
if (!container) return;
|
||||
const isNearBottom =
|
||||
container.scrollHeight - container.scrollTop - container.clientHeight < 200;
|
||||
setShowScrollDown(!isNearBottom);
|
||||
}, []);
|
||||
|
||||
const handleScroll = () => {
|
||||
checkScrollPosition();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// Check scroll position when messages change or scroll ready state changes
|
||||
if (scrollReady) {
|
||||
checkScrollPosition();
|
||||
}
|
||||
}, [chatMessages.length, scrollReady, checkScrollPosition]);
|
||||
|
||||
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
if (!chatViewRef.current) return;
|
||||
const { left, top } = chatViewRef.current.getBoundingClientRect();
|
||||
@@ -890,7 +901,7 @@ export default function ChatView({ onStartCall, onStartGroupCall }: { onStartCal
|
||||
)}
|
||||
|
||||
{/* Ввод сообщения */}
|
||||
<MessageInput chatId={activeChat} />
|
||||
{activeChat && <MessageInput chatId={activeChat} />}
|
||||
|
||||
{/* Профиль пользователя */}
|
||||
<AnimatePresence>
|
||||
|
||||
Reference in New Issue
Block a user