Lock-screen service: spike + headless send host + app-yield coordination
Local checkpoint - NOT for public release. First increment of the send-only Windows service feature (design in memory/project_remsound_service). THE SPIKE PASSED: the send engine runs fully headless (no window, no message pump) and streams, proven by a real self-test — the one genuine unknown that gated the whole feature. Also proves the app-yield model end to end. What's in this increment (all headless, all tested, 19/19 gate): - AppConfig: ServiceProfileName + ServiceLoggingEnabled (machine-wide). - InteractivePresence (Core): the cross-session app-yield token. App holds a Global\ mutex for its lifetime; the service checks it and yields while an interactive app is present, resuming when it closes OR crashes (OS frees the mutex). Name-parameterised internal seams for isolated testing. - ServiceSendHost (App): loads a send-only profile and streams it to its peers, WASAPI-only, no ASIO/receive. ApplyProfile/Suspend/Resume + a RunLoop that drives them from the presence token with a settle delay. v1 sends to direct peer addresses (LAN/port-forwarded); NAT/relay discovery stays the app's job. - Program.cs: the interactive app now acquires the presence token at startup so a future service yields to it. - Tests: "Service app-yield token" (held=present, released=absent) and "Service send host (headless stream + yield)" — streams a captured device to a local receiver over loopback, verifies start/suspend/resume, then drives the full RunLoop against the token (held=suspended, released=resumes-and-flows). Still to come (later increments): the --run-service entry + Windows-service registration, the Service menu, the 3-tab config dialog, updater integration, docs. None user-facing yet, so nothing deployed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8f61eb800d
commit
e648bee531
@@ -113,7 +113,7 @@ public sealed class MainForm : Form
|
||||
// programmatically repopulate them (mode switch, profile apply, reconcile) so those handlers
|
||||
// don't fire MarkProfileDirty or trigger re-entrant rebuilds on our own writes.
|
||||
private bool suppressSendAppEvents;
|
||||
// The two sendModeList rows, in order. Index 0 = whole sound devices (classic), 1 = applications.
|
||||
// The two sendModeList rows, in order. Index 0 = whole audio devices (classic), 1 = applications.
|
||||
private const int SendModeDevicesIndex = 0;
|
||||
private const int SendModeApplicationsIndex = 1;
|
||||
// ASIO-side lists. Always present in the form but hidden when ASIO is disabled. The two
|
||||
@@ -3299,7 +3299,7 @@ public sealed class MainForm : Form
|
||||
sendCheckboxPanel.Controls.Add(sendMyAudioCheckbox);
|
||||
panel.Controls.Add(sendCheckboxPanel, 1, 6);
|
||||
|
||||
// Row 7: "how to send WASAPI audio" chooser — sound devices (the classic loopback list) or
|
||||
// Row 7: "how to send WASAPI audio" chooser — audio devices (the classic loopback list) or
|
||||
// specific applications. Sits right after "Send my audio". Built manually (like the ASIO
|
||||
// driver row) so we keep the label reference to collapse the whole row on old Windows.
|
||||
BuildSendModeRow(panel, 7);
|
||||
@@ -3338,7 +3338,7 @@ public sealed class MainForm : Form
|
||||
sendModeLabel.Click += (_, _) => FocusControl(sendModeList);
|
||||
sendModeList.AccessibleName = "How to send WASAPI audio (Alt+6)";
|
||||
sendModeList.Items.Clear();
|
||||
sendModeList.Items.Add("Send whole sound devices"); // SendModeDevicesIndex
|
||||
sendModeList.Items.Add("Send whole audio devices"); // SendModeDevicesIndex
|
||||
sendModeList.Items.Add("Send specific applications"); // SendModeApplicationsIndex
|
||||
sendModeList.SelectedIndex = SendModeDevicesIndex;
|
||||
panel.Controls.Add(sendModeLabel, 0, row);
|
||||
|
||||
Reference in New Issue
Block a user