From 5e85a4eaa11d6bf06c6b32bdb25d48d1cdedd2bb Mon Sep 17 00:00:00 2001 From: isaacclad Date: Wed, 1 Jul 2026 13:57:25 +0000 Subject: [PATCH] Fix meeting audio attach, prune left tiles, drop Ladill Meet eyebrow. Attach remote audio tracks for playback, remove stale participant cards on leave, and remove the redundant Ladill Meet label from kiosk join pages. Co-authored-by: Cursor --- resources/js/meet-room.js | 111 ++++++++++++++++-- resources/views/meet/join/cancelled.blade.php | 2 +- resources/views/meet/join/denied.blade.php | 2 +- resources/views/meet/join/show.blade.php | 2 +- resources/views/meet/left/thanks.blade.php | 2 +- 5 files changed, 103 insertions(+), 16 deletions(-) diff --git a/resources/js/meet-room.js b/resources/js/meet-room.js index f27f1ae..37eda69 100644 --- a/resources/js/meet-room.js +++ b/resources/js/meet-room.js @@ -175,9 +175,6 @@ function meetRoom() { room.on(RoomEvent.TrackSubscribed, (track, publication, participant) => { this.attachTrack(track, publication, participant); - if (track.kind === Track.Kind.Audio) { - this.ensureAudioPlayback(); - } }); room.on(RoomEvent.TrackUnsubscribed, (track, publication, participant) => { track.detach(); @@ -191,6 +188,7 @@ function meetRoom() { this.updateParticipantTile(participant); } if (publication.kind === Track.Kind.Audio) { + publication.track?.detach(); this.updateParticipantTile(participant); } if (participant === room.localParticipant) { @@ -201,7 +199,8 @@ function meetRoom() { if (publication.kind === Track.Kind.Video && publication.track) { this.attachTrack(publication.track, publication, participant); } - if (publication.kind === Track.Kind.Audio) { + if (publication.kind === Track.Kind.Audio && publication.track) { + this.attachTrack(publication.track, publication, participant); this.updateParticipantTile(participant); } if (participant === room.localParticipant) { @@ -221,8 +220,14 @@ function meetRoom() { } this.syncLocalMediaState(); }); - room.on(RoomEvent.ParticipantConnected, () => this.syncParticipants()); - room.on(RoomEvent.ParticipantDisconnected, () => this.syncParticipants()); + room.on(RoomEvent.ParticipantConnected, (participant) => { + this.attachExistingTracks(participant); + this.syncParticipants(); + }); + room.on(RoomEvent.ParticipantDisconnected, (participant) => { + this.removeParticipantTile(participant.identity); + this.syncParticipants(); + }); room.on(RoomEvent.Disconnected, () => { this.connectionStatus = 'Disconnected'; }); @@ -261,12 +266,9 @@ function meetRoom() { this.setupCaptionPipeline(); - this.updateParticipantTile(room.localParticipant); - room.localParticipant.videoTrackPublications.forEach((pub) => { - if (pub.track && !pub.isMuted && pub.source !== Track.Source.ScreenShare) { - this.attachTrack(pub.track, pub, room.localParticipant); - } - }); + this.attachExistingTracks(room.localParticipant); + room.remoteParticipants.forEach((participant) => this.attachExistingTracks(participant)); + this.syncParticipants(); } catch (e) { console.error(e); this.connectionStatus = this.connectionErrorMessage(e); @@ -472,6 +474,13 @@ function meetRoom() { await this.poll(); }, + removeParticipantTile(identity) { + const grid = document.getElementById('video-grid'); + if (!grid || !identity) return; + + grid.querySelector(`[data-participant-tile="${identity}"]`)?.remove(); + }, + getOrCreateParticipantTile(participant) { const grid = document.getElementById('video-grid'); if (!grid) return null; @@ -686,7 +695,40 @@ function meetRoom() { }); }, + attachExistingTracks(participant) { + if (!participant) return; + + const isLocal = room && participant === room.localParticipant; + + if (!isLocal) { + participant.audioTrackPublications.forEach((pub) => { + if (pub.track && !pub.isMuted) { + this.attachTrack(pub.track, pub, participant); + } + }); + } + + participant.videoTrackPublications.forEach((pub) => { + if (pub.track && !pub.isMuted && pub.source !== Track.Source.ScreenShare) { + this.attachTrack(pub.track, pub, participant); + } + }); + + this.updateParticipantTile(participant); + }, + attachTrack(track, publication, participant) { + if (track.kind === Track.Kind.Audio) { + if (participant === room?.localParticipant) return; + if (publication?.isMuted) return; + + const element = track.attach(); + element.className = 'meet-remote-audio'; + this.getAudioContainer().appendChild(element); + this.ensureAudioPlayback(); + return; + } + if (track.kind !== Track.Kind.Video) return; const isScreen = publication?.source === Track.Source.ScreenShare @@ -711,11 +753,55 @@ function meetRoom() { this.attachVideoToTile(participant, track); }, + getAudioContainer() { + let container = document.getElementById('meet-audio-elements'); + if (!container) { + container = document.createElement('div'); + container.id = 'meet-audio-elements'; + container.className = 'sr-only'; + container.setAttribute('aria-hidden', 'true'); + document.body.appendChild(container); + } + + return container; + }, + syncParticipants() { if (!room) return; + const all = [room.localParticipant, ...room.remoteParticipants.values()]; + const activeIdentities = new Set(all.map((p) => p.identity)); + this.participants = all.map((p) => ({ identity: p.identity, name: p.name })); all.forEach((participant) => this.updateParticipantTile(participant)); + + const grid = document.getElementById('video-grid'); + if (!grid) return; + + grid.querySelectorAll('[data-participant-tile]').forEach((tile) => { + if (!activeIdentities.has(tile.dataset.participantTile)) { + tile.remove(); + } + }); + }, + + pruneTilesFromSession() { + const joinedIds = new Set( + this.sessionParticipants + .filter((p) => p.status === 'joined') + .map((p) => p.uuid), + ); + + const grid = document.getElementById('video-grid'); + if (!grid) return; + + grid.querySelectorAll('[data-participant-tile]').forEach((tile) => { + const identity = tile.dataset.participantTile; + if (room?.localParticipant?.identity === identity) return; + if (!joinedIds.has(identity)) { + tile.remove(); + } + }); }, async toggleMute() { @@ -862,6 +948,7 @@ function meetRoom() { const data = await res.json(); if (data.participants) { this.sessionParticipants = data.participants; + this.pruneTilesFromSession(); } this.updateChatFromPoll(data.messages || []); this.qaItems = data.qa || []; diff --git a/resources/views/meet/join/cancelled.blade.php b/resources/views/meet/join/cancelled.blade.php index 54074da..646a4dd 100644 --- a/resources/views/meet/join/cancelled.blade.php +++ b/resources/views/meet/join/cancelled.blade.php @@ -1,4 +1,4 @@ - +

{{ $room->title }}

diff --git a/resources/views/meet/join/denied.blade.php b/resources/views/meet/join/denied.blade.php index 635351a..e413d00 100644 --- a/resources/views/meet/join/denied.blade.php +++ b/resources/views/meet/join/denied.blade.php @@ -1,4 +1,4 @@ - +
diff --git a/resources/views/meet/join/show.blade.php b/resources/views/meet/join/show.blade.php index 2d63d2d..7b7545d 100644 --- a/resources/views/meet/join/show.blade.php +++ b/resources/views/meet/join/show.blade.php @@ -1,4 +1,4 @@ - +

{{ $room->title }}

diff --git a/resources/views/meet/left/thanks.blade.php b/resources/views/meet/left/thanks.blade.php index 29cde7d..820ed4d 100644 --- a/resources/views/meet/left/thanks.blade.php +++ b/resources/views/meet/left/thanks.blade.php @@ -1,4 +1,4 @@ - +