Service: offer "Use Windows default output" (Christopher's request), reusing the app's follower

The service profile could only pick named output devices, so it couldn't "just send
whatever this machine plays and follow the Windows default". The main app already had
exactly that (its DefaultLoopbackSendFollower + ResolveDefaultDeviceId) - so rather
than invent a parallel mechanism (which would silently diverge), this pulls the shared
piece out and has the service reuse it.

- New AudioDefaultFollower: one home for the loopback-send sentinel
  ("__use-default-loopback-send__"), the follower list entry, and the default-endpoint
  resolver. MainForm now references it (its DefaultLoopbackSendFollower and
  ResolveDefaultDeviceId delegate to it) so there is a single definition.
- Service config dialog: the Audio send tab lists "Use Windows default audio device,
  follows Windows changes" as the first output choice. Ticking it persists the same
  sentinel the app uses.
- ServiceSendHost.BuildSendSpecs resolves that sentinel to the LIVE default render
  endpoint (with de-dup against explicitly-ticked devices), never passing the raw
  sentinel through. Because the service re-applies its profile on every device-change
  notification - and OnDefaultDeviceChanged is one of them - it FOLLOWS the default:
  change Windows' default output and the service switches to it within a beat.
- Manual: documents the new option in the service section.

Test: new "Default-output follower" self-test - follower is flagged + shares the app's
sentinel, and the service resolves it to the current Windows default render endpoint
(never leaks the raw sentinel into a capture spec). Gate 44/44.

The ASIO "Rea" devices Ed noticed are real registry drivers (Realtek ASIO + REAPER's
ReaRoute), not injected dummies - we only ever list HKLM\SOFTWARE\ASIO. No code change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ednunp
2026-07-17 23:08:55 +01:00
co-authored by Claude Opus 4.8
parent 43e249e90e
commit 4a86a82ec8
6 changed files with 103 additions and 16 deletions
+6 -1
View File
@@ -197,7 +197,12 @@ internal sealed class ServiceProfileDialog : Form
suppressAppEvents = true;
try
{
PopulateDeviceList(outputsList, AudioDeviceCatalog.LoadOutputs(), working.SelectedWasapiSendOutputs);
// Offer "Use Windows default output" as the first output choice (Christopher's request):
// send whatever this machine currently plays, following the Windows default. Same shared
// follower + sentinel the main window uses, so a ticked follower persists and resolves identically.
var outputChoices = new List<AudioDeviceChoice> { AudioDefaultFollower.LoopbackSendChoice() };
outputChoices.AddRange(AudioDeviceCatalog.LoadOutputs());
PopulateDeviceList(outputsList, outputChoices, working.SelectedWasapiSendOutputs);
PopulateDeviceList(inputsList, AudioDeviceCatalog.LoadInputs(), working.SelectedWasapiSendInputs);
var appsMode = ProcessLoopbackCapture.IsSupported