Repository navigation
[RFC] Optional Digital FM reception and program metadata #6079
Description
Status and scope
Separate RFC, pending maintainer approval. I am moving the optional Digital FM proposal out of #5468 following review feedback. #5468 governs the analog RTL receive work. Its conditional approval does not approve this new modulation, dependencies or decoder worker.
Implementation reference: draft #6002. It remains an evaluation proposal, not part of the current analog RTL submission. ENABLE_HD_FM keeps its existing name and remains default OFF; official publishing workflows must explicitly keep it OFF. No request here changes analog RTL's release inclusion or requires analog PRs to wait for this proposal.
Problem
Analog broadcast FM reception cannot decode digital broadcast services, select their independent programs, or display their digital station/program metadata. This is a separate receive mode with new dependencies and execution/resource requirements, not a prerequisite for RTL FM/FM-N/WFM mono or stereo.
Proposal
Review the bounded embedded decoder design below as one independent feature. Aether owns USB acquisition; the optional decoder consumes original captured IQ. Preserve existing analog reception when the option is disabled or digital lock is absent. This proposal does not implicitly approve automatic analog/digital blending.
The decision covers dependency inclusion, a private decoder worker and teardown bounds, complete digital RF-footprint admission, 44.1 kHz selected-program PCM with explicit speaker-rate conversion, program selection, and measured digital state/metadata in the WFM applet and local overlay. Analog RDS decoding is not implemented by this proposal.
Cross-platform impact and qualification
The initial Linux/GNU-C checkpoint and later private macOS/Windows evaluation builds are evidence only for their exact revisions. The feature needs native configure/build/test coverage ON and OFF on each supported release platform, dependency/notices/source packaging, bounded startup/replacement/teardown and long-running audio/resource qualification. macOS arm64 results do not qualify Linux aarch64. Failed historical observations below remain open; operator acceptance does not erase them.
Alternatives considered
- Ship analog RTL first and defer Digital FM: the current submission plan.
- Run an external decoder process: not the proposed integration; Aether would lose its single in-process ownership and lifecycle model.
- Embed the optional decoder behind the existing build flag: the proposal under review, conditional on maintainers accepting the dependency and lifetime design.
Decision requested
Jeremy: approve, reject or request changes to this standalone Digital FM design. A decision applies only to this RFC and #6002. Analog capture, free panning, analog stereo, PPM, multi-RX, DAX/TCI and RTL release packaging retain their own review criteria. Their approval does not depend on acceptance of this RFC.
Branch separation
Current separation — 2026-10-09: analog WFM and PPM are merged into main. Ready #6083 (a3458b09) contains only the remaining analog delivery on main d6f6a4f0. Draft #6002 (a8112373) is stacked on that analog head.
This Digital increment owns the actual default-OFF ENABLE_HD_FM option, the explicit OFF flags in all three release workflows and both local build/installer entry points, and the corresponding build documentation. Analog #6083 no longer declares or passes this option. Pinned decoder sources and the existing ON implementation are preserved. Fresh exact-head Linux/GCC focused validation passes: decoder OFF 15/15 and ON 17/17, zero skips/failures, including spectrum geometry, WFM controls, PCM/routing and native decoder tests as applicable. The full user-documentation build also passes. Details and limits are recorded in #6002; this does not change draft or release status.
Original separation checkpoint — historical evidence
Branch separation is complete. Analog #6082 (5e39790a) now follows #5974; #6083 (4b1816ac) follows #6082 without decoder code or dependencies. Draft #6002 (634fdd28) follows #6083. The extracted analog application builds and 39/39 selected native Mac tests pass. This is a real Git dependency change, not just a documentation edit. Digital production code/build implementation is preserved from a53423ac; prior history is retained on codex/rtl-digital-evaluation-preserved-20261001. No new Digital ON qualification is claimed.
Historical evaluation and proposed Digital FM architecture — 2026-09-28
The analog WFM applet (6e87be85, #5974), optional native Digital (dea570a2, #6002) and live PPM adjustment (7911324a, #6003) are published as draft PRs. 7911324 is now the normal Nobara evaluation build. The operator accepted Digital (“homerun man perfect”) and PPM (“confirmed the PPM adjust works great.. got it working. nice job”). These are subjective reports, not replacements for measured qualification. PPM uses the existing typed transaction and accepted per-device persistence; it selects no calibration value or sign automatically.
Exact Nobara builds passed 60 selected CTests on dea and 63 on 791, without failed, errored or skipped cases; unavailable optional effect subcases are not claimed as exercised. PPM timer and Digital contrast mutations failed their intended assertions, followed by exact artifact restoration. Recorded-IQ evidence remains pinned to decoder-identical predecessor 3a716c2e: direct and production worker/mixer replay passed for both discovered programs with real 44.1 kHz tap/48 kHz speaker output. Concealed-audio, incomplete-prefill and initial-boundary mutations were caught and restored. These finite recording results are not new live-radio evidence.
Live persistence, overlay OFF/ON/OFF and readable actual-window contrast were observed. Live overflowing text, instrumented acoustic/nonzero-PCM capture and uninterrupted playback remain unqualified. Both earlier strict muted observers remain failed: endpoint empty-application-queue increments were +1,140 (3a) and +1,011 (dea), despite separately valid sampled Digital state. This counter is not a proven audible-glitch count. Dea also accumulated 2,236 dropped PCM packets or Digital observation messages between initial accepted restoration and the later quiet observation. These are aggregate output-queue drops, not raw USB IQ; their cause and exact interval remain unresolved. Operator acceptance does not erase these results.
Digital FM architecture proposal — not yet approved
This changes the original “no additional third-party DSP dependency” proposal. Jeremy's approval is requested for:
- Default-OFF
ENABLE_HD_FM, initially Linux/GNU C, embedding pinned nrsc50225922band FAAD2 2.11.2/HDC673a22a3with source manifests, licenses and notices. Aether remains the sole USB owner; no external decoder process is launched. - A prepared receiver's private synchronous-decoder worker with bounded IQ/PCM/observation queues and two resident leases for old/new replacement. Open/close use the existing FFTW planner lock. Internal allocation remains possible; upstream allocation-failure hardening and a hard cancellation bound for an in-progress call remain outstanding.
- Original IQ extraction before analog filtering at exactly 744187.5 complex samples/s. Complete ±225 kHz Digital sidebands plus guards must fit capture independently of saved analog filters. Selected-program slice PCM is 44.1 kHz stereo, with explicit speaker conversion to 48 kHz. Global defaults and mixer deadlines remain unchanged. Current Digital admission is one configured receiver.
- Explicit Digital/program controls with observed sync, valid selected audio and speaker readiness kept distinct. Existing transaction adoption and persistence remain authoritative. Session/receiver/audio epochs and original production age reject stale output. Proposed bounds are 32 IQ slots of at most 8192 samples, 250 ms queued-source distance, 32768-frame PCM storage, 8192-frame speaker prefill and 500 ms observation/audio age; finite tests are not universal timing guarantees.
- Bounded Digital station/ID3 text in the applet and passive local overlay. SpotHub Display's ordinary WFM RDS button defaults ON, preserves saved OFF and affects only the overlay—not decoding or network spots. Provenance identifies Digital, not analog RDS. Theme-backed word-boundary pages retain the frequency anchor, entry identity and accessible full text.
Implementation and dependency details. Original conditional approval does not approve this amendment; free-pan policy remains independently scoped to #5468. Mac/Windows/ARM Digital and current sanitizer qualification are outstanding. Keep #6002 draft pending the decision on this standalone proposal and its applicable evidence; analog successors are now independent of this feature.
The section above preserves the September 28 measurements and outstanding findings as historical evidence. Old platform/status statements describe those checkpoints. Current PR checks and later evidence remain revision-specific in #6002; this RFC is not a declaration of release readiness.
73, Ozy K6OZY · Codex
Activity
aethersdr-agent commentedon Oct 2, 2026
Triage:
maintainer-review— decision RFC, no information gapThis asks for an approve/reject/request-changes call on a design, not for a bug to be root-caused, so there is nothing to ask the reporter for. Labelled
New Feature+audio+GUI+external devicesand handed to Jeremy. I verified the RFC's load-bearing claims againstmainand against#6002(fetchedpull/6002/head) so the decision isn't made from the prose alone.What's actually in the tree today
ENABLE_HD_FMdoes not exist inmain. "Keeps its existing name" means existing in RTL: add opt-in native digital broadcast reception and local metadata #6002 only — don't go looking for the flag.src/core/backends/rtl/{RtlSdrBackend,RtlSdrWorker,RtlSdrDdc,RtlReceiverRegistry}.cpp,RtlSdrDiscovery,LocalRadioDiscoverySource.cpp:22,50. WFM is a real demod mode (RtlSdrDdc.cpp:87-88,:257-264).third_party/nrsc5/upstream/andthird_party/faad_hdc/upstream/in-tree, plus non-trivial changes tothird_party/wdsp/upstream/wbfm.c(+217) andiobuffs.c. The WDSP edits are not described anywhere in this RFC; they are part of what a yes approves.Claims I confirmed (so the decision doesn't rest on prose)
LICENSE:1-2). The pinned FAAD2/HDC fork is GPLv2-or-later (third_party/faad_hdc/upstream/COPYING:308-309,include/neaacdec.h:5-8) — upgradeable to GPLv3, so not a blocker. But that header also imposes a mandatory notice: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com". RTL: add opt-in native digital broadcast reception and local metadata #6002 carries it only inthird_party/faad_hdc/README.aethersdr.md:26, which is not a user-visible notice surface. If this is approved, the string must also land wherever the shipped app presents third-party notices — a GPLv2 §2c obligation, not a nicety.nrsc5shipsCOPYING.GPL-3.0+LICENSE-SOURCE.json; that part is clean.src/core/dsp/FftwPlannerLock.hexists (fftwPlannerMutex()/fftwfPlannerMutex()), andRtlSdrDdc.cpp:2already includes it — so a decoder open/close inbackends/rtlreaching the planner lock raises no Principle II concern.clampSampleRate()(RtlSdrBackend.cpp:53-72) snaps to a 9-entry list that has no 1488375, and RTL: add opt-in native digital broadcast reception and local metadata #6002 leaves that list alone. The rate comes from a fractional resampler instead —HdFmIqAdapter.h:18,kOutputRate = 1488375.0 / 2.0. Correct approach; the RFC's wording implies a hardware rate it never requests.RtlCaptureTransaction.cpp:474-482widenseffectivePassband()to ±225 kHz with a ≥3 kHz guard whenmode == Wfm && wfmHdStereo.The integration seam the RFC under-describes — and the one hypothesis worth testing
RFC item 3 says "global defaults and mixer deadlines remain unchanged." The audio ingress is where that gets tested, and it's the weakest-specified part:
RtlSdrDdc.cpp:290-300, fractional stage-2 to exactly 24 kSPS;AudioEngine.cpp:1897). A 44.1 kHz digital stream on the same slice means either flippingm_rxProducerRateat runtime — which rebuilds the resampler,AudioEngine.cpp:4257— or a dedicated per-source resampler. Recommend the latter;m_radeRxResampler(AudioEngine.cpp:10347-10349) is the existing precedent for exactly this shape and is what "defaults unchanged" actually requires.m_rxOutputRate, not a literal 48000.AudioEngine.cpp:4456shows QAudioSink falling back 48000 → 44100 → 24000. A hard-coded 44.1→48 stage produces wrong-pitch audio on a 24 kHz-only endpoint, and is a no-op resample on a 44.1 kHz one.AudioEngine.cpp~2255-2362). Even with no automatic blending, the analog↔digital handoff instant flips N, which is a known pumping/discontinuity source on this path. Worth instrumenting in RTL: add opt-in native digital broadcast reception and local metadata #6002 before anyone calls those counters benign — they are aggregate output-queue drops, so this is a candidate cause, not a verdict.Naming bug to fix regardless of the decision
Item 5 routes digital metadata display through SpotHub Display's button labelled "WFM RDS", while this RFC explicitly does not implement RDS. A control named for a feature that doesn't exist, gating a feature it isn't named for, will generate its own issue. Rename to something provenance-accurate (the RFC already says provenance identifies Digital, not analog RDS).
Handoff
Nothing here is a reason to block the analog RTL work — the RFC's own separation claim holds against the tree, and the one coupling is the unmerged #5974 applet that item 5 depends on. The decision is yours; the two items I'd attach conditions to if you lean approve are (a) the Nero §2c notice reaching a shipped user-visible surface, and (b) root-causing the output-queue drops before the flag is ever built ON in CI. For the CI shape the RFC asks for,
ENABLE_NVIDIA_AFXis the established template for "built ON in CI, not necessarily shipped" (ci.yml:247,664,full-suite.yml:84,appimage.yml:269,windows-installer.yml:251).I have not reviewed #6002 line-by-line — that's a separate pass after
aetherclaude-eligible, and at 104k insertions it needs its own scope decision.🤖 aethersdr-agent · cost: $3.0876 · model: claude-opus-5
aethersdr-agent commentedon Oct 2, 2026
Correction to my diff attribution above. My
FETCH_HEADhad been overwritten between reads, so two of the size/scope figures described the whole stack rather than this RFC's increment. Re-fetchedpull/6002/headatb6f87a9dand isolated it:third_party/wdspedits are not part of this proposal.wbfm.c(+217) andiobuffs.ccome from208bc220"Add dedicated WFM applet and observed stereo controls" and290bca55"Qualify opt-in WBFM filtering, headroom and stereo" — analog RTL WFM: native stereo, dedicated applet and bounded receive exchange #5974 work, already in RTL: add opt-in native digital broadcast reception and local metadata #6002's base (all 12 wdsp files, +746/-30, land at or before6e87be85). I withdraw "not described anywhere in this RFC; part of what a yes approves." Approving this RFC adds no WDSP changes.main, not the HD increment. The analog base alone (main→6e87be85) is 827 files / +64,905. The HD-specific vendored footprint is 161 files / +80,351 —third_party/nrsc5+third_party/faad_hdc. That's the number attached to the dependency-inclusion decision.The #5974 status in my comment holds, now tested rather than quoted from the RFC:
6e87be85is an ancestor of #6002's head (exit 0) but not ofmain(exit 1) — unmerged. TheWfmDeviceDialog.cpponmainis a pre-existing dialog last touched by #4279, not the #5974 applet. So item 5's prerequisite claim stands.Everything else is unchanged: GPLv2-or-later is compatible, the Nero §2c notice still needs a shipped user-visible surface, the planner lock is real and correctly layered,
clampSampleRateis untouched with the rate conversion inHdFmIqAdapter, andeffectivePassband()genuinely widens to ±225 kHz.🤖 aethersdr-agent · cost: $4.2239 · model: claude-opus-5
release: prep v26.10.1 — controls that work or say why not, a CTR2 re…
RTL WFM: native stereo, dedicated applet and bounded receive exchange (…
RTL: analog multi-receiver audio, meters and release packaging (#6083)
release: prep v26.10.2 — a unified title bar, docs.aethersdr.com and …
RTL: add SSB/CW and AM/SAM reception with selected decoder audio. Pri…