Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
226 commits
Select commit Hold shift + click to select a range
0b29273
Stream screens with an odd width or height
whoisaldo Nov 3, 2026
f88d43b
Run the odd-screen end-to-end test off Windows, like the other input …
whoisaldo Nov 3, 2026
477f3ad
Merge pull request #180 from sidebandstudio/fix/odd-capture-size
whoisaldo Nov 3, 2026
49753c0
Keep the laptop panel when the virtual display turns on alone
whoisaldo Nov 6, 2026
53a6684
Say when Windows Firewall keeps iPads out, and let Setup remove the b…
whoisaldo Nov 6, 2026
1035382
Warn about the firewall only when the block is certain
whoisaldo Nov 6, 2026
03b5271
Judge all-programs firewall rules, and never trust a field it couldn'…
whoisaldo Nov 6, 2026
7ec08e4
Show the firewall warning only for what Setup or one switch fixes
whoisaldo Nov 6, 2026
6daa9d5
Merge pull request #184 from sidebandstudio/fix/no-reply-diagnosis
whoisaldo Nov 6, 2026
443a143
Split the BGRA to YUV conversion across threads
whoisaldo Nov 7, 2026
9b5a2ca
Hold the virtual display on when it takes a hybrid laptop's panel away
whoisaldo Nov 7, 2026
36b36c4
Find a saved PC again when its address changes
whoisaldo Nov 7, 2026
d852931
Add a test hook that loses the window's graphics device
whoisaldo Nov 7, 2026
287860f
Tell the iPad when the stream stops for good, and log a stuck transpo…
whoisaldo Nov 7, 2026
75c0dff
Vendor egui-wgpu 0.36.2 unchanged
whoisaldo Nov 7, 2026
08ffddc
Recover a first frame that never completes, and say when Wi-Fi is off…
whoisaldo Nov 7, 2026
b12abfa
Log pairing-off at info and collapse unchanged mDNS re-advertisements
whoisaldo Nov 7, 2026
e2cd001
Draw the PC's pointer on the iPad, sent apart from the video
whoisaldo Nov 7, 2026
bd84c45
Name the Wi-Fi off card as the app does in SETUP.md
whoisaldo Nov 7, 2026
1319b2e
Keep the window and the stream running when the window's graphics dev…
whoisaldo Nov 7, 2026
fcbc720
Tell the iPad when the PC is locked
whoisaldo Nov 7, 2026
e0a4f73
Deliver the storm-brake goodbye, refuse HELLOs after a stop, and name…
whoisaldo Nov 7, 2026
190fbba
Repair a keyframe until it completes on lossy WiFi
whoisaldo Nov 7, 2026
c594d0e
Merge pull request #190 from sidebandstudio/fix/log-volume
whoisaldo Nov 7, 2026
99ba31a
Move a saved PC only after it shows it is the same PC
whoisaldo Nov 7, 2026
15d4b6f
Keep a stop's goodbye when it lands while the transport starts
whoisaldo Nov 7, 2026
c9a17ab
Say Wi-Fi is off only for an unsatisfied path, keep the Apple Devices…
whoisaldo Nov 7, 2026
dcc2073
Give a keyframe's requests one schedule apart from its hold
whoisaldo Nov 7, 2026
0a23752
Hand iPad input to Windows on its own thread, never on the transport …
whoisaldo Nov 7, 2026
01bb4d2
Clear the Apple Devices hint when it expires, even on an idle screen
whoisaldo Nov 7, 2026
62b6942
Run no Disable task at startup when Windows reports the display disabled
whoisaldo Nov 7, 2026
e7c0ee7
Try the second screen again once the desktop is back after it failed …
whoisaldo Nov 7, 2026
8ebc254
Check that a moved PC is the saved one at the address it was found
whoisaldo Nov 7, 2026
15432be
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 7, 2026
cfb6783
Let the moved-PC e2e stand the Mac's interface in for the iPad's Wi-Fi
whoisaldo Nov 7, 2026
f7705eb
Merge pull request #194 from sidebandstudio/fix/pairing-locked
whoisaldo Nov 7, 2026
fac2c21
Bring an AMF session's first keyframe out on a still desktop
whoisaldo Nov 7, 2026
eb6d5b6
Merge remote-tracking branch 'origin/fix/session-drops' into fix/inpu…
whoisaldo Nov 7, 2026
7f0df48
Replace a failing window device too, and let go of the lost one
whoisaldo Nov 7, 2026
85a88fa
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 7, 2026
87a1c0f
Merge pull request #195 from sidebandstudio/perf/loss-recovery
whoisaldo Nov 7, 2026
d39ce5b
Test that an answer signing other addresses, or none, isn't the saved PC
whoisaldo Nov 7, 2026
303254f
Keep the idle picture going while only the pointer moves
whoisaldo Nov 7, 2026
1438561
Sign the home network address first, answer nothing without one, and …
whoisaldo Nov 7, 2026
82861e9
Merge pull request #188 from sidebandstudio/fix/session-drops
whoisaldo Nov 7, 2026
c249c96
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 7, 2026
93e91b4
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 7, 2026
fd6c1bc
Send vdd_only and panel_lost as their own summary fallbacks
whoisaldo Nov 7, 2026
2284eac
Don't count a closed lid as a lost panel
whoisaldo Nov 7, 2026
981456f
Sign no home network address once its listing has expired
whoisaldo Nov 7, 2026
64be3d6
Turn a lost panel's display off at quit, start-up and in the reporter
whoisaldo Nov 7, 2026
c39e5c9
Ask for a restart only while the lost panel is still off
whoisaldo Nov 7, 2026
cafdf42
Let go of the kept picture when a newer capture arrives
whoisaldo Nov 7, 2026
4a67b21
Wait for the pointer's next frame budget on a high-resolution timer
whoisaldo Nov 7, 2026
0d411b2
Give a picture given again its own PTS under ETERNAL_LEGACY_PTS
whoisaldo Nov 7, 2026
68f0055
Wait for the encoder's warm-up in the still-desktop keyframe test
whoisaldo Nov 7, 2026
ae1b7a5
Allow the boot time setter's dead code off Windows
whoisaldo Nov 7, 2026
e707882
Take a panel for lost only once Windows says the lid is open
whoisaldo Nov 7, 2026
074e7ba
Pass the guard one driver change, not eight arguments
whoisaldo Nov 7, 2026
42ee21f
Say where input_soak's log must not go
whoisaldo Nov 7, 2026
82c0c73
Stream on libx264 when a hardware encoder open hangs, remember failed…
whoisaldo Nov 7, 2026
fa30fdd
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into pe…
whoisaldo Nov 7, 2026
913edfd
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 7, 2026
99b1102
Hand every stream's input to one thread, the old stream's releases first
whoisaldo Nov 7, 2026
7a04153
Let go of the capture rect before Windows refreshes a still Pencil
whoisaldo Nov 7, 2026
d6980b0
Never lose a release at the input queue's bound
whoisaldo Nov 7, 2026
11b5914
Measure the hop from the transport to the input thread
whoisaldo Nov 7, 2026
4e0d82a
Merge pull request #187 from sidebandstudio/fix/ipad-saved-pc-address
whoisaldo Nov 7, 2026
a31b93f
Merge origin/release/0.3.5-candidate into fix/ipad-picture-messages
whoisaldo Nov 7, 2026
a636f30
Back off replacing a lost window device, and give up after ten failures
whoisaldo Nov 7, 2026
d54c43e
Count a device lost before the window works as that backend's failure
whoisaldo Nov 7, 2026
c2715bf
Keep the device-loss test hook out of release builds
whoisaldo Nov 7, 2026
1a3a452
Make log-capturing host tests deterministic under parallel runs
whoisaldo Nov 7, 2026
9598d56
Merge remote-tracking branch 'origin/release/0.3.5-candidate' into fi…
whoisaldo Nov 7, 2026
903380f
Make the input restart and late-input tests wait on the queue, not th…
whoisaldo Nov 7, 2026
d57d646
Merge a backed-up move into the newest of its kind, not only the last…
whoisaldo Nov 7, 2026
5d661f0
Log a Windows input call that has been held for 5 s while it is still…
whoisaldo Nov 7, 2026
d85993e
Release held input at quit even when the last stream never queued its…
whoisaldo Nov 7, 2026
6305797
Format the startup Disable test
whoisaldo Nov 7, 2026
732e9fa
Read a UTF-16 virtual display settings file and write it back as UTF-8
whoisaldo Nov 7, 2026
e97697a
Keep a stuck graphics driver from holding the window at start
whoisaldo Nov 7, 2026
b4bbfb7
Merge pull request #189 from sidebandstudio/fix/ipad-picture-messages
whoisaldo Nov 7, 2026
f732b25
Offer Beta builds the newer Beta
whoisaldo Nov 7, 2026
d65edd5
Merge pull request #191 from sidebandstudio/fix/hybrid-vdd-only
whoisaldo Nov 7, 2026
5dd5b9c
Require a signed manifest before offering a Beta
whoisaldo Nov 7, 2026
db1f46a
Merge pull request #203 from sidebandstudio/fix/flaky-fallback-summar…
whoisaldo Nov 7, 2026
c6776bc
Pin Beta signing to the nightly run and refuse replayed Betas
whoisaldo Nov 7, 2026
88bd272
Check an expected Beta version on its own when verifying
whoisaldo Nov 7, 2026
d897b3f
Don't take a PC that slept for a wedged pipeline
whoisaldo Nov 7, 2026
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
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
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
a4781b3
Merge pull request #219 from sidebandstudio/fix/no-video-path-fallback
whoisaldo Nov 8, 2026
bbce161
Merge pull request #221 from sidebandstudio/fix/vdd-settings-codepage
whoisaldo Nov 8, 2026
21eb8a9
Merge pull request #206 from sidebandstudio/fix/gpu-detect-timebox-035
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
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
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
4 changes: 3 additions & 1 deletion SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ try fewer words. If your problem isn't here, see [Known issues](https://eternalm
| **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,8 @@ 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 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
30 changes: 30 additions & 0 deletions docs/decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,36 @@ such frames then completed from late or repaired fragments. The iPad now
requests a wide gap in several NACKs and asks for a keyframe only when a frame
is dropped. Evidence: `EternalMonitor-Handoff/evidence/rc-hardware-20260924/`.

