zebra-report/web
Russell Ballestrini 794f10a9a5
zebra-spaces: persist mic/speaker by LABEL — survive Firefox pre-permission + Chrome ID rotation
Two regressions in the existing localStorage-restore path that forced
the host to re-pick the monitor input after every hard refresh:

1. Pre-permission Firefox returns deviceId='' for every device in
   enumerateDevices(). refreshMicList ran at page load BEFORE the
   entry-click gesture granted gUM, every match against the saved
   micDeviceId failed, and the `else: micDeviceId = sel.value` clobber
   silently reset the saved selection to ''. After that, getMic()
   picked the default mic instead of the monitor.

   Fix: detect the all-empty case (allEmpty) and bail out — preserve
   the saved selection until a real post-permission enumerate runs.

2. Chrome (and other browsers in some configs) rotates deviceIds
   across browser sessions for privacy. Saved deviceId stops matching
   anything. Old code fell through to the clobber.

   Fix: also save the human-readable label (e.g. "Monitor of WH-
   1000XM5") and fall back to label-match when deviceId doesn't
   resolve. When the label matches, refresh micDeviceId to the
   current session's value + persist the new deviceId.

Two new localStorage keys: MIC_LABEL_KEY, SPK_LABEL_KEY. Change
handlers strip the 'input '/'output ' prefix from the option's
textContent before saving. Same pattern applied to both refreshMic-
List and refreshSpeakerList.

Doesn't help when the saved label also doesn't match any current
device (e.g. headphones unplugged) — sel.value defaults to first
device, same as before. But the common case fox 2026-06-04 hit
("monitor selected, hard refresh, monitor not restored, manual re-
pick needed") is now zero-tap.
2026-06-04 12:36:09 -04:00
..
blog phase 1: unfirehose reconstruction from session JSONL ingest 2026-05-27 13:51:14 -04:00
fonts phase 2: gap analysis — cat>> append + binary asset recovery 2026-05-27 13:54:19 -04:00
chat.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
host-your-own.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
how-it-works.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
index.html web: bump mobile body padding from 1rem to 1.25rem so the right edge has visible breathing room 2026-05-31 14:13:25 -04:00
kernel.html web: bump mobile body padding from 1rem to 1.25rem so the right edge has visible breathing room 2026-05-31 14:13:25 -04:00
stamp.js web: stamp each zebra-report page with build date + md5/sha256 2026-05-28 17:50:12 -04:00
zebra-audio.html zebra-spaces: listener mute button doubles as audio-unlock gesture 2026-06-03 20:57:09 -04:00
zebra-spaces.html zebra-spaces: persist mic/speaker by LABEL — survive Firefox pre-permission + Chrome ID rotation 2026-06-04 12:36:09 -04:00