Symptom: in a voice room with a continuous tone as the fake mic (--use-file-for-fake-audio-capture, 220 Hz, about −8 dBFS), I muted and waited 10 s. The host's "You're muted — click to unmute" toast (cinny #117, useMutedTalkWarning) never appeared. The setting mutedTalkWarning is on, PTT is off, and the call is joined.
Cause.observeLocalMicSample$ (src/lotus/lotusMicLevel.ts) is vm.allConnections$.pipe(switchMap(() => new Observable(...)), share()). Every emission of allConnections$ (connectionManager.connectionManagerData$.pipe(map(d => d.value))) tears the tap down: stopTap() stops the clone, closes the AudioContext and emits null. It then builds a new clone and a new AudioContext. I traced MediaStreamTrack.clone/stop inside the call frame:
The source track (675609) never changes, yet the sampler restarts every 0.4–1 s.
In observeSpeakingWhileMuted$ (lotusMutedSpeech.ts), a null sample resets the MutedSpeechGate, so the flag is dropped on every restart. It needs 300 ms of voice to come back on.
The host needs speakingWhileMuted to stay true for 1.5 s straight (HOLD_MS, polled every 250 ms, and call_state is throttled to 500 ms).
The flag therefore never stays true long enough, and the nudge can't fire.
The same churn creates and closes an AudioContext about once a second for the whole call. The host's mic meter mostly hides it thanks to its hysteresis, but it dips to one bar now and then.
The nudge was verified when it landed (c2267800). The shared sampler (cee6bab9, cinny #146) is where the null-on-restart path sits. This stack also logs Failed to set E2EE enabled on room … e2ee not configured on join, which may be why connectionManagerData$ re-emits so often here. Prod may differ in rate, but any re-emission resets the gate.
Fix:
Restart only when the set of LiveKit rooms changes: map(d => d.getConnections().map(c => c.livekitRoom)), then distinctUntilChanged(sameRooms), before the switchMap.
Don't emit null when re-tapping the same source track (keep tapped across restarts, or have reconcile reuse it).
Optionally let the gate tolerate a single null.
Test: a connectionManagerData$ re-emission with the same rooms doesn't stop the clone, and a continuous tone while muted keeps speakingWhileMuted true for more than 2 s.
Found in the October 2026 client audit (Playwright against a local Synapse + LiveKit stack, plus code reading). Code refs are at cinny 30e2dbcd, cinny-desktop 8f67ec7, element-call 3b0050e8.
**Symptom:** in a voice room with a continuous tone as the fake mic (`--use-file-for-fake-audio-capture`, 220 Hz, about −8 dBFS), I muted and waited 10 s. The host's **"You're muted — click to unmute"** toast (cinny #117, `useMutedTalkWarning`) never appeared. The setting `mutedTalkWarning` is on, PTT is off, and the call is joined.
**Cause.** `observeLocalMicSample$` (`src/lotus/lotusMicLevel.ts`) is `vm.allConnections$.pipe(switchMap(() => new Observable(...)), share())`. Every emission of `allConnections$` (`connectionManager.connectionManagerData$.pipe(map(d => d.value))`) tears the tap down: `stopTap()` stops the clone, closes the `AudioContext` and emits `null`. It then builds a new clone and a new `AudioContext`. I traced `MediaStreamTrack.clone/stop` inside the call frame:
```
1.9 stop c9c29f · clone of 675609 → 36ba85 (before mute)
2.3 stop 36ba85 · clone → 2c4ebd
2.7 stop 2c4ebd · clone → 65903b
3.5 stop 65903b · clone → f2fb6a
4.2 enabled=false on 675609 (mute) · stop f2fb6a · clone → 7764c2 · clone → 5011da
5.1 stop 7764c2 · clone → f09951
6.1 stop f09951 · clone → 9448e1
```
The source track (`675609`) never changes, yet the sampler restarts every 0.4–1 s.
- In `observeSpeakingWhileMuted$` (`lotusMutedSpeech.ts`), a `null` sample resets the `MutedSpeechGate`, so the flag is dropped on every restart. It needs 300 ms of voice to come back on.
- The host needs `speakingWhileMuted` to stay true for 1.5 s straight (`HOLD_MS`, polled every 250 ms, and `call_state` is throttled to 500 ms).
- The flag therefore never stays true long enough, and the nudge can't fire.
The same churn creates and closes an `AudioContext` about once a second for the whole call. The host's mic meter mostly hides it thanks to its hysteresis, but it dips to one bar now and then.
The nudge was verified when it landed (c2267800). The shared sampler (cee6bab9, cinny #146) is where the `null`-on-restart path sits. This stack also logs `Failed to set E2EE enabled on room … e2ee not configured` on join, which may be why `connectionManagerData$` re-emits so often here. Prod may differ in rate, but any re-emission resets the gate.
**Fix:**
- Restart only when the set of LiveKit rooms changes: `map(d => d.getConnections().map(c => c.livekitRoom))`, then `distinctUntilChanged(sameRooms)`, before the `switchMap`.
- Don't emit `null` when re-tapping the same source track (keep `tapped` across restarts, or have `reconcile` reuse it).
- Optionally let the gate tolerate a single `null`.
- Test: a `connectionManagerData$` re-emission with the same rooms doesn't stop the clone, and a continuous tone while muted keeps `speakingWhileMuted` true for more than 2 s.
---
_Found in the October 2026 client audit (Playwright against a local Synapse + LiveKit stack, plus code reading). Code refs are at cinny `30e2dbcd`, cinny-desktop `8f67ec7`, element-call `3b0050e8`._
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.
Symptom: in a voice room with a continuous tone as the fake mic (
--use-file-for-fake-audio-capture, 220 Hz, about −8 dBFS), I muted and waited 10 s. The host's "You're muted — click to unmute" toast (cinny #117,useMutedTalkWarning) never appeared. The settingmutedTalkWarningis on, PTT is off, and the call is joined.Cause.
observeLocalMicSample$(src/lotus/lotusMicLevel.ts) isvm.allConnections$.pipe(switchMap(() => new Observable(...)), share()). Every emission ofallConnections$(connectionManager.connectionManagerData$.pipe(map(d => d.value))) tears the tap down:stopTap()stops the clone, closes theAudioContextand emitsnull. It then builds a new clone and a newAudioContext. I tracedMediaStreamTrack.clone/stopinside the call frame:The source track (
675609) never changes, yet the sampler restarts every 0.4–1 s.observeSpeakingWhileMuted$(lotusMutedSpeech.ts), anullsample resets theMutedSpeechGate, so the flag is dropped on every restart. It needs 300 ms of voice to come back on.speakingWhileMutedto stay true for 1.5 s straight (HOLD_MS, polled every 250 ms, andcall_stateis throttled to 500 ms).The same churn creates and closes an
AudioContextabout once a second for the whole call. The host's mic meter mostly hides it thanks to its hysteresis, but it dips to one bar now and then.The nudge was verified when it landed (
c2267800). The shared sampler (cee6bab9, cinny #146) is where thenull-on-restart path sits. This stack also logsFailed to set E2EE enabled on room … e2ee not configuredon join, which may be whyconnectionManagerData$re-emits so often here. Prod may differ in rate, but any re-emission resets the gate.Fix:
map(d => d.getConnections().map(c => c.livekitRoom)), thendistinctUntilChanged(sameRooms), before theswitchMap.nullwhen re-tapping the same source track (keeptappedacross restarts, or havereconcilereuse it).null.connectionManagerData$re-emission with the same rooms doesn't stop the clone, and a continuous tone while muted keepsspeakingWhileMutedtrue for more than 2 s.Found in the October 2026 client audit (Playwright against a local Synapse + LiveKit stack, plus code reading). Code refs are at cinny
30e2dbcd, cinny-desktop8f67ec7, element-call3b0050e8.