diff --git a/src/components/Video.tsx b/src/components/Video.tsx index 6eee6ce..9d6bb6d 100644 --- a/src/components/Video.tsx +++ b/src/components/Video.tsx @@ -13,51 +13,94 @@ interface Props { user?: IUser; } +const SPEAKING_HIDE_DELAY_MS = 400; + function Video({ mediaStream, muted, user }: Props) { const remoteVideoRef = useRef(null); + const remoteAudioRef = useRef(null); const isSpeaking = useIsAudioActive({ source: mediaStream }); + const [showSpeakingBorder, setShowSpeakingBorder] = useState(false); + const hideTimeoutRef = useRef | null>(null); const [_muted, setMuted] = useState(muted); const [isLoading, setIsLoading] = useState(true); const [minimized, setMinimized] = useState(user?.isAdmin ? false : true); + const hasVideo = (mediaStream?.getVideoTracks().length ?? 0) > 0; + + useEffect(() => { + if (user && user.micEnabled === false) { + if (hideTimeoutRef.current) { + clearTimeout(hideTimeoutRef.current); + hideTimeoutRef.current = null; + } + setShowSpeakingBorder(false); + return; + } + if (isSpeaking) { + if (hideTimeoutRef.current) { + clearTimeout(hideTimeoutRef.current); + hideTimeoutRef.current = null; + } + setShowSpeakingBorder(true); + } else { + hideTimeoutRef.current = setTimeout(() => { + setShowSpeakingBorder(false); + hideTimeoutRef.current = null; + }, SPEAKING_HIDE_DELAY_MS); + } + return () => { + if (hideTimeoutRef.current) clearTimeout(hideTimeoutRef.current); + }; + }, [isSpeaking, user?.micEnabled]); + function toggleSound() { - if (!remoteVideoRef.current) return; - // remoteVideoRef.current.muted = !remoteVideoRef.current.muted; setMuted((prev) => !prev); } useEffect(() => { - if (!remoteVideoRef.current) return; + if (!mediaStream) return; - remoteVideoRef.current.srcObject = mediaStream; - remoteVideoRef.current.onloadedmetadata = () => { - remoteVideoRef.current?.play(); - }; - - remoteVideoRef.current.onplay = () => { + if (hasVideo && remoteVideoRef.current) { + remoteVideoRef.current.srcObject = mediaStream; + remoteVideoRef.current.onloadedmetadata = () => { + remoteVideoRef.current?.play(); + }; + remoteVideoRef.current.onplay = () => setIsLoading(false); + } else if (!hasVideo && remoteAudioRef.current) { + remoteAudioRef.current.srcObject = mediaStream; + remoteAudioRef.current.onloadedmetadata = () => { + remoteAudioRef.current?.play(); + }; + remoteAudioRef.current.onplay = () => setIsLoading(false); setIsLoading(false); - }; - - console.log("mediaStream", mediaStream?.getTracks()); - }, [mediaStream]); - - useEffect(() => { - console.log("remoteVideoRef.current", remoteVideoRef); - }, [remoteVideoRef.current]); + } + }, [mediaStream, hasVideo]); return (
- + {hasVideo ? ( + + ) : ( + <> +