diff --git a/web/zebra-spaces.html b/web/zebra-spaces.html index 090f197..f805fcd 100644 --- a/web/zebra-spaces.html +++ b/web/zebra-spaces.html @@ -4633,6 +4633,26 @@ async function sfuPublishCamera(){ 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'){ + 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'); + } fsm.send('FAILED', { error: e.message }); fsm.send('DONE'); return; } } @@ -8125,8 +8145,8 @@ logLine('', 'ready — pick a handle, type a rendezvous code, enter the space');