Commit Graph
7446 Commits
Author SHA1 Message Date
Robin 11fadebb87 Fix test failures due to scoped class names 2026-07-08 17:06:25 +02:00
Robin 943ce5b853 Update test snapshots to use scoped class names 2026-07-08 17:06:09 +02:00
Timo K. 137093350b Merge branch 'livekit' into toger5/logger-getChild-fix 2026-07-08 17:04:42 +02:00
Robin 000ee66cfe Use vitest's default for scoped class names
It reduces confusion when reading snapshots if class names are still scoped to their respective CSS modules. It also discourages the use of class names in tests, which is a good thing. (https://testing-library.com/docs/guiding-principles)

Thanks to Johannes for the suggestion.
2026-07-08 17:03:51 +02:00
Johannes Marbach 58a8b7316e Merge pull request #4077 from element-hq/renovate/github-actions
Update GitHub Actions
2026-07-08 16:20:07 +02:00
renovate[bot] 1e6d3d3357 Update GitHub Actions 2026-07-08 14:02:37 +00:00
Robin 9f681b87a0 Merge branch 'livekit' into mobile-gradient 2026-07-08 15:47:59 +02:00
Timo dc21233767 Merge pull request #4097 from element-hq/toger5/fix-playwright-related-to-voice-in-pip
Consider voice calls starting in pip for playwright tests
2026-07-08 15:42:50 +02:00
Robin 27315a7090 Rename bgStyle to 'background' 2026-07-08 14:01:38 +02:00
Robin bebe79d109 Create type alias for background style 2026-07-08 13:56:10 +02:00
Robin 4ca0270115 Fix broken gradient SVG 2026-07-08 13:52:24 +02:00
Timo K. 374f56651c Consider voice calls starting in pip for playwright tests 2026-07-08 13:19:23 +02:00
Timo K. eefa6f843d fmt 2026-07-07 19:52:50 +02:00
Timo K. 2b84c587f2 lint 2026-07-07 19:45:22 +02:00
Timo K. 706cddafb0 Add lint rule to make sure future child loggers are setup correctly 2026-07-07 19:34:03 +02:00
Timo K. a6921e2bfb all the other logs 2026-07-07 19:12:11 +02:00
Timo K. 3cc396f42c fix getChild before rageshake setup 2026-07-07 19:05:10 +02:00
Timo 59999b9b37 Merge pull request #4059 from element-hq/toger5/remove-blur-on-mobile
Remove blur on mobile
2026-07-07 15:30:36 +08:00
Robin e68321e16c Merge branch 'livekit' into mobile-gradient 2026-07-06 12:17:04 +02:00
Johannes Marbach ad76969ce2 Merge pull request #4084 from element-hq/renovate/compound
Update dependency @vector-im/compound-web to v9.7.0
2026-07-06 09:03:10 +02:00
Johannes Marbach c170aad364 Merge pull request #4085 from element-hq/renovate/livekit-client
Update dependency livekit-client to v2.20.0
2026-07-06 09:01:51 +02:00
renovate[bot] 9e8bebc3bf Update dependency livekit-client to v2.20.0 2026-07-06 02:54:08 +00:00
renovate[bot] d5cdbfd4d1 Update dependency @vector-im/compound-web to v9.7.0 2026-07-06 02:53:46 +00:00
Johannes Marbach 1811b36205 Make renovate track docker-compose files and pin synapse / element-web for playwright tests 2026-07-03 08:48:28 +02:00
Lotus CIandClaude Opus 4.8 0ffe247929 fix(lotus): Wave-1 audit fixes (EC1–EC6)
CI / Build embedded bundle (push) Successful in 1m0s
CI / Publish to Gitea npm registry (push) Has been skipped
- EC1: lotusQuality — track + clearTimeout the 500ms settle re-apply per room
  (was leaking a timer that fired on torn-down rooms).
- EC2/EC3: lotusQuality + lotusAudioInject drive off vm.allConnections$ instead
  of the remote-gated livekitRoomItems$ (were no-ops when alone), matching
  lotusDenoise.
- EC4: lotusDecorations resets its roster to {} on teardown so a decoration from
  a previous call can't render on a shared user in the next one.
- EC5: hoisted a stable useSyncExternalStore subscribe fn (was re-subscribing
  every tile render).
- EC6: lotusFocus only sets the spotlight when the userId field is present
  (a partial payload no longer clears the pin).

tsc clean. Needs a republish to ship.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:13:01 -04:00
Lotus CIandClaude Opus 4.8 02666c0c04 feat(lotus): io.lotus.set_deafen action — deafen remote audio at the source
CI / Build embedded bundle (push) Successful in 39s
CI / Publish to Gitea npm registry (push) Has been skipped
New toWidget action { deafened, screenshareAudioMuted } that sets each remote
RemoteParticipant.setVolume per source (Microphone + ScreenShareAudio), applied
to existing participants + re-applied to late joiners via
RoomEvent.ParticipantConnected (subscribed through vm.livekitRoomItems$). Closure-
scoped state, matching the sibling lotus modules; the cinny host re-sends on join
so a fresh call never inherits stale deafen state.

Replaces cinny's brittle iframe-DOM <audio>.muted hack (which broke on EC
re-render / late tracks). Folded into unpublished 0.20.1-lotus.2.

