diff --git a/src/app/features/call/CallControls.tsx b/src/app/features/call/CallControls.tsx index 53c7d11c1..882bfaa11 100644 --- a/src/app/features/call/CallControls.tsx +++ b/src/app/features/call/CallControls.tsx @@ -24,6 +24,7 @@ import { FullscreenButton, MicrophoneButton, ScreenShareButton, + ScreenshareAudioButton, SoundButton, VideoButton, } from './Controls'; @@ -67,9 +68,8 @@ export function CallControls({ callEmbed }: CallControlsProps) { } }, [callEmbedRef]); - const { microphone, video, sound, screenshare, spotlight } = useCallControlState( - callEmbed.control, - ); + const { microphone, video, sound, screenshare, spotlight, screenshareAudioMuted } = + useCallControlState(callEmbed.control); const [cords, setCords] = useState(); const [shareConfirm, setShareConfirm] = useState(false); @@ -346,6 +346,10 @@ export function CallControls({ callEmbed }: CallControlsProps) { onToggle={() => callEmbed.control.toggleMicrophone()} /> callEmbed.control.toggleSound()} /> + callEmbed.control.toggleScreenshareAudio()} + /> {!compact && } diff --git a/src/app/features/call/Controls.tsx b/src/app/features/call/Controls.tsx index 20b86e19f..3bbfd21f5 100644 --- a/src/app/features/call/Controls.tsx +++ b/src/app/features/call/Controls.tsx @@ -197,11 +197,41 @@ export function FullscreenButton({ isFullscreen, onToggle }: FullscreenButtonPro aria-pressed={isFullscreen} outlined > - {isFullscreen ? ( - - ) : ( - - )} + {isFullscreen ? : } + + )} + + ); +} + +type ScreenshareAudioButtonProps = { + muted: boolean; + onToggle: () => void; +}; +export function ScreenshareAudioButton({ muted, onToggle }: ScreenshareAudioButtonProps) { + return ( + + {muted ? 'Unmute Screenshare Audio' : 'Mute Screenshare Audio'} + + } + > + {(anchorRef) => ( + + )} diff --git a/src/app/plugins/call/CallControl.ts b/src/app/plugins/call/CallControl.ts index 1a405e5df..9133f22ee 100644 --- a/src/app/plugins/call/CallControl.ts +++ b/src/app/plugins/call/CallControl.ts @@ -93,6 +93,10 @@ export class CallControl extends EventEmitter implements CallControlState { return this.state.spotlight; } + public get screenshareAudioMuted(): boolean { + return this.state.screenshareAudioMuted; + } + public async applyState() { await this.setMediaState({ audio_enabled: this.microphone, @@ -145,11 +149,24 @@ export class CallControl extends EventEmitter implements CallControlState { const callDocument = this.iframe.contentDocument ?? this.iframe.contentWindow?.document; if (callDocument) { callDocument.querySelectorAll('audio').forEach((el) => { - el.muted = !sound; + const isScreenshareAudio = el.getAttribute('data-lk-source') === 'screen_share_audio'; + el.muted = !sound || (isScreenshareAudio && this.screenshareAudioMuted); }); } } + private applyScreenshareAudioMuted(): void { + if (!this.sound) return; + const callDocument = this.iframe.contentDocument ?? this.iframe.contentWindow?.document; + if (callDocument) { + callDocument + .querySelectorAll('audio[data-lk-source="screen_share_audio"]') + .forEach((el) => { + el.muted = this.screenshareAudioMuted; + }); + } + } + public onMediaState(evt: CustomEvent) { const { data } = evt.detail; if (!data) return; @@ -160,6 +177,7 @@ export class CallControl extends EventEmitter implements CallControlState { this.sound, this.screenshare, this.spotlight, + this.screenshareAudioMuted, ); this.state = state; @@ -171,8 +189,6 @@ export class CallControl extends EventEmitter implements CallControlState { } public onControlMutation() { - const prevScreenshare = this.screenshare; - const screenshare: boolean = this.screenshareButton?.getAttribute('data-kind') === 'primary'; const spotlight: boolean = this.spotlightButton?.checked ?? false; @@ -182,9 +198,9 @@ export class CallControl extends EventEmitter implements CallControlState { this.sound, screenshare, spotlight, + this.screenshareAudioMuted, ); this.emitStateUpdate(); - } public setMicrophone(enabled: boolean) { @@ -215,6 +231,8 @@ export class CallControl extends EventEmitter implements CallControlState { const sound = !this.sound; this.setSound(sound); + // After un-deafening, re-apply screenshare audio mute if active + if (sound) this.applyScreenshareAudioMuted(); const state = new CallControlState( this.microphone, @@ -222,6 +240,7 @@ export class CallControl extends EventEmitter implements CallControlState { sound, this.screenshare, this.spotlight, + this.screenshareAudioMuted, ); this.state = state; this.emitStateUpdate(); @@ -231,6 +250,20 @@ export class CallControl extends EventEmitter implements CallControlState { } } + public toggleScreenshareAudio() { + const screenshareAudioMuted = !this.screenshareAudioMuted; + this.state = new CallControlState( + this.microphone, + this.video, + this.sound, + this.screenshare, + this.spotlight, + screenshareAudioMuted, + ); + this.emitStateUpdate(); + this.applyScreenshareAudioMuted(); + } + public toggleScreenshare() { this.screenshareButton?.click(); } diff --git a/src/app/plugins/call/CallControlState.ts b/src/app/plugins/call/CallControlState.ts index 03e35a1c7..b11dc3856 100644 --- a/src/app/plugins/call/CallControlState.ts +++ b/src/app/plugins/call/CallControlState.ts @@ -9,17 +9,21 @@ export class CallControlState { public readonly spotlight: boolean; + public readonly screenshareAudioMuted: boolean; + constructor( microphone: boolean, video: boolean, sound: boolean, screenshare = false, spotlight = false, + screenshareAudioMuted = false, ) { this.microphone = microphone; this.video = video; this.sound = sound; this.screenshare = screenshare; this.spotlight = spotlight; + this.screenshareAudioMuted = screenshareAudioMuted; } }