When the host's mic device disappears (BT disconnect, USB unplug, OS
audio swap to laptop speakers), the active MediaStreamTrack ends but
the senders on every PC keep pointing at the dead track. Host goes
silent until a full leave+rejoin tears everything down and re-publishes.
Fix:
- watchMicTrack(track) listens for 'ended' on every mic track we hand
out (initial getMic + applyMicMode re-acquire)
- reacquireMic() gets a fresh getUserMedia with the same constraints,
then sender.replaceTrack on every live mesh peer + sfuPubPC.
No renegotiation — codec / SDP stays the same, just the track
swaps under the existing transceiver. Single in-flight guard so a
burst of devicechange events doesn't race.
- devicechange listener is now an active probe: if the current track
has gone readyState='ended' or muted=true since the last event,
trigger reacquireMic. Firefox in particular doesn't always fire
'ended' on BT swap — the track stays 'live' but emits silence.