From d391e0fb3beaa8bb0f146208f46887d6a0d37fa1 Mon Sep 17 00:00:00 2001 From: codex Date: Fri, 12 Jun 2026 21:51:04 +0200 Subject: [PATCH] Fix repeated screen sharing --- public/app.js | 85 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 26 deletions(-) diff --git a/public/app.js b/public/app.js index ea9f0e9..13030d2 100644 --- a/public/app.js +++ b/public/app.js @@ -67,6 +67,7 @@ let localMicDestination; let micMeterAnimationFrame = 0; let micMeterLevel = 0; let screenStream; +let stoppingScreenShare = false; let localPresentationTile; let events; let audioContext; @@ -1539,38 +1540,65 @@ async function getScreenShareStream() { } async function startScreenShare() { - if (!localStream || screenStream) return; + if (!localStream || screenStream || stoppingScreenShare) return; - screenStream = await getScreenShareStream(); - const screenTrack = screenStream.getVideoTracks()[0]; - await constrainScreenTrack(screenTrack); - createLocalPresentationTile(screenStream); - await replaceOutboundVideoTrack(screenTrack); - shareButton.textContent = "Stop Sharing"; - await sendRoomEvent({ type: "presentation-state", sharing: true }); - setActivity(displayName, "started sharing their screen."); + const nextScreenStream = await getScreenShareStream(); + screenStream = nextScreenStream; + const screenTrack = nextScreenStream.getVideoTracks()[0]; - screenTrack.onended = () => { - stopScreenShare().catch((error) => { - console.error(error); - setStatus("Could not stop screen sharing cleanly."); + try { + await constrainScreenTrack(screenTrack); + + screenTrack.onended = () => { + if (screenStream?.getVideoTracks()[0] !== screenTrack) return; + stopScreenShare().catch((error) => { + console.error(error); + setStatus("Could not stop screen sharing cleanly."); + }); + }; + + createLocalPresentationTile(nextScreenStream); + await replaceOutboundVideoTrack(screenTrack); + shareButton.textContent = "Stop Sharing"; + await sendRoomEvent({ type: "presentation-state", sharing: true }); + setActivity(displayName, "started sharing their screen."); + } catch (error) { + if (screenStream === nextScreenStream) { + screenStream = undefined; + } + nextScreenStream.getTracks().forEach((track) => { + track.onended = null; + if (track.readyState !== "ended") track.stop(); }); - }; + removeLocalPresentationTile(); + shareButton.textContent = "Share Screen"; + throw error; + } } async function stopScreenShare() { - if (!screenStream) return; + if (!screenStream || stoppingScreenShare) return; + stoppingScreenShare = true; + const streamToStop = screenStream; const cameraTrack = localStream?.getVideoTracks()[0]; - screenStream.getTracks().forEach((track) => track.stop()); screenStream = undefined; - removeLocalPresentationTile(); - if (cameraTrack) { - await replaceOutboundVideoTrack(cameraTrack); + + try { + removeLocalPresentationTile(); + if (cameraTrack) { + await replaceOutboundVideoTrack(cameraTrack); + } + shareButton.textContent = "Share Screen"; + await sendRoomEvent({ type: "presentation-state", sharing: false }); + setActivity(displayName, "stopped sharing their screen."); + } finally { + streamToStop.getTracks().forEach((track) => { + track.onended = null; + if (track.readyState !== "ended") track.stop(); + }); + stoppingScreenShare = false; } - shareButton.textContent = "Share Screen"; - await sendRoomEvent({ type: "presentation-state", sharing: false }); - setActivity(displayName, "stopped sharing their screen."); } initialNameForm.addEventListener("submit", async (event) => { @@ -1735,10 +1763,15 @@ clearPlaylistButton.addEventListener("click", () => { shareButton.addEventListener("click", async () => { if (!localStream) return; - if (screenStream) { - await stopScreenShare(); - } else { - await startScreenShare(); + try { + if (screenStream) { + await stopScreenShare(); + } else { + await startScreenShare(); + } + } catch (error) { + console.error(error); + setStatus("Could not update screen sharing."); } });