Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
339 commits
Select commit Hold shift + click to select a range
f35b3a5
Recover capture when displays come and go, and tell the iPad
whoisaldo Nov 7, 2026
5ec6552
Keep the pointer in the video on the second screen
whoisaldo Nov 7, 2026
f8b110b
Make a replacement window device off the window's thread, time-boxed
whoisaldo Nov 7, 2026
34692a8
Record a device lost before the window works when it is dropped
whoisaldo Nov 7, 2026
1184b16
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 7, 2026
03f9754
Capture the GPU detection test's log lines whatever ran first
whoisaldo Nov 7, 2026
7ad2e26
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into pe…
whoisaldo Nov 7, 2026
eba142f
Give a waking PC's displays 10 s before the watchdog judges capture
whoisaldo Nov 7, 2026
d34cf2c
Check a lost output cheaply, reopen a moved display at once, cap a he…
whoisaldo Nov 7, 2026
ba9e653
Merge pull request #204 from sidebandstudio/feat/beta-channel-updates
whoisaldo Nov 7, 2026
163ade5
End the swscale frame when a conversion fails
whoisaldo Nov 7, 2026
b3de1f7
Skip the startup Disable only when no driver task is queued or running
whoisaldo Nov 7, 2026
26330a7
Leave a UTF-32 settings file untouched
whoisaldo Nov 7, 2026
e79e6dc
Convert on one thread when swscale can't start its threads
whoisaldo Nov 7, 2026
69ec7ca
Keep swscale on one thread where Accelerate converts
whoisaldo Nov 7, 2026
a6e1e09
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into pe…
whoisaldo Nov 7, 2026
513a426
Answer the iPad while the PC isn't streaming, and say why (#196)
whoisaldo Nov 7, 2026
59b0d19
Check the hard-limit release itself, not the quit's
whoisaldo Nov 7, 2026
9598ae9
Leave the virtual display on when making a window device panics
whoisaldo Nov 7, 2026
13a9cab
Give the polling test room for a loaded machine
whoisaldo Nov 7, 2026
ddbffdd
Let go of the kept picture under the mailbox lock
whoisaldo Nov 7, 2026
8171c7b
Count the keyframe retry deadline from the keyframe's submission
whoisaldo Nov 7, 2026
e6172dd
Test the keyframe retry deadline without racing the scheduler
whoisaldo Nov 7, 2026
0948574
Test the panic hook in its own process, as installed
whoisaldo Nov 7, 2026
1131531
Try a BGRA open that fails in the background again at YUV420
whoisaldo Nov 7, 2026
8b39c87
Drop an HEVC open in the background once the frame wants H.264
whoisaldo Nov 7, 2026
e4496ea
Let a stopped or restarting PC prove it is the saved PC
whoisaldo Nov 8, 2026
e09aee9
Count IDENTIFY answers only, and keep test address lists apart
whoisaldo Nov 8, 2026
6d35f25
Skip the startup Disable without recording the display as off
whoisaldo Nov 8, 2026
805b22e
Build the dark second screen test's picture with its first image seen
whoisaldo Nov 8, 2026
4fe24ef
Import the second screen's pointer rule in the Windows capture loop
whoisaldo Nov 8, 2026
80bf784
Wait for the standby's address listing itself in the tests
whoisaldo Nov 8, 2026
c631569
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
87f8a20
Merge pull request #208 from sidebandstudio/perf/ss-conversion
whoisaldo Nov 8, 2026
ac11806
Keep a proven second screen proven across reopens, and time tests on …
whoisaldo Nov 8, 2026
1b901a0
Merge release/0.3.5-candidate into feat/ipad-drawn-cursor
whoisaldo Nov 8, 2026
19f54b1
List the pointer messages in the architecture notes
whoisaldo Nov 8, 2026
7961ceb
Name the panic hook test's folder so Windows accepts it
whoisaldo Nov 8, 2026
ddb03a8
Let the window close while a device replacement is stuck
whoisaldo Nov 8, 2026
4856cac
Say in vendor/README.md why the replacement surface doesn't hold the …
whoisaldo Nov 8, 2026
09cb15c
Run no Disable task at an idle quit when Windows reports the display …
whoisaldo Nov 8, 2026
7962561
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
88a16b1
Send the second screen's pointer apart, keep old shapes out, clip to …
whoisaldo Nov 8, 2026
c83bc30
Wait up to 3 s for a stopped stream's port, on the address it bound
whoisaldo Nov 8, 2026
3e94620
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
7523805
Tie a second screen's proof to its output and attachment
whoisaldo Nov 8, 2026
90b3d9c
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fe…
whoisaldo Nov 8, 2026
d21bbd0
Send the first picture, then wait to hear from the iPad (#200)
whoisaldo Nov 8, 2026
3524c91
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
c77b220
Bring PC audio back when another app lets go of the output
whoisaldo Nov 8, 2026
9cb3a2c
Wait for the window in two steps, and watch its first frame
whoisaldo Nov 8, 2026
4d8805f
Back off and step the bitrate down when the system has no buffer spac…
whoisaldo Nov 8, 2026
6d268cc
Tell iPad users when their PC app is out of date
whoisaldo Nov 8, 2026
2c02675
Merge pull request #198 from sidebandstudio/perf/first-frame
whoisaldo Nov 8, 2026
a0e1089
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
b228783
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
8f61706
Know each PC by its pairing and remember what its session proved
whoisaldo Nov 8, 2026
c56d893
Expect a stopped stream to hand its port on, as #196 made it
whoisaldo Nov 8, 2026
668ec4a
Keep the window's surface out of the device replacement thread
whoisaldo Nov 8, 2026
57d3203
Link a USB session to the PC's own service, and keep other PCs' proofs
whoisaldo Nov 8, 2026
c1dea61
Say in the architecture notes when the second screen sends the pointe…
whoisaldo Nov 8, 2026
4c566e1
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fe…
whoisaldo Nov 8, 2026
7d8fa2a
Link a PC's own service by name only when it is unambiguous
whoisaldo Nov 8, 2026
e9238ee
Hold the first picture's deadline however long the open takes to start
whoisaldo Nov 8, 2026
fbc0cfb
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
4511f28
Keep one showing for a PC linked by name across launches
whoisaldo Nov 8, 2026
d240404
Start pointer messages once the iPad has answered, and resume refused…
whoisaldo Nov 8, 2026
b1e5c7d
Start each audio session's wait for a taken output afresh
whoisaldo Nov 8, 2026
1c82d48
Merge pull request #199 from sidebandstudio/fix/input-off-transport
whoisaldo Nov 8, 2026
57a5a3b
Merge pull request #209 from sidebandstudio/fix/standby-identify
whoisaldo Nov 8, 2026
cb523e2
Prefer the adapter that drew, and make the renderer off the window's …
whoisaldo Nov 8, 2026
bb92d40
Draw no pointer over Windows' own, and trust the second screen's curs…
whoisaldo Nov 8, 2026
feaa4ea
Wait for NVENC's session before the stalled-reopen test's ABR step
whoisaldo Nov 8, 2026
98d4be7
Merge pull request #211 from sidebandstudio/fix/ipad-old-pc-update
whoisaldo Nov 8, 2026
c51be80
Translate the out-of-date PC card and the locked-PC notice
whoisaldo Nov 8, 2026
1a6a884
Expect every string translated again
whoisaldo Nov 8, 2026
2ece40c
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
0bba883
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
36d2e91
Clear a second screen's proof when capture's listing misses its output
whoisaldo Nov 8, 2026
0b7e302
Choose a replacement only among the candidates without a selector too
whoisaldo Nov 8, 2026
f42dd9b
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
e5c5389
Count refused repairs, wait the downgrade cooldown, and log a failed …
whoisaldo Nov 8, 2026
567366e
Merge pull request #202 from sidebandstudio/fix/encoder-fallback
whoisaldo Nov 8, 2026
97a86fb
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
75acc7e
Keep a stopped PC stopped when its chosen network changes
whoisaldo Nov 8, 2026
b546298
Time the iPad's retries to a stopped PC by when they arrive
whoisaldo Nov 8, 2026
e83f790
Start each capture with the pointer hidden
whoisaldo Nov 8, 2026
79296bc
Merge pull request #212 from sidebandstudio/fix/audio-device-in-use
whoisaldo Nov 8, 2026
18e1f2d
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fe…
whoisaldo Nov 8, 2026
8e71925
Merge pull request #214 from sidebandstudio/fix/send-congestion
whoisaldo Nov 8, 2026
c0c7f04
Tell identical graphics cards apart by their LUID
whoisaldo Nov 8, 2026
7afc087
Merge pull request #207 from sidebandstudio/fix/ss-enable-failed
whoisaldo Nov 8, 2026
cced05b
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
4508997
Give the startup and quit device read a 2 s limit
whoisaldo Nov 8, 2026
d9e5a79
Tie the second screen's pointer to the running driver's start
whoisaldo Nov 8, 2026
c7add56
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fe…
whoisaldo Nov 8, 2026
223b9ec
Merge pull request #215 from sidebandstudio/fix/standby-network-test
whoisaldo Nov 8, 2026
db9ec41
Tag a stream's restart request with its own generation
whoisaldo Nov 8, 2026
486447f
Wait for the supervisor's answer, and require kernel receive times
whoisaldo Nov 8, 2026
a5074d7
Merge pull request #213 from sidebandstudio/l10n/ios-strings-20261108
whoisaldo Nov 8, 2026
2cc4ae3
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
f50860d
Allow the LUID reading's unsafe calls in the vendored crate
whoisaldo Nov 8, 2026
fa80817
Watch the window until it is confirmed drawing, and key it by a list …
whoisaldo Nov 8, 2026
e5cc8e0
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
6365a06
Show the mirror before the moved-screen test's second screen attaches
whoisaldo Nov 8, 2026
bf02088
Merge pull request #216 from sidebandstudio/fix/restart-stream-genera…
whoisaldo Nov 8, 2026
5163125
List display outputs only through one judge of the second screen's proof
whoisaldo Nov 8, 2026
496e538
Merge pull request #217 from sidebandstudio/fix/ss-moved-card-test
whoisaldo Nov 8, 2026
f6a174f
Find an adapter again after a driver update gives it a new LUID
whoisaldo Nov 8, 2026
27672a5
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fe…
whoisaldo Nov 8, 2026
2157f65
Leave no public listing without the judge, and scan for aliases
whoisaldo Nov 8, 2026
8ac6495
Count more of the second screen's driver as unknown
whoisaldo Nov 8, 2026
a0abf49
Merge pull request #201 from sidebandstudio/fix/window-device-lost
whoisaldo Nov 8, 2026
5ff9982
Prove a presented frame, leave a minimized window alone, and wait out…
whoisaldo Nov 8, 2026
61ea998
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
96c6055
Merge pull request #218 from sidebandstudio/fix/vdd-cm-read-timeout
whoisaldo Nov 8, 2026
8e43c59
Use smaller packets or the PC's other address when no video arrives
whoisaldo Nov 8, 2026
5f82701
Count an unread root device as an unreadable driver state
whoisaldo Nov 8, 2026
f3c6ef5
Read vdd_settings.xml saved in a Windows code page
whoisaldo Nov 8, 2026
241fa1b
Merge pull request #205 from sidebandstudio/fix/capture-recovery
whoisaldo Nov 8, 2026
60f0b8b
Translate the no-display notice
whoisaldo Nov 8, 2026
233001d
Keep the macOS release build free of an unused second screen method
whoisaldo Nov 8, 2026
9000971
Check the remembered address's proof and cap the media-size keyframes
whoisaldo Nov 8, 2026
47d5186
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fe…
whoisaldo Nov 8, 2026
bb02855
Hand a lost duplication during the pointer rebuild to the handler
whoisaldo Nov 8, 2026
568bbe3
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
e909a94
Retire a remembered address that fails, and check it is on this network
whoisaldo Nov 8, 2026
8ef2b61
Give an unanswered HELLO2 time to give up before the connect timeout …
whoisaldo Nov 8, 2026
12b5b76
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
fcaf6af
Convert code page settings files the card does not change
whoisaldo Nov 8, 2026
8f660c2
Bound the wait for a presented frame, and accept only this span's answer
whoisaldo Nov 8, 2026
034caf6
Keep the HUD up in the pairing UI test
whoisaldo Nov 8, 2026
89d6000
Merge pull request #220 from sidebandstudio/l10n/ios-no-display-20261108
whoisaldo Nov 8, 2026
57cd87d
Make the encoding tests independent of the system code page and date
whoisaldo Nov 8, 2026
47eca9b
Merge pull request #192 from sidebandstudio/feat/ipad-drawn-cursor
whoisaldo Nov 8, 2026
40710e0
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
3aaa902
Accept the second screen step as where a session-locked loop is stuck
whoisaldo Nov 8, 2026
32d5b37
Leave release clippy out of CI
whoisaldo Nov 8, 2026
a4781b3
Merge pull request #219 from sidebandstudio/fix/no-video-path-fallback
whoisaldo Nov 8, 2026
229904a
Start the audio stage tests' fake tone at its first read
whoisaldo Nov 8, 2026
bbce161
Merge pull request #221 from sidebandstudio/fix/vdd-settings-codepage
whoisaldo Nov 8, 2026
f7ceae3
Ride out GitHub's 5xx spells on release downloads
whoisaldo Nov 8, 2026
21eb8a9
Merge pull request #206 from sidebandstudio/fix/gpu-detect-timebox-035
whoisaldo Nov 8, 2026
6e7397f
Retry a release download cut off partway
whoisaldo Nov 8, 2026
09dd5f0
Give AMF its last picture again only when no picture is due
whoisaldo Nov 8, 2026
b88fc92
Let the first-frame probe answer as the app does
whoisaldo Nov 8, 2026
f63f477
Merge pull request #223 from sidebandstudio/fix/pairing-e2e-flake
whoisaldo Nov 8, 2026
bd45bd5
Merge pull request #224 from sidebandstudio/fix/release-clippy-panel-…
whoisaldo Nov 8, 2026
2e58ecb
Remember the media size a path needed
whoisaldo Nov 8, 2026
70eb57c
Tell the encoder which pictures capture resent from its cache
whoisaldo Nov 8, 2026
d068357
Keep a remembered media size per network
whoisaldo Nov 8, 2026
f879fb4
Keep the session-summary tests from sharing the fallback slot
whoisaldo Nov 8, 2026
12cc34e
End the second screen's attach wait early when its device runs with n…
whoisaldo Nov 8, 2026
34a72a4
Merge pull request #222 from sidebandstudio/fix/transport-stall-phase
whoisaldo Nov 8, 2026
3254f68
Keep the iPad's session alive while the stream restarts
whoisaldo Nov 8, 2026
1ad5934
Merge pull request #225 from sidebandstudio/fix/audio-stage-test-flake
whoisaldo Nov 8, 2026
23985fc
Merge pull request #226 from sidebandstudio/fix/release-download-retry
whoisaldo Nov 8, 2026
c70f270
Say goodbye when the PC sleeps, shuts down or signs out
whoisaldo Nov 8, 2026
3416d29
Tell the iPad when the PC can't capture from its graphics card
whoisaldo Nov 8, 2026
4a800ec
Hold a restarting session only until the limit, even once the stream …
whoisaldo Nov 8, 2026
9bc86e7
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
6b0eda1
Stop answering the cable while the PC turns the iPad down
whoisaldo Nov 8, 2026
571da5b
Merge pull request #229 from sidebandstudio/fix/remember-media-size
whoisaldo Nov 8, 2026
ed30efa
Log why a USB tunnel closed, and how it opened
whoisaldo Nov 8, 2026
4283c55
Treat a capture error as the stream stops as the stop
whoisaldo Nov 8, 2026
d9dcf88
Merge pull request #230 from sidebandstudio/fix/summary-test-isolation
whoisaldo Nov 8, 2026
7c8e228
End the attach wait early only on a confirmed absence of monitors
whoisaldo Nov 8, 2026
c541fea
Keep USB tunnels through a failed device list
whoisaldo Nov 8, 2026
fbfeea9
Count only frames that go out, and keep an iPad's own goodbye, in the…
whoisaldo Nov 8, 2026
8dc190d
Connect by itself when a PC that didn't answer comes back
whoisaldo Nov 8, 2026
f439518
Make the moving-desktop test need the wait's half frame of margin
whoisaldo Nov 8, 2026
d166809
Time the cable-hold test on a sleeper it controls
whoisaldo Nov 8, 2026
a68319e
Log each USB tunnel once in the hub, without device ids
whoisaldo Nov 8, 2026
cd9c963
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into co…
whoisaldo Nov 8, 2026
6b598c6
Mark the GPU fallback test's pictures as new ones
whoisaldo Nov 8, 2026
7f4691e
Tell the iPad when the PC is restarting its stream
whoisaldo Nov 8, 2026
5e1fb9d
Prove the PC before an automatic try, and go where Bonjour has it
whoisaldo Nov 8, 2026
cf56340
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
2d9c27d
Keep a root device that couldn't be read as uncertain in the attach wait
whoisaldo Nov 8, 2026
58d0932
Restart the notice wait for each refusal, and keep lost video lost
whoisaldo Nov 8, 2026
950076b
Show USB as it was while a failed list keeps the tunnels
whoisaldo Nov 8, 2026
5643386
Merge remote-tracking branch 'origin/fix/usb-ten-second-close' into f…
whoisaldo Nov 8, 2026
6e5f725
Name the tunnel tests after what they check
whoisaldo Nov 8, 2026
86a8a10
Keep the capture's own notice over the restarting one
whoisaldo Nov 8, 2026
088a34a
Make three host lib tests independent of the machine's load
whoisaldo Nov 8, 2026
2013b68
Treat an installer closing the app as a quit, and bound the shutdown …
whoisaldo Nov 8, 2026
96cb943
Run the link's silent-peer test on a paused clock too
whoisaldo Nov 8, 2026
e7dde1a
Look at the chosen network first when a stream starts
whoisaldo Nov 8, 2026
ac866f6
Mirror at once on Windows 10 and say Second screen needs Windows 11
whoisaldo Nov 8, 2026
a616664
Ask the PC's listings until one proves the pairing
whoisaldo Nov 8, 2026
0e3181e
Merge pull request #236 from sidebandstudio/fix/log-noise
whoisaldo Nov 8, 2026
8117d4a
Show on the iPad that Second screen needs Windows 11
whoisaldo Nov 8, 2026
3ca530d
Bring Second screen back after a lock Windows reports late
whoisaldo Nov 8, 2026
85e3b57
Run each AMF encoder test alone, from a clean launch
whoisaldo Nov 8, 2026
3b7ea7c
Offer a one-click fix for a Windows Firewall block on EternalMonitor
whoisaldo Nov 8, 2026
14d3a28
Ask every listing of the PC in turn
whoisaldo Nov 8, 2026
e40494a
Quit when an installer closes the app, and keep the power window
whoisaldo Nov 8, 2026
0ee7e3e
Merge pull request #239 from sidebandstudio/fix/usb-list-failure-keep…
whoisaldo Nov 8, 2026
5faace5
Merge pull request #232 from sidebandstudio/fix/hybrid-no-picture-notice
whoisaldo Nov 8, 2026
887d65d
Clear the renderer marker when Windows closes the app
whoisaldo Nov 8, 2026
3357754
Merge release/0.3.5-candidate into fix/win10-second-screen
whoisaldo Nov 8, 2026
55bf14d
Log the Windows 10 hold as its own line, not as a Second screen fallback
whoisaldo Nov 8, 2026
e361a04
Merge pull request #234 from sidebandstudio/fix/refused-stops-retry
whoisaldo Nov 8, 2026
bd1b637
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
4deecfd
Install the virtual display driver on Windows 11 only
whoisaldo Nov 8, 2026
e29b29f
Run no Disable task when Windows confirms there is no display device
whoisaldo Nov 8, 2026
bed6111
Merge pull request #231 from sidebandstudio/fix/restart-keeps-ipad
whoisaldo Nov 8, 2026
707b25a
Fix the firewall block without ever removing a rule that works
whoisaldo Nov 8, 2026
8c2b11f
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
146101a
Log what started each held picture on the iPad
whoisaldo Nov 8, 2026
16a6bff
Check every capture notice comes before the restarting one
whoisaldo Nov 8, 2026
30b2d57
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
f9a5fe7
Pass the GPU refusal to the summary written before the PC goes down
whoisaldo Nov 8, 2026
5cee557
Start a mirror from the screen's picture when duplication gives none
whoisaldo Nov 8, 2026
361b1ed
End the idle capture nap when a viewer connects
whoisaldo Nov 8, 2026
707b30b
Merge pull request #228 from sidebandstudio/fix/amf-resubmit-interval
whoisaldo Nov 8, 2026
e50d7ea
Merge pull request #242 from sidebandstudio/fix/stopped-network-test-…
whoisaldo Nov 8, 2026
2973934
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
e493446
Merge pull request #233 from sidebandstudio/fix/ss-no-monitor-after-e…
whoisaldo Nov 8, 2026
7c572dd
Merge pull request #244 from sidebandstudio/fix/ss-back-after-late-lock
whoisaldo Nov 8, 2026
b83bfb8
Judge the firewall fix as the Stream page does, and remove only the r…
whoisaldo Nov 8, 2026
5d6a6be
Merge pull request #240 from sidebandstudio/fix/restart-notice
whoisaldo Nov 8, 2026
f53bbc1
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
09fa47e
Merge pull request #241 from sidebandstudio/fix/lib-test-flakes
whoisaldo Nov 8, 2026
905ffd5
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into pe…
whoisaldo Nov 8, 2026
dd0fdd9
Mark the GDI start picture cached, and read it only when it can be right
whoisaldo Nov 8, 2026
5239f87
Merge release/0.3.5-candidate into fix/win10-second-screen
whoisaldo Nov 8, 2026
89a5b62
Merge pull request #248 from sidebandstudio/fix/ipad-hold-reason-log
whoisaldo Nov 8, 2026
02d8024
Merge pull request #238 from sidebandstudio/fix/goodbye-on-power
whoisaldo Nov 8, 2026
92db5fe
Answer a loss after a recovery at once
whoisaldo Nov 8, 2026
ae7d639
Read firewall rule paths with the machine's own values only
whoisaldo Nov 8, 2026
85f21a8
Merge pull request #237 from sidebandstudio/fix/connect-when-pc-returns
whoisaldo Nov 8, 2026
32f17bb
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
5ca3f4a
Expand machine values that name others, and never call an unreadable …
whoisaldo Nov 8, 2026
5b58abf
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
8165326
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
0a08a43
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 8, 2026
9972aec
Read a missing display device through the confirmed device query
whoisaldo Nov 8, 2026
badb3a7
Merge pull request #249 from sidebandstudio/perf/cold-first-picture
whoisaldo Nov 8, 2026
5b4f651
Bound how much work expanding machine values can take
whoisaldo Nov 8, 2026
4e45330
Merge pull request #245 from sidebandstudio/fix/amf-test-isolation
whoisaldo Nov 8, 2026
73ead8f
Merge pull request #246 from sidebandstudio/fix/win10-second-screen
whoisaldo Nov 8, 2026
f271721
Wake a laptop's discrete card when an iPad looks for PCs
whoisaldo Nov 8, 2026
b3dd4cd
Merge pull request #253 from sidebandstudio/fix/loss-recovery
whoisaldo Nov 8, 2026
53e6a55
Merge pull request #251 from sidebandstudio/fix/setup-no-driver-on-win10
whoisaldo Nov 8, 2026
2ea4a2c
Keep the browse watch running, and wake only when the card will be used
whoisaldo Nov 8, 2026
25b5fbc
Wake the card of the encoder that streams, as the pipeline last opene…
whoisaldo Nov 8, 2026
d794343
Merge pull request #247 from sidebandstudio/fix/firewall-one-click
whoisaldo Nov 8, 2026
a968a80
Change NVENC's bitrate on the open session, and step up less often wh…
whoisaldo Nov 8, 2026
51584b5
Merge pull request #256 from sidebandstudio/perf/amd-idle-wake
whoisaldo Nov 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions .github/workflows/beta-installer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,30 @@ jobs:
- name: Download the bundled virtual display driver
shell: pwsh
run: |
# GitHub's download servers sometimes answer 5xx for a minute or two.
# Up to 5 tries over 2 minutes; another 4xx fails at once. The next
# step checks the driver's pinned SHA-256 either way.
function Get-WithRetry($uri, $out) {
$waits = 10, 20, 30, 60
for ($try = 1; ; $try++) {
try {
Invoke-WebRequest -Uri $uri -OutFile $out
return
} catch {
$status = [int]$_.Exception.Response.StatusCode
$transient = $status -eq 0 -or $status -eq 429 -or $status -ge 500
if (-not $transient -or $try -gt $waits.Count) { throw }
Write-Warning "Download of $uri failed (try $try): $($_.Exception.Message). Retrying in $($waits[$try - 1]) s."
Start-Sleep -Seconds $waits[$try - 1]
}
}
}
$dest = "installer\vendor\vdd"
$url = "https://github.com/VirtualDrivers/Virtual-Display-Driver/releases/download/$env:VDD_RELEASE_TAG/$env:VDD_ASSET"
Invoke-WebRequest -Uri $url -OutFile (Join-Path $dest $env:VDD_ASSET)
Get-WithRetry $url (Join-Path $dest $env:VDD_ASSET)
# Its MIT license text, redistributed alongside the binary.
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/VirtualDrivers/Virtual-Display-Driver/$env:VDD_RELEASE_TAG/LICENSE" `
-OutFile (Join-Path $dest "LICENSE-VirtualDisplayDriver.txt")
Get-WithRetry "https://raw.githubusercontent.com/VirtualDrivers/Virtual-Display-Driver/$env:VDD_RELEASE_TAG/LICENSE" `
(Join-Path $dest "LICENSE-VirtualDisplayDriver.txt")

- name: Verify the driver against the pinned SHA-256
shell: pwsh
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ jobs:
- name: Verify Setup hands its language to the app
shell: powershell
run: ./installer/tests/Test-InstallerLanguages.ps1
- name: Verify Setup leaves the virtual display driver off Windows 10
shell: powershell
run: ./installer/tests/Test-InstallerWindows10.ps1

rust-macos:
name: Rust (macOS, full workspace + E2E)
Expand Down
19 changes: 17 additions & 2 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ name: Beta builds
# https://github.com/sidebandstudio/EternalMonitor/releases/download/beta/EternalMonitor-Setup-beta.exe
# never changes (docs/download.html?channel=beta links it). No tag here starts
# with v, so release.yml and testflight.yml never run for a beta build, and
# docs/latest.json, /releases/latest and the apps' update checks never see
# one. scripts/nightly.py has the version, branch and retention rules.
# docs/latest.json, /releases/latest and stable installs never see one. A
# Beta install reads the beta release's body for the newest Beta
# (host/src/updates.rs). scripts/nightly.py has the version, branch and
# retention rules.
#
# Only a run on main publishes. A manual run with dry_run, on any other
# branch or for a pull request that changes this pipeline, builds and scans
Expand Down Expand Up @@ -163,6 +165,19 @@ jobs:
python3 scripts/nightly.py notes --version "$VERSION" --branch "$BRANCH" \
--sha "$SHA" --stable "$STABLE" --sha256 "$SHA256" > notes.md

# What scripts/sign_beta_manifest.py --sha256/--version must be given:
# the hash the build computed, which the step above checked.
- name: Summarize the build to sign
run: |
{
echo "### Beta build to sign"
echo
echo "| | |"
echo "|---|---|"
echo "| Version | $VERSION |"
echo "| Installer SHA-256 | \`$SHA256\` |"
} >> "$GITHUB_STEP_SUMMARY"

# The dated release first, checked anonymously; then the fixed beta link,
# swapped by renames and checked byte for byte before the old asset goes;
# the beta tag; and last the marker plan reads to skip a finished commit,
Expand Down
24 changes: 21 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,30 @@ jobs:
- name: Download the bundled virtual display driver
shell: pwsh
run: |
# GitHub's download servers sometimes answer 5xx for a minute or two.
# Up to 5 tries over 2 minutes; another 4xx fails at once. The next
# step checks the driver's pinned SHA-256 either way.
function Get-WithRetry($uri, $out) {
$waits = 10, 20, 30, 60
for ($try = 1; ; $try++) {
try {
Invoke-WebRequest -Uri $uri -OutFile $out
return
} catch {
$status = [int]$_.Exception.Response.StatusCode
$transient = $status -eq 0 -or $status -eq 429 -or $status -ge 500
if (-not $transient -or $try -gt $waits.Count) { throw }
Write-Warning "Download of $uri failed (try $try): $($_.Exception.Message). Retrying in $($waits[$try - 1]) s."
Start-Sleep -Seconds $waits[$try - 1]
}
}
}
$dest = "installer\vendor\vdd"
$url = "https://github.com/VirtualDrivers/Virtual-Display-Driver/releases/download/$env:VDD_RELEASE_TAG/$env:VDD_ASSET"
Invoke-WebRequest -Uri $url -OutFile (Join-Path $dest $env:VDD_ASSET)
Get-WithRetry $url (Join-Path $dest $env:VDD_ASSET)
# Its MIT license text, redistributed alongside the binary.
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/VirtualDrivers/Virtual-Display-Driver/$env:VDD_RELEASE_TAG/LICENSE" `
-OutFile (Join-Path $dest "LICENSE-VirtualDisplayDriver.txt")
Get-WithRetry "https://raw.githubusercontent.com/VirtualDrivers/Virtual-Display-Driver/$env:VDD_RELEASE_TAG/LICENSE" `
(Join-Path $dest "LICENSE-VirtualDisplayDriver.txt")

- name: Verify the driver against the pinned SHA-256
shell: pwsh
Expand Down
11 changes: 10 additions & 1 deletion ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ Rust and Swift share golden vectors and stable packet-type registry tests.
| KEYFRAME_REQUEST | Recovery after repair expiry or decoder error |
| PING / PONG | Min-RTT clock estimate for end-to-end latency |
| INPUT_EVENT | Normalized mouse/touch events, HID keys and UTF-16 text |
| POINTER_SHAPE / POINTER_STATE | The Mirror's pointer image (chunked premultiplied BGRA and an invert mask) and its position, at most once a frame budget, for an iPad that draws the pointer itself (feature bit 5, host capability bit 6); the video then leaves the pointer out. The Second screen does the same when the running virtual display driver started with a hardware cursor (as the host's settings file sets it), which the host knows from its record of that start (boot and device arrival); a pointer image larger than that cursor's caps stays in the video. When the host can't tell, it does as 0.3.4: no pointer messages, and the pointer in the video. |
| Audio | Sequenced Opus packets with discontinuity and capture timing |
| BYE | User, background or shutdown teardown; the host ending a silent session |

Expand Down Expand Up @@ -196,7 +197,15 @@ connected client, writes the requested mode first in VDD XML, and reports actual
task failures. Setup and the host log the active display paths around every
driver change; when a change leaves the PC without any real screen it had, they
re-apply the saved layout once, else switch to "PC screen only" if the built-in
panel was on (`display_guard.rs`, `display-guard.ps1`). It also ships a UDP
panel was on (`display_guard.rs`, `display-guard.ps1`). At runtime the host also
acts while the virtual display is still on: a turn on that leaves it alone
switches Windows to "Extend" (else the saved layout or "PC screen only"), and a
turn off never runs while it is the only screen, until Windows ends the session.
On a hybrid laptop whose panel the virtual display takes away until a restart
(Windows withdraws its target while the lid is open), it tries nothing and
keeps the display on while the host runs; the turn offs at start-up, quit and
in the failure reporter run, so the restart starts without it. Second screen
mirrors there until the user chooses it again. It also ships a UDP
firewall rule. Runtime upgrade, task-ACL and
uninstall checks remain hardware gates.

Expand Down
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
# docs/ contains the static website (GitHub Pages). Never write build output here.
[workspace]
members = ["host", "proto", "updater"]
exclude = ["vendor"]
resolver = "2"

[profile.release]
strip = "symbols"
opt-level = 3

# Patched copies of upstream crates; vendor/README.md says why.
[patch.crates-io]
egui-wgpu = { path = "vendor/egui-wgpu" }
11 changes: 10 additions & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,16 @@ Knowing these limits helps you judge whether a finding is new.
- The installer is not code-signed yet. Check its SHA-256 against the release page.
- In-app updates (Windows) trust the network for nothing: the host fetches over
HTTPS from an allowlist of GitHub hosts, and the installer must match the
SHA-256 in both eternalmonitor.dev/latest.json and the GitHub release. Against
SHA-256 in both eternalmonitor.dev/latest.json and the GitHub release. A Beta
build may also update to the newer Beta from the fixed `beta` GitHub release.
Beta updates are signed: the release must carry a manifest with a valid
Ed25519 signature by a public key pinned in the app, made with a key the
release workflows don't have, and the manifest's version, SHA-256 and size
must match the release body, GitHub's digest of the installer and the
downloaded file. Without a valid signature no Beta is offered, and a signed
Beta older than one the install has already verified is refused, so an old
signed release can't be replayed to hold testers back. Stable builds never
take a Beta. Against
other software already running as your Windows user, the updater adds defense
in depth rather than a guarantee. Its helper loads DLLs only from System32 and
imports only Windows system libraries. It inherits only its output pipe from
Expand Down
8 changes: 6 additions & 2 deletions SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,12 +255,13 @@ try fewer words. If your problem isn't here, see [Known issues](https://eternalm
| **EternalMonitor can't look for PCs** | The iPad isn't allowed to search your local network. | Tap **Open Settings** and turn on **Local Network**, or go to **Settings > Privacy & Security > Local Network** and turn on **EternalMonitor**. Then tap **Search again**. A USB cable works without this setting. |
| **Couldn't search for PCs** | The iPad's search for PCs failed for a reason other than Local Network access. | Tap **Search again**, or scan the QR code or type the **Address** shown in the PC window. If it keeps failing, turn on **Local Network** for EternalMonitor in the iPad's Settings. |
| **Couldn't get its address. Type the Address shown on the PC.** under a found PC | The iPad saw the PC's name but not its address. | Type the **Address** shown in the PC window, then tap **Connect to PC**. |
| **Your PC didn't answer** | Nothing came back from the PC. It may be closed, asleep, on another network, or blocked by a firewall. | Check that EternalMonitor is open on the PC and says **Ready for your iPad**, that the PC is awake, and that both are on the same Wi-Fi, not a guest network. If all of that is right, Windows Firewall or security software is probably blocking EternalMonitor: run EternalMonitor-Setup.exe again, or use a USB cable. Then tap **Try again**. |
| **Your PC didn't answer** | Nothing came back from the PC. It may be closed, asleep, on another network, or blocked by a firewall. | Check that EternalMonitor is open on the PC and says **Ready for your iPad**, that the PC is awake, and that both are on the same Wi-Fi, not a guest network. If all of that is right, Windows Firewall or security software is probably blocking EternalMonitor: run EternalMonitor-Setup.exe again, or use a USB cable. Then tap **Try again**. If you open EternalMonitor on the PC within a few minutes of the message appearing, the iPad connects by itself. |
| **Your PC didn't answer over the cable** | The cable is connected, but EternalMonitor on the PC didn't reply through it. | Check that EternalMonitor and Apple Devices are both open on the PC, then unplug the cable and plug it in again. |
| **Your PC answered, but no picture arrived** | The connection worked, but the PC's second screen didn't start, or the PC couldn't send its screen. | On the PC, choose **Mirror my screen** (**Main display (mirror)** in version 0.3.1), then tap **Try again** on the iPad. If the PC already mirrors, click **Restart** there first. After two attempts in a row end this way, the iPad stops reconnecting by itself until you tap **Try again**. |
| **That looks like the pairing code, not the PC's address** | A six-digit number was typed where the address goes. | Type the **Address** from the PC window, for example 192.168.1.20. The iPad asks for the code after it connects. |
| **That looks like your router's address, not your PC's** | Nothing answered at an address ending in .1, which is usually the Wi-Fi router. | Type the **Address** shown in the PC window. |
| **That address doesn't look right** | The iPad couldn't find anything by that name. | Type the **Address** exactly as the PC window shows it. |
| **Wi-Fi is off** | iPadOS has no network for the connection: Wi-Fi is off on the iPad, or it hasn't joined a network. | Turn on Wi-Fi and join the same network as the PC, or use a USB cable. |
| **This iPad isn't connected to a network** | Wi-Fi is off on the iPad, or it hasn't joined a network. | Turn on Wi-Fi and join the same network as the PC, or use a USB cable. |
| **Local Network is turned off for EternalMonitor** | Local Network access is off for EternalMonitor on the iPad, so it can't reach the PC over Wi-Fi. | Tap **Open Settings** and turn on **Local Network**, or go to **Settings > Privacy & Security > Local Network** and turn on **EternalMonitor**. Then tap **Try again**. A USB cable works without this setting. |
| **Couldn't connect to your PC** | The connection failed for another reason. | Check that both are on the same Wi-Fi and that EternalMonitor is open on the PC, then tap **Try again**. |
Expand All @@ -274,7 +275,10 @@ try fewer words. If your problem isn't here, see [Known issues](https://eternalm
| **The connection over the cable stopped** | The USB connection broke after it had started. | Keep EternalMonitor and Apple Devices open on the PC, unlock the iPad, then unplug the cable and plug it in again. |
| **The USB cable was disconnected** | The cable came out, or the PC lost it. | Plug the cable back in. The iPad reconnects by itself. |
| **USB connections were turned off** | **Allow USB connections** is off in the iPad app's settings. | Turn on **Allow USB connections** to use the cable again. |
| **Your PC ended the session** | Someone clicked **Stop** on the PC, changed a setting that restarts the stream, or closed EternalMonitor. Or the connection dropped, for example in a Wi-Fi stall, or the PC ran into a problem. | Tap **Try again** when the PC says **Ready for your iPad**. |
| **Your PC ended the session** | Someone clicked **Stop** on the PC, changed a setting that restarts the stream, or closed EternalMonitor. | Tap **Try again** when the PC says **Ready for your iPad**. |
| **The connection to your PC ended** | The connection dropped, for example in a Wi-Fi stall, the PC ran into a problem, or EternalMonitor restarted itself on the PC. | Tap **Try again**. With **Reconnect automatically** on, the iPad tries again by itself first. |
| **Your PC went to sleep** | Windows put the PC to sleep while it streamed. | Wake the PC, then tap **Try again**. |
| **Your PC is shutting down or signing out** | Windows shut down, restarted or signed out while the PC streamed. | Tap **Try again** once the PC is on, someone has signed in, and EternalMonitor is open. |
| **Your PC is already streaming to another device** | Only one iPad can connect at a time. | Disconnect the other iPad first, then tap **Try again**. |
| **Your PC is updating EternalMonitor** | The PC is installing a new version. | Wait. With **Reconnect automatically** on, the iPad connects again by itself. Otherwise tap **Try again** once EternalMonitor has opened on the PC. |
| **Your PC hasn't come back from its update yet** | The update is taking longer than expected. | Check that EternalMonitor opened again on the PC. Windows may be waiting for you to click **Yes** there. Then tap **Try again**. |
Expand Down
24 changes: 24 additions & 0 deletions docs/beta-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,30 @@ back to Stable by running the Stable installer over it.
`docs/latest.json`, else that release's next patch. It sorts below `0.3.4`,
so Beta users get the next Stable release from the normal update prompt, and
Stable users are never offered a Beta build.
- **Updates on Beta:** a Beta build also reads the `beta` release below and
offers the newer of that Beta and the next Stable release, with the same
banner, popup and helper as a Stable update. Beta updates are signed and
verified against a public key pinned in the app: the release must carry
`beta-manifest.txt` and its Ed25519 signature `beta-manifest.sig`, and the
manifest's version, SHA-256 and size must match the release body
`nightly.py` writes, GitHub's digest of the installer and the downloaded
file. The nightly does not sign; until a build is signed, Beta installs are
offered no Beta. After a nightly publishes, open its run (Actions, Beta
builds) and copy **Installer SHA-256** and **Version** from the Publish
job's summary, "Beta build to sign": the hash the Windows installer job
computed for the build it scanned, which Publish checks against the file
it uploads. Then run
`scripts/sign_beta_manifest.py --sha256 <hash> --version <version>` with
the signing key on stdin. It refuses a release that names another
installer or version, checks the release's parts agree, signs, checks the
signature with the pinned key, uploads both files and verifies them;
`--verify-only` checks what is published. A signed Beta older than one an
install has already seen is refused, so taking a bad Beta back means
signing a newer build, not re-signing an older one.
A new Beta is announced at most once a day, never during a stream. Settings, General, **Get Beta updates** (shown only on a
Beta build) turns this off. Taking a Stable release leaves the Beta channel.
Betas built before this arrived can't update themselves, so their testers
install one newer Beta by hand.
- **On GitHub:** each build is a pre-release tagged `beta-<YYYYMMDD>-<sha>`,
titled like "EternalMonitor 0.3.4 beta (Oct 30, 2026)". The newest 7 are
kept. The pre-release `beta` always holds the newest, so this link never
Expand Down
Loading
Loading