getLocalDevices() re-invoked getUserMedia() (open+stop a mic stream)
inside its own devicechange listener, so any devicechange event
re-triggered a permission grant cycle. On Chrome for Android this
manifests as a repeatedly-reappearing mic-in-use notification since
opening/closing an audio stream can itself raise devicechange there.
getUserMedia is now requested once on mount; the devicechange handler
only re-enumerates devices, which still returns labeled devices from
that earlier grant per Chrome's enumerateDevices() behavior (86+).
Fixes #60
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TXGoTbTJnaEGdheJzSqAR5