diff --git a/client/src/App.tsx b/client/src/App.tsx index c1be5a1..0c11ae1 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -23,17 +23,19 @@ const Lobby: React.FC = (props: LobbyProps) => { const [global, setGlobal] = useState({ connected: false, ws: undefined, + sessionId: sessionId, name: "", chat: [], }); - useEffect(() => { - console.log(global); - }, [global]); - const onWsMessage = (event: MessageEvent) => { const data = JSON.parse(event.data); switch (data.type) { + case "update": + if ("name" in data) { + setName(data.name); + } + break; case "error": setError(data.error); break; diff --git a/client/src/GlobalContext.tsx b/client/src/GlobalContext.tsx index cbcb273..9660a11 100644 --- a/client/src/GlobalContext.tsx +++ b/client/src/GlobalContext.tsx @@ -4,6 +4,7 @@ interface GlobalContextType { connected: boolean; ws?: WebSocket; name?: string; + sessionId?: string; chat?: any[]; [key: string]: any; } @@ -12,6 +13,7 @@ const GlobalContext = createContext({ connected: false, ws: undefined, name: "", + sessionId: undefined, chat: [] }); diff --git a/client/src/MediaControl.tsx b/client/src/MediaControl.tsx index 8044126..ec8d998 100644 --- a/client/src/MediaControl.tsx +++ b/client/src/MediaControl.tsx @@ -14,7 +14,8 @@ const debug = true; // Types for peer and track context interface Peer { - name: string; + sessionId: string; + peerName: string; hasAudio: boolean; hasVideo: boolean; attributes: Record; @@ -33,6 +34,7 @@ interface TrackContext { interface AddPeerConfig { peer_id: string; + peer_name: string; hasAudio: boolean; hasVideo: boolean; should_create_offer?: boolean; @@ -85,7 +87,7 @@ type MediaAgentProps = { const MediaAgent = (props: MediaAgentProps) => { const { setPeers } = props; - const { name, ws } = useContext(GlobalContext); + const { name, ws, sessionId } = useContext(GlobalContext); const [peers] = useState>({}); const [track, setTrack] = useState(undefined); const ignore = useRef(false); @@ -127,7 +129,7 @@ const MediaAgent = (props: MediaAgentProps) => { console.log(`media-agent - No local media track`); return; } - const peer_id = config.peer_id; + const { peer_id, peer_name } = config; if (peer_id in peers) { if (!peers[peer_id].dead) { /* This is normal when peers are added by other connecting @@ -140,7 +142,8 @@ const MediaAgent = (props: MediaAgentProps) => { * have its peer state change and trigger an update from * */ const peer: Peer = { - name: peer_id, + sessionId: peer_id, + peerName: peer_name, hasAudio: config.hasAudio, hasVideo: config.hasVideo, attributes: {}, @@ -442,15 +445,16 @@ const MediaAgent = (props: MediaAgentProps) => { }, [ws, track, peers, setPeers, sendMessage]); useEffect(() => { - if (!name) { + if (!sessionId) { return; } let update = false; if (track) { - if (!(name in peers)) { + if (!(sessionId in peers)) { update = true; - peers[name] = { - name: name, + peers[sessionId] = { + peerName: name || "Unknown", + sessionId: sessionId, local: true, muted: true, videoOn: false, @@ -468,7 +472,7 @@ const MediaAgent = (props: MediaAgentProps) => { /* Renaming the local connection requires the peer to be deleted * and re-established with the signaling server */ for (let key in peers) { - if (peers[key].local && key !== name) { + if (peers[key].local && key !== sessionId) { delete peers[key]; update = true; } @@ -485,21 +489,27 @@ const MediaAgent = (props: MediaAgentProps) => { return; } + type setup_local_media_props = { + audio?: boolean; + video?: boolean; + } const setup_local_media = async ( - options: { audio?: boolean; video?: boolean } = { audio: true, video: true } + props?: setup_local_media_props ): Promise => { + const { audio = true, video = true } = props ?? {}; // Ask user for permission to use the computers microphone and/or camera console.log( - `media-agent - Requesting access to local audio: ${!!options.audio} / video: ${!!options.video} inputs` + `media-agent - Requesting access to local audio: ${audio} / video: ${video} inputs` ); try { const media = await navigator.mediaDevices.getUserMedia({ - audio: !!options.audio, - video: !!options.video, + audio, + video, }); - sendMessage({ type: "media_status", video: !!options.video, audio: !!options.audio }); + sendMessage({ type: "media_status", video, audio }); // Optionally apply constraints - if (options.video && media.getVideoTracks().length > 0) { + if (video && media.getVideoTracks().length > 0) { + console.log(`media-agent - Applying video constraints to ${media.getVideoTracks().length} video tracks`); media.getVideoTracks().forEach((track) => { track.applyConstraints({ width: { min: 160, max: 320 }, @@ -507,13 +517,13 @@ const MediaAgent = (props: MediaAgentProps) => { }); }); } - return { media, audio: !!options.audio, video: !!options.video }; + return { media, audio, video }; } catch (error) { - if (options.video) { + if (video) { console.log(`media-agent - Access to audio and video failed. Trying just audio.`); // Try again with only audio if video failed - return setup_local_media({ audio: options.audio, video: false }); - } else if (options.audio) { + return setup_local_media({ audio, video: false }); + } else if (audio) { console.log(`media-agent - Access to audio failed.`); sendMessage({ type: "media_status", video: false, audio: false }); // Return a dummy context with no media @@ -530,14 +540,16 @@ const MediaAgent = (props: MediaAgentProps) => { if (debug) console.log(`media-agent - WebSocket open request. ` + `Attempting to create local media.`); setup_local_media() .then((context) => { + console.log(`media-agent - local media setup complete`, context); /* once the user has given us access to their * microphone/camcorder, join the channel and start peering up */ - if (ignore.current) { - console.log(`media-agent - aborting setting local media`); - } else { + console.log(`media-agent - ignore set to ${ignore.current}`); + // if (ignore.current) { + // console.log(`media-agent - aborting setting local media`); + // } else { console.log("media-agent - setTrack called with context:", context); setTrack(context); - } + // } }) .catch((error) => { /* user denied access to a/v */ @@ -572,8 +584,8 @@ const MediaControl: React.FC = ({ isSelf, peer, className }) }); useEffect(() => { - if (peer && peer.name) { - const el = document.querySelector(`.MediaControl[data-peer="${peer.name}"]`); + if (peer && peer.peerName) { + const el = document.querySelector(`.MediaControl[data-peer="${peer.sessionId}"]`); setTarget(el ?? undefined); } }, [setTarget, peer]); @@ -594,7 +606,7 @@ const MediaControl: React.FC = ({ isSelf, peer, className }) console.log(`media-control - render`); const toggleMute = (event: React.MouseEvent | React.TouchEvent) => { - if (debug) console.log(`media-control - toggleMute - ${peer.name}`, !muted); + if (debug) console.log(`media-control - toggleMute - ${peer.peerName}`, !muted); if (peer) { peer.muted = !muted; setMuted(peer.muted); @@ -603,11 +615,11 @@ const MediaControl: React.FC = ({ isSelf, peer, className }) }; const toggleVideo = (event: React.MouseEvent | React.TouchEvent) => { - if (debug) console.log(`media-control - toggleVideo - ${peer.name}`, !videoOn); + if (debug) console.log(`media-control - toggleVideo - ${peer.peerName}`, !videoOn); if (peer) { peer.videoOn = !videoOn; if (peer.videoOn && media) { - const video = document.querySelector(`video[data-id="${media.name}"]`) as HTMLVideoElement | null; + const video = document.querySelector(`video[data-id="${media.peerName}"]`) as HTMLVideoElement | null; if (video && typeof video.play === "function") { video.play(); } @@ -622,7 +634,7 @@ const MediaControl: React.FC = ({ isSelf, peer, className }) return; } if (media.attributes.srcObject) { - console.log(`media-control - audio enable - ${peer.name}:${!muted}`); + console.log(`media-control - audio enable - ${peer.peerName}:${!muted}`); (media.attributes.srcObject.getAudioTracks() as MediaStreamTrack[]).forEach((track: MediaStreamTrack) => { track.enabled = media.hasAudio && !muted; }); @@ -634,7 +646,7 @@ const MediaControl: React.FC = ({ isSelf, peer, className }) return; } if (media.attributes.srcObject) { - console.log(`media-control - video enable - ${peer.name}:${videoOn}`); + console.log(`media-control - video enable - ${peer.peerName}:${videoOn}`); (media.attributes.srcObject.getVideoTracks() as MediaStreamTrack[]).forEach((track: MediaStreamTrack) => { track.enabled = Boolean(media.hasVideo) && Boolean(videoOn); }); @@ -651,9 +663,9 @@ const MediaControl: React.FC = ({ isSelf, peer, className }) } return ( - +
-
+
{isSelf && (
@@ -712,7 +724,7 @@ const MediaControl: React.FC = ({ isSelf, peer, className }) />