Note: injected/soundboard audio (Track.Source.Unknown) is not silenced — the
livekit-client setVolume type only accepts Microphone|ScreenShareAudio.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 14:12:08 -04:00
Robin 7840f4bccb Merge branch 'livekit' into mobile-gradient 2026-07-02 13:00:38 +02:00
Johannes Marbach 9199dcb583 Merge pull request #4076 from element-hq/renovate/all-minor-patch
Update all non-major dependencies
2026-07-02 11:37:07 +02:00
Johannes Marbach cbc4b77a4f Dismiss Element Web release announcements 2026-07-02 11:19:16 +02:00
Johannes Marbach ffb881436a Eliminate @livekit/protocol 2026-07-02 08:47:07 +02:00
Johannes Marbach 9cf87efc6b Remove global-jsdom 2026-07-02 08:35:59 +02:00
Johannes Marbach b71454d63a Bump mcr.microsoft.com/playwright 2026-07-02 08:35:40 +02:00
Lotus CIandClaude Opus 4.8 d71d8d6799 chore(lotus): fix stale denoise flag docs + prep 0.20.1-lotus.2
CI / Build embedded bundle (push) Successful in 40s
CI / Publish to Gitea npm registry (push) Has been skipped
The in-source ML denoiser is gated on lotusDenoiseSource (see lotusDenoise.ts
gate), not the legacy build-time shim flag lotusDenoise=ml. Correct the two
stale references (lotusDenoise.ts JSDoc + InCallView.tsx comment) to
lotusDenoiseSource=1.

