Skip to content

Add targeted restore-token reset control - #36

Open
minpeter wants to merge 15 commits into
omarroth:mainfrom
minpeter:feat/control-source-reset
Open

Add targeted restore-token reset control#36
minpeter wants to merge 15 commits into
omarroth:mainfrom
minpeter:feat/control-source-reset

Conversation

@minpeter

@minpeter minpeter commented Aug 28, 2026

Copy link
Copy Markdown

Summary

  • add reset-restore-token <target> to the daemon socket, Go client, and doubletake-ctl
  • reserve only a fully streaming receiver with an exclusive capture group, preserving its actual port
  • clear only that receiver's Wayland portal restore token; pairing credentials and unrelated devices remain intact
  • keep credential backend I/O outside the global daemon mutex while status and shutdown remain responsive
  • leave the original stream and capture generation untouched when credential persistence fails
  • reject missing, inactive, PIN-waiting, shared-group, concurrent-disconnect, and shutdown races with accurate aggregate state
  • reconnect only after atomically swapping to the validated replacement generation; blocking cleanup remains outside the mutex
  • isolate Wayland capture from encoding with a raw-frame process boundary so encoder references cannot retain portal DMA-BUFs
  • preserve automatic HEVC selection while applying a separate Wayland raw-relay scheduling lead

Motivation

Omarchy control surfaces need a first-class way to re-open the Wayland source picker. Editing the credential store from a helper script is racy and can discard pairing state, so the daemon should own this lifecycle transition.

Consumed by glennbarosen/omarchy-airplay#1, which uses this command to expose source switching from the Omarchy bar.

Extended physical-TV QA also showed that the original one-process Wayland pipeline retained portal-backed buffers across conversion and encoding. That exhausted Hyprland's screencopy pool and left late receivers without a decodable SPS/PPS+IDR startup unit.

Verification

  • current reviewed PR head: 70bc11b2985b1cc2e5a78c05e2254eb38487d22e
  • go test -race -shuffle=on -count=1 ./...
  • go vet ./...
  • go build ./cmd/doubletake ./cmd/doubletake-ctl
  • gofumpt review and git diff --check
  • gopls diagnostics on changed Go files
  • deterministic channel-gated tests for blocked credential I/O, failure atomicity, file-backend rollback, peer-join exclusion, shutdown ordering, and concurrent disconnect state
  • real doubletake-ctl subprocess test against a one-request Unix-socket fixture, including exact request fields and invalid-arity no-contact paths
  • media-first setup test proves the 250 ms Wayland relay floor does not downgrade automatic HEVC
  • hostile receiver dimensions are bounded before reaching the raw-frame parser
  • installed integration on the approved meeting-room Apple TV completed streamingreset-restore-token → Hyprland source picker → output selection → resumed streaming → targeted disconnect back to idle

Wayland capture QA

  • physical and local A/B isolated pipewiresrc always-copy=true as a black-frame regression on this Intel/PipeWire portal
  • the final VA path imports the original DMA-BUF once, forces a system-memory NV12 download before the compositor, drops stale raw frames before expensive conversion, then relays fixed-size raw frames to an isolated encoder process
  • final TV gate sent more than 2,200 frames with positive presentation slack, remained alive for 60 seconds, and produced no portal Out of buffers event during the gate
  • late sinks retain the existing next-read cutover and wait for the encoder's next self-contained live keyframe rather than replaying an incomplete reference chain
  • TV QA revision: 0f38ba6

Final TV stability fix

  • Root cause: the 67 ms timestamped fan-out queue reused the portal raw-frame budget for encoded system-memory frames. A normal receiver socket-write stall overflowed that queue, detached the only sink, and surfaced as capture EOF before cleanup killed both GStreamer children.
  • Fix: encoded fan-out now tolerates two seconds of nominal frame duration while retaining the independent 8 MiB payload cap and slow-peer detachment.
  • Failing-first evidence: the transient-stall regression failed at frame 2 before the fix and passes with 15 queued 30 fps frames after it.
  • Final installed-binary QA: meeting-room TV 192.168.0.134 remained streaming for 60 seconds with positive presentation slack and zero portal Out of buffers events.
  • TV stability revision: 0f38ba624364f1ea1ae1ef9a4bce438f8602c4df.

Let control clients clear one target's Wayland portal restore token and reconnect it without rewriting other credentials. Preserve receiver ports and reject shared capture groups so unrelated streams stay intact.

Co-authored-by: minpeter <minpeterx@gmail.com>

Generated with [OpenAI Codex](https://openai.com/codex/)
Reserve the active capture generation while credential I/O runs outside the daemon mutex, keep the original stream intact on persistence failure, reject peer joins during reset, and report disconnect or shutdown races accurately.

Co-authored-by: minpeter <minpeterx@gmail.com>

Generated with [OpenAI Codex](https://openai.com/codex/)
Exercise the public command through its real process boundary, verify the exact Unix-socket request, and reject invalid arity before daemon contact.

Co-authored-by: minpeter <minpeterx@gmail.com>

Generated with [OpenAI Codex](https://openai.com/codex/)
@minpeter
minpeter marked this pull request as ready for review August 28, 2026 10:53
@minpeter
minpeter marked this pull request as draft August 28, 2026 12:28
minpeter and others added 9 commits August 28, 2026 22:36
Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
@minpeter
minpeter marked this pull request as ready for review August 28, 2026 18:30
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.

1 participant