Bump to v3.1.2: tray icon re-stamps on state change, recording shows as a flag

- Tray icon now re-registers itself (hide+re-show) whenever the meaningful
  state changes — peer connect/drop, send/receive toggle, recording
  start/stop — so the name a screen reader announces stays in step with
  the live state. Fixes the persistent "no peers" then "1 peer" double
  announcement that the old "show window then minimise again" trick used
  to clear by hand. Same root cause as the v3.1.1 stuck-tooltip fix, just
  exposed when the state changes a moment after the icon appears.
- Recording shows as a plain "recording" flag in the tray rather than a
  live timer. A ticking timer would have either flickered the icon once a
  second or left a screen reader announcing a stale time next to the live
  one. Removed the now-dead FormatRecordingElapsed helper.
- Bundles the earlier Win7 updater fix (6cbde0d): a failed secure
  connection is no longer mislabelled as "you're up to date".
- About box, RELEASE_NOTES.md, readme.html and MANUAL.md updated to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ednunp
2026-05-30 23:34:44 +01:00
co-authored by Claude Opus 4.8
parent 6cbde0da12
commit baf50baf73
7 changed files with 111 additions and 39 deletions
+2 -2
View File
@@ -188,11 +188,11 @@ Tab| What it's for
When RemSound is **minimised to the tray** (via **File → Minimise to tray**, the “Show or hide window” global hotkey, or by starting minimised on launch), the main window hides and an icon appears in your Windows system tray (the small icons cluster next to the clock). When RemSound is **minimised to the tray** (via **File → Minimise to tray**, the “Show or hide window” global hotkey, or by starting minimised on launch), the main window hides and an icon appears in your Windows system tray (the small icons cluster next to the clock).
**Hovering over the tray icon** shows a short summary of what RemSound is doing right now — the number of healthy peers, whether you're sending or receiving and in which mode (WASAPI, ASIO, or both), and how long any current recording has been running. The summary refreshes every second. Examples: **Hovering over the tray icon** shows a short summary of what RemSound is doing right now — the number of healthy peers, whether you're sending or receiving and in which mode (WASAPI, ASIO, or both), and whether a recording is running. The summary keeps itself up to date as things change. It tells you a recording is in progress, but not its exact length — for that, glance at the main window. Examples:
* _RemSound — not connected_ * _RemSound — not connected_
* _RemSound — 2 peers, sending (WASAPI), receiving (WASAPI)_ * _RemSound — 2 peers, sending (WASAPI), receiving (WASAPI)_
* _RemSound — recording for 5:23, 1 peer, sending (WASAPI + ASIO), receiving (WASAPI + ASIO)_ * _RemSound — recording, 1 peer, sending (WASAPI + ASIO), receiving (WASAPI + ASIO)_
+20 -12
View File
@@ -1,32 +1,40 @@
# RemSound v3.1.1 # RemSound v3.1.2
Hot-fix for one small but annoying bug introduced in v3.1. A small accessibility fix for the system tray icon, plus a clearer "check for updates" message for Windows 7 users. Minor update — safe to take, nothing else changes.
## What was happening ## The tray icon's double announcement (screen reader users)
If the v3.1 auto-update fired while RemSound was set to start minimised to the tray, the tray icon's hover tooltip could get stuck saying **"RemSound — starting up"** indefinitely, instead of switching to the live "X peers, sending, receiving" summary after a second or so. The workaround was to show the main window and then minimise it again that cleared the stuck text. If you run RemSound minimised to the tray with a screen reader, you may have noticed the tray icon reading out **two states one after the other** every time you landed on it — for example "no peers connected" and then immediately "1 peer connected". It always happened in that same order, and showing the window then minimising it again was the only thing that cleared it.
## Why it happened ### Why it happened
Windows registers a tray icon's tooltip text with the shell at the exact moment the icon becomes visible. RemSound was setting an initial "starting up" string at construction time, and the shell tended to keep showing that text on hover even after the live state had been computed and pushed through. The hide-then-re-show workaround forced the shell to rebuild its registration of the icon, which picked up whatever the current live text was. Windows stamps a tray icon with its name at the exact moment the icon appears. On a fresh start — say, just after you log in — the icon appears a second or so before your other machine has reconnected, so the honest state at that instant really is "no peers". Windows remembers that as the icon's name and only ever refreshes the little hover bubble afterwards, never the stamped name. So your screen reader read the frozen name ("no peers") followed by the live bubble ("1 peer") — two readings of what should be one thing.
## The fix ### The fix
The right tooltip text is now computed once, just before the icon becomes visible for the first time, so Windows registers the icon with the correct live summary from the start. From there, the same 1-second refresh keeps it current — same as before. RemSound now re-stamps the icon itself whenever something real changes — a peer connecting or dropping, sending or receiving switching on or off, or a recording starting or stopping. That's the automatic version of the old "show the window then minimise again" trick. Your screen reader now hears a single, current state.
## Recording shows as "recording" in the tray
While a recording is running, the tray summary now simply says **"recording"** rather than counting the seconds. A live timer would have forced the icon to flicker every second or left a screen reader announcing a stale time — neither was good. If you want the exact length, it's on the main window.
## Clearer update message on Windows 7
On a Windows 7 machine that can't make a secure (HTTPS) connection to the update server, **Check for updates** used to report "you're already on the latest version" — which was wrong and confusing. It now tells you plainly that the secure connection failed, names the Windows updates that fix it, and gives you a direct link to download the new version by hand if you'd rather. Windows 10 and 11 were never affected.
## Nothing else has changed ## Nothing else has changed
Same wire format, same codec list, same audio cues, same everything else from v3.1. If you didn't see the stuck-tooltip issue, this update is small and silent — but worth taking because the underlying cause was a real Windows shell behaviour and the fix is solid. Same wire format, same codec list, same audio cues, same everything else from v3.1. v3.1.2 talks to v3.0.x and v3.1.x peers exactly as before.
## Install ## Install
1. Download `RemSound-v3.1.1.zip` from this release. 1. Download `RemSound-v3.1.2.zip` from this release.
2. Close RemSound. 2. Close RemSound.
3. Extract the zip **over your existing RemSound folder**, overwriting program files when prompted. The zip is program files only — it will not touch your profiles, settings or recordings. 3. Extract the zip **over your existing RemSound folder**, overwriting program files when prompted. The zip is program files only — it will not touch your profiles, settings or recordings.
4. Run `RemSound.exe`. 4. Run `RemSound.exe`.
## Upgrading ## Upgrading
**v1.9 through v3.1:** Help → Check for updates works — it will fetch and install v3.1.1 automatically. If you've ticked "Check for updates on startup" and "Silently install updates", v3.1.1 installs itself shortly after launch. **v1.9 through v3.1.1:** Help → Check for updates works — it will fetch and install v3.1.2 automatically. If you've ticked "Check for updates on startup" and "Silently install updates", v3.1.2 installs itself shortly after launch.
**v1.8 and earlier:** the auto-updater in those versions has a fault that prevents it from installing updates, so Check for updates will download v3.1.1 but not apply it. Install v3.1.1 by hand using the steps above — just this once. From the build you install onward, updates are automatic. **v1.8 and earlier:** the auto-updater in those versions has a fault that prevents it from installing updates, so Check for updates will download v3.1.2 but not apply it. Install v3.1.2 by hand using the steps above — just this once. From the build you install onward, updates are automatic.
+2 -2
View File
@@ -217,12 +217,12 @@ ul, ol { padding-left: 1.4em; }
<p>When RemSound is <strong>minimised to the tray</strong> (via <strong>File &rarr; Minimise to tray</strong>, the &ldquo;Show or hide window&rdquo; global hotkey, or by starting minimised on launch), the main window hides and an icon appears in your Windows system tray (the small icons cluster next to the clock).</p> <p>When RemSound is <strong>minimised to the tray</strong> (via <strong>File &rarr; Minimise to tray</strong>, the &ldquo;Show or hide window&rdquo; global hotkey, or by starting minimised on launch), the main window hides and an icon appears in your Windows system tray (the small icons cluster next to the clock).</p>
<p><strong>Hovering over the tray icon</strong> shows a short summary of what RemSound is doing right now &mdash; the number of healthy peers, whether you're sending or receiving and in which mode (WASAPI, ASIO, or both), and how long any current recording has been running. The summary refreshes every second. Examples:</p> <p><strong>Hovering over the tray icon</strong> shows a short summary of what RemSound is doing right now &mdash; the number of healthy peers, whether you're sending or receiving and in which mode (WASAPI, ASIO, or both), and whether a recording is running. The summary keeps itself up to date as things change. It tells you a recording is in progress, but not its exact length &mdash; for that, glance at the main window. Examples:</p>
<ul> <ul>
<li><em>RemSound &mdash; not connected</em></li> <li><em>RemSound &mdash; not connected</em></li>
<li><em>RemSound &mdash; 2 peers, sending (WASAPI), receiving (WASAPI)</em></li> <li><em>RemSound &mdash; 2 peers, sending (WASAPI), receiving (WASAPI)</em></li>
<li><em>RemSound &mdash; recording for 5:23, 1 peer, sending (WASAPI + ASIO), receiving (WASAPI + ASIO)</em></li> <li><em>RemSound &mdash; recording, 1 peer, sending (WASAPI + ASIO), receiving (WASAPI + ASIO)</em></li>
</ul> </ul>
<p><strong>Right-clicking the tray icon</strong> opens a small menu with everything you might want to reach without re-opening the main window:</p> <p><strong>Right-clicking the tray icon</strong> opens a small menu with everything you might want to reach without re-opening the main window:</p>
+38
View File
@@ -20,6 +20,44 @@ internal sealed class AboutDialog : Form
/// updates" path.</summary> /// updates" path.</summary>
private const string ReleaseNotes = private const string ReleaseNotes =
""" """
RemSound v3.1.2
A small accessibility fix for the system tray
icon, plus a clearer "check for updates" message
for Windows 7.
The tray icon's double announcement: if you use a
screen reader, the tray icon could read out two
states one after the other for example "no peers"
and then "1 peer" every time you landed on it. It
always happened in that same order. Windows stamps
a tray icon's name at the moment the icon appears,
which on a fresh start is a second before your other
machine has reconnected so the name was frozen as
"no peers" while only the hover text caught up to
"1 peer". RemSound now refreshes the icon itself
whenever something real changes a peer connecting
or dropping, sending or receiving switching on or
off, a recording starting or stopping so the
screen reader hears a single, current state.
Recording in the tray: while a recording is running
the tray now simply says "recording" rather than
counting the seconds. A live timer would have made
the icon flicker or read out a stale time; the exact
length is on the main window if you need it.
Windows 7 update message: on a Windows 7 machine
that can't make a secure connection to the update
server, "Check for updates" used to say "you're on
the latest version", which was misleading. It now
explains that the secure connection failed and points
to the Windows updates that fix it, with a manual
download link as a fallback. Windows 10 and 11 were
never affected.
Everything else from v3.1 is unchanged.
RemSound v3.1.1 RemSound v3.1.1
Hot-fix for a small but annoying bug with the system Hot-fix for a small but annoying bug with the system
+9 -22
View File
@@ -5292,14 +5292,15 @@ public sealed class MainForm : Form
if (ph.State == PeerHealthState.Healthy) healthyPeers++; if (ph.State == PeerHealthState.Healthy) healthyPeers++;
} }
} }
// Recording timer — only included when a recording is actually running. Slots in // Recording status — a plain "recording" flag while a capture is running, with no
// right after the "RemSound" leader as Ed asked, so it reads as a status on the // elapsed timer. A live timer would have to rewrite the tooltip every second, which
// app itself rather than a property of the peer list. // fights the tray icon's re-stamp-on-change behaviour: it would either flicker the
string? recordingPart = null; // icon once a second or leave a screen reader announcing a stale time next to the live
if (recordingController.IsRecording && recordingController.RecordingStartedUtc is { } startedUtc) // one. Recording starting and stopping are real state changes that re-stamp cleanly;
{ // the second-by-second count is intentionally left to the main window. Slots in right
recordingPart = $"recording for {FormatRecordingElapsed(DateTime.UtcNow - startedUtc)}"; // after the "RemSound" leader so it reads as a status on the app itself rather than a
} // property of the peer list.
string? recordingPart = recordingController.IsRecording ? "recording" : null;
if (healthyPeers == 0 && !sendMyAudioCheckbox.Checked && !receiveAudioCheckbox.Checked) if (healthyPeers == 0 && !sendMyAudioCheckbox.Checked && !receiveAudioCheckbox.Checked)
{ {
return recordingPart is null return recordingPart is null
@@ -5346,20 +5347,6 @@ public sealed class MainForm : Form
return list.CheckedItems.Count > 0; return list.CheckedItems.Count > 0;
} }
/// <summary>Compact duration formatter for the tray tooltip's "recording for X" segment.
/// Under an hour shows MM:SS; from an hour on it shows H:MM:SS — the same shape Windows
/// uses for media-player elapsed-time displays, so it reads naturally to people who
/// don't otherwise know it's a custom format.</summary>
private static string FormatRecordingElapsed(TimeSpan elapsed)
{
// Negative elapsed (clock skew across a sleep cycle) gets clamped to zero — better
// than displaying "-00:01" mid-tooltip.
if (elapsed < TimeSpan.Zero) elapsed = TimeSpan.Zero;
return elapsed.TotalHours >= 1
? $"{(int)elapsed.TotalHours}:{elapsed.Minutes:D2}:{elapsed.Seconds:D2}"
: $"{elapsed.Minutes:D2}:{elapsed.Seconds:D2}";
}
/// <summary>Pretty-print "WASAPI", "ASIO", "WASAPI + ASIO", or "no devices" depending /// <summary>Pretty-print "WASAPI", "ASIO", "WASAPI + ASIO", or "no devices" depending
/// on which of the two flags are set. "no devices" covers the awkward case where the /// on which of the two flags are set. "no devices" covers the awkward case where the
/// user has the send/receive checkbox on but hasn't ticked anything for the engine to /// user has the send/receive checkbox on but hasn't ticked anything for the engine to
@@ -40,6 +40,13 @@ internal sealed class MainFormTrayController : IDisposable
private readonly Func<string> buildTooltip; private readonly Func<string> buildTooltip;
private readonly Action exit; private readonly Action exit;
/// <summary>The tooltip text the icon was last (re-)registered with. We compare against
/// this so we only re-register on a real state change — a peer connecting or dropping, a
/// lane switching, a recording starting or stopping. The tray tooltip has no per-second
/// element (recording shows a plain "recording" flag, not a ticking timer), so the text
/// only changes on those real events and the icon never flickers. Null until first shown.</summary>
private string? lastRegistrationText;
private readonly ToolStripMenuItem sendingItem; private readonly ToolStripMenuItem sendingItem;
private readonly ToolStripMenuItem receivingItem; private readonly ToolStripMenuItem receivingItem;
private readonly ToolStripMenuItem profilesItem; private readonly ToolStripMenuItem profilesItem;
@@ -152,6 +159,38 @@ internal sealed class MainFormTrayController : IDisposable
// NotifyIcon.Text throws on the same string-assigning path under some shell // NotifyIcon.Text throws on the same string-assigning path under some shell
// conditions (rare race during a session-end). Best-effort: swallow. // conditions (rare race during a session-end). Best-effort: swallow.
try { trayIcon.Text = text; } catch { /* harmless */ } try { trayIcon.Text = text; } catch { /* harmless */ }
// Keep the icon's *registered* name — the text a screen reader announces — in step
// with the live state. Windows stamps a tray icon's accessible name at the moment the
// icon is added (NIM_ADD) and afterwards only refreshes the little hover bubble, not
// that stamped name. So if the icon appears at launch before the first peer has
// connected, the name is frozen as "no peers"; when the peer links up a second later
// the bubble updates to "1 peer" but the frozen name stays — and NVDA reads BOTH (the
// stale name, then the live bubble), which is the confusing double announcement.
//
// The cure is to re-add the icon (hide then re-show = NIM_DELETE + NIM_ADD) whenever
// the text changes, which re-stamps the name with the current text. This is exactly
// what the old "show the window then minimise again" workaround did by hand. The tray
// tooltip has no per-second element (recording shows a plain "recording" flag, not a
// ticking timer), so the text only changes on real events and this never flickers.
if (!trayIcon.Visible)
{
// The first call arrives from Minimize() a moment before the icon is shown — just
// record the baseline so the NIM_ADD that immediately follows is our reference.
lastRegistrationText = text;
return;
}
if (text == lastRegistrationText) return;
// Don't yank the icon out from under an open right-click menu (that would dismiss it
// mid-navigation). Leave the record stale so the next tick re-stamps once it closes.
if (trayIcon.ContextMenuStrip?.Visible == true) return;
lastRegistrationText = text;
try
{
trayIcon.Visible = false;
trayIcon.Visible = true;
}
catch { /* harmless — the 1 Hz snapshot tick will try again next second */ }
} }
public void Toggle() public void Toggle()
+1 -1
View File
@@ -14,7 +14,7 @@
tag_name on the latest GitHub release; bump it on every public release. The tag_name on the latest GitHub release; bump it on every public release. The
AssemblyVersion / FileVersion default to this value, and Assembly.GetName().Version AssemblyVersion / FileVersion default to this value, and Assembly.GetName().Version
is what the About dialog and the updater both read. --> is what the About dialog and the updater both read. -->
<Version>3.1.1</Version> <Version>3.1.2</Version>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>