### Repair a keyframe until it completes

On WiFi with 4-22% loss, iPads held a frozen picture for 1-4 s and then
reconnected. The PC answered every keyframe request at once, but each
replacement keyframe arrived incomplete. A keyframe at 1080p is 80-300
fragments, so at 10% loss one round of requests and repairs leaves some
missing. The iPad asked again once, and dropped the keyframe at its 25 ms
deadline because the small frames sent after it were already complete. Those
frames need the keyframe, so the decoder held the picture and asked for
another, which failed the same way.

A keyframe now keeps its place while the frames after it complete. At its
deadline it is held, like a frame with nothing behind it, until it completes,
a newer keyframe completes, a second has passed, or the 32 frames the
assembler holds are full. The hold only moves its deadline. The keyframe's
requests follow one schedule: after its first retry it asks again every RTT +
5 ms, sooner than which no repair can return, and only once something has
arrived since its last request. The repair simulation
(`proto/tests/wifi_repair_sim.rs`, 10% loss each way, 150-fragment keyframes
at 60 fps) completed 148 of 390 keyframes before, with 35 freezes over a
second and the longest 3.4 s. After, it completes 394 of 399, the longest
freeze is 0.61 s, and no freeze lasts a second. The 1% loss rows also lost
fewer frames.

Delta frames keep the 25 ms rule and their single retry. Holding them too,
for at most 100 ms, with every frame asking again, removed nearly every
remaining drop in the simulation, but raised the p50 latency at 10% loss from
6.6 to 10.7 ms. It would also undo the repair-window rules above, which were
tuned on a physical iPad, so it waits for a device run.

