Skip to content

RTL: publish multi-receiver audio, meters and release packaging - #6077

Merged
Ozy311 merged 1 commit into
codex/rtl-native-hd-fmfrom
codex/rtl-multirx-delivery
Oct 2, 2026
Merged

Ozy311 merged 1 commit into
codex/rtl-native-hd-fmfrom
codex/rtl-multirx-delivery

Conversation

@Ozy311

@Ozy311 Ozy311 commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Review moved to #6083

During separation of Digital FM into RFC #6079, branch ancestry was changed before PR bases were retargeted. GitHub automatically recognized this head inside the Digital branch and marked this PR merged there, then deleted the branch. This was not a merge into main. I restored the branch and created #6083 against the correct analog base. That replacement is Ready for review; original review discussion and historical evidence remain here.

Current analog order: #5924 → #5973 → #5974 → #6082 → #6083. Draft Digital #6002 follows #6083 and is no longer an analog dependency. The previous full integration remains preserved at codex/rtl-digital-evaluation-preserved-20261001.

Prior PR description, retained as historical context

Summary

Publish the tested RTL multi-receiver and delivery changes that were previously local: opt-in 2/4/8 receive banks, independent manual/Auto SQL, selected-receiver APRS input, stable TCI mapping, native DAX receive feeds, truthful relative meters with a per-device switch, and preservation of spectrum averaging during monitor-volume edits. The WFM applet follows the selected receiver; optional digital program selection retains user intent during telemetry updates.

Stacked on #6003 and part of RFC #5468. This combines the previously tested 7601593f delivery with upstream 68cdf661, preserving upstream ANAN audio controls, the single spectrum/waterfall path, receive-contract tests, Qt 6.12 pin and generated engine manifests. No running user installation is replaced by this PR.

Release builds

  • Official Linux AppImage, macOS DMG and Windows installer workflows explicitly use ENABLE_RTL=ON, REQUIRE_RTL=ON, ENABLE_HD_FM=OFF.
  • Missing RTL/float-FFTW dependencies fail configuration instead of silently omitting RTL. Pinned native dependency setup, package linkage checks, notices and matching-source materials accompany release packaging.
  • Resolved native dependency paths are preserved at link time. Darwin libusb uses its supported pipe fallback. Current version remains 26.9.5.
  • Digital decoding stays default OFF. The private operator-tested packages used ON; they are not the official release configuration.

Receiver admission and dependencies

Normal production admission still defaults to one receiver. The tested desktop evaluation enables 2/4/8 through AETHER_AUTOMATION=1 plus AETHER_RTL_EVALUATION_RECEIVERS, on Linux x86_64, Windows x64 and macOS arm64. Eight-receiver normal-launch admission needs an explicit qualified-profile/default decision; this PR does not silently promote that default or claim ARM qualification.

The current branch is based on #6003 → draft #6002 → #5974 → #5973 → #5924. Keeping #6002 draft also holds this downstream stack from landing in its current shape. Review can proceed in order; merging remains a separate maintainer action. AM/SSB/CW work and the later AetherModem/i-gate sprint are outside this submission.

Validation

  • Delivered 7601593f: native Mac and Windows builds, 33 selected tests per platform, recorded decoder programs, disconnected GUI/daemon checks and launcher checks are retained as historical delivery evidence. The Windows runtime ZIP is about 174 MB with matching sources separate; its command launcher uses process-only PowerShell execution-policy bypass.
  • The operator reports successful RTL hardware tests, working DAX/TCI/APRS/PPM, and days of stable reception. This is operator-reported evidence on the delivered build, not an instrumented soak of the upstream reconciliation.
  • Reconciled current source: native Apple Silicon AetherSDR build with Qt 6.12, RTL required and Digital OFF succeeds. The expanded offline run passed 39/40 tests. The WFM multi-receiver test passed in the initial focused run, then withdrew a receiver during a filter/stereo change in the expanded run. Three subsequent runs with failure-trace instrumentation passed, but did not establish a root cause or a fix. The diagnostic patch and logs are retained outside the submitted source. This is under investigation; no green qualification claim is made. The stale upstream capability expectation was separately corrected to match implemented FM/FM-N filter controls and now passes.
  • Thirteen static/parser checks and all 16 RTL requirement combinations pass locally. Generated seam and engine manifests are current. The existing full Linux suite workflow is running against this exact head (a53423ac); its build was still in progress at the readiness checkpoint. Submitted for review at the operator’s explicit request after successful multi-receiver hardware testing and days of stable use. The intermittent offline WFM withdrawal remains unresolved and is disclosed for review; readiness does not claim that validation failure is fixed.

