Skip to content

Commit 88fdb6b

Browse files
ten9876claude
andauthored
docs: expand v0.9.5.1 release notes with all post-v0.9.5 fixes (#2288)
The v0.9.5.1 entry was originally cut for just the TCI TX hotfix (#2285), but six additional fixes had already landed in main between the v0.9.5 tag and v0.9.5.1: - #2275 NR2 wisdom generation off the audio thread - #2278 SmartLink disconnect teardown - #2279 Reset RX slice tabs on disconnect (#2254) - #2280 macOS panadapter pop-out refresh + multi-pan dock layout - #2282 SmartLink reconnect after WAN drop - #2284 Qt log handler serialization fixes macOS tune-time crash CHANGELOG.md gets a per-fix entry with root cause + behavior change. WhatsNewData.cpp regenerated via scripts/gen_whatsnew.py so the in-app What's New dialog reflects the full v0.9.5.1 contents. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d2f382f commit 88fdb6b

2 files changed

Lines changed: 94 additions & 15 deletions

File tree

CHANGELOG.md

Lines changed: 88 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,105 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
55

66
## [v0.9.5.1] — 2026-05-02
77

8-
### TCI TX hotfix
8+
### Stability & polish hotfix sweep
99

10-
Hotfix for a regression introduced by the v0.9.5 DAX2 coexistence policy
11-
(#2271): TCI digital TX (WSJT-X / JTDX / MSHV) was silent on Windows and
12-
Linux non-PipeWire because `evaluateDaxTxPolicy()` denied `dax_tx`
13-
stream creation for `TciTxAudio` on those platforms. The radio was
14-
told `dax=1` but no audio packets ever flowed, so the modulator stayed
15-
silent during TX.
10+
A focused follow-up release that lands the TCI TX policy hotfix plus six
11+
post-v0.9.5 fixes already in main: SmartLink WAN reconnect after radio
12+
drops, sequenced WAN disconnect teardown, RX slice-tab reset between
13+
radios with different slice counts, macOS panadapter pop-out live
14+
updates and dock-splitter layout, NR2 wisdom-generation safety on the
15+
audio thread, and a Qt log-handler serialization fix that resolves a
16+
macOS tune-time crash.
1617

17-
The conceptual mistake: SmartSDR DAX2 owns the Windows DAX *audio
18-
devices*, not the radio's `dax_tx` stream slot. Multiple GUI clients
19-
can each register their own `dax_tx` stream, and TCI's audio source is
20-
a WebSocket — it doesn't touch the local DAX devices at all, so there's
21-
no conflict.
22-
23-
### Bug fix
18+
### Bug fixes
2419

2520
**TCI TX silent on Windows / Linux non-PipeWire (#2276)**
2621
- `evaluateDaxTxPolicy()` now always allows `DaxTxRequestReason::TciTxAudio`
2722
regardless of platform / hosted-DAX availability. TCI receives audio
2823
over WebSocket and feeds it into a dedicated `dax_tx` stream that's
29-
independent of SmartSDR DAX2.
24+
independent of SmartSDR DAX2 (which owns the Windows DAX *audio
25+
devices*, not the radio's `dax_tx` stream slot — multiple GUI clients
26+
can each register their own).
3027
- Test assertions in `tests/radio_status_ownership_test.cpp` flipped to
3128
match the corrected policy and a new Linux-non-PipeWire test case
3229
added.
3330

31+
**SmartLink reconnect after WAN drop (#2282)**
32+
- `MainWindow` now owns a WAN reconnect timer that re-requests a
33+
SmartLink radio connection using the last selected WAN radio when
34+
`RadioModel` reports an unexpected WAN disconnect, instead of
35+
leaving the app stuck on the "Radio disconnected — waiting for
36+
reconnect" popup.
37+
- `SmartLinkClient::reconnect()` refreshes Auth0 credentials via the
38+
saved refresh token before reconnecting, avoiding reuse of an
39+
expired `id_token`. Auth-refresh failure stops the retry loop and
40+
shows a sign-in-required status instead of retrying forever.
41+
- `RadioModel::forceDisconnect()` now handles WAN connections so
42+
missed pings transition the app to disconnected/reconnecting
43+
promptly. Ping watchdog logs and forces disconnect once per outage
44+
rather than every second.
45+
- `PanadapterStack::prepareShutdown()` releases QRhi GPU resources
46+
before main-window teardown to avoid the macOS Metal teardown crash
47+
that could fire after a stale-state Disconnect.
48+
49+
**SmartLink disconnect teardown (#2278)**
50+
- WAN disconnect previously closed the WAN socket *after* disconnecting
51+
RadioModel's signals and nulled `m_wanConn` directly, skipping
52+
`RadioModel::onDisconnected()` cleanup entirely. Panadapters,
53+
slices, meters, and streams stayed alive in the model after the user
54+
clicked Disconnect.
55+
- Now runs the normal model teardown path on intentional WAN
56+
disconnect, so WAN sessions emit `connectionStateChanged(false)` and
57+
clear model state the same way LAN disconnects do.
58+
59+
**Reset RX slice tabs on disconnect between radios with different slice counts (#2254)**
60+
- `RxApplet::clearSliceButtons()` tears down generated slice tab buttons
61+
and restores the static slice badge on disconnect. Stale A–H buttons
62+
no longer linger after switching from a high-slice radio to a
63+
smaller one.
64+
- `MainWindow`'s `infoChanged` initializer is now per-connection rather
65+
than one-shot, so each radio rebuilds its slice row from its own
66+
`maxSlices`. Slice button click connections are guarded against
67+
duplicate signal handlers across reconnects.
68+
69+
**Qt log handler serialization fixes macOS tune-time crash (#2284)**
70+
- The global `qInstallMessageHandler` callback wrote through a single
71+
`QFile*` without synchronization, and concurrent `qCInfo`/`qDebug`
72+
output from main + worker threads corrupted Qt's internal file
73+
write-buffer state. The tune-policy diagnostic line happened to be
74+
the log call that exposed the corruption — the failing object was
75+
the logging sink, not the Flex tune command path.
76+
- Now serializes the handler with an intentionally leaked mutex
77+
(mirroring the existing shutdown-safe treatment of the redaction
78+
regexes) and replaces per-message `QTextStream` wrapping with a
79+
direct UTF-8 `QFile::write()`/`flush()` path. No change to radio
80+
command ordering or panadapter policy.
81+
82+
**macOS panadapter pop-out refresh + multi-pan dock layout (#2280)**
83+
- Detached panadapter windows on macOS no longer show a static/stale
84+
spectrum image. Cross-window reparenting now resets the native
85+
QRhi/Metal surface and re-requests pan dimensions from the radio
86+
after every float/dock cycle.
87+
- Saved floating-window state is no longer restored after later
88+
user-added pans, so adding a second panadapter does not spawn an
89+
unwanted blank floating window.
90+
- `rebuildDockedSplitter()` keeps the main-window splitter compact
91+
when multiple pans float/dock — no more empty placeholder slots.
92+
93+
**NR2 wisdom generation no longer freezes the audio thread (#2275)**
94+
- `AudioEngine::needsWisdomGeneration()` previously only checked
95+
whether `aethersdr_fftw_wisdom` existed. If the file was stale or
96+
incompatible (e.g. `fftw-3.3.10` header on a build that uses FFTW
97+
3.3.11), `setNr2Enabled()` ran full FFTW wisdom generation on the
98+
audio worker thread, blocking RX audio and the WAVE scope for
99+
several minutes.
100+
- Adds `SpectralNR::loadWisdom()` for import-only validation, makes
101+
`needsWisdomGeneration()` return true when the file exists but
102+
cannot be imported, and routes generation through the existing
103+
background progress dialog instead of the audio thread. If wisdom
104+
import fails at enable time, NR2 falls back to runtime
105+
`FFTW_MEASURE` plans rather than hanging audio.
106+
34107
## [v0.9.5] — 2026-05-02
35108

36109
### Reliability sweep + DAX2 coexistence overhaul

src/generated/WhatsNewData.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ const std::vector<ReleaseEntry>& whatsNewEntries() {
88
static const std::vector<ReleaseEntry> entries = {
99
{QStringLiteral("0.9.5.1"), QStringLiteral("2026-05-02"), QStringLiteral(""), {
1010
{ChangeCategory::BugFix, QStringLiteral("TCI TX silent on Windows / Linux non-PipeWire"), QStringLiteral("`evaluateDaxTxPolicy()` now always allows `DaxTxRequestReason::TciTxAudio` regardless of platform / hosted-DAX availability. TCI receives audio over WebSocket and feeds it into a dedicated `dax_tx...")},
11+
{ChangeCategory::BugFix, QStringLiteral("SmartLink reconnect after WAN drop"), QStringLiteral("`MainWindow` now owns a WAN reconnect timer that re-requests a SmartLink radio connection using the last selected WAN radio when `RadioModel` reports an unexpected WAN disconnect, instead of leavin...")},
12+
{ChangeCategory::BugFix, QStringLiteral("SmartLink disconnect teardown"), QStringLiteral("WAN disconnect previously closed the WAN socket *after* disconnecting RadioModel's signals and nulled `m_wanConn` directly, skipping `RadioModel::onDisconnected()` cleanup entirely. Panadapters, s...")},
13+
{ChangeCategory::BugFix, QStringLiteral("Reset RX slice tabs on disconnect between radios with different slice counts"), QStringLiteral("`RxApplet::clearSliceButtons()` tears down generated slice tab buttons and restores the static slice badge on disconnect. Stale A–H buttons no longer linger after switching from a high-slice radio...")},
14+
{ChangeCategory::BugFix, QStringLiteral("Qt log handler serialization fixes macOS tune-time crash"), QStringLiteral("The global `qInstallMessageHandler` callback wrote through a single `QFile*` without synchronization, and concurrent `qCInfo`/`qDebug` output from main + worker threads corrupted Qt's internal file...")},
15+
{ChangeCategory::BugFix, QStringLiteral("macOS panadapter pop-out refresh + multi-pan dock layout"), QStringLiteral("Detached panadapter windows on macOS no longer show a static/stale spectrum image. Cross-window reparenting now resets the native QRhi/Metal surface and re-requests pan dimensions from the radio a...")},
16+
{ChangeCategory::BugFix, QStringLiteral("NR2 wisdom generation no longer freezes the audio thread"), QStringLiteral("`AudioEngine::needsWisdomGeneration()` previously only checked whether `aethersdr_fftw_wisdom` existed. If the file was stale or incompatible (e.g. `fftw-3.3.10` header on a build that uses FFTW 3...")},
1117
}},
1218
{QStringLiteral("0.9.5"), QStringLiteral("2026-05-02"), QStringLiteral("Reliability sweep + DAX2 coexistence overhaul"), {
1319
{ChangeCategory::Feature, QStringLiteral("Aetherial Parametric EQ Smoothing combo"), QStringLiteral("New Smoothing combo on the EQ analyzer with 1/24, 1/12, 1/6, 1/3, 1/1 octave fractional smoothing options (linear-power averaging). Persists via `EqAnalyzerSmoothing`; defaults to 1/12 octave. Audi...")},

0 commit comments

Comments
 (0)