From e4493f292d71f27d83056f448e6a1cace4a20d66 Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Sun, 7 Jun 2026 21:14:54 -0400 Subject: [PATCH] zebra-report: deploy bare-constraints camera retry --- zebra-report/zebra-spaces.html | 52 ++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/zebra-report/zebra-spaces.html b/zebra-report/zebra-spaces.html index f805fcd..6975f49 100644 --- a/zebra-report/zebra-spaces.html +++ b/zebra-report/zebra-spaces.html @@ -4632,23 +4632,39 @@ async function sfuPublishCamera(){ logLine('err','camera open retry failed: '+(e2.name||'Error')+' — '+e2.message); fsm.send('FAILED', { error: e2.message }); fsm.send('DONE'); return; } + } else if (e.name === 'NotAllowedError'){ + /* Firefox on Fedora/Wayland: NotAllowedError fires WITHOUT + * showing a permission prompt even when site permission is + * unset/removed (fox 2026-06-08 ticket 0002). That signature + * is firefox-canonical for "no prompt fired" — and one known + * cause is the constraints object: certain hardware + driver + * combos make Firefox reject {width/height/aspectRatio/frameRate} + * ideals as if they were a permission denial. + * + * Retry once with bare {video:true}. If THAT works, the + * elaborate constraints were the culprit. If THAT also fires + * NotAllowedError, it's a real permission denial — surface + * the recovery notice. */ + logLine('', 'camera open retry: NotAllowedError → bare {video:true}'); + try { + stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: false }); + logLine('', 'camera open recovered with bare {video:true} — firefox constraint misclassification'); + } catch(e2){ + logLine('err','camera open retry failed: '+(e2.name||'Error')+' — '+e2.message); + if (e2.name === 'NotAllowedError'){ + const ua = navigator.userAgent || ''; + const ff = /Firefox\//.test(ua); + showNotice( + ff + ? 'Camera blocked by your browser. Click the lock icon in the URL bar → "Connection secure" → "More information" → Permissions, then change "Use the camera" to Allow. Reload and try again.' + : 'Camera blocked. Click the lock or camera icon in the URL bar and allow camera access for this site, then try again.', + 'warn' + ); + } + fsm.send('FAILED', { error: e2.message }); fsm.send('DONE'); return; + } } else { - /* User-facing notice on the common "no prompt, instant fail" case. - * NotAllowedError fired without a prompt = the browser has a saved - * Block for this origin's camera permission. Tell the user how to - * unstick it — Firefox doesn't surface this in the URL bar after - * the block is saved; only by visiting site permissions does the - * user discover what's wrong. Ticket 0002. */ - if (e.name === 'NotAllowedError'){ - const ua = navigator.userAgent || ''; - const ff = /Firefox\//.test(ua); - showNotice( - ff - ? 'Camera blocked by your browser. Click the lock icon in the URL bar → "Connection secure" → "More information" → Permissions, then change "Use the camera" to Allow. Reload and try again.' - : 'Camera blocked. Click the lock or camera icon in the URL bar and allow camera access for this site, then try again.', - 'warn' - ); - } else if (e.name === 'NotFoundError'){ + if (e.name === 'NotFoundError'){ showNotice('No camera detected. Connect a camera and try again.', 'warn'); } else if (e.name === 'NotReadableError'){ showNotice('Camera is in use by another application. Close the other app and try again.', 'warn'); @@ -8145,8 +8161,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');