New/modified TCI and DAX tests exercise Aether's own server/routing, not a simulated radio peer. Current-head Windows artifacts, sanitizer execution, Linux ARM performance and fresh live RF soak are not claimed. Maintainer approval is still needed for the shared-control/UX choices disclosed in the RFC and parent PRs.

Constitution principles

II: only accepted receiver state publishes; V/XIV: scoped persistent settings; VIII/XI: separate historical hardware evidence from current executed tests. Signed commits; no TX feature is added.


73, Ozy K6OZY · Codex

@Ozy311 Ozy311 self-assigned this Oct 2, 2026
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown

Accessibility check findings

This PR touches src/gui/ files with 17 accessibility issue(s).
Full details appear as inline annotations on the diff above.

Files scanned : 26
Files with findings: 5
Total findings : 17

See docs/a11y.md for the canonical
Qt patterns (setAccessibleName, QAccessibleValueChangeEvent,
QAccessibleInterface subclasses, etc.). Structural remediation
(keyboard navigation, custom QAccessibleInterface subclasses)
is tracked in #3288.

Findings are warnings only — the build is not blocked.

@aethersdr-agent

Copy link
Copy Markdown
Contributor

CI: control_receive_test — two stale capability expectations, not infrastructure

The full-suite lane you dispatched against a53423ac found exactly what you ran it to find. Good news first: the build is clean and 614 of 615 tests pass. Static checks and Sanitizer option configures both passed on this SHA. The only red is run 36949363792:

99% tests passed, 1 tests failed out of 615

The following tests FAILED:
	 35 - control_receive_test (Failed)

with these two assertions:

control_receive_test: [FAIL] RTL adjustable filter qualification excludes legacy WFM
control_receive_test: [FAIL] RTL desktop squelch declares the implemented detector's modes and units

Both are the branch's own test expectations disagreeing with the branch's own RtlSdrBackend::capabilities(). Nothing environmental, nothing to do with the runner. They're deterministic — they will fail on every Linux run with RTL enabled, which is why the per-PR gate (which doesn't run this test) stayed green.

