Skip to content

fix(macos): wake sleeping display at the beginning of capture session - #5291

Merged
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
martona:pr-sleeping-display
Jun 17, 2026
Merged

fix(macos): wake sleeping display at the beginning of capture session#5291
ReenigneArcher merged 3 commits into
LizardByte:masterfrom
martona:pr-sleeping-display

Conversation

@martona

@martona martona commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Description

Wakes the display at the beginning of the capture session, and does not let it go to sleep while it's active.

macOS does not present any capture frames on a sleeping display, thus the capture thread hangs indefinitely at session start, never sending video data to Moonlight, and therefore is not able to receive any input to wake the display either. The end result is a forever "spinning on connect" Moonlight client, and a hung Sunshine process.

This PR fixes the problem by issuing an IOPMAssertionDeclareUserActivity before capture start to handle the initial wake, and holding an kIOPMAssertPreventUserIdleDisplaySleep assertion for the lifetime of the capture object to prevent sleep.

I realize it's chonky; I could cut this down to about 30-40% of the proposed size by eliminating the display diagnostic logging that I added to help me track down the issue. I think it's useful to have there though, so I'm leaving it in for the original PR; but very much open to reducing it if needed.

Issues Fixed or Closed

Roadmap Issues

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semicolons, etc.)
  • refactor: Code change that neither fixes a bug nor adds a feature
  • perf: Code change that improves performance
  • test: Adding missing tests or correcting existing tests
  • build: Changes that affect the build system or external dependencies
  • ci: Changes to CI configuration files and scripts
  • chore: Other changes that don't modify src or test files
  • revert: Reverts a previous commit
  • BREAKING CHANGE: Introduces a breaking change (can be combined with any type above)

Checklist

  • Code follows the style guidelines of this project
  • Code has been self-reviewed
  • Code has been commented, particularly in hard-to-understand areas
  • Code docstring/documentation-blocks for new or existing methods/components have been added or updated
  • Unit tests have been added or updated for any new or modified functionality

AI Usage

  • None: No AI tools were used in creating this PR
  • Light: AI provided minor assistance (formatting, simple suggestions)
  • Moderate: AI helped with code generation or debugging specific parts
  • Heavy: AI generated most or all of the code changes

@ReenigneArcher

Copy link
Copy Markdown
Member

We should probably add display automation logic to https://github.com/LizardByte/libdisplaydevice

LizardByte/roadmap#57

@martona

martona commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

That makes sense long-term. I think this belongs in libdisplaydevice once macOS support exists there.

But since AVFoundation capture can hang before any frames are delivered if the target display is asleep, Sunshine never reaches the point where client input can wake it. Would you be open to keeping the minimal wake/prevent-sleep logic here for now?

I can also trim the diagnostic logging from this PR to keep it tighter. (Actually already have, would just need to resubmit the PR: it's -122 lines at the cost of some log clarity around display initialization.)

@ReenigneArcher

Copy link
Copy Markdown
Member

The size of this PR is not really a problem, it's small enough as is.

Would you be willing to help implement the library for macOS? This is not really work I can do since I don't own any macOS devices.

@martona

martona commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

Yeah I could. It's a non-trivial amount of work but it makes sense to do. I took a quick look at the code and there's almost certainly blockers in the way to complete feature parity using only public APIs (EnsurePrimary, EnsureOnlyDisplay, HDR...) but most of it - the parts that actually matter: enumeration, wake, mode selection, revert/persistence - are straightforward to implement.

My recommendation would be to keep this PR as the Sunshine-side bugfix if you’re generally OK with the approach. Then I can follow up with a draft/best-effort libdisplaydevice port and a feature matrix for what works vs what macOS doesn’t expose cleanly. Once that happens, we can integrate Sunshine with it and remove the duplicated macOS display handling here.

@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Bundle Report

Bundle size has no change ✅

@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 38.77551% with 90 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (master@a103db8). Learn more about missing BASE report.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/platform/macos/display.mm 38.77% 36 Missing and 54 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #5291   +/-   ##
=========================================
  Coverage          ?   17.86%           
=========================================
  Files             ?      111           
  Lines             ?    24589           
  Branches          ?    10888           
=========================================
  Hits              ?     4392           
  Misses            ?    17650           
  Partials          ?     2547           
Flag Coverage Δ
Archlinux 11.19% <ø> (?)
FreeBSD-amd64 13.24% <ø> (?)
Homebrew-ubuntu-24.04 13.23% <ø> (?)
Linux-AppImage 12.11% <ø> (?)
Windows-AMD64 14.91% <ø> (?)
Windows-ARM64 13.20% <ø> (?)
macOS-arm64 19.13% <38.77%> (?)
macOS-x86_64 18.60% <38.77%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/platform/macos/display.mm 42.38% <38.77%> (ø)

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a103db8...73c013b. Read the comment docs.

@ReenigneArcher ReenigneArcher left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just have a small nit pic.

Comment thread src/platform/macos/display.mm Outdated
@sonarqubecloud

Copy link
Copy Markdown

@ReenigneArcher
ReenigneArcher merged commit c9863eb into LizardByte:master Jun 17, 2026
73 checks passed
azarashi11037 added a commit to azarashi11037/Sunshine that referenced this pull request Aug 6, 2026
Wake the selected display before encoder probing, hold a display-sleep assertion for the capture lifetime, and bound first-frame waits so a sleeping virtual display cannot hang launch indefinitely.

Based on the macOS power assertion approach from upstream Sunshine PR LizardByte#5291 (c9863eb).
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