Fix meeting audio attach, prune left tiles, drop Ladill Meet eyebrow.
Deploy Ladill Meet / deploy (push) Successful in 30s

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 <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-01 13:57:25 +00:00
co-authored by Cursor
parent dc3c6dee2d
commit 5e85a4eaa1
5 changed files with 103 additions and 16 deletions
+99 -12
View File
@@ -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 || [];
@@ -1,4 +1,4 @@
<x-meet-kiosk-layout :title="'Meeting cancelled'" :organization="$organization ?? null" eyebrow="Ladill Meet">
<x-meet-kiosk-layout :title="'Meeting cancelled'" :organization="$organization ?? null">
<div class="flex min-h-[calc(100vh-8rem)] flex-col items-center justify-center text-center">
<div class="w-full max-w-md rounded-3xl border border-slate-200 bg-white p-8 shadow-sm">
<h1 class="text-2xl font-bold text-slate-900">{{ $room->title }}</h1>
+1 -1
View File
@@ -1,4 +1,4 @@
<x-meet-kiosk-layout :title="'Access denied · '.$room->title" :organization="$organization" eyebrow="Ladill Meet">
<x-meet-kiosk-layout :title="'Access denied · '.$room->title" :organization="$organization">
<div class="flex min-h-[calc(100vh-8rem)] flex-col items-center justify-center text-center">
<div class="w-full max-w-md rounded-3xl border border-slate-200 bg-white p-8 shadow-sm">
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-amber-50 text-amber-600">
+1 -1
View File
@@ -1,4 +1,4 @@
<x-meet-kiosk-layout :title="'Join · '.$room->title" :organization="$organization" eyebrow="Ladill Meet">
<x-meet-kiosk-layout :title="'Join · '.$room->title" :organization="$organization">
<div class="flex min-h-[calc(100vh-8rem)] flex-col items-center justify-center text-center">
<div class="w-full max-w-lg">
<h1 class="text-3xl font-bold tracking-tight text-slate-900 sm:text-4xl">{{ $room->title }}</h1>
+1 -1
View File
@@ -1,4 +1,4 @@
<x-meet-kiosk-layout :title="'Thank you'" :organization="$organization" eyebrow="Ladill Meet">
<x-meet-kiosk-layout :title="'Thank you'" :organization="$organization">
<div class="flex min-h-[calc(100vh-8rem)] flex-col items-center justify-center text-center">
<div class="w-full max-w-md rounded-3xl border border-slate-200 bg-white p-8 shadow-sm">
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-emerald-50 text-emerald-600">