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:
@@ -34,7 +34,6 @@ import {
|
|||||||
useCallHangupEvent,
|
useCallHangupEvent,
|
||||||
useCallJoined,
|
useCallJoined,
|
||||||
useCallThemeSync,
|
useCallThemeSync,
|
||||||
useCallMemberSoundSync,
|
|
||||||
useCallStart,
|
useCallStart,
|
||||||
} from '../hooks/useCallEmbed';
|
} from '../hooks/useCallEmbed';
|
||||||
import { callChatAtom, callEmbedAtom } from '../state/callEmbed';
|
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`.
|
// the mobile in-call chat. Both are gated on `joined`.
|
||||||
useCallHotkeys(embed, joined);
|
useCallHotkeys(embed, joined);
|
||||||
useAfkAutoMute(joined ? embed : undefined);
|
useAfkAutoMute(joined ? embed : undefined);
|
||||||
useCallMemberSoundSync(embed);
|
|
||||||
useCallJoinLeaveSounds(embed);
|
useCallJoinLeaveSounds(embed);
|
||||||
useCallThemeSync(embed);
|
useCallThemeSync(embed);
|
||||||
useCallQuality(embed);
|
useCallQuality(embed);
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { ThemeKind, useTheme } from './useTheme';
|
|||||||
import { callEmbedAtom } from '../state/callEmbed';
|
import { callEmbedAtom } from '../state/callEmbed';
|
||||||
import { useResizeObserver } from './useResizeObserver';
|
import { useResizeObserver } from './useResizeObserver';
|
||||||
import { CallControlState } from '../plugins/call/CallControlState';
|
import { CallControlState } from '../plugins/call/CallControlState';
|
||||||
import { useCallMembersChange, useCallSession } from './useCall';
|
|
||||||
import { CallPreferences } from '../state/callPreferences';
|
import { CallPreferences } from '../state/callPreferences';
|
||||||
import { useSetting } from '../state/hooks/settings';
|
import { useSetting } from '../state/hooks/settings';
|
||||||
import { NoiseSuppressionMode, settingsAtom } from '../state/settings';
|
import { NoiseSuppressionMode, settingsAtom } from '../state/settings';
|
||||||
@@ -184,14 +183,6 @@ export const useCallHangupEvent = (embed: CallEmbed, callback: () => void) => {
|
|||||||
useClientWidgetApiEvent(embed.call, ElementWidgetActions.Close, callback);
|
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) => {
|
export const useCallThemeSync = (embed: CallEmbed) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ export class CallControl extends EventEmitter implements CallControlState {
|
|||||||
audio_enabled: this.microphone,
|
audio_enabled: this.microphone,
|
||||||
video_enabled: this.video,
|
video_enabled: this.video,
|
||||||
});
|
});
|
||||||
this.setSound(this.sound);
|
this.setSound();
|
||||||
this.emitStateUpdate();
|
this.emitStateUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,10 +251,6 @@ export class CallControl extends EventEmitter implements CallControlState {
|
|||||||
this.onControlMutation();
|
this.onControlMutation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public applySound() {
|
|
||||||
this.setSound(this.sound);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async setMediaState(state: ElementMediaStatePayload) {
|
private async setMediaState(state: ElementMediaStatePayload) {
|
||||||
// transport.send resolves once EC has ACK'd the command, which is enough to
|
// 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
|
// 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);
|
return this.call.transport.send(ElementWidgetActions.DeviceMute, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setSound(sound: boolean): void {
|
// [Gitea #209] Deafen is applied by the fork (io.lotus.set_deafen). The
|
||||||
const callDocument = getCallDocument(this.iframe);
|
// iframe-DOM `.muted` fallback that used to live here (plus the per-member
|
||||||
if (callDocument) {
|
// re-apply in useCallMemberSoundSync) fought EC's audio renderer and is gone
|
||||||
callDocument.querySelectorAll('audio').forEach((el) => {
|
// now that the pin is ≥ 0.25.0-lotus.2 — late joiners are the fork's job.
|
||||||
const isScreenshareAudio = el.getAttribute('data-lk-source') === 'screen_share_audio';
|
private setSound(): void {
|
||||||
el.muted = !sound || (isScreenshareAudio && this.screenshareAudioMuted);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.sendDeafenState();
|
this.sendDeafenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private applyScreenshareAudioMuted(): void {
|
private applyScreenshareAudioMuted(): void {
|
||||||
if (!this.sound) return;
|
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();
|
this.sendDeafenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
// P6-2: send deafen state to the fork (io.lotus.set_deafen). The DOM .muted
|
// P6-2: send deafen state to the fork (io.lotus.set_deafen). Join-gated: the
|
||||||
// code above is a transitional fallback — remove once the fork ships & the
|
// fork's handler only exists once joined; onCallJoined() re-sends the current
|
||||||
// pin is bumped.
|
// state so a pre-join deafen is not lost.
|
||||||
private sendDeafenState(): void {
|
private sendDeafenState(): void {
|
||||||
if (!this.joined) return;
|
if (!this.joined) return;
|
||||||
this.call.transport
|
this.call.transport
|
||||||
@@ -398,7 +383,7 @@ export class CallControl extends EventEmitter implements CallControlState {
|
|||||||
);
|
);
|
||||||
this.state = state;
|
this.state = state;
|
||||||
|
|
||||||
this.setSound(sound);
|
this.setSound();
|
||||||
// After un-deafening, re-apply screenshare audio mute if active
|
// After un-deafening, re-apply screenshare audio mute if active
|
||||||
if (sound) this.applyScreenshareAudioMuted();
|
if (sound) this.applyScreenshareAudioMuted();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user