Bump to v2.2.0: Opus native binding, efficiency tidy-up, diag self-meter

Single biggest change: added the Concentus.Native NuGet package. Concentus
2.0+ auto-detects native libopus at runtime and routes encode calls
through it; encoder state lives on the C side and is reused across calls
rather than `new`ing ~15 working buffers per call (Concentus issue #22,
open since 2018). Measured on the desktop test at 15:36:55 — Opus 10 ms
allocation rate dropped from 4,625 KB/s to 108 KB/s, a 97.7% reduction.
Process CPU dropped from 4.7% to 1.6% in the same config. Audio is bit-
for-bit identical (it's literally the same encoder, just better
packaged). `OpusEncoderState.cs` itself unchanged on the call site.

Diagnostic / measurement layer (gated on Enable-logs, zero cost when off):
* ProcessSelfMeter: CPU%, managed heap MB, working set MB, allocation
  rate per second, GC counts per generation
* Per-thread work-time counters: captureMs / sendMs / recvMs / renderMs
  expressed as milliseconds of CPU consumed by each audio thread per
  second
* Inter-packet arrival gap measured at the user-space UDP socket
  (rxNetGapMs) — pinpoints whether arrival jitter is in the network or
  our own dispatch path

Small efficiency wins (each one was small but cumulative):
* deviceRefreshTimer interval 1s -> 3s (item 4)
* WaitHandle array allocations eliminated in MixingEngine.MixLoop and
  MultiOutputPlayout.ProduceLoop (item 6)
* MultiOutputPlayout caches its output-buffer snapshot and only rebuilds
  on SetOutputDevices, instead of rebuilding every 10 ms (item 7)
* HeartbeatService reuses an outbound ping byte[] instead of allocating
  per send (item 14)
* PeerDiscoveryService caches broadcast addresses and invalidates on
  Windows' NetworkChange event instead of walking all NICs every 1.5 s
  (item 16)

Legacy / dead-code removal:
* KeepAlive packet's implementation (struct, enums, writer, reader, size
  constant) — all dead since HeartbeatService landed 2026-05-06. Kept
  the RemPacketType.KeepAlive enum value and silent-drop dispatch for
  wire compat with any pre-2026-05-06 build still in the wild (item 30)
* driftDropFramesTotal / driftRepeatFramesTotal fields and accessors —
  Phase-2 splice corrector relics, never incremented since Phase-4
  resampler design landed; backed five always-zero diag log columns
  (items 34 + 35)
* DriftAccumulator (always returned 0) — same shape, removed alongside
  the driftAcc= column (item 35)
* TakeMaxFanOutCacheBytes / Ms + fanCacheMs column — FanOutSource was
  retired in May (item 36)

Project documentation:
* RemSoundefficiency.md added as the canonical record of the efficiency
  analysis, every item's status, and the measured wins from this round
* Honest item-by-item review of the original 50-item list — several
  items I had sized optimistically in the original analysis turned out
  to be already-done (item 20), already-optimal (item 22), or below
  the meter floor (items 9, 15, 17, 25). Recorded so future passes
  don't re-investigate.

Wire format and audio pipeline unchanged from v1.5 onward — v1.5 through
v2.2 peers interoperate.
This commit is contained in:
Ednunp
2026-05-23 15:56:03 +01:00
parent 79b28b6c02
commit 6d6d6897e4
22 changed files with 847 additions and 232 deletions
+50 -7
View File
@@ -20,14 +20,57 @@ internal sealed class AboutDialog : Form
/// updates" path.</summary>
private const string ReleaseNotes =
"""
RemSound v2.1
RemSound v2.2
Automatic router setup for internet streaming, a small
notice before background updates install, a "lock this
profile" option for users who don't want close prompts,
and a fix for the "no sound after the laptop wakes up"
problem. No wire-format or audio-pipeline changes
v1.5 through v2.1 peers interoperate.
A maintenance release that makes RemSound use less of
your computer's CPU and memory, especially when sending
with the Opus codec. No new features to learn, no
settings have changed, and audio sounds exactly the same.
Wire format and audio pipeline are unchanged every
version from v1.5 to v2.2 still talks to every other
version cleanly.
What's lighter on your computer:
* Opus sending uses much less memory. RemSound's
Opus encoder used to put quite a lot of work on
Windows' memory manager about 4 megabytes per
second of "throwaway" memory churn while sending
Opus audio. v2.2 ships a native build of the same
encoder that does its work in a tighter, faster way.
The audio you hear is identical (it really is the
same encoder, just packaged better); the memory
churn drops by about 97 per cent. On laptops you
should see less background CPU when streaming Opus,
and longer sessions are less likely to see brief
pauses while Windows tidies up memory.
* Smaller all-round efficiency tidy-up. A handful of
small fixes RemSound checks the audio-device list
less often, reuses some small bits of memory it
used to make fresh each time, and skips some
paperwork on the receive side when there's nothing
to do. Each one is small on its own; together they
cut RemSound's everyday memory churn modestly.
* Removed some old leftover code that was retired
months ago but still lived on as zero-valued
columns in the diagnostic log. Same behaviour,
cleaner files.
For people who use the diagnostic logs:
* Several new columns. "cpu" shows how much of one
CPU core RemSound just used. "memMB" and "wsMB" are
its memory footprint. "allocKBps" is the per-second
memory-churn rate. "captureMs / sendMs / recvMs /
renderMs" show how busy each of the four audio
threads is. All of this only writes to the log when
Enable logs is ticked; with logs off it costs
nothing.
* "fanCacheMs", "driftDrop", "driftRep" and "driftAcc"
columns have been removed they were always zero
after the playback engine changed in May.
No bug fixes in v2.2 specifically everything carried
over from v2.1's UPnP, lock-profile, wake-from-sleep
and hibernate fixes is still in place.
What's new:
* Automatic router port opening (UPnP). RemSound can