fix: skip participant leave sounds during self-disconnect

Added justDisconnected guard to the participant sound loop. When
the user hangs up, isLiveKitConnected transitions to false — but
in a separate or same subscription tick, the participants list
also empties. Without the guard, SoundController plays user_leave
for every departed participant AND the disconnect sound simultaneously.

Now: if justDisconnected is true, the entire participant loop is
skipped. Only the disconnect sound plays.
This commit is contained in:
Jannis Braun
2026-04-08 15:05:49 +02:00
parent 22aa1e3f66
commit 1468b68199
@@ -64,21 +64,26 @@ export function SoundController() {
prevIsScreenSharing.current = state.isScreenSharing;
}
// Disconnect (Self)
if (prevIsConnected.current && !state.isLiveKitConnected) {
// Self-disconnect detection — check BEFORE participant sounds
const justDisconnected = prevIsConnected.current && !state.isLiveKitConnected;
const justConnected = !prevIsConnected.current && state.isLiveKitConnected;
if (justDisconnected) {
audioManager.playSound('disconnect', sfxOpts);
}
// Connect (Self)
if (!prevIsConnected.current && state.isLiveKitConnected) {
if (justConnected) {
audioManager.playSound('user_join', sfxOpts);
}
prevIsConnected.current = state.isLiveKitConnected;
// Participant Joins/Leaves & Screen Sharing
// CRITICAL: Skip entirely if we just disconnected or are not connected.
// Without this guard, hanging up plays "user_leave" for every participant
// (they "left" from our perspective) simultaneously with the disconnect sound.
const currentParticipantIds = new Set(state.participants.map(p => p.userId));
const currentScreenShareUserIds = new Set(state.participants.filter(p => p.isScreenSharing).map(p => p.userId));
if (state.isLiveKitConnected) {
if (state.isLiveKitConnected && !justDisconnected) {
// Someone joined voice (Others only)
state.participants.forEach(p => {
if (!prevParticipantIds.current.has(p.userId) && p.userId !== currentUser?.id) {
@@ -107,7 +112,7 @@ export function SoundController() {
}
});
}
prevParticipantIds.current = currentParticipantIds;
prevScreenShareUserIds.current = currentScreenShareUserIds;