Release v4.2: fix connect-freeze (#10) and new-profile minimize (#12); smoother WASAPI timing

- Connect no longer freezes: PushDiscoveryUnicastHints resolved remembered
  hostnames with synchronous Dns.GetHostAddresses on the UI thread, blocking the
  whole window for the DNS timeout on an unresolvable name. A screen-reader user
  experiences that as the entire machine locking up. Resolution now runs off the
  UI thread. Same class of bug as the v3.0.1 UPnP-on-the-UI-thread hang. (#10)

- New profile / profile switch no longer hides the window: OnShown ORed the
  global StartMinimised into every instance, so creating a new profile while
  Start minimised was on dropped the window to the tray and looked like a crash.
  StartMinimised now applies only to a genuine cold launch; relaunches honour the
  explicit per-instance flag. (#12)

- Smoother WASAPI audio: the receive producer loop and sender mix loop pace
  themselves with WaitHandle.WaitOne, bound by the system timer (~15.6ms default).
  Without a fine timer the 10ms feed slips to ~16-31ms and delivers audio in
  chunky bursts (the desktop-render chunkiness behind Andre's dropouts/lag). New
  SystemTimerResolution holds a 1ms timer whenever a stream is live, independent
  of the opt-in Priority mode.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ednunp
2026-06-15 09:21:04 +01:00
co-authored by Claude Opus 4.8
parent 5abbeefe29
commit 034a7de632
7 changed files with 165 additions and 47 deletions
@@ -239,6 +239,13 @@ internal sealed class MultiOutputPlayout : IRenderBackend
{
// Pro Audio MMCSS for the producer thread — it's the one feeding all WASAPI outputs.
using var threadBoost = new WindowsAudioThreadBoost("Pro Audio");
// Hold the system timer at 1 ms for as long as we're producing. This loop paces itself with
// WaitHandle.WaitOne below, whose granularity is the system timer — coarse (~15.6 ms) by
// default, which slips the 10 ms feed to ~1631 ms and delivers audio to the outputs in
// chunky bursts (the receive-render chunkiness behind Andre's dropouts/lag). The MMCSS boost
// above raises priority but NOT timer granularity. Deliberately NOT gated behind the opt-in
// Priority mode — the audio path must run smoothly without a user toggle. 2026-06-15.
using var timerResolution = new SystemTimerResolution(1);
var ticksPerFrame = Stopwatch.Frequency * FrameMs / 1000;
var nextTickStopwatch = Stopwatch.GetTimestamp() + ticksPerFrame;