The test suite, modelled on Andre's Sensor Readout (an in-app self-test + a build
script), runnable as one step before every publish.
Part 1 - in-app multi-step self-test (SelfTest.cs), run by --selftest:
audio round-trip (PCM + Opus over localhost, dedicated test port so it never
clashes with a running instance), encryption right/wrong-password + fingerprint,
packet framing + malformed rejection, client<->server wire-format compatibility,
settings save/reload, profile save/reload (temp folder), diagnostics-report
privacy (never leaks a password), and bundled-resources present. Each step is
timed and reported PASS/FAIL/SKIP; exit 0 only if nothing failed. Replaces the
old single-shot --selftest. RunDiagnostics refactored to expose
BuildDiagnosticsReport(AppConfig) for the privacy step.
Part 2 - run-tests.ps1: builds, then checks the package (sounds, readme, native
opus, framework-dependent, dll version == csproj), the About-box changelog, the
client/server wire contract (relay magic/version/port still match RemPacket),
the CLI surface, and runs --selftest. build-release.ps1 now runs this gate first
and aborts the release if it fails.
Bug caught + fixed: the published release zip carried ZERO cue sounds (startup
sound + connect/disconnect/etc.) - MSBuild's incremental Content-copy marker
skipped sounds\ on a fresh publish. Added an AfterTargets=Publish copy in the
csproj that lands every cue WAV in the published sounds\ folder regardless of
the marker. Verified: a staging publish now contains all 9 cue WAVs.
Manual/help: --selftest description updated (readme.html + MANUAL.md).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Recover an unplugged/replugged output sound card automatically (issue #5):
detect the dead WASAPI device and remember the receive-output selection so it
re-ticks and re-opens when the card returns.
- Adaptive per-card WASAPI buffer target sized to each card's pull chunk, held
stable so it never flits about under CPU/network load.
- Consolidate all per-user data (config, profiles, logs, sounds) into one
"user settings and logs" folder; migrate every older layout; exclude it from
the updater so custom cue sounds now survive updates.
- Mic-privacy detector: warn once when a Windows-blocked mic is switched on, or a
profile loads with one already on.
- All warning/notice dialogs now come to the foreground even when minimised.
- Apply volume + mute on profile load (were saved but not restored).
- Crash-safe (atomic) profile/config saves.
- Fix two resource leaks (push-mode capture MMDevice; UPnP DeviceFound handler).
- Remove dead code (baseline-diff machinery, dead ASIO probes, no-op stubs).
- Docs: readme.html, MANUAL.md, About-box changelog and release notes for v3.5.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Freezes the v3.4 feature set (everything since the v3.3 public release):
- Fix the receiver handle leak: the 3-second device-refresh timer reopened the
configured ASIO driver every tick, and Realtek's ASIO driver leaks Event+Mutant
handles on every open. Cache the ASIO probe per driver so it is opened once.
- Realtek ASIO block: detect a Realtek ASIO driver, offer once to disable it, and
never touch it again if disabled; Options-menu toggle to reverse. Global config.
- Device hot-plug is event-driven (AudioDeviceChangeNotifier) instead of a 3s poll;
debounced refresh, falls back to polling if registration fails.
- Quick profile switch: new global hotkey opens an NVDA-friendly popup of all
profiles (current marked); Enter/click switches; plays a new "profile menu open"
cue with Preferences mute + custom-sound.
- Announce assigned global hotkeys on the controls/menu items they drive (NVDA reads
"press X anywhere"). File > Open already had Ctrl+O.
- Held-back changes folded in: config-folder migration, codec-column fix, Tailscale
endpoint network-prune, empty-password guard, and the handle-leak diagnostics
(ProcessSelfMeter, HandleTypeProbe).
Version bumped to 3.4.0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two Windows-specific gotchas the previous code didn't handle:
1) The 'python' / 'python3' commands on most Windows installs are
Microsoft Store execution aliases. They appear on PATH, accept
any invocation, exit with code 9009, and print a "go install
from the Store" message instead of running the script.
2) The 'py' launcher accepts --version and returns the right thing
(it knows about registered Pythons via the registry), but on
some setups it refuses to run scripts and falls through to the
Store alias too. Seen here: 'py --version' prints 3.11.9 but
'py sync-manual.py' prints the Store message and exits 9009.
The new approach runs an actual sentinel script via -c with each
candidate and only accepts the candidate when stdout matches the
expected string. User-local install paths come first because they
skip the Store-alias issue entirely. Falls through to 'py' and the
PATH commands as backstops.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
People landing on the repo page were having to install RemSound just to read what
it does and how to use it. Two doc changes fix that:
1) README.md rewritten as a plain-English landing page. Drops the developer-focused
highlights / build-from-source / project-layout sections in favour of what
RemSound is, who it's for, how to install it, and a prominent link to the manual.
No jargon, no command lines, no NuGet / SDK / ASIO-protocol talk. The dev-side
information that used to live here (build commands, source layout, relay setup)
is still discoverable for anyone who wants it — the source itself is on the same
page, and the relay docs are under server/README.md.
2) MANUAL.md added at the repo root as the GitHub-rendered version of the F1 help.
Markdown derived directly from readme.html via sync-manual.py (new), so visitors
can read the manual inline on the repo page with no download. readme.html stays
exactly where it was (bundled inside RemSound, opened by F1) — it remains the
canonical source of the manual content; MANUAL.md is auto-generated from it.
The sync-manual.py script is invoked automatically from build-release.ps1 as step 0,
before any other release work. It regenerates MANUAL.md from readme.html and then
checks `git diff` on MANUAL.md — if the file changed, the release is paused with a
message asking the user to commit the updated MANUAL.md alongside the release commit.
That makes it structurally impossible to ship a release with a stale GitHub-facing
manual: forgetting to commit MANUAL.md after editing the bundled help triggers a
deliberate release-time stop.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The script's ValidatePattern was '^v[0-9]+\.[0-9]+$', which rejected v3.0.1
because the v3.0 line predated any hot-fix releases. Widened to accept an
optional third component so v3.0.1 (and future patch releases) build via
the same path as v3.0 / v2.2 / etc.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The client and the relay server are published from the same GitHub repo;
the server's releases use "server-" prefixed tags. RemSoundUpdater hit
/releases/latest, which is repo-wide — when a server release was newest,
the updater fed "server-v2.3" to ParseTag (-> a bogus 0.0.3) and concluded
"up to date", silently skipping real client updates.
CheckForUpdateAsync now lists /releases and picks the highest-versioned
release whose tag is a RemSound client tag (new IsClientReleaseTag: after
an optional leading "v", first char must be a digit). Drafts and
pre-releases are skipped. The server-side updater already filters to
"server-" tags, so client + server coexist in one repo cleanly.
Also rewrites build-release.ps1 with a data-safety check: it publishes to
a fresh staging folder and aborts the release if any logs/, profiles/,
recordings/ folder, .log file or remsound.config.json is present in the
staged output or the finished zip — preventing a repeat of the v1.5/v1.6
zips that shipped with developer logs and profiles.
No wire-format or audio-pipeline changes — v1.5/v1.6/v1.7 interoperate.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>