fix: reliable speaking indicator via direct store writes + polling safety net

Eliminate double-state architecture (useState → useEffect bridge → store)
that lost speaking events due to React 18 batching. ActiveSpeakersChanged
now writes speakingParticipantIds directly to voiceStore; 200ms poll
catches missed SDK events. Each VoiceUser subscribes to its own identity
via fine-grained selector for minimal re-renders. Also adds connection
quality indicator and ConnectionInfoPopover.
This commit is contained in:
Jannis Braun
2026-02-23 02:36:39 +01:00
parent 176f4db27e
commit 9091f08ced
10 changed files with 604 additions and 46 deletions
@@ -74,9 +74,10 @@ export function GlobalAudioRenderer() {
const watchingStreams = useVoiceStore((s) => s.watchingStreams);
const streamAttenuationEnabled = useVoiceStore((s) => s.streamAttenuationEnabled);
const streamAttenuationStrength = useVoiceStore((s) => s.streamAttenuationStrength);
const speakingParticipantIds = useVoiceStore((s) => s.speakingParticipantIds);
// Determine if someone is currently speaking (for stream attenuation)
const someoneIsSpeaking = participants.some((p) => !p.isLocal && p.isSpeaking);
const someoneIsSpeaking = participants.some((p) => !p.isLocal && speakingParticipantIds.has(p.identity));
// Only render audio for remote participants
const remoteParticipants = participants.filter((p) => !p.isLocal);