Built-in Opus codec for browsers without one; cameras on by default with per-person hide

- libopus in WebAssembly takes over voice where WebCodecs audio is missing
  (Firefox on Android); tested for tone, timing and bitrate, and in a browser
  forced onto it
- Cameras in the channel show by themselves once the IP note was confirmed;
  a person's camera can be hidden from the right-click menu, all of them with
  one button; an enlarged camera leaves its tile
- CSP allows wasm-unsafe-eval for the codec

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-02 00:36:43 +02:00
co-authored by Claude Opus 5.5
parent 6368e63b0e
commit 5d43b8e4ae
17 changed files with 353 additions and 43 deletions
+4 -3
View File
@@ -288,7 +288,8 @@
{@const stream = streamOf(u.session)}
{@const sharing = session.sharing[u.session]}
{@const isSelf = u.session === self?.session}
{@const cam = camOf(u.session)}
<!-- While a camera is shown large, its tile goes back to the avatar: one picture, not two -->
{@const cam = focus === u.session ? null : camOf(u.session)}
{@const w = watchOf(u.session)}
<button class="tile" class:talking={talking(u.session)} class:self={isSelf} class:focused={focus === u.session}
onclick={() => tileClick(u.session)}
@@ -359,8 +360,8 @@
{/if}
</button>
{#if anyCamera || share.cams}
<button class="icon-btn" class:live={share.cams} aria-pressed={share.cams} title={share.cams ? 'Stop watching the cameras' : 'Watch everyone\'s camera'}
aria-label={share.cams ? 'Stop watching the cameras' : 'Watch all cameras'} onclick={() => share.setCams(sessions.active, !share.cams)}>
<button class="icon-btn" class:live={share.cams} aria-pressed={share.cams} title={share.cams ? 'Hide everyone\'s camera' : 'Show everyone\'s camera'}
aria-label={share.cams ? 'Hide all cameras' : 'Show all cameras'} onclick={() => share.setCams(sessions.active, !share.cams)}>
<Icon name="camera" size={18} />
</button>
{/if}