This is not the intermittent WFM multi-receiver withdrawal you disclosed in the PR body. wfm_controls_test passed here (#589, 9.95 s). That investigation stands on its own; this is a separate, fully deterministic mismatch.


1. Filter mode count: the WFM entry is always appended

tests/control_receive_test.cpp:632 asserts:

check(rtlCaps.receiveFilterControl && rtlCaps.receiveFilterControl->modes.size() == 2
    && rtlCaps.receiveFilterControl->modes[0].mode == QStringLiteral("FM")
    ...
    "RTL adjustable filter qualification excludes legacy WFM");

But src/core/backends/rtl/RtlSdrBackend.cpp:233-236 appends a third entry:

if (RtlReceivePipeline::kQualifiedWfmEnabled) {
    c.receiveFilterControl->modes.append({QStringLiteral("WFM"),
        -100000, -15000, 15000, 100000, 30000, 200000});

and RtlReceivePipeline.h:120 is static constexpr bool kQualifiedWfmEnabled = true; — unconditionally. So modes.size() is always 3. The modes[0]/modes[1] FM/FMN bound checks still pass; only the count term is stale.

The assertion name no longer describes what it should check either. The appended entry isn't "legacy WFM" — it's the new qualified ±100 kHz native WFM. Suggested shape:

check(rtlCaps.receiveFilterControl
    && rtlCaps.receiveFilterControl->modes.size() == (RtlReceivePipeline::kQualifiedWfmEnabled ? 3 : 2)
    && rtlCaps.receiveFilterControl->modes[0].mode == QStringLiteral("FM")
    && rtlCaps.receiveFilterControl->modes[1].mode == QStringLiteral("FMN")
    && rtlCaps.receiveFilterControl->modes[0].minimumLowHz == -21600
    && rtlCaps.receiveFilterControl->modes[1].maximumHighHz == 21600
    && (!RtlReceivePipeline::kQualifiedWfmEnabled
        || (rtlCaps.receiveFilterControl->modes[2].mode == QStringLiteral("WFM")
            && rtlCaps.receiveFilterControl->modes[2].minimumLowHz == -100000
            && rtlCaps.receiveFilterControl->modes[2].maximumHighHz == 100000)),
    "RTL narrow-FM filter qualification is ±21.6 kHz; qualified WFM is a separate wider entry");

That pins the real contract — the FM/FMN entries don't cover WFM's passband — instead of a count that the WFM work invalidated.

2. Squelch unit string: the rename missed one call site

tests/control_receive_test.cpp:642 expects "dBFS/bin"; RtlSdrBackend.cpp:249 declares "dBFS/2048-bin":

c.receiveSquelchModel = ReceiveSquelchModel{
    {QStringLiteral("FM"), QStringLiteral("FMN")},
    RtlSquelchGate::kReferenceDb, RtlSquelchGate::kStepDb, QStringLiteral("dBFS/2048-bin"), true, false};

The other three fields are fine — RtlSquelchGate.h:17-18 gives kReferenceDb = -120.0 and kStepDb = 1.2, and the mode list matches. Only the unit string. "dBFS/2048-bin" is the more honest label (it names the bin width the detector actually uses), and no GUI code pins either string, so the one-line fix is on the test side: update line 642 to "dBFS/2048-bin".

Worth a glance while you're in there: tests/fm_filter_controls_test.cpp:106 still hand-builds a fixture with "dBFS/bin". It passes (#588 green) because that struct is constructed locally and never compared against the backend, but it now describes a unit the backend no longer declares.


Which PR in the stack should carry each fix

These two have different origins, and fixing both only at this tip would leave the parents red on their own heads:

Failure Introduced by Lowest PR that is already red
filter modes.size() == 2 d7d50ed0 "Route RTL WFM as confirmed 48 kHz stereo" — adds the third entry, leaves the assertion at 2 #5974 (inherited by #6003 and this PR)
squelch unit string eac471e0 "Fix independent RTL Auto SQL and admit eight-RX evaluation" — renames the backend's unit and updates rx_applet_squelch_reconciliation_test.cpp, but not control_receive_test.cpp this PR (#6077)

I verified #5924's head does not append the WFM entry, so size() == 2 is correct there and that layer is unaffected. The filter fix belongs in #5974; the squelch fix belongs here.

Housekeeping

The full-suite bot filed #6080 as "test suite failing on main", but its commit is a53423a — this PR's head, from the run you dispatched. main is not regressed by this. That issue should be closed as a PR-branch run rather than chased as a main break.

Also, for completeness: no Copilot or other reviewer comments on this PR. The only bot comment is the accessibility scan (17 findings across 5 src/gui/ files) — those are warnings only, don't block the build, and are unrelated to this failure. The canonical patterns are in docs/a11y.md if you want to pick any of them up, with structural work tracked in #3288.

Two one-line literals across a 615-test suite on a six-deep stack is a good place to be. Thanks for running the full lane deliberately rather than waiting for it to surface downstream — that's what caught these.

73


🤖 aethersdr-agent · cost: $8.9871 · model: claude-opus-5

@Ozy311
Ozy311 force-pushed the codex/rtl-live-ppm branch from 9c50425 to 5e39790 Compare October 2, 2026 02:17
@Ozy311
Ozy311 force-pushed the codex/rtl-multirx-delivery branch from a53423a to 4b1816a Compare October 2, 2026 02:17
Base automatically changed from codex/rtl-live-ppm to codex/rtl-native-hd-fm October 2, 2026 02:17
@Ozy311
Ozy311 merged commit 4b1816a into codex/rtl-native-hd-fm Oct 2, 2026
@Ozy311
Ozy311 deleted the codex/rtl-multirx-delivery branch October 2, 2026 02:17
@Ozy311
Ozy311 restored the codex/rtl-multirx-delivery branch October 2, 2026 02:19
ten9876 added a commit that referenced this pull request Oct 11, 2026
Analog RTL receivers gain independent squelch, receive-audio exports,
meters and release packaging. This is the remaining analog delivery
increment under RFC #5468; the WFM foundation, applet and live PPM
changes are already in `main`.

## Scope and separation

Rebased onto main `d6f6a4f00e40e292d575c40cad7d0848406d89f5`. Only the
five remaining analog commits were replayed, followed by the
release-control and user-documentation cleanup. The merged WFM/PPM
changes and newer main changes are retained.

- Independent manual/Auto SQL; selected-receiver APRS; stable TCI
mapping; native Linux/macOS DAX receive feeds; relative receive meters
with a per-device switch; averaging preserved during monitor-volume
edits.
- WFM controls follow the selected receiver and reject stale bindings.
The normal launch remains **one receiver**. Explicit process-only 2/4/8
receiver evaluation remains separate from production capacity
qualification; no new Linux ARM capacity result is claimed.
- Official AppImage, macOS DMG and Windows packages require
`ENABLE_RTL=ON` and `REQUIRE_RTL=ON`. Configuration fails if RTL or
float-FFTW is missing. Jeremy [approved required RTL and bundling pinned
libusb](#6083 (comment)).
The completed AppImage is extracted and audited after the final
linuxdeploy pass, including a byte comparison of its libusb payload.
Windows dependency validation follows normal and delay imports
recursively.
- **No `ENABLE_HD_FM` declaration, placeholder, release flag or decoder
dependency remains in this analog increment.** The actual optional
switch and all explicit OFF release/build flags belong to deferred draft
#6002 / RFC #6079. That feature is not a prerequisite for this PR.
- User documentation now covers RTL packaging, evaluation limits,
squelch, meters, selected-slice AetherModem and receive-only DAX/TCI
routing.

## Shared behavior for review

Auto SQL uses the existing typed receive dispatcher and confirmed-state
guards. RTL's 2048-bin detector scale is relative dBFS, not calibrated
dBm or directly comparable with the display FFT; no misleading threshold
line is drawn. An accepted capture revision retires a receiver's
relative-level sample only when that receiver's detector input changes
(passband, mode, membership, front end, capture placement or DC
suppression); monitor gain, pan, mute and squelch edits keep it, so the
meter does not blank during an AF gain drag. Other adapters retain their
manual behavior and refuse the automatic request.

TCI initialization is batched as one worker job for every family.
`AETHER_SETTINGS_DIR` suppresses legacy-profile migration and normal log
pruning. The `activeSliceCommandIssued` connection uses
`receiveCommandSource()` identity and `Qt::DirectConnection`; this
shared-family guard remains part of the increment. Receive-only PipeWire
routing drains stale audio while preserving the legacy Flex FIFO's
sole-reader/EPIPE behavior. Dependency-prefix and Qt deployment fixes
remain in packaging.

## Validation

Native Nobara / GCC 16.2.1 / Qt 6.12 / Release application and daemon
builds pass at `a3458b09`. **53/53 selected CTests pass**, zero
skips/failures, 221.35 seconds. This covers RTL capture/control/receiver
banks, FM/WFM, SQL, spectrum/averaging, APRS, DAX/TCI, meters, applet
lifecycle and actual PipeWire FIFO behavior. The analog CMake cache
contains no Digital switch.

[Platform
CI](https://github.com/aethersdr/AetherSDR/actions/runs/38001349724)
passes on Linux, macOS and Windows. [Static
Checks](https://github.com/aethersdr/AetherSDR/actions/runs/38001349782)
and
[Docs](https://github.com/aethersdr/AetherSDR/actions/runs/38001349759)
pass.

[Full
Suite](https://github.com/aethersdr/AetherSDR/actions/runs/38001374779)
passes: **691 passed, five skipped, zero failures**, 696 registered
tests, 932.37 seconds. The skipped cases are four AppSettings safety
scenarios and `hl2_probe_spectrum_panadapter`; they are not claimed as
exercised.

All branch release-package workflows pass at exact head `a3458b09`:
[AppImage](https://github.com/aethersdr/AetherSDR/actions/runs/38001377190)
x86-64 and ARM, [macOS
DMG](https://github.com/aethersdr/AetherSDR/actions/runs/38001379572)
Apple Silicon and Intel, and [Windows
Installer](https://github.com/aethersdr/AetherSDR/actions/runs/38001382004).
Both completed AppImages pass RTL runtime closure and libusb byte
comparison. Both DMGs pass signing/notarization; Windows passes actual
DLL closure and installer/artifact packaging. Artifact identities and
checksums are retained. Release/Store publication jobs were skipped.

Already passed on this revision: 16 required-RTL configuration
combinations, 9 package-helper tests, engine/routing/capability gates,
generated manifests and references, frozen-test-gate and registration
checks, build-options checks, LogAnalyzer checks, and the
user-documentation production build. Commits are signed.

Historical operator multi-RX acceptance and earlier package/full-suite
results remain in the PR discussion and original #6077. They are not
substituted for this head's results. The intermittent historical Mac WFM
receiver withdrawal during a filter/stereo transition remains
unexplained; passing reruns did not establish a cause. No new live-RF,
audible, sanitizer or production-capacity qualification is claimed.

This PR requests its own maintainer/code-owner review. #6002 remains
draft. No release or Store publication is part of this validation.

---
73, Ozy **K6OZY** · Codex

---------

Co-authored-by: jensenpat <patjensen@gmail.com>
Co-authored-by: Jeremy [KK7GWY] <kk7gwy@aethersdr.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant