Skip to content

fix(screensharing): prevent the "hall of mirrors" when sharing a screen - #1826

Open
vladopol wants to merge 1 commit into
nextcloud:mainfrom
vladopol:feat/screenshare-content-protection
Open

fix(screensharing): prevent the "hall of mirrors" when sharing a screen#1826
vladopol wants to merge 1 commit into
nextcloud:mainfrom
vladopol:feat/screenshare-content-protection

Conversation

@vladopol

Copy link
Copy Markdown

When a user shares their whole screen on the desktop client, the Talk window is itself on the shared screen and renders the live screen-share, so the capture recurses into an infinite "hall of mirrors" (#7792) — especially when sharing the entire desktop.

Unlike the browser, the desktop client knows what is being shared (getDesktopMediaSource returns the source id), so it can solve this natively: while a whole screen is being shared, the Talk window is excluded from OS screen capture via BrowserWindow.setContentProtection. The window then doesn't appear in the shared stream at all — no recursion, and remote participants see a clean desktop instead of the call window.

How

  • Detection wraps getUserMedia: when a screen (not a single window) capture starts, the window is protected; when the capture track ends or is stopped, protection is released. On page (re)load the state is reset to a known baseline. Talk (spreed) is not modified and the media stream is not touched.
  • Only screen / entire‑desktop captures are protected — sharing a single window is unaffected.
  • Windows: WDA_EXCLUDEFROMCAPTURE (the window is excluded; the desktop behind it shows through). macOS: NSWindowSharingNone. Linux: setContentProtection is a no‑op there, so the window stays in the stream — the spreed‑side overlay (#18690) covers that case.

Performance

Measured on low‑end hardware — enabling content protection adds no measurable CPU/GPU cost; the capture path is unchanged.

Testing

Verified on Windows and macOS with a second participant — sharing a whole screen no longer mirrors, the Talk window is absent from the shared stream, and sharing a single window is unchanged.


Refs #7792. Complements the cross‑platform overlay in #18690 (which remains the fallback on Linux and in browsers).

When a user shares their whole screen on the desktop client, the Talk window is
itself on the shared screen and renders the live screen-share, so the capture
recurses into an infinite "hall of mirrors" (#7792) - especially when sharing
the entire desktop.

Unlike the browser, the desktop client knows what is being shared
(getDesktopMediaSource returns the source id), so it can solve this natively:
while a whole screen is being shared, the Talk window is excluded from OS screen
capture via BrowserWindow.setContentProtection. The window then does not appear
in the shared stream at all - no recursion, and remote participants see a clean
desktop instead of the call window.

Detection wraps getUserMedia: when a screen (not a single window) capture starts,
the window is protected; when the capture track ends or is stopped, protection is
released. Talk (spreed) is not modified and the media stream is not touched. Only
screen / entire-desktop captures are protected - sharing a single window is
unaffected.

setContentProtection maps to WDA_EXCLUDEFROMCAPTURE on Windows and
NSWindowSharingNone on macOS; it is a no-op on Linux, where the spreed overlay
(#18690) covers the case.

Refs #7792

Signed-off-by: Vladimir Poluliashenko <vladopol@gmail.com>
@ShGKme

ShGKme commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Hi @vladopol

Thank you for your contribution here.
The issue has been already fixed on the web-client side in:

We'll discuss with the team if it still makes sense to block entire windows and not only the screensharing preview.

But if we do want to block the entire window from the screensharing, overriding mediaDevices.getUserMedia is too risky and indirect way to archive that. The patch isn't trivial, it is easy to miss something during the patching while the implemented feature isn't critical. Instead, we need an explicit API from the Talk side to get that screensharing state and react on its change. We can add API from the Talk side for that. It would be useful in the future to have more control during the screensharing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants