feat(network): VITA-49 RX buffer — raise default to 4 MiB + operator-adjustable slider (#3810)#3811
Conversation
…drops Closes #3810. The PanadapterStream UDP socket never raised SO_RCVBUF, so it used the OS default (~208 KB on Linux). VITA-49 bursts (panadapter FFT + waterfall + audio + meters) — or a brief worker-thread drain stall under host load — overflow that buffer; the kernel drops the excess, which surfaces as VITA-49 sequence gaps. RadioModel::evaluateNetworkQuality() reads those as packet loss, degrades the net state, and the adaptive throttle caps the radio's pan FPS (down to 4 fps) — the visible 'network stats drop at various times'. Live evidence: a running session's stream socket showed 370 receive-buffer overflow drops (ss -m d370) against an rb212992 (~208 KB) buffer, arriving in a burst rather than a steady leak. Fix: request a 4 MiB SO_RCVBUF on the bound socket (all three bind paths: LAN, ephemeral rebind, WAN) via a shared applyReceiveBufferSize() helper, and log the granted size — the kernel caps the request at net.core.rmem_max, so a too-small rmem_max is now visible in the logs instead of silently limiting us. Absorbs normal bursts so they no longer present as false sequence-loss and stop tripping the throttle. Cross-platform (ReceiveBufferSizeSocketOption). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Thanks for this, @ten9876 — clean, tightly-scoped fix with a well-argued root cause. The change is solid and I'd be comfortable seeing it merge. A few observations:
What's good
applyReceiveBufferSize()is correctly called after a successfulbind()and before the UDP registration datagram on all three paths (start,rebindToEphemeralPort,startWan), so the buffer is enlarged before the radio can start sending. Good that you didn't miss the WAN site.m_socketnull-guard up front,QAbstractSocket::ReceiveBufferSizeSocketOptionfor cross-platform behavior, and logging the granted size to expose an undersizednet.core.rmem_max— all the right instincts at this system boundary.- No conventions concerns (no settings, no ownership/RAII surface), and it stays within the two files the PR claims.
One thing worth a note (cosmetic, not blocking):
On Linux the kernel stores SO_RCVBUF as double the requested value for its own bookkeeping, and getsockopt(SO_RCVBUF) (which Qt's socketOption() reads) returns that doubled figure. So on an uncapped host, requesting 4 MiB will log granted=8388608 — roughly 2× what you asked for — which can read as surprising. The capped-detection logic still works correctly (a 208 KB rmem_max doubles to ~416 KB, still < 4 MiB), so this is purely a log-readability point. If you want the log to be unambiguous you could note the doubling, e.g. append (Linux reports 2×) or halve the displayed value on Linux — but it's entirely optional.
Minor, optional: the 4 MiB target is a hardcoded constant. Fine as a default for this fix; just flagging that if a future host needs tuning it'd require a rebuild rather than a setting. Not worth changing now.
The test plan still has the live-FLEX verification boxes unchecked — worth confirming the granted= log lands near 4 MiB and the ss -m drop counter stops climbing on real hardware before merge, since that's the actual proof the buffer size resolves the symptom. Nice work.
🤖 aethersdr-agent · cost: $7.1913 · model: claude-opus-4-8
…der) Extends the SO_RCVBUF fix into a user-tunable control. Radio Setup → Advanced gets a snap-to-preset slider (256K / 512K / 1M / 2M / 4M, default 4M) for the VITA-49 stream socket receive buffer, with a live 'granted:' readout so the kernel's net.core.rmem_max clamp is visible rather than silently limiting the request. - NetworkSettings (new): persists the request as nested JSON under the single AppSettings 'Network' key (Principle V — no new flat keys). - PanadapterStream: seeds m_desiredRcvBufBytes from NetworkSettings at init; applyReceiveBufferSize() requests it on every bind, records the granted size, and emits receiveBufferApplied(requested, granted). New Q_INVOKABLE setReceiveBufferSizeBytes() re-applies live on the network worker thread. - RadioSetupDialog: the slider persists the choice and re-applies live via QMetaObject::invokeMethod onto the worker thread (mirrors the existing PLC toggle), and the granted label updates from receiveBufferApplied (queued). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update: the buffer is now operator-adjustablePer maintainer request, extended this beyond the fixed 4 MiB into a user control. Radio Setup → Advanced → "VITA-49 RX buffer" — a snap-to-preset slider (256K / 512K / 1M / 2M / 4M, default 4M) with a live How it's wired
Latency note (raised in review)
Test plan (updated)
|
|
Should there be an “auto” mode that self adjusts based on observed metrics over some timeframe? |
Summary
Closes #3810. Raises
SO_RCVBUFon thePanadapterStreamVITA-49 UDP socket to 4 MiB, fixing the "network stats drop at various times" symptom.Root cause
The stream socket never set
SO_RCVBUF, so it used the OS default (~208 KB on Linux). VITA-49 bursts (panadapter FFT + waterfall tiles + audio + meters) — or a brief worker-thread drain stall under host load — overflow that buffer; the kernel drops the excess. Those drops surface as VITA-49 sequence gaps →RadioModel::evaluateNetworkQuality()reads them as packet loss → degrades the net state → the adaptive throttle caps the radio's pan FPS (down to 4 fps) → visible stat drop, held 5 s (min-dwell), then lifts → re-trips on the next burst.Live evidence: a running session's stream socket showed 370 receive-buffer overflow drops (
ss -m→d370) against anrb212992(~208 KB) buffer, arriving in a burst, not a steady leak.Change
applyReceiveBufferSize()helper, called after a successful bind on all three paths (LANstart, ephemeralrebindToEphemeralPort,startWan).net.core.rmem_max, so an undersizedrmem_maxis now visible in the logs (granted=… (capped by net.core.rmem_max …)) instead of silently limiting the buffer.QAbstractSocket::ReceiveBufferSizeSocketOption). +36 lines, one subsystem.Test plan
granted=near 4 MiB; the stream socket'sss -mdrop counter stops climbing across bursts/band-changesstartWancall site)Relation to #3797
The pegged GUI thread (#3797) makes overflow more likely (it can stall the socket drain during bursts), so the two compound — but the buffer is the directly fixable root for this symptom; #3797 is the separate render-side bottleneck.
🤖 Generated with Claude Code