refactor(calls): drop the deafen iframe-DOM fallback now that the fork owns it (#209)

CallControl.setSound()/applyScreenshareAudioMuted() no longer poke <audio>.muted
inside the EC frame, and the per-membership re-apply (useCallMemberSoundSync)
is gone: with the pin at 0.25.0-lotus.4 the fork applies deafen and the
screenshare-audio mute through its own renderer, including for late joiners.
Verified headless: deafen set before a second participant joins mutes their
track on arrival; deafen/undeafen leaves the screenshare-audio mute in place.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
2026-09-19 00:53:24 -04:00
co-authored by Claude Opus 5
parent a9e0b893be
commit bbcbdad55a
3 changed files with 10 additions and 36 deletions
-2
View File
@@ -34,7 +34,6 @@ import {
useCallHangupEvent,
useCallJoined,
useCallThemeSync,
useCallMemberSoundSync,
useCallStart,
} from '../hooks/useCallEmbed';
import { callChatAtom, callEmbedAtom } from '../state/callEmbed';
@@ -673,7 +672,6 @@ function CallUtils({ embed, joined }: { embed: CallEmbed; joined: boolean }) {
// the mobile in-call chat. Both are gated on `joined`.
useCallHotkeys(embed, joined);
useAfkAutoMute(joined ? embed : undefined);
useCallMemberSoundSync(embed);
useCallJoinLeaveSounds(embed);
useCallThemeSync(embed);
useCallQuality(embed);
-9
View File
@@ -13,7 +13,6 @@ import { ThemeKind, useTheme } from './useTheme';
import { callEmbedAtom } from '../state/callEmbed';
import { useResizeObserver } from './useResizeObserver';
import { CallControlState } from '../plugins/call/CallControlState';
import { useCallMembersChange, useCallSession } from './useCall';
import { CallPreferences } from '../state/callPreferences';
import { useSetting } from '../state/hooks/settings';
import { NoiseSuppressionMode, settingsAtom } from '../state/settings';
@@ -184,14 +183,6 @@ export const useCallHangupEvent = (embed: CallEmbed, callback: () => void) => {
useClientWidgetApiEvent(embed.call, ElementWidgetActions.Close, callback);
};
export const useCallMemberSoundSync = (embed: CallEmbed) => {
const callSession = useCallSession(embed.room);
useCallMembersChange(
callSession,
useCallback(() => embed.control.applySound(), [embed]),
);
};
export const useCallThemeSync = (embed: CallEmbed) => {
const theme = useTheme();
+10 -25
View File
@@ -159,7 +159,7 @@ export class CallControl extends EventEmitter implements CallControlState {
audio_enabled: this.microphone,
video_enabled: this.video,
});
this.setSound(this.sound);
this.setSound();
this.emitStateUpdate();
}
@@ -251,10 +251,6 @@ export class CallControl extends EventEmitter implements CallControlState {
this.onControlMutation();
}
public applySound() {
this.setSound(this.sound);
}
private async setMediaState(state: ElementMediaStatePayload) {
// transport.send resolves once EC has ACK'd the command, which is enough to
// consider the mute applied. We deliberately do NOT gate completion on a
@@ -265,33 +261,22 @@ export class CallControl extends EventEmitter implements CallControlState {
return this.call.transport.send(ElementWidgetActions.DeviceMute, state);
}
private setSound(sound: boolean): void {
const callDocument = getCallDocument(this.iframe);
if (callDocument) {
callDocument.querySelectorAll('audio').forEach((el) => {
const isScreenshareAudio = el.getAttribute('data-lk-source') === 'screen_share_audio';
el.muted = !sound || (isScreenshareAudio && this.screenshareAudioMuted);
});
}
// [Gitea #209] Deafen is applied by the fork (io.lotus.set_deafen). The
// iframe-DOM `.muted` fallback that used to live here (plus the per-member
// re-apply in useCallMemberSoundSync) fought EC's audio renderer and is gone
// now that the pin is ≥ 0.25.0-lotus.2 — late joiners are the fork's job.
private setSound(): void {
this.sendDeafenState();
}
private applyScreenshareAudioMuted(): void {
if (!this.sound) return;
const callDocument = getCallDocument(this.iframe);
if (callDocument) {
callDocument
.querySelectorAll<HTMLAudioElement>('audio[data-lk-source="screen_share_audio"]')
.forEach((el) => {
el.muted = this.screenshareAudioMuted;
});
}
this.sendDeafenState();
}
// P6-2: send deafen state to the fork (io.lotus.set_deafen). The DOM .muted
// code above is a transitional fallback — remove once the fork ships & the
// pin is bumped.
// P6-2: send deafen state to the fork (io.lotus.set_deafen). Join-gated: the
// fork's handler only exists once joined; onCallJoined() re-sends the current
// state so a pre-join deafen is not lost.
private sendDeafenState(): void {
if (!this.joined) return;
this.call.transport
@@ -398,7 +383,7 @@ export class CallControl extends EventEmitter implements CallControlState {
);
this.state = state;
this.setSound(sound);
this.setSound();
// After un-deafening, re-apply screenshare audio mute if active
if (sound) this.applyScreenshareAudioMuted();