fix(soundboard): mount-once hotkey registration to avoid call-state churn

This commit is contained in:
byGalax
2026-05-17 17:49:08 +02:00
parent e19a71e892
commit fc8fc275cb
+14 -3
View File
@@ -2263,10 +2263,21 @@ export function CallProvider({ children }: { children: ReactNode }) {
// a call we route through `playSoundboard` so peers hear; outside a call // a call we route through `playSoundboard` so peers hear; outside a call
// we fall back to `playSoundboardLocal` which plays through the system // we fall back to `playSoundboardLocal` which plays through the system
// default output only. // default output only.
//
// We deliberately do NOT depend on `state.kind` in the effect dep array:
// every call state transition (idle → connecting → connected → reconnecting
// → ...) would trigger a full unregister+re-register cycle through IPC, and
// during the 150 ms gap the hotkeys are silently dead. Instead we read the
// current call state through a ref that's always kept in sync.
const callStateKindRef = useRef(state.kind);
callStateKindRef.current = state.kind;
const playSoundboardRef = useRef(playSoundboard);
playSoundboardRef.current = playSoundboard;
useEffect(() => { useEffect(() => {
const teardown = startSoundboardHotkeys((id) => { const teardown = startSoundboardHotkeys((id) => {
if (state.kind === 'connected') { if (callStateKindRef.current === 'connected') {
void playSoundboard(id); void playSoundboardRef.current(id);
} else { } else {
void (async () => { void (async () => {
const entries = await listSoundboard(); const entries = await listSoundboard();
@@ -2276,7 +2287,7 @@ export function CallProvider({ children }: { children: ReactNode }) {
} }
}); });
return teardown; return teardown;
}, [state.kind, playSoundboard]); }, []); // eslint-disable-line react-hooks/exhaustive-deps
const setAudioInputDevice = useCallback(async (deviceId: string | null) => { const setAudioInputDevice = useCallback(async (deviceId: string | null) => {
updateAudioSettings({ inputDeviceId: deviceId }); updateAudioSettings({ inputDeviceId: deviceId });