Skip to content

Commit 2ffdf9a

Browse files
committed
fix: WebRTC broadcast edge cases — server shutdown cleanup, reset UI before async, hide join button while viewing
1 parent ec277a7 commit 2ffdf9a

File tree

1 file changed

+43
-10
lines changed

1 file changed

+43
-10
lines changed

client/js/app.js

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,14 @@ async function stopBroadcast() {
17681768

17691769
isBroadcasting = false;
17701770

1771+
// Reset UI immediately — before any async calls that might fail
1772+
const startBtn = document.getElementById('startBroadcastBtn');
1773+
if (startBtn) {
1774+
startBtn.textContent = '📡 Broadcast';
1775+
startBtn.classList.remove('is-live');
1776+
startBtn.onclick = startBroadcast;
1777+
}
1778+
17711779
// Close all peer connections to viewers
17721780
peerConnections.forEach(pc => pc.close());
17731781
peerConnections.clear();
@@ -1777,14 +1785,8 @@ async function stopBroadcast() {
17771785
broadcastStream = null;
17781786
}
17791787

1780-
await fetch('/broadcast/end', { method: 'POST' });
1781-
1782-
const startBtn = document.getElementById('startBroadcastBtn');
1783-
if (startBtn) {
1784-
startBtn.textContent = '📡 Broadcast';
1785-
startBtn.classList.remove('is-live');
1786-
startBtn.onclick = startBroadcast;
1787-
}
1788+
// Best effort — server may already be down
1789+
try { await fetch('/broadcast/end', { method: 'POST' }); } catch (e) { }
17881790
}
17891791

17901792
// Called when broadcaster gets notified a new viewer joined
@@ -1861,21 +1863,27 @@ function joinBroadcast() {
18611863
label.textContent = `${document.getElementById('broadcastLabel').textContent}`;
18621864
panel.style.display = 'flex';
18631865

1866+
// Hide join button while viewing
1867+
const joinBtn = document.getElementById('broadcastJoinBtn');
1868+
if (joinBtn) joinBtn.style.display = 'none';
1869+
18641870
// Reset position to default top-right on each join
18651871
panel.style.left = '';
18661872
panel.style.top = '';
18671873
panel.style.right = '20px';
18681874

18691875
makeDraggable(panel);
1870-
1871-
// Tell server we joined — get last frame immediately
18721876
socket.emit('broadcast-join');
18731877
}
18741878

18751879
function leaveBroadcast() {
18761880
const panel = document.getElementById('viewerPanel');
18771881
if (panel) panel.style.display = 'none';
18781882

1883+
// Restore join button
1884+
const joinBtn = document.getElementById('broadcastJoinBtn');
1885+
if (joinBtn) joinBtn.style.display = 'inline-block';
1886+
18791887
// Clean up viewer peer connection
18801888
if (viewerPeerConnection) {
18811889
viewerPeerConnection.close();
@@ -2094,6 +2102,31 @@ socket.on('webrtc-ice', async ({ candidate, fromId }) => {
20942102
}
20952103
});
20962104

2105+
socket.on('disconnect', () => {
2106+
// Trigger the same cleanup flow as a normal broadcast-ended event
2107+
if (isBroadcasting || viewerPeerConnection) {
2108+
isBroadcasting = false;
2109+
2110+
peerConnections.forEach(pc => pc.close());
2111+
peerConnections.clear();
2112+
2113+
if (broadcastStream) {
2114+
broadcastStream.getTracks().forEach(t => t.stop());
2115+
broadcastStream = null;
2116+
}
2117+
2118+
const startBtn = document.getElementById('startBroadcastBtn');
2119+
if (startBtn) {
2120+
startBtn.textContent = '📡 Broadcast';
2121+
startBtn.classList.remove('is-live');
2122+
startBtn.onclick = startBroadcast;
2123+
}
2124+
2125+
hideBroadcastBar();
2126+
leaveBroadcast();
2127+
}
2128+
});
2129+
20972130
// ─── RAISE HAND ──────────────────────────────────────────────
20982131

20992132
socket.on('broadcast-reaction-received', ({ from }) => {

0 commit comments

Comments
 (0)