Bump the embedded package to 0.20.1-lotus.2 for the next publish and update the
CI comment: the checked-in version now tracks the intended release, while a
pushed tag still wins (npm version "$TAG" overwrites at publish time).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 23:56:28 -04:00
Lotus CIandClaude Opus 4.8 98fbdbd5cf fix(lotus-audio-inject): close double-publish window on rapid inject actions
playInjectedClip only registered its cleanup (and thus became abortable by a
later clip's replace-mode loop) AFTER publishing. Two inject actions fired in
quick succession could both pass their fetch/decode/publish awaits before
either was registered, so both tracks got published.

Register a synchronous placeholder abort BEFORE the first await: it aborts the
in-flight fetch and flips an `aborted` flag checked after every await, so a
newer clip cancels the older one during the vulnerable window. The real
cleanup replaces the placeholder once the track is live, and if we were
superseded mid-publish we tear the just-published track down immediately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 23:56:13 -04:00
Lotus CIandClaude Opus 4.8 bb3fb7e573 refactor(lotus-spotlight): extract manual-override into src/lotus/lotusSpotlight.ts
Remove the rebase hazard from CallViewModel: upstream's spotlightSpeaker$
auto-selection had been renamed to autoSpotlightSpeaker$ and an inline
manual-override + screenshare-coexistence block was spliced into
spotlightAndPip$. Both diverge from upstream and would conflict on every
rebase.

Restore spotlightSpeaker$ to its byte-for-byte upstream form and move the
[lotus #4] override into a pure wrapper, overrideSpotlight$(), invoked at a
single call point in spotlightAndPip$. Behaviour is unchanged: identical to
upstream while manualSpotlightUserId$ is null (the default), and preserves the
"pin a participant" and "focus camera during screenshare" (#4 / A5) rules when
the host sends io.lotus.focus_participant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 23:56:03 -04:00
Lotus CIandClaude Fable 5 0aef1c5fe2 feat(lotus-audio-inject): one soundboard clip at a time (replace mode)
CI / Build embedded bundle (push) Successful in 35s
CI / Publish to Gitea npm registry (push) Has been skipped
playInjectedClip now stops any in-flight clip (via the existing idempotent
cleanup) before starting a new one, so rapid taps replace rather than
overlap/stack — no track leak. The host also debounces the button.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 23:21:50 -04:00
Lotus CIandClaude Opus 4.8 940d71da92 feat(lotus-denoise): AGC off for ML tier + init/build leak hardening
CI / Build embedded bundle (push) Successful in 2m34s
CI / Publish to Gitea npm registry (push) Has been skipped
AEC/AGC audit fix + two hardening items from the engine review.

- Add an `autoGainControl` capture param (UrlParams -> CallViewModel ->
  ConnectionFactory audioCaptureDefaults), mirroring echoCancellation/
  noiseSuppression. Defaults true (unchanged); the host sets it false only for
  the ML tier so the browser's auto gain control doesn't fight the in-source ML
  denoiser (pumping). Echo cancellation stays on. Tests cover the URL parse and
  the audioCaptureDefaults wiring.
- L1: init() now closes the owned AudioContext on a build failure (was orphaned;
  browsers cap live contexts, so repeated failures could exhaust them).
- L2: buildGraph() disposes its partially-built nodes on failure (disposeGraph
  previously only cleaned the prior graph).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 00:46:39 -04:00
Lotus CIandClaude Opus 4.8 6ab52d9926 feat(lotus-denoise): quality — dry/wet attenuation floor, gate-after-ML, softer DFN
CI / Build embedded bundle (push) Successful in 1m38s
CI / Publish to Gitea npm registry (push) Has been skipped
Track-B audio-quality changes to reduce the "robotic/underwater" artifact.

- Dry/wet attenuation floor (default 0.15 ≈ -16 dB) blends a little of the raw
  mic under the denoised signal so suppression can't fully collapse the noise
  floor between words (the main cause of the RNNoise "underwater"/pumping
  sound). Applied ONLY to the low-latency flat models (RNNoise/Speex); DTLN/DFN
  add algorithmic latency that would comb-filter an undelayed dry mix, so they
  rely on their own level instead. Tunable via `lotusDenoiseFloor`.
- Noise gate now runs AFTER the ML model, not before — gating the raw signal
  fed hard-zeroed frames into the model and tuned the threshold on pre-denoise
  levels.
- DeepFilterNet 3 noiseReductionLevel 80 -> 60: full strength was the main
  "over-processed" contributor; 60 keeps voice natural.

Defaults are conservative and tunable; final values are meant to be dialed in
with real-call A/B listening.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-01 00:16:23 -04:00
Lotus CIandClaude Opus 4.8 9a4e9bf7da fix(lotus-denoise): reliability — never-silent watchdog, resume timeout, cache + activation
Track-A robustness fixes from the engine review; no quality/model changes.

- H1: auto-resume the AudioContext on `statechange` if it suspends mid-call
  (mobile backgrounding / audio interruption). Previously the dest node emitted
  digital silence with no recovery — a silent mute of the sender.
- H2: `resumeCtx()` races `resume()` against a timeout. A suspended context can
  only resume on a user gesture; the action can arrive via postMessage, so a
  bare `await resume()` inside LiveKit's track-change lock could hang and
  deadlock all later mute/unmute/device-switch. Now it proceeds and the H1
  watcher heals it.
- M1: don't cache a REJECTED wasm fetch — a transient blip during a reconnect
  used to permanently disable denoise for the session. Evict on failure.
- M2: activate denoise off `allConnections$` (local participant's connections)
  instead of `livekitRoomItems$`, which excludes the local participant and only
  surfaces rooms with a remote member — so denoise now also runs when you're
  alone and no longer couples to a remote-render concern.
- Context lifecycle: `closeContext()` removes the state watcher before closing;
  `ensureContext()` closes a half-initialised context on any failure (no leak).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 23:27:44 -04:00
renovate[bot] b0feb33ec4 Update all non-major dependencies 2026-07-01 00:31:28 +00:00
Lotus CIandClaude Opus 4.8 a4309f3e0c lotus: don't call AudioContext.setSinkId with an undefined device id
CI / Build embedded bundle (push) Successful in 56s
CI / Publish to Gitea npm registry (push) Has been skipped
audioOutputId comes from `useMediaDevices().audioOutput.selected$?.id`, which is
undefined until a device is selected. On the Tauri desktop webview the observable
emits undefined first, so setSinkId(undefined) threw "The provided value is not
of type 'AudioSinkOptions'" on every call join (repeatedly). Guard on a string
(the default device is the empty string, still valid).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 18:39:50 -04:00
Robin 900d0abd27 Let page background shine through the footer
By visually separating it from other page content with an additional gradient background only when necessary.
2026-06-30 16:29:20 +02:00
Robin a3d3a1e951 Add "sound waves" to transparent spotlight tiles
To indicate when the user is speaking.
2026-06-30 16:29:20 +02:00
Robin 8fa3f33f37 Let page background shine through spotlight tiles
By giving spotlight tiles a transparent background in certain layouts.
2026-06-30 16:29:20 +02:00
Robin 360a4ff026 Add mobile gradient background 2026-06-30 16:29:20 +02:00
Robin 8c6a16f3d7 Add URL param to control background style 2026-06-30 16:29:20 +02:00
Robin 9d21581259 Dismiss sections release announcement in end-to-end tests 2026-06-30 16:29:20 +02:00
Lotus CIandClaude Opus 4.8 e2ce8f5e3a lotus(#1): gate in-source denoise on dedicated lotusDenoiseSource flag
CI / Build embedded bundle (push) Successful in 46s
CI / Publish to Gitea npm registry (push) Has been skipped
The host already sets lotusDenoise=ml and injects its getUserMedia shim;
reusing that flag would double-process audio the moment this fork ships.
Gate the in-source engine on lotusDenoiseSource=1 instead, so the fork is
inert on deploy and the host cuts over explicitly (set the flag + drop the
shim) when ready.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 00:49:11 -04:00
Lotus CIandClaude Opus 4.8 e903f98bbe lotus(#1): make denoise asset base absolute (fixes DTLN/DFN load)
CI / Build embedded bundle (push) Successful in 42s
CI / Publish to Gitea npm registry (push) Has been skipped
Review found native dynamic import() of the DTLN/DeepFilterNet ESM
resolves "./denoise/…" against the bundled JS chunk's URL (-> /assets/…)
not the document, so those two models 404'd and silently fell back to raw
mic in the default config. Resolve the asset base to an absolute
same-origin href against the document; addModule()/fetch() accept absolute
too, so all three load paths stay consistent. (rnnoise/speex were
unaffected since addModule resolves against the document.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 00:37:51 -04:00
Lotus CIandClaude Opus 4.8 78350a21f4 lotus(#1): implement all 4 denoise models; fix gate name + rates
CI / Build embedded bundle (push) Successful in 1m20s
CI / Publish to Gitea npm registry (push) Has been skipped
Faithful port of cinny's proven pipeline into the TrackProcessor, closing
protocol gap F3 (host offers rnnoise/speex/dtln/deepfilternet; only the
first two existed in-source).

- Fix real bug: gate worklet registers as "noise-gate" (hyphenated), not
  "noiseGate" — the gated path would have failed to construct the node.
- Per-model sample rate: DTLN runs at 16kHz, others 48kHz (worklets don't
  resample); verify the context actually got the rate, else fall back.
- resume() a suspended context (host postMessage isn't a gesture).
- DTLN via dynamic-imported @workadventure helper (bypassUntilReady);
  DeepFilterNet via dynamic-imported ESM + DeepFilterNet3Core pointed at
  the self-hosted base. Same-origin base (kept from the C1 fix) makes these
  dynamic imports safe.
- Prefer SIMD rnnoise.wasm with non-SIMD fallback; cache wasm per URL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 00:28:10 -04:00