Fix meeting audio attach, prune left tiles, drop Ladill Meet eyebrow.
Deploy Ladill Meet / deploy (push) Successful in 30s
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:
+99
-12
@@ -175,9 +175,6 @@ function meetRoom() {
|
|||||||
|
|
||||||
room.on(RoomEvent.TrackSubscribed, (track, publication, participant) => {
|
room.on(RoomEvent.TrackSubscribed, (track, publication, participant) => {
|
||||||
this.attachTrack(track, publication, participant);
|
this.attachTrack(track, publication, participant);
|
||||||
if (track.kind === Track.Kind.Audio) {
|
|
||||||
this.ensureAudioPlayback();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
room.on(RoomEvent.TrackUnsubscribed, (track, publication, participant) => {
|
room.on(RoomEvent.TrackUnsubscribed, (track, publication, participant) => {
|
||||||
track.detach();
|
track.detach();
|
||||||
@@ -191,6 +188,7 @@ function meetRoom() {
|
|||||||
this.updateParticipantTile(participant);
|
this.updateParticipantTile(participant);
|
||||||
}
|
}
|
||||||
if (publication.kind === Track.Kind.Audio) {
|
if (publication.kind === Track.Kind.Audio) {
|
||||||
|
publication.track?.detach();
|
||||||
this.updateParticipantTile(participant);
|
this.updateParticipantTile(participant);
|
||||||
}
|
}
|
||||||
if (participant === room.localParticipant) {
|
if (participant === room.localParticipant) {
|
||||||
@@ -201,7 +199,8 @@ function meetRoom() {
|
|||||||
if (publication.kind === Track.Kind.Video && publication.track) {
|
if (publication.kind === Track.Kind.Video && publication.track) {
|
||||||
this.attachTrack(publication.track, publication, participant);
|
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);
|
this.updateParticipantTile(participant);
|
||||||
}
|
}
|
||||||
if (participant === room.localParticipant) {
|
if (participant === room.localParticipant) {
|
||||||
@@ -221,8 +220,14 @@ function meetRoom() {
|
|||||||
}
|
}
|
||||||
this.syncLocalMediaState();
|
this.syncLocalMediaState();
|
||||||
});
|
});
|
||||||
room.on(RoomEvent.ParticipantConnected, () => this.syncParticipants());
|
room.on(RoomEvent.ParticipantConnected, (participant) => {
|
||||||
room.on(RoomEvent.ParticipantDisconnected, () => this.syncParticipants());
|
this.attachExistingTracks(participant);
|
||||||
|
this.syncParticipants();
|
||||||
|
});
|
||||||
|
room.on(RoomEvent.ParticipantDisconnected, (participant) => {
|
||||||
|
this.removeParticipantTile(participant.identity);
|
||||||
|
this.syncParticipants();
|
||||||
|
});
|
||||||
room.on(RoomEvent.Disconnected, () => {
|
room.on(RoomEvent.Disconnected, () => {
|
||||||
this.connectionStatus = 'Disconnected';
|
this.connectionStatus = 'Disconnected';
|
||||||
});
|
});
|
||||||
@@ -261,12 +266,9 @@ function meetRoom() {
|
|||||||
|
|
||||||
this.setupCaptionPipeline();
|
this.setupCaptionPipeline();
|
||||||
|
|
||||||
this.updateParticipantTile(room.localParticipant);
|
this.attachExistingTracks(room.localParticipant);
|
||||||
room.localParticipant.videoTrackPublications.forEach((pub) => {
|
room.remoteParticipants.forEach((participant) => this.attachExistingTracks(participant));
|
||||||
if (pub.track && !pub.isMuted && pub.source !== Track.Source.ScreenShare) {
|
this.syncParticipants();
|
||||||
this.attachTrack(pub.track, pub, room.localParticipant);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
this.connectionStatus = this.connectionErrorMessage(e);
|
this.connectionStatus = this.connectionErrorMessage(e);
|
||||||
@@ -472,6 +474,13 @@ function meetRoom() {
|
|||||||
await this.poll();
|
await this.poll();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
removeParticipantTile(identity) {
|
||||||
|
const grid = document.getElementById('video-grid');
|
||||||
|
if (!grid || !identity) return;
|
||||||
|
|
||||||
|
grid.querySelector(`[data-participant-tile="${identity}"]`)?.remove();
|
||||||
|
},
|
||||||
|
|
||||||
getOrCreateParticipantTile(participant) {
|
getOrCreateParticipantTile(participant) {
|
||||||
const grid = document.getElementById('video-grid');
|
const grid = document.getElementById('video-grid');
|
||||||
if (!grid) return null;
|
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) {
|
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;
|
if (track.kind !== Track.Kind.Video) return;
|
||||||
|
|
||||||
const isScreen = publication?.source === Track.Source.ScreenShare
|
const isScreen = publication?.source === Track.Source.ScreenShare
|
||||||
@@ -711,11 +753,55 @@ function meetRoom() {
|
|||||||
this.attachVideoToTile(participant, track);
|
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() {
|
syncParticipants() {
|
||||||
if (!room) return;
|
if (!room) return;
|
||||||
|
|
||||||
const all = [room.localParticipant, ...room.remoteParticipants.values()];
|
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 }));
|
this.participants = all.map((p) => ({ identity: p.identity, name: p.name }));
|
||||||
all.forEach((participant) => this.updateParticipantTile(participant));
|
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() {
|
async toggleMute() {
|
||||||
@@ -862,6 +948,7 @@ function meetRoom() {
|
|||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (data.participants) {
|
if (data.participants) {
|
||||||
this.sessionParticipants = data.participants;
|
this.sessionParticipants = data.participants;
|
||||||
|
this.pruneTilesFromSession();
|
||||||
}
|
}
|
||||||
this.updateChatFromPoll(data.messages || []);
|
this.updateChatFromPoll(data.messages || []);
|
||||||
this.qaItems = data.qa || [];
|
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="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="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>
|
<h1 class="text-2xl font-bold text-slate-900">{{ $room->title }}</h1>
|
||||||
|
|||||||
@@ -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="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="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">
|
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-amber-50 text-amber-600">
|
||||||
|
|||||||
@@ -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="flex min-h-[calc(100vh-8rem)] flex-col items-center justify-center text-center">
|
||||||
<div class="w-full max-w-lg">
|
<div class="w-full max-w-lg">
|
||||||
<h1 class="text-3xl font-bold tracking-tight text-slate-900 sm:text-4xl">{{ $room->title }}</h1>
|
<h1 class="text-3xl font-bold tracking-tight text-slate-900 sm:text-4xl">{{ $room->title }}</h1>
|
||||||
|
|||||||
@@ -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="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="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">
|
<div class="mx-auto flex h-14 w-14 items-center justify-center rounded-full bg-emerald-50 text-emerald-600">
|
||||||
|
|||||||
Reference in New Issue
Block a user