enough-match-43171
12/17/2025, 7:49 PMtall-airline-16756
12/17/2025, 7:49 PMtall-airline-16756
12/17/2025, 7:49 PMenough-match-43171
12/17/2025, 7:50 PMtall-airline-16756
12/17/2025, 7:50 PMTrackPublished, TrackUnpublished, TrackMuted, TrackUnmuted, TrackSubscriptionFailed, and trackStreamStateChanged.
• Check publication.kind === Track.Kind.Video and publication.isSubscribed / publication.muted to determine video availability.
3) Render logic (web/JS example)
• Create a tile that contains both a video container and a placeholder element.
• On video available: attach the track and show the video element, hide the placeholder.
• On video unavailable/muted/unsubscribed/failed: detach or hide the video element and show the placeholder.
Example (simplified):
function updateParticipantTile(publication, participant) {
const videoEl = document.getElementById(`video-${participant.sid}`);
const placeholderEl = document.getElementById(`placeholder-${participant.sid}`);
if (publication && publication.isSubscribed && !publication.muted && publication.track) {
placeholderEl.style.display = 'none';
videoEl.style.display = 'block';
videoEl.appendChild(publication.track.attach());
} else {
// show avatar/initials
videoEl.style.display = 'none';
placeholderEl.style.display = 'flex';
placeholderEl.textContent = getInitials(participant.name);
}
}
4) UX considerations
• Show a frozen frame or paused indicator when trackStreamStateChanged signals a network pause.
• Animate transitions between placeholder and video to avoid jarring layout shifts.
• Prefer caching avatar images to reduce flicker on quick reconnects.
If you'd like, tell me:
• Which SDK/framework you're using (React, plain JS, Flutter), and
• Whether you want initials, an uploaded avatar, or a default image — I can provide a code example tailored to that. Sources: Virtual avatar plugins | LiveKit Docs | Managing Video Quality During Network Congestion | Subscribing to tracks | LiveKit docs