import React, { useEffect } from 'react'; import { useVoiceStore } from '../../stores/voiceStore'; import { useServerStore } from '../../stores/serverStore'; import { useAuthStore } from '../../stores/authStore'; import { getActiveRoom } from '../../hooks/useLiveKit'; import { wsSend } from '../../hooks/useWebSocket'; import { VideoPresets, VideoPreset } from 'livekit-client'; const QUALITY_MAP: Record = { '1080p60': new VideoPreset(1920, 1080, 15_000_000, 60), '1080p': new VideoPreset(1920, 1080, 8_000_000, 30), '720p60': new VideoPreset(1280, 720, 8_000_000, 60), '720p': new VideoPreset(1280, 720, 5_000_000, 30), '540p': new VideoPreset(960, 540, 2_000_000, 30), '360p': new VideoPreset(640, 360, 1_000_000, 30), }; export function DmCallView() { const activeDmCall = useVoiceStore((s) => s.activeDmCall); const participants = useVoiceStore((s) => s.participants); const isMuted = useVoiceStore((s) => s.isMuted); const isDeafened = useVoiceStore((s) => s.isDeafened); const isCameraOn = useVoiceStore((s) => s.isCameraOn); const isScreenSharing = useVoiceStore((s) => s.isScreenSharing); const toggleMic = useVoiceStore((s) => s.toggleMic); const toggleDeafen = useVoiceStore((s) => s.toggleDeafen); const toggleCamera = useVoiceStore((s) => s.toggleCamera); const toggleScreenShare = useVoiceStore((s) => s.toggleScreenShare); const setActiveDmCall = useVoiceStore((s) => s.setActiveDmCall); const leaveVoice = useVoiceStore((s) => s.leaveVoice); const dmChannels = useServerStore((s) => s.dmChannels); const authUser = useAuthStore((s) => s.user); const dmChannel = dmChannels.find(dm => dm.id === activeDmCall?.dmChannelId); const otherUser = dmChannel?.members.find(m => m.id !== authUser?.id); const otherName = otherUser?.displayName ?? otherUser?.username ?? 'User'; const handleMute = () => { const room = getActiveRoom(); if (room) { room.localParticipant.setMicrophoneEnabled(isMuted); } toggleMic(); }; const handleDeafen = () => { const room = getActiveRoom(); if (room) { const newDeafened = !isDeafened; room.remoteParticipants.forEach((p) => { p.audioTrackPublications.forEach((pub) => { if (pub.track) { (pub.track as any).setVolume?.(newDeafened ? 0 : 1); } }); }); if (newDeafened) { room.localParticipant.setMicrophoneEnabled(false); } else if (!isMuted) { room.localParticipant.setMicrophoneEnabled(true); } } toggleDeafen(); }; const handleCamera = async () => { const room = getActiveRoom(); if (room) { const willEnable = !isCameraOn; if (willEnable) { const videoQuality = useVoiceStore.getState().videoQuality; const preset = QUALITY_MAP[videoQuality]; if (preset) { await room.localParticipant.setCameraEnabled(true, { resolution: preset.resolution }, { videoEncoding: preset.encoding, simulcast: videoQuality === '1080p' || videoQuality === '720p' } ); } else { await room.localParticipant.setCameraEnabled(true); } } else { await room.localParticipant.setCameraEnabled(false); } } toggleCamera(); }; const handleScreenShare = () => { const room = getActiveRoom(); if (room) { room.localParticipant.setScreenShareEnabled(!isScreenSharing); } toggleScreenShare(); }; const handleEndCall = () => { if (activeDmCall) { wsSend({ type: 'dm_call_end', dmChannelId: activeDmCall.dmChannelId }); } setActiveDmCall(null); leaveVoice(); }; // Attach video elements useEffect(() => { participants.forEach((p) => { if (p.videoTrack) { const el = document.getElementById(`dm-video-${p.userId}`) as HTMLVideoElement | null; if (el && (el.srcObject as MediaStream | null)?.getVideoTracks()[0]?.id !== p.videoTrack.id) { el.srcObject = new MediaStream([p.videoTrack]); } } }); }, [participants]); if (!activeDmCall) return null; const localParticipant = participants.find(p => p.isLocal); const remoteParticipant = participants.find(p => !p.isLocal); return (
{/* Header */}
{otherName} In Call
{/* Main call area - 1-on-1 layout */}
{/* Remote participant (or waiting) */}
{remoteParticipant?.videoTrack ? (
) : (
{otherName.charAt(0).toUpperCase()}
{remoteParticipant?.isSpeaking && (
)}
)} {remoteParticipant ? otherName : 'Connecting...'} {remoteParticipant?.isMuted && ( Muted )}
{/* Local participant */}
{localParticipant?.videoTrack ? (
) : (
{(authUser?.displayName ?? authUser?.username ?? 'Y').charAt(0).toUpperCase()}
{localParticipant?.isSpeaking && (
)}
)} {authUser?.displayName ?? authUser?.username ?? 'You'} (You)
{/* Control bar */}
{/* Mute */} {/* Deafen */} {/* Camera */} {/* Screen Share */} {/* Spacer */}
{/* End Call */}
); }