🐛(frontend) make the device-in-use logic race-free

The device-in-use logic could race when multiple detection events
fired close together (e.g. rapid mic/cam toggles or several devices
becoming busy at once), leading to inconsistent store state.

Refactor the flow so all updates go through a serialized path,
removing the race conditions and keeping the in-use state
consistent regardless of event ordering.
This commit is contained in:
lebaudantoine
2026-08-23 17:14:17 +02:00
committed by aleb_the_flash
parent e000377b5c
commit 84845709d0
2 changed files with 15 additions and 6 deletions
@@ -36,10 +36,18 @@ function useWatchKind(
useEffect(() => {
if (!inUse) return
const id = setInterval(
() => void probeDeviceReleased(kind, selectedDeviceId || undefined),
RETRY_INTERVAL_MS
)
return () => clearInterval(id)
let stopped = false
let timer: number | undefined
const tick = async () => {
await probeDeviceReleased(kind, selectedDeviceId || undefined)
if (!stopped) {
timer = window.setTimeout(tick, RETRY_INTERVAL_MS)
}
}
timer = window.setTimeout(tick, RETRY_INTERVAL_MS)
return () => {
stopped = true
window.clearTimeout(timer)
}
}, [kind, inUse, selectedDeviceId])
}
@@ -151,14 +151,15 @@ function useLocalTrack<T extends LocalAudioTrack | LocalVideoTrack>({
let cancelled = false
create()
.then((newTrack) => {
noteDeviceReady(permissionKind)
if (cancelled) {
newTrack.stop()
return
}
noteDeviceReady(permissionKind)
setTrack(newTrack)
})
.catch((error) => {
if (cancelled) return
onMediaPermissionError(
error as Error,
permissionKind,