UPnP close hang:
- RouterPortMapper.Stop()/Dispose() does a SYNCHRONOUS DeletePortMap call to the router
(plus StopDiscovery). When the router is slow or unresponsive that blocks — and it ran on
the UI thread in FormClosing, so enabling UPnP could make RemSound impossible to close
(Andre, this morning; his logs show UPnP teardown taking several seconds even on a good
run). Moved the router teardown into the same bounded background-task pattern already used
for the ASIO audio dispose: UPnP + audio now tear down off the UI thread, in parallel, under
one 3s cap. Anything unfinished is reclaimed on process exit, so the window always closes.
Mnemonics on dialog buttons:
- Andre flagged the "RemSound is already running" dialog (single-instance) having no shortcut
keys. Its three TaskDialog buttons had no & mnemonics; added Alt+S / Alt+F / Alt+C.
- Swept every dialog. Custom TaskDialog buttons and Form OK/Cancel/Close buttons that lacked
mnemonics now have them: single-instance (Switch/Force/Cancel), save-onto-read-only
(Save/Cancel), Add EQ band, Change/Manage profile password, Quick profile switch (Close),
Rename peer (OK), About (Close). Cancel stays on Esc in the few dialogs where Alt+C is
already taken (Rename peer's Clear, Service profile's peers list) — by design, not a miss.
- The rest already had mnemonics (Keyboard-shortcut import, Update-install notice, Profile
selection, Recording settings). The dialog-accessibility gate (mnemonic uniqueness + names)
stays green, so nothing collides.
Gate 46/46.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RemSound's password boxes are deliberately NOT PasswordChar-masked (a screen-reader user can't see
a mask), so the key-click hook's "is this a password field?" check (UseSystemPasswordChar /
PasswordChar) was always false and the distinct passkey.wav never played. Password fields now mark
themselves with Tag = KeyClickService.PasswordFieldTag, and the hook checks that (keeping the
masking-flag check as a fallback). Tagged both password fields - ProfilePasswordDialog (which all
password entry routes through, including the send/receive streaming gate) and
ProfilePasswordManagerDialog. So a key click + passkey now layer together on every password keystroke.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Headline: all audio is now encrypted (AES-256-GCM), keyed by a per-profile
password. Mandatory — v3.3 only interoperates with v3.3+.
Encryption
- RemSoundCrypto (Core): PBKDF2 key derivation, AES-GCM encrypt/decrypt
(low-alloc, into-span), password fingerprint, light on-disk obfuscation.
- Wire: SenderLane encrypts the audio payload (PCM split across parts when the
+28 overhead crosses MTU); AudioReceiver/StreamSession decrypt via a shared
single-thread AudioDecryptor. Fingerprint piggybacks on the Format packet
(offset 36, backward-compatible) so a peer can detect a password mismatch.
- Profile.Password (scrambled), carried through BuildCurrentProfile; MainForm
derives + pushes the key/fingerprint to sender + receiver (RecomputeAudioCrypto).
- UX: ask-for-password on profile create; File -> Change this profile's password
(ProfilePasswordDialog); Options -> Profile passwords (manager); a gate that
prompts before streaming without a password; and a clear "passwords don't
match" / "peer needs to update" message driven by the fingerprint.
Cue fixes
- CuePlayer (NAudio) replaces System.Media.SoundPlayer, which silently failed
on the 96 kHz/24-bit cue WAVs (and any custom file) — cues now play reliably,
resampled to 48 kHz/16-bit. Also fixes the Preferences preview button.
- Connect/disconnect cues now audio-gated with hysteresis: connected when audio
flows OR heartbeat healthy; lost only when audio stops AND heartbeat
unreachable. Kills false disconnects and the receive-only "no cues" case.
- Honest cue logging (played / muted / not loaded).
Smaller
- Endpoint stickiness: keep the audio target pinned to the heartbeat-proven
address instead of chasing a multi-homed peer's other (unreachable) address.
- "Online/offline" label now audio+heartbeat aware, not discovery-only.
- "Show what's new after each update" preference (on by default).
Docs: About v3.3 block, RELEASE_NOTES, README (encryption as a headline),
manual section 12 "Passwords and encryption" (+ renumber), MANUAL.md regenerated.
Version 3.2.0 -> 3.3.0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>