macOS host — compile fix (Tier A), then a desktop host on ScreenCaptureKit + VideoToolbox (Tier B) #299
Open
opened 2026-08-18 13:26:52 +00:00 by enricobuehler
·
0 comments
No Branch/Tag Specified
main
worktree-amd-program-wave2
worktree-actions-pin
worktree-security-review-fixes
worktree-abr-dscp-default
worktree-abr-control-loop
worktree-abr-transmission-plane
worktree-pyrowave-forces-auto
worktree-web-console-native-identity
worktree-abr-encode-downdriver
worktree-gamescope-exclusive-panel-off
worktree-bitrate-picker
worktree-fix-mic-tap-format-abort
worktree-release-0313-recut
ci-skia-download-retry
worktree-audio-devnode-orphans
worktree-gamescope-rebuild-keeps-hdr
worktree-gamescope-idled-handback
worktree-hevc-idr-storm-coalesce
worktree-gamestream-pad-heartbeat
worktree-steam-prelaunch-latch
worktree-release-0312-prep
worktree-firewall-program-scoped-rules
worktree-blackscreen-data-plane-source-ip
worktree-fix-frozen-local-ip
worktree-android-pad-mapping-regression
worktree-android-console-extra-keys
worktree-data-plane-firewall-and-delivery-truth
worktree-android-gamepad-ui-and-corner
worktree-android-pad-hid-remap
worktree-gamestream-xbox-hid-parity
worktree-release-next-prep
worktree-win-client-installer
worktree-kwin-vout-enable-repair
worktree-wp4-install-script
docs-wp2-to-main
worktree-docs-wp0-wp1-anti-drift
worktree-kwin-vout-failed-permanent
worktree-android-asc-hdr-dataspace
worktree-console-controllers-page
worktree-gamepad-probe-stack
worktree-agents-md-setup
worktree-android-skia-console
worktree-android-asc-presenter
worktree-win-teardown-abort
worktree-audio-hires-default-on
worktree-console-ui-aa
worktree-pr270-review-fixes
worktree-console-ui-overhaul
worktree-hires-audio-pcm
worktree-audio-stutter-fixes
worktree-ds-pad-sink-pro-audio
worktree-console-diagnostics
worktree-ds-inhibit-storm
worktree-security-review-2026-08-15-fixes
worktree-pairing-friendly-device-name
worktree-shield-select-back-quit
worktree-android-canary-open-testing
fix-host-cer-alias-null-key
worktree-azure-trusted-signing
worktree-audio-soft-limit-gain
worktree-gamescope-exclusive-dpms
fix/playnite-launcher-resolve
worktree-macos-mic-rebuild-loop
worktree-hyprland-cursor-mode-negotiation
worktree-hd2-idle-recording-default
worktree-steam-art-root-windows
worktree-android-aaudio-shield-silence
worktree-unpair-all-button
worktree-appletv-present-depth
worktree-av1-level-sentinel
worktree-nix-plugin-runner-resolve
worktree-release-0280
worktree-console-plugin-update-all
worktree-flatpak-skia-099-pin
worktree-debian-ubuntu-support
worktree-wowlan-support
worktree-decky-shortcut-dup
worktree-vk-level-gate-clamp
worktree-edition-2024
worktree-win-sleep-blockers
worktree-rt-gpu-priority-defaults
worktree-black-stream-fixes
worktree-edid-lock-toggle
worktree-gate-double-arm-fix
chore/rust-safety-programme
worktree-console-pinned-profile-library
worktree-blackscreen-fixes
build/web-silence-rollup-directive-warnings
worktree-android-console-visual-refresh
worktree-nixos-capped-compositor-exe-denied
worktree-release-0270
worktree-dm-helper-diagnosis
worktree-gamescope-pin-bump-nobara
worktree-notes-capsysnice-correction
worktree-bazzite-docs-warning
worktree-kwin-capability-identification
worktree-gamescope-rpm-deb-builddeps
worktree-pyrowave-wire-dead-code
worktree-release-0260
worktree-cursor-composite-hardening
worktree-library-settings-origin-split
worktree-native-decode-m0
worktree-july-rpm-and-cursor
worktree-presenter-cadence-wp1
worktree-decky-brand-name
worktree-win-amd-decoder-order
worktree-stall-ride-through
fix/pad-audio-wasapi-module-path
feat/android-pad-audio
worktree-adl-emul-probe
worktree-haptics-m12-dry
worktree-haptics-m9-richfb
worktree-haptics-m11-settings
worktree-apple-store-screenshots
worktree-decky-slim-rework
worktree-appstore-copy
worktree-haptics-m10-wire
worktree-haptics-m8-proto
worktree-haptics-m7-windows
worktree-haptics-m6-presenter
worktree-wire-mtu-resilience
worktree-haptics-m5-android
worktree-haptics-m4-apple
worktree-haptics-m3-rumble-engine
worktree-android-presenter-023-triage
worktree-vdisplay-resume-recovery
worktree-kwin-vout-demirror
fix/web-console-sweep
fix/windows-web-console-lifecycle
chore/windows-rerender-semantics
fix/pf-encode-phase8
fix/pf-encode-phase7
feat/cursor-channel
feat/desktop-mouse-mode
feat/plugin-kit
fix/network-split-standing-latency
fix/windows-msix-arm64-and-manifest
fix/encode-medium-tier
fix/encode-rfi-taint-and-oob
fix/encode-init-leak-and-twin-drift
fix/encode-teardown-uaf
feat/pyrowave-windows
fix/ubuntu-2404-host-deb
fix/ios-archive-provisioning
merge/first-frame-latency
feat/shared-clipboard-v2
feat/apple-live-activities-widgets
debug/touch-finger-logging
feat/shared-clipboard
midstream-resize
v0.31.4
sdk-v0.1.6
v0.31.3
v0.31.2
v0.31.1
plugin-kit-v0.4.4
v0.31.0
sdk-v0.1.5
plugin-kit-v0.4.3
v0.30.0
plugin-kit-v0.4.2
v0.29.0
v0.28.1
v0.28.0
plugin-kit-v0.4.1
v0.27.0
v0.26.0
plugin-kit-v0.4.0
sdk-v0.1.4
plugin-kit-v0.3.3
sdk-v0.1.3
plugin-kit-v0.3.2
v0.25.0
plugin-kit-v0.3.1
plugin-kit-v0.3.0
v0.24.0
v0.23.0
v0.22.3
v0.22.2
v0.22.1
v0.22.0
v0.21.0
v0.20.1
v0.20.0
plugin-kit-v0.2.0
v0.19.2
v0.19.1
v0.19.0
v0.18.0
v0.17.2
v0.17.1
v0.17.0
v0.16.0
v0.15.0
v0.14.0
v0.13.0
v0.12.0
v0.11.0
v0.10.1
v0.10.0
v0.9.2
v0.9.1
v0.9.0
v0.8.4
v0.8.3
v0.8.2
v0.8.1
v0.8.0
v0.7.4
v0.7.3
v0.7.2
v0.7.1
v0.7.0
v0.6.0
v0.5.1
v0.5.0
v0.4.2
v0.4.1
v0.4.0
v0.3.1
v0.3.0
v0.2.1
v0.2.0
v0.1.1
v0.1.0
Labels
No items
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: unom/punktfunk#299
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Make
punktfunk-hostbuild on macOS, then ship a macOS desktop host.Design:
design/macos-host-feasibility.mdin punktfunk-planning (39130c5, onmain) — investigation only, no code anywhere.The finding that reframes this: the macOS port is four backends and a packaging story, not a host rewrite. The W6 crate extraction already left a real third-platform seam —
cfg(not(any(linux, windows)))arms exist across thepf-*crates andpf-injecteven ships aBackend::Unsupportedplaceholder. Everything portable — orchestrator, session plan, GameStream plane,punktfunk/1native plane, pairing, mDNS, mgmt API + OpenAPI, web console, plugin runner, game library, update-check — already compiles on macOS today.For scale: the existing per-platform backend volume is ~41k LOC Linux / ~34k LOC Windows. Tier B is estimated ~3–5k.
Tier A — make it compile (<1 day, unblocked, do this regardless)
Worth doing on its own merits even if Tiers B/C never happen, because it retires the openapi tax:
cargo run -p punktfunk-host -- openapican only run on Linux/Windows today, soapi/openapi.jsonhas to be hand-patched or regenerated on a Linux box, andmgmt::tests::openapi_document_is_complete_and_checked_inis the only signal that a mgmt-API change left the spec stale. It also makes the Mac a first-class dev box for all the portable host code above. Must not be gated on the Tier B/C decision.Re-measured on
4ce7a3c1(2026-08-18, arm64):cargo check -p punktfunk-host= 10 errors in 6 files;pf-capture,pf-encode,pf-inject,pf-clipboard,pf-vdisplayall check clean, unmodified.audio/mic_pump.rs:172— unresolvedopus(two sites on the line). Gate the call sites to match the manifest gating.hooks.rs:457— unresolvedlibc. Same.session_plan.rs:306-307—crate::zerocopy,encode::linux_zero_copy_is_vaapi,encode::cursor_blend_capable. Give the three helpers non-Linux siblings.gamestream/stream.rs:808+native/compositor.rs:106—vdisplay::cancel_pending_tv_restore;native/compositor.rs:63—vdisplay::try_recover_session. Add no-op non-Linux siblings next to the Linux ones.gamelease.rs:1062—procscan::Scanner. New since the design doc was written (the doc measured 9 errors in 5 files on2d3f9f86, 2026-08-01).cargo check -p punktfunk-hostCI leg. The hole count grew by one in 17 days with nobody trying — without a guard this rots straight back.Tier B — the desktop host (~3–5k LOC, public APIs only)
No entitlement requests, no private symbols. Ordered; each step independently useful.
pf-capturemacOS backend — asrc/macos/sibling tolinux//windows/implementingCapturer(pf-capture/src/lib.rs:21). ScreenCaptureKit is the best capture platform of the three:SCStreamhands back IOSurface-backedCVPixelBuffers that go straight into VideoToolbox, so the project's zero-copy invariant is the default path rather than something to fight for — no EGL/dmabuf/CUDA import worker, no IDD driver, no compositor matrix.supports_arrival_wait()(:65) =true—SCStream's delegate callback is the frame-arrival wakeup the latency work wants, so the frame-driven encode trigger comes free. macOS arms forcapturer_supports_hdr(:421-430) andcapturer_supports_444(:400/498/511).pf-encodemacOS backend —Encoder(enc/codec.rs:319) overVTCompressionSession+EnableLowLatencyRateControl, wired intoopen_video(pf-encode/src/lib.rs:163).submit/pollmap naturally onto VT's async completion callback; the frame-index prediction contract in the trait docs holds unchanged. One vendor, so no backend matrix — ~1–2k vs 16.3k (Linux) / 11.5k (Windows).AudioCapturerfrom the sameSCStream(system audio arrives alongside video); macOS arm onopen_audio_capture(punktfunk-host/src/audio.rs:222/227/237). Mic uplink via AVAudioEngine, which ships a real platform AEC — directly relevant tomic-latency-and-echo.md.pf-injectmacOS backend —Backend::CgEventreplacing theUnsupportedplaceholder (pf-inject/src/lib.rs:76, dispatch at:241);InputInjectoroverCGEventPost(+ Accessibility grant). Absolute mapping is straightforward. Keyboard/mouse only — pads are Tier C.pf-clipboard—NSPasteboardbehindHostClipboard; flip theavailable = falsefallback (pf-clipboard/src/lib.rs:98-110). No delayed-rendering complication to match Win32's.packaging/macos/. The Dev ID / notarization machinery already exists for the Mac client, so this is reuse.Deliberately not in the list:
pf-vdisplay(Tier C),pf-zerocopy(nothing to do — SCK → VT is already zero-copy),pf-gpu(one vendor), the compositor matrix (no analogue).Known ceilings: VideoToolbox has no 4:4:4; HEVC is the workhorse. AV1 encode on Apple silicon is unverified — the only sourcing found was content-farm pages claiming M4 Ultra / M5 Pro / M5 Max have hardware AV1 encoders. Confirm against a real VideoToolbox capability query before it reaches any capability matrix or release note.
Tier C — the game host: NOT recommended, and must not gate A or B
The asymmetry: on Linux and Windows the virtual display and emulated pads are the headline features; on macOS they are exactly the two things the platform withholds — and the Mac game library is the weakest of the three, so Tier C's value is lowest precisely where its cost is highest. Two blockers of different kinds:
CGVirtualDisplay. It works and is widely shipped, and Apple can remove it in any point release. Whether that is acceptable under a headline feature is a product decision, not a technical one.CoreHID.HIDVirtualDevice+com.apple.developer.hid.virtual.device), so DriverKit/Karabiner is no longer needed — but the Game Controller framework deliberately ignores virtual HID devices to prevent input loopback, and macOS has no virtual-controller framework. EveryGCControllergame is blind to an emulated pad however correct the descriptor. The ~8.4k-LOCpf-injectpad stack has no macOS analogue.Do not re-propose a DriverKit system extension for pads —
HIDVirtualDevicesupersedes its plumbing and the GameController filter defeats both routes, so the heavier path buys nothing.One-day spike before any Tier C planning: can SDL / Steam Input see a
HIDVirtualDevicepad? They readIOHIDDevicedirectly, bypassing GameController. If yes, Tier C is partially recoverable for the Steam library specifically.Structural constraint worth knowing up front
No headless operation, and no service equivalent. Screen Recording and Accessibility are TCC grants that only exist in a logged-in GUI session ⇒ LaunchAgent only, no
LocalSystem-service analogue, no pre-login streaming, and "wake and stream" is unreachable (Wake-on-LAN is limited on a Mac host). TCC is per-signed-binary, so the updater must preserve the signing identity or every update revokes capture — that needs a real update-and-verify run before a macOS host could ship an updater at all.Remaining spikes
hdr-pipeline-plan.mdwould need a macOS column.HIDVirtualDevice(Tier C gate, above).