diff --git a/crates/punktfunk-host/src/capture/composed_flip.rs b/crates/punktfunk-host/src/capture/composed_flip.rs index 6e1a3f2..73d00a2 100644 --- a/crates/punktfunk-host/src/capture/composed_flip.rs +++ b/crates/punktfunk-host/src/capture/composed_flip.rs @@ -17,7 +17,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use windows::core::{w, PCWSTR}; +use windows::core::w; use windows::Win32::Foundation::{HWND, LPARAM, LRESULT, WPARAM}; use windows::Win32::System::LibraryLoader::GetModuleHandleW; use windows::Win32::System::StationsAndDesktops::{ diff --git a/crates/punktfunk-host/src/capture/dxgi.rs b/crates/punktfunk-host/src/capture/dxgi.rs index a982368..ec6b134 100644 --- a/crates/punktfunk-host/src/capture/dxgi.rs +++ b/crates/punktfunk-host/src/capture/dxgi.rs @@ -202,10 +202,15 @@ unsafe fn duplicate_output( .ok() .and_then(|s| s.parse().ok()) .unwrap_or(200); + // Default 1 (no retry → immediate legacy fallback). On the secure desktop DuplicateOutput1 + // ALWAYS refuses (only LOGON_UI may use it), so retrying there just blocks the capture thread; + // and on the normal desktop the release-before-reduplicate + gentle recovery already keep the + // legacy dup stable. Raise PUNKTFUNK_DUP_RETRY_N only on a box where DuplicateOutput1 can win + // the old-dup-teardown race (then PUNKTFUNK_DUP_RETRY_MS sets the per-wait, default 200). let attempts: u64 = std::env::var("PUNKTFUNK_DUP_RETRY_N") .ok() .and_then(|s| s.parse().ok()) - .unwrap_or(6) + .unwrap_or(1) .max(1); let mut last_err = None; for attempt in 0..attempts { @@ -225,10 +230,16 @@ unsafe fn duplicate_output( } } if let Some(e) = last_err { - tracing::warn!( - error = %format!("{e:?}"), - "DuplicateOutput1 failed after retries — falling back to legacy DuplicateOutput (will churn)" - ); + // Expected on the secure (Winlogon) desktop (DuplicateOutput1 is LOGON_UI-only) and fires + // once per gentle recovery there — throttle so a lock dwell doesn't flood the log. The + // legacy fallback below handles it; gentle recovery keeps it from churning. + static FALLBACKS: AtomicU64 = AtomicU64::new(0); + if FALLBACKS.fetch_add(1, Ordering::Relaxed) % 64 == 0 { + tracing::warn!( + error = %format!("{e:?}"), + "DuplicateOutput1 unavailable — using legacy DuplicateOutput (expected on the secure desktop)" + ); + } } } output.DuplicateOutput(device).context("DuplicateOutput") diff --git a/crates/punktfunk-host/src/capture/wgc.rs b/crates/punktfunk-host/src/capture/wgc.rs index e84eb01..6d4c888 100644 --- a/crates/punktfunk-host/src/capture/wgc.rs +++ b/crates/punktfunk-host/src/capture/wgc.rs @@ -20,7 +20,7 @@ use super::dxgi::{ find_output, make_device, nudge_cursor_onto, D3d11Frame, HdrConverter, WinCaptureTarget, }; use super::{CapturedFrame, Capturer, FramePayload, PixelFormat}; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{bail, Context, Result}; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Condvar, Mutex}; use std::time::{Duration, Instant}; @@ -30,7 +30,6 @@ use windows::Graphics::Capture::{ Direct3D11CaptureFrame, Direct3D11CaptureFramePool, GraphicsCaptureItem, GraphicsCaptureSession, }; use windows::Graphics::DirectX::DirectXPixelFormat; -use windows::Graphics::SizeInt32; use windows::Win32::Foundation::{CloseHandle, HANDLE}; use windows::Win32::Graphics::Direct3D11::{ ID3D11Device, ID3D11DeviceContext, ID3D11RenderTargetView, ID3D11ShaderResourceView, diff --git a/crates/punktfunk-host/src/capture/wgc_relay.rs b/crates/punktfunk-host/src/capture/wgc_relay.rs index 54b2a37..73d8f88 100644 --- a/crates/punktfunk-host/src/capture/wgc_relay.rs +++ b/crates/punktfunk-host/src/capture/wgc_relay.rs @@ -15,7 +15,7 @@ use crate::capture::dxgi::WinCaptureTarget; use anyhow::{bail, Context, Result}; -use std::io::{BufRead, BufReader, Read, Write}; +use std::io::{BufRead, BufReader, Read}; use std::sync::mpsc::{Receiver, SyncSender}; use std::sync::Mutex; use windows::core::PWSTR;