From ec149ed09ecf8cbf66b6a1f02650c479f1652643 Mon Sep 17 00:00:00 2001 From: Ednunp <29843396+Ednunp@users.noreply.github.com> Date: Fri, 17 Jul 2026 12:13:29 +0100 Subject: [PATCH] Service crackle fix: un-throttle the process while streaming (PerformanceMode) The send-only service sounded hideous/crackly vs the main app, even standalone, with clean capture (capPeak ~0.44) and clean receiver metrics (no underruns/drops/gaps) -- the fingerprint of a process being starved by the OS scheduler, not a data problem. Cause: a headless Windows SERVICE is a background process, so Windows aggressively downclocks it (EcoQoS), migrates its threads onto efficiency cores, and gives it a coarse scheduler quantum -- exactly what starves the audio send loop into crackling. The interactive app engages PerformanceMode only on the user high-priority toggle; the service never engaged it at all, and being a service it is throttled far harder. Fix: the service now engages PerformanceMode (EcoQoS opt-out, High priority, 1ms timer, no deep C-states, working-set floor) whenever it is streaming, released on suspend/ dispose. Unconditional -- the service has no foreground/battery use case; it exists solely to stream and must not be throttled. Gate: 39/39. Co-Authored-By: Claude Opus 4.8 --- src/RemSound.App/ServiceSendHost.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/RemSound.App/ServiceSendHost.cs b/src/RemSound.App/ServiceSendHost.cs index 10baa96..f75a6e5 100644 --- a/src/RemSound.App/ServiceSendHost.cs +++ b/src/RemSound.App/ServiceSendHost.cs @@ -348,6 +348,14 @@ public sealed class ServiceSendHost : IDisposable // blind push. Same well-known audio port and the same components the interactive app uses. presence.Start(RemPacket.DefaultPort, endpoints); running = true; + // Un-throttle the process while streaming. A headless Windows SERVICE is treated by the OS as a + // background process and gets aggressively downclocked (EcoQoS), migrated onto efficiency cores + // and given a coarse scheduler quantum — which starves the send loop and makes the stream + // CRACKLE even though capture and the network look clean. The interactive app only does this on + // the user's opt-in "high priority" toggle, but the service has no foreground/battery use case + // (it exists solely to stream), so it always engages while sending. Idempotent; released in + // Suspend. This is the fix for "the service sounds hideous vs the main app". + try { PerformanceMode.Apply(true, msg => log?.Invoke($"service: {msg}")); } catch { /* best-effort */ } log?.Invoke($"service: streaming \"{profile.Title}\" — {specs.Count} source(s) to {endpoints.Count} peer(s)"); return true; } @@ -366,6 +374,7 @@ public sealed class ServiceSendHost : IDisposable SwapMeterDevices(Array.Empty()); // release the endpoint-meter readers try { sessionKick?.Dispose(); } catch { /* ignore */ } sessionKick = null; + try { PerformanceMode.Apply(false, msg => log?.Invoke($"service: {msg}")); } catch { /* best-effort */ } running = false; log?.Invoke("service: suspended (interactive app present)"); } @@ -607,6 +616,7 @@ public sealed class ServiceSendHost : IDisposable try { deviceNotifier?.Dispose(); } catch { } deviceNotifier = null; try { sessionKick?.Dispose(); } catch { } sessionKick = null; SwapMeterDevices(Array.Empty()); + try { PerformanceMode.Apply(false); } catch { } try { presence.Dispose(); } catch { } try { sender.Stop(); } catch { } try { sender.Dispose(); } catch { }