[QA] §D2 Element Call fork feature sweep: in-source denoise reconnect, call_state indicators, focus-participant, in-call decorations, transparent bg, soundboard, quality controls, server-enforced call permissions #174
Closed
opened 2026-09-17 23:24:06 -04:00 by jared
·
2 comments
No Branch/Tag Specified
lotus
update-packages
sw-fix
read-me-update
image-path-changes
dm-calls
fix-2469
renovate/element-hq-element-call-embedded-0.x
renovate/npm-i18next-http-backend-vulnerability
renovate/npm-vite-vulnerability
dev
docs-update
more-theme
fix-257
imporve-thread-reply
revert-2402-improve-menu-congestion
mxidColor-toggle
update-sw-main-msg
v4.11.1
v4.10.5
v4.10.4
v4.10.3
v4.10.2
v4.10.1
v4.10.0
v4.9.1
v4.9.0
v4.8.1
v4.8.0
v4.7.1
v4.7.0
v4.6.0
v4.5.1
v4.5.0
v4.4.0
v4.3.2
v4.3.0
v4.2.3
v4.2.2
v4.2.1
v4.2.0
v4.1.0
v4.0.3
v4.0.0
v3.2.0
v3.1.0
v3.0.0
v2.2.6
v2.2.5
v2.2.4
v2.2.3
v2.2.2
v2.2.1
v2.2.0
v2.1.3
v2.1.2
v2.1.1
v2.1.0
v2.0.4
v2.0.3
v2.0.2
v2.0.1
v2.0.0
v1.8.2
v1.8.1
v1.8.0
v1.7.0
v1.6.1
v1.6.0
v1.5.1
v1.5.0
v1.4.0
v1.3.2
v1.3.1
v1.3.0
v1.2.1
v1.2.0
v1.1.0
v1.0.0
Labels
Clear labels
a11y
area: appearance
area: auth-session
area: build-ci
area: calls
area: desktop
area: media
area: messaging
area: mobile
area: moderation
area: navigation
area: notifications
area: settings
area: threads
bug
dependencies
docs
duplicate
enhancement
help wanted
invalid
needs-human-review
performance
planning
priority: critical
priority: high
priority: low
priority: medium
qa
question
research
security
tech-debt
ux
wontfix
Accessibility: keyboard, screen reader, contrast, motion
Client area: appearance
Client area: auth-session
Client area: build-ci
Client area: calls
Client area: desktop
Client area: media
Client area: messaging
Client area: mobile
Client area: moderation
Client area: navigation
Client area: notifications
Client area: settings
Client area: threads
Something is not working
Third-party package versions and advisories
README / LOTUS_* docs wrong or missing
This issue or pull request already exists
New feature
Need some help
Something is wrong
Re-render storms, leaks, heavy work on hot paths
Data loss, security hole, or crash on a main path
Broken feature or serious usability problem
Minor issue or polish
Wrong behaviour in an edge case or notable degradation
Manual QA: shipped, needs a human in a real environment
More information is needed
XSS, unsafe URLs, data leaks, auth/session
Code health, dead code, fragile patterns
Usability or visual inconsistency
This won't be fixed
Milestone
No items
No Milestone
Manual QA backlog
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: LotusGuild/cinny#174
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Migrated from
LOTUS_TESTING.md§D2 on 2026-09-17 — the file is now reference-only.How to report: tick each item as it passes; on FAIL comment with what you saw vs expected, browser/OS, web (chat.lotusguild.org) vs desktop (Tauri), theme, and any browser-console errors. Screenshots for anything visual.
Checklist
D2-1. Denoise in-source — survives reconnect (fixes A7) ⭐ highest risk (everyone's mic)
Flag: cinny sets
lotusDenoiseSource=1when ML denoise is selected (the old build-time getUserMediashim is removed). This is the single change with the widest blast radius — test deliberately.
so EC shows "Connection lost / Reconnect", then restore. Mic still works AND still denoised
afterward, without End+rejoin. (This is the exact bug that was reintroduced then fixed; if it
regresses, mic dies on every reconnect.)
restart()path as reconnect).rnnoise(default),speex,dtln,deepfilternet—each loads + denoises, no silence. (All four are in-source now; DTLN runs at 16 kHz, others 48 kHz.)
injected alongside the in-source engine).
@element-hqparity).D2-2. Speaking + mute indicators from widget events (#2)
Flag:
lotusCallState=1. cinny now reads speaker/mute state fromio.lotus.call_stateevents instead ofscraping EC's DOM (DOM fallback retained). Overlaps G1.
D2-3. Focus camera during a screenshare (#4 / A5)
Action: cinny sends
io.lotus.focus_participant(the DOM.click()hack is gone). Overlaps A5 / G2.spotlighted alongside/over the shared screen (not ignored).
D2-4. In-call avatar decorations (#6) — NEW, beyond A6
Action: cinny pushes
io.lotus.decorations. A6 only covered the lobby roster and called in-call ECtiles out of scope — that's now in scope.
their in-call video-tile avatar (inside EC, not just the lobby), correctly sized/positioned.
D2-5. Native transparent background (#5)
Flag:
lotusTransparent=1(native, replacing the injectedbackground:none !important).see-through, or layout breakage (also covered loosely by §D2 "looks right").
D2-7. In-Call Soundboard (#3 / P5-15) — 👥 2 people — NEW
Flag:
lotusAudioInject=1. A 🔔 Soundboard button now sits in the call controls bar (left group,next to the chat button). Clips are user-uploadable and sync across your devices like emoji packs.
Prereq: Settings → General → Calls → Soundboard must be ON (default on).
It appears as a clip tile. (Too-big / too-many shows an error, doesn't crash.)
you hear it locally too. ✅ good if both hear it; ❌ tell us if only one side does.
D2-8. Call Quality Controls (#7 / P5-31) — 👥 2 people — NEW
Action:
io.lotus.set_quality. User settings in Settings → General → Calls (Microphone Bitrate,Screenshare Bitrate, Screenshare Framerate; all default Auto). Admin caps in Room Settings →
General → Voice → Call Quality Caps.
still flows (thinner is fine). Set Screenshare Framerate to 15 fps and share your screen — it
still shares. ❌ tell us if any setting kills audio/screenshare.
Room Settings → Voice. A member whose user setting is higher (e.g. 256) should be clamped to 64
(best-effort/UX — this is client-side; hard server enforcement is a separate follow-up).
D2-9. Call Permissions — HARD server-side, cross-client (👥 2 people, admin) — NEW
This is enforced by the
voice-limit-guardon the server (re-signs the LiveKit JWT), so it applies toevery client, not just Lotus Chat. Set in Room Settings → General → Voice → Call Permissions.
(Requires the guard deployed on LXC 151 — auto-deploys on a
matrixrepo push.)screenshare button disappears in Lotus Chat. ✅ good if no one can screenshare.
X and try to screenshare → the server refuses the track (it won't publish). This proves it's
not just our client hiding a button.
server-blocked for all clients; microphones still work.
Screen Sharing off. Within a few seconds their screenshare should stop for everyone on its own
(no rejoin needed) — this is the server reconcile loop revoking it live. Works even if the sharer is
on stock Element. ✅ good if the share drops within ~3–5 s; ❌ tell us if it keeps going.
Fork feature sweep on the local LiveKit stack (two real participants)
io.lotus.call_statedrives both; remote mute state correct both waysio.lotus.set_qualityis sent once on join with the user's bitrate setting ✓ (effect on the encoder not measurable here)matrix@ee5f78b— livekit-server's JSON usescan_publish_sources(snake_case) and the guard readcanPublishSources, so it decided nobody publishes and never revoked. Now the share track is gone from the SFU 2.0 s after the policy flip. Follow-up #223: the sharer's own button stays lit ~30 s.max_users: 1→ second user sees "Channel Full (1/1)", Join disabled ✓, and a direct token request to the guard is refused403 This voice channel is full✓ — enforced for every clientLeaving open for D2-3/4/7.
Verified end-to-end on the local calls stack (fork
0.25.0-lotus.4; two headless clients; widget messages recorded on both sides of the iframe, SFU state fromListParticipants).df_bg.wasm,DeepFilterNet3_onnx.tar.gz,noiseGateWorklet.js), audio reaches the other side,speaking=true; after killing and restartinglivekit-servermid-call both republish within ~2 s and audio flows again. Whether it sounds right is the human item belowio.lotus.call_statecarries{id:"@u:hs:DEVICE:0", speaking, audioEnabled, videoEnabled}per participant; flips on mute/unmute and camera on/off, status bar shows "alice and bob are speaking…"io.lotus.focus_participant {userId, id}sent, alice's camera spotlighted; menu flips to "Unfocus camera" and sends{userId:null}io.lotus.avatar_decoration=joystick(MSC4133); host pushesio.lotus.decorations {"@bob:localhost": …/joystick.png}to both ECs; the joystick renders on bob's tilebackground-color: rgba(0,0,0,0), classeslotus-transparent lotus-theme, host#lotus-ec-stylesinjected,theme=param follows the app themeio.lotus.inject_audio {url: blob:…, volume: 0.8}→ SFU shows an extraAUDIO/UNKNOWNtrack on alice for the clip's duration; one-at-a-time guard disables the button; with the mic muted the host refuses with "Unmute your microphone to play a soundboard clip."{audioMaxBitrate:null,…}; settingio.lotus.room_quality {audio_max_kbps:32, screenshare_max_kbps:1000, screenshare_max_fps:15}mid-call re-sendsio.lotus.set_quality {32000, 1000000, 15}; clearing it sends nulls again. Server-side enforcement remains the known open itemee5f78b)Also confirmed: join/leave chimes (now debounced, #145), camera-off default on join, "N Live" pill, call status bar, member glance, in-call chat (message lands in the room), second-call guard ("Already in another call — End the current call to join!"), call-button scoping (DM ✅, private room without space parent ✅, public room ✗, room inside a space ✗), DM ring dialog → Reject → caller sees "Declined your call".
Found & fixed while here: screenshare-audio mute undone by a re-share (fork
lotus.4), SecurityError burst when EC fails to load (70620d4b). Found & filed: speaking indicator stuck after an SFU restart (element-call), see-through PiP (cinny).Closing; by-ear items → the new human-QA issue.