Host half is LotusGuild/cinny (toast). Fork half: while the local mic is muted, LiveKit keeps the MediaStreamTrack alive (mute publishes silence; stopMicTrackOnMute is not set) but VAD/speaking is false, so the host cannot tell the user is talking into a muted mic.
Scope
While the local audio track is muted, run a cheap level tap (AnalyserNode RMS on the local track, ~10 Hz, same threshold family as the AFK VAD) and add speakingWhileMuted: boolean for the local participant to the existing io.lotus.call_state payload (500 ms trailing throttle already applies).
Respect the denoise pipeline: tap the processed track EC publishes (post-denoise), not raw capture, so keyboard noise doesn't trigger it.
Zero cost when unmuted (tap torn down), zero when no host is listening (behind the existing lotus-actions gate).
Never exposed to other participants — local-only field.
Host half is LotusGuild/cinny (toast). Fork half: while the local mic is **muted**, LiveKit keeps the MediaStreamTrack alive (mute publishes silence; `stopMicTrackOnMute` is not set) but VAD/`speaking` is false, so the host cannot tell the user is talking into a muted mic.
### Scope
- While the local audio track is muted, run a cheap level tap (AnalyserNode RMS on the local track, ~10 Hz, same threshold family as the AFK VAD) and add `speakingWhileMuted: boolean` for the **local** participant to the existing `io.lotus.call_state` payload (500 ms trailing throttle already applies).
- Respect the denoise pipeline: tap the *processed* track EC publishes (post-denoise), not raw capture, so keyboard noise doesn't trigger it.
- Zero cost when unmuted (tap torn down), zero when no host is listening (behind the existing lotus-actions gate).
- Never exposed to other participants — local-only field.
jared
added this to the Features 2026-Q4 milestone 2026-09-17 15:21:20 -04:00
Done in 0.25.0-lotus.9 (src/lotus/lotusMutedSpeech.ts): while a muted mic publication exists, a clone of the published track (the post-processor track when the in-source denoiser is on, so keyboard noise doesn't count) feeds an AnalyserNode sampled at 10 Hz through a hysteresis gate — 300 ms of voice on, 800 ms of quiet off, threshold ≈ −36 dBFS RMS. The result rides the existing io.lotus.call_state throttle as speakingWhileMuted on the local entry only; the tap is torn down the moment the mic is unmuted/unpublished, and nothing exists at all when the host isn't listening (same lotusCallState gate). Gate unit-tested; verified end-to-end: muted with a tone mic → true within 2.5 s, silence → false, unmute → false. Host half: cinny #117.
Done in `0.25.0-lotus.9` (`src/lotus/lotusMutedSpeech.ts`): while a muted mic publication exists, a **clone** of the published track (the post-processor track when the in-source denoiser is on, so keyboard noise doesn't count) feeds an AnalyserNode sampled at 10 Hz through a hysteresis gate — 300 ms of voice on, 800 ms of quiet off, threshold ≈ −36 dBFS RMS. The result rides the existing `io.lotus.call_state` throttle as `speakingWhileMuted` on the **local** entry only; the tap is torn down the moment the mic is unmuted/unpublished, and nothing exists at all when the host isn't listening (same `lotusCallState` gate). Gate unit-tested; verified end-to-end: muted with a tone mic → `true` within 2.5 s, silence → `false`, unmute → `false`. Host half: cinny #117.
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.
Host half is LotusGuild/cinny (toast). Fork half: while the local mic is muted, LiveKit keeps the MediaStreamTrack alive (mute publishes silence;
stopMicTrackOnMuteis not set) but VAD/speakingis false, so the host cannot tell the user is talking into a muted mic.Scope
speakingWhileMuted: booleanfor the local participant to the existingio.lotus.call_statepayload (500 ms trailing throttle already applies).Done in
0.25.0-lotus.9(src/lotus/lotusMutedSpeech.ts): while a muted mic publication exists, a clone of the published track (the post-processor track when the in-source denoiser is on, so keyboard noise doesn't count) feeds an AnalyserNode sampled at 10 Hz through a hysteresis gate — 300 ms of voice on, 800 ms of quiet off, threshold ≈ −36 dBFS RMS. The result rides the existingio.lotus.call_statethrottle asspeakingWhileMutedon the local entry only; the tap is torn down the moment the mic is unmuted/unpublished, and nothing exists at all when the host isn't listening (samelotusCallStategate). Gate unit-tested; verified end-to-end: muted with a tone mic →truewithin 2.5 s, silence →false, unmute →false. Host half: cinny #117.