Per-app send fixes + apps-mode UI rework (no send-all) + truly-global remembered lists
Per-app capture (the "foobar alone = no sound" report):
- ProcessLoopbackCapture: take ActivateAudioInterfaceAsync's out operation as a raw
IntPtr (released after completion) instead of a typed interface. The eager RCW cast
of the not-yet-realised operation object threw InvalidCastException / E_NOINTERFACE
and killed EVERY specific-app capture at start.
- CompositeCaptureBackend: single IsPushEligible authority shared by Start,
UpdateSources and the coalesced rebuild. The update paths were missing the
ProcessLoopback exclusion, so switching whole-device -> one app kept the push
backend and fed it "proc:<pid>" (GetDevice ArgumentException).
- PushModeWasapiBackend: loud backstop rejecting process-loopback specs.
- Self-test: lifecycle test now FAILS on an activation error (it previously passed
green with the feature completely dead) + pure routing-rule checks.
Apps-mode UI (Ed 2026-07-16): the "Send all applications" checkbox is GONE from the
main window - applications mode always means picking specific apps; whole-system
audio is devices mode's job. Active list = running apps + any ticked app that is not
running ("(not running)" so it can be unticked); Remembered list = global address
book minus whatever is ticked. In-place list reconcile (no Clear+rebuild) kills the
NVDA double-read of the toggled row. Profile.SendAllApplications stays for the
SERVICE (deliberate divergence - a headless lock-screen sender wants system audio).
Remembered lists now genuinely machine-wide (AppConfig-backed): the settings store is
an intra-process cache, so remembered applications were forgotten on every exit and
remembered peers were per-profile in practice. Both books moved to AppConfig; legacy
per-profile peers are unioned in on profile load; profile save snapshots the global
book back for old-build compat. Cross-instance persistence pinned by self-test.
Service (issue #23): 15s capture pulse (callbacks/bytes/pre-encode peak/frames sent)
while sending - distinguishes "endpoint mix is genuinely silent at the lock screen"
from a pipeline fault, which callbacks alone cannot.
Gate: 38/38.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
92ad77ff52
commit
1003bbfdf2
+121
-115
@@ -94,18 +94,15 @@ public sealed class MainForm : Form
|
||||
// is forced to "devices". The app list is tracked by process NAME (so a selection survives an app
|
||||
// restart) and reconciled on sendAppsReconcileTimer so apps dropping in and out don't pile up.
|
||||
// Unlike the device lists this selection IS persisted — per profile (WasapiSendMode /
|
||||
// SendAllApplications / SelectedSendApplications) — matching how Ed wants a profile to remember its
|
||||
// whole send setup.
|
||||
// SelectedSendApplications) — matching how Ed wants a profile to remember its whole send setup.
|
||||
// There is deliberately NO "send all applications" option here (Ed removed it 2026-07-16): picking
|
||||
// the applications mode means picking specific apps; whole-system audio is what devices mode is for.
|
||||
// (The SERVICE still has its own send-all concept — a headless lock-screen sender wants system audio —
|
||||
// so Profile.SendAllApplications stays for ServiceProfileDialog/ServiceSendHost.)
|
||||
private readonly ListBox sendModeList = new() { Width = 430, Height = 38, IntegralHeight = false };
|
||||
private MnemonicLabel? sendModeLabel;
|
||||
private readonly AccessibleCheckBox sendAllApplicationsCheckbox = new()
|
||||
{
|
||||
Text = "Send all applications (Alt+&7)",
|
||||
AccessibleName = "Send all applications",
|
||||
AutoSize = true,
|
||||
Checked = true,
|
||||
};
|
||||
// "Currently active applications" — the apps running right now (like Discovered peers).
|
||||
// "Currently active applications" — the apps running right now (like Discovered peers), PLUS any
|
||||
// ticked app that isn't running (shown "(not running)") so the user can always find and untick it.
|
||||
private readonly CheckedListBox sendAppsList = new() { CheckOnClick = true, Width = 430, Height = 90 };
|
||||
private readonly Label sendAppsStatusLabel = new() { AutoSize = true, Text = "No application selected." };
|
||||
private MnemonicLabel? sendAppsLabel;
|
||||
@@ -124,12 +121,7 @@ public sealed class MainForm : Form
|
||||
// when the ticked apps' actual process ids change (an app opened or closed).
|
||||
private RemSound.Sender.AudioSessionStartWatcher? sessionStartWatcher;
|
||||
private string? lastSendAppPidSignature;
|
||||
// The active-apps list's FIRST ROW is a synthetic "Send all applications" toggle (Ed's design): ticked =
|
||||
// send the whole system, and the individual apps below collapse away; unticked reveals them. It's backed
|
||||
// by sendAllApplicationsCheckbox (kept as hidden state). This reserved process-name marks that row so the
|
||||
// handlers can tell it apart from a real app.
|
||||
private const string SendAllAppsSentinel = " | ||||