Rebrand to ScreenSound (v2.0.0)#9
Conversation
Mechanical pass 1 of the rebrand. This commit covers the CamelCase form of the name only; user-facing "Audio Monitor Router" strings, assembly metadata, version bump, installer defines, single-instance mutex, and description rewrite all follow in subsequent commits. - git mv the solution, project folder, and .csproj so history follows - Blanket sed-replace across .cs/.xaml/.csproj/.sln/.manifest/.iss/.yml/ .html: "AudioMonitorRouter" -> "ScreenSound" - This catches: all C# namespaces and usings, XAML x:Class + xmlns: local/vm, IconBuilder RootNamespace, app.manifest assembly identity name, UpdateService API URL + User-Agent product token + fallback URL repo path, XAML NavigateUri to GitHub, csproj RepositoryUrl, installer MyAppExeName + MyAppURL + OutputBaseFilename + SetupIconFile + Run-key ValueName + UninstallDelete path, CI/release workflow .sln and artifact names, design/preview.html and IconBuilder comments, SettingsService AppData folder literal, and MainWindowViewModel AppRegistryName constant. Release build: 0 warnings, 0 errors. The remaining "Audio Monitor Router" spaced-form hits (window titles x2, About page header, tray tooltip, <Product>, <AssemblyTitle>, installer MyAppName, installer comment header) are intentionally left for commit 2.
Mechanical pass 2 of the rebrand. This commit flips the 8 remaining "Audio Monitor Router" spaced-form strings to "ScreenSound", bumps the version from 1.0.0 (which was stale anyway — the real last release was v1.3.0) straight to 2.0.0 to signal the rebrand as a major release, and gives the installer a fresh AppId GUID so Windows treats the rebranded app as its own identity in Add/Remove Programs. - Spaced-form sed pass across .cs/.xaml/.csproj/.iss catches: window titles (MainWindow.xaml x2), About page header, tray tooltip, csproj <Product>/<AssemblyTitle>, installer MyAppName and comment header, wrapping up the CamelCase-vs-spaced split from commit 1. - csproj <Version>/<AssemblyVersion>/<FileVersion> bumped to 2.0.0(.0) - csproj <Description> rewritten to fit the ScreenSound brand: "Sound follows your windows. Per-app audio routing for multi-monitor Windows 11 — each app plays through the speaker paired with the monitor it's on." - app.manifest assembly identity version bumped to 2.0.0.0 - installer.iss AppId regenerated (3BBBE2CE-314A-48FE-85F7-BD0DD3762B6F). Updated the surrounding comment so the "NEVER change this" warning reflects that we just changed it — the v2 GUID is the new forever. - installer.iss MyAppVersion fallback also bumped to 2.0.0 for local builds without APP_VERSION env var. Release build: 0 warnings, 0 errors. Remaining work on this branch: add single-instance mutex (commit 3), then verify and PR.
ScreenSound lives in the system tray and configures Windows-wide audio routing state (per-app PolicyConfig calls, HKCU Run key for startup). Two copies running would race on the Run-key writes, both try to own the tray icon, and double-route the same audio sessions. Nothing in the app was guarding against that — a user double-clicking the desktop shortcut or the installer's post-install launch line while the app was already in the tray would happily start a second process. The guard is a named mutex with a "Local\" prefix. Local scope means fast-user-switching still lets each Windows user have their own copy (each login session has its own Local namespace), while blocking accidental double-launches within one session. Details worth calling out in code: - Acquire the mutex before any side effects (DPI awareness config, window creation, tray setup). Nothing half-initialised. - AbandonedMutexException handled: if a previous instance crashed without releasing, WaitOne still hands us ownership — we treat the exception as success, not failure. - Explicit ReleaseMutex + Dispose in OnExit. The OS would clean it up on process exit anyway, but explicit release closes a brief race window where a fast relaunch sees the mutex as still held. - Message on the losing path points the user at the tray — the primary failure mode is "I double-clicked the shortcut and nothing happened," and the app is already sitting in the tray a click away. Release build: 0 warnings, 0 errors.
📝 WalkthroughWalkthroughThe project undergoes comprehensive rebranding from "AudioMonitorRouter" to "ScreenSound," including namespace refactoring across all source files, version bump to 2.0.0, updated GitHub repository references, and addition of single-instance mutex enforcement in the application startup. CI/CD pipelines, project configuration, and UI strings are updated accordingly. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
ScreenSound/App.xaml.cs (1)
82-83: Minor: Comment is slightly misleading.The comment states "Not owned (e.g. after an AbandonedMutexException path)" but
AbandonedMutexExceptionactually grants ownership, soReleaseMutex()would succeed in that case. The catch is still appropriate as a defensive measure for unexpected edge cases, but the example in the comment is incorrect.Suggested comment fix
- try { _singleInstanceMutex.ReleaseMutex(); } - catch (ApplicationException) { /* Not owned (e.g. after an AbandonedMutexException path) — nothing to release. */ } + try { _singleInstanceMutex.ReleaseMutex(); } + catch (ApplicationException) { /* Not owned — nothing to release. */ }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ScreenSound/App.xaml.cs` around lines 82 - 83, The comment next to the call to _singleInstanceMutex.ReleaseMutex() is misleading about AbandonedMutexException; update the comment to accurately explain that AbandonedMutexException actually grants ownership (so ReleaseMutex would normally succeed) and that the catch is a defensive fallback for unexpected cases (e.g., mutex not owned or already disposed), keeping the existing try/catch around _singleInstanceMutex.ReleaseMutex() intact; reference the _singleInstanceMutex field and the ReleaseMutex() call when updating the comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@ScreenSound/Services/SettingsService.cs`:
- Around line 9-13: Load currently only looks at SettingsDir/SettingsFile so
existing users under the old path (%AppData%\AudioMonitorRouter\settings.json)
will be ignored; update the SettingsService.Load() (and any save/initialization)
to check for the legacy path (e.g., Path.Combine(Environment.GetFolderPath(...),
"AudioMonitorRouter", "settings.json"), detect if the legacy file exists, create
the new SettingsDir if needed, atomically move/rename the legacy file to
SettingsFile (or copy and delete on failure) and log any errors, ensuring
subsequent calls use SettingsFile; also ensure Save() writes to the new
SettingsFile so future launches use the new location.
In `@ScreenSound/ViewModels/MainWindowViewModel.cs`:
- Line 138: The autostart rename left legacy registry entries behind; update
ApplyAutoStart (and any startup-related methods) to handle migration/cleanup by
checking for and deleting the old Run value name in addition to setting/deleting
the new AppRegistryName ("ScreenSound"), and when enabling autostart ensure any
legacy key is removed or migrated to the new name so toggling autostart off
truly stops an upgraded install from launching; reference the AppRegistryName
constant and the ApplyAutoStart method (and any autostart enable/disable
callers) to implement the check/delete of the previous registry value name.
---
Nitpick comments:
In `@ScreenSound/App.xaml.cs`:
- Around line 82-83: The comment next to the call to
_singleInstanceMutex.ReleaseMutex() is misleading about AbandonedMutexException;
update the comment to accurately explain that AbandonedMutexException actually
grants ownership (so ReleaseMutex would normally succeed) and that the catch is
a defensive fallback for unexpected cases (e.g., mutex not owned or already
disposed), keeping the existing try/catch around
_singleInstanceMutex.ReleaseMutex() intact; reference the _singleInstanceMutex
field and the ReleaseMutex() call when updating the comment.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: ca9be1c0-224c-42c5-8ffa-2e01aa3b3101
⛔ Files ignored due to path filters (2)
ScreenSound/Assets/app-icon.pngis excluded by!**/*.pngScreenSound/app.icois excluded by!**/*.ico
📒 Files selected for processing (32)
.github/workflows/ci.yml.github/workflows/release.ymlScreenSound.slnScreenSound/App.xamlScreenSound/App.xaml.csScreenSound/AssemblyInfo.csScreenSound/GlobalUsings.csScreenSound/Interop/AudioPolicyConfig.csScreenSound/Interop/NativeMethods.csScreenSound/Interop/WinEventHook.csScreenSound/Models/AppSettings.csScreenSound/Models/AudioDeviceInfo.csScreenSound/Models/AudioSessionInfo.csScreenSound/Models/MonitorInfo.csScreenSound/ScreenSound.csprojScreenSound/Services/AudioDeviceNotifier.csScreenSound/Services/AudioDeviceService.csScreenSound/Services/AudioRouterService.csScreenSound/Services/AudioSessionNotifier.csScreenSound/Services/AudioSessionService.csScreenSound/Services/MonitorService.csScreenSound/Services/RoutingEngine.csScreenSound/Services/SettingsService.csScreenSound/Services/UpdateService.csScreenSound/ViewModels/MainWindowViewModel.csScreenSound/Views/MainWindow.xamlScreenSound/Views/MainWindow.xaml.csScreenSound/app.manifestdesign/preview.htmldesign/tools/IconBuilder/IconBuilder.csprojdesign/tools/IconBuilder/Program.csinstaller/installer.iss
|
Released as v2.0.0. |
Summary
Full rebrand from Audio Monitor Router → ScreenSound. Every surface flipped: code, XAML, assembly metadata, installer, CI workflows, design assets. Version bumped 1.3.0 → 2.0.0 to signal the break. Fresh installer
AppIdso the rebrand gets its own Add/Remove Programs identity. Opportunistic single-instance mutex added during the churn.Split into three commits for review sanity (each is independently buildable):
f64f9c5) —git mvof solution/project folder/csproj so history follows, then a sed pass replacing the CamelCaseAudioMonitorRoutertoken across every tracked text file. Catches namespaces, usings, XAMLx:Class+xmlns,UpdateServiceAPI URL + User-Agent,RepositoryUrl,app.manifestassembly identity,SettingsServiceAppData folder literal,MainWindowViewModelRun-key constant, installerMyAppExeName/MyAppURL/OutputBaseFilename/SetupIconFile/ValueName/UninstallDelete, CI workflow sln + artifact names. 67 replacements across 30 files.073e554) — flips the 8 remaining spaced-formAudio Monitor Routerstrings (window titles ×2, About page header, tray tooltip,<Product>,<AssemblyTitle>, installerMyAppName, installer header comment). Version bump to 2.0.0(.0) in csproj +app.manifest+ installer fallback. NewAppIdGUID (3BBBE2CE-314A-48FE-85F7-BD0DD3762B6F) and rewritten<Description>to fit the new brand ("Sound follows your windows. Per-app audio routing for multi-monitor Windows 11 — each app plays through the speaker paired with the monitor it's on.").c85ed9b) —Local\ScreenSound-SingleInstanceacquired inApp.OnStartupbefore any side effects, released inOnExit. HandlesAbandonedMutexException(previous crash) as success, shows a "check the system tray" message on the losing path. Not strictly part of the rebrand but the rebrand churn is the natural home for this fix.Pre-flight that already happened
twibster/AudioMonitorRouter→twibster/ScreenSoundviagh repo rename(GitHub auto-redirects the old URL).F4B8A24A-...AppIdgrep confirms zero remaining references outside of the comment explaining why we regenerated it.AudioMonitorRouter/Audio Monitor Routerhit is gone (verified viagit grep).Why the AppId changed (differs from original plan)
Original plan was to keep the
AppIdfor in-place upgrade. Changed course after confirming no v1 installs exist in the wild other than the maintainer's own dev box (already uninstalled). FreshAppId+ no settings migration gives the v2 product a clean slate. If a v1 install somehow surfaces later, the user will see it sitting next to v2 in Add/Remove Programs and can uninstall it manually — simpler than maintaining migration code for an audience of none.Version bump 1.3.0 → 2.0.0 (not 1.0.0 → 2.0.0)
The csproj
<Version>was stale at1.0.0but the actual release history (tagv1.3.0from earlier today) is the real predecessor. Fixed in this PR so the next release metadata matches git truth.Test plan
dotnet build ScreenSound/ScreenSound.csproj -c Releaseclean locally (done: 0 warnings, 0 errors)%APPDATA%\ScreenSound\settings.jsonis where settings land (not the old path)api.github.com/repos/twibster/ScreenSound/releases/latestv2.0.0, auto-release workflow producesScreenSound-Setup-2.0.0.exeandScreenSound-2.0.0-portable.zipSummary by CodeRabbit
Release Notes
New Features
Chores