### Use Apple's usbmuxd tunnel for USB

Apple's installed device service handles the cable/trust relationship. EMLINK
Expand Down
5 changes: 4 additions & 1 deletion host/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ socket2 = "0.5"
[features]
# Lets a release build obey ETERNAL_SIMULATE_STARTUP_FAILURE, for native
# failure-path checks. Debug builds always do; shipped builds never do.
fault-injection = []
fault-injection = ["windows/Win32_Graphics_Direct3D12"]
# Lets a release build obey ETERNAL_USB_DIRECT, for the end-to-end scripts.
# Debug builds always do; shipped builds never do.
usb-direct = []
Expand Down Expand Up @@ -86,13 +86,15 @@ features = [
"Win32_System_Kernel",
"Win32_System_LibraryLoader",
"Win32_System_Com_StructuredStorage",
"Win32_System_Ole",
"Win32_System_Threading",
"Win32_System_LibraryLoader",
"Win32_System_Performance",
"Win32_System_Power",
"Win32_System_ProcessStatus",
"Win32_Storage_FileSystem",
"Win32_Devices_FunctionDiscovery",
"Win32_Devices_Properties",
"Win32_UI_Shell_PropertiesSystem",
"Win32_Graphics_DXCore",
"Win32_Graphics_Dxgi",
Expand All @@ -107,6 +109,7 @@ features = [
"Win32_System_IO",
"Win32_NetworkManagement_IpHelper",
"Win32_NetworkManagement_Ndis",
"Win32_NetworkManagement_WindowsFirewall",
"Win32_Networking_WinSock",
"Win32_UI_Input_KeyboardAndMouse",
"Win32_UI_Input_Pointer",
Expand Down
Loading
Loading