Skip to content

Recorder: DAX RX audio delivered at 48 kHz on 8000-series but pipeline assumes 24 kHz → ~50% trimmed (chopped/quiet recordings) #3837

Description

@jensenpat

Summary

On 8000-series FLEX radios (FLEX-8600M / FLEX-8400M), DAX RX audio is delivered at ~2× the rate the DAX audio pipeline consumes, so roughly half of every second is trimmed. The result is chopped / "crackling" DAX recordings that are also very quiet at 100%. This is the audio half of #3626 — split out here because it is an independent root cause from the connection-quality storm (which is fixed in #3796).

Evidence

VirtualAudioBridge's per-channel DAX RX ch N summary lines show, every ~1000 ms interval, the sink keeping up at real-time plus trimming almost another full second:

DAX RX ch 2 summary: interval_ms=1004 written_ms=1018.7 backlog_ms=82.7 trim_events=6 trimmed_ms=992.0 overruns=0
DAX RX ch 1 summary: interval_ms=1000 written_ms=986.7  backlog_ms=56.0 trim_events=6 trimmed_ms=992.0 overruns=0

written_ms + trimmed_ms ≈ 2000 ms per 1000 ms interval → the stream arrives at 2× real-time. Reproduced on both a FLEX-8600M (#3626 reporter log) and a FLEX-8400M (test capture aethersdr-20260626-101017), on every DAX RX channel, constant from stream start, independent of the #3626 stream-storm.

Root cause (analysis)

The reduced-bandwidth DAX audio packets are pcc=0x0123, bytes=284284 − 28 (VITA49_HEADER_BYTES) = 256 payload bytes = 128 int16 mono samples per packet. At the observed packet rate that is 48 kHz, but the DAX audio pipeline assumes 24 kHz everywhere:

  • src/core/VirtualAudioBridge.cppsamplesToMs() divides by 24000 * 2; kRxTargetBacklogFrames / kRxMaxBacklogFrames are sized "@ 24 kHz"; openShmSegment() sets sampleRate = 24000; feedDaxAudio()'s comment states "float32 stereo PCM @ 24 kHz … HAL plugin also runs at 24 kHz, so no resampling needed."
  • The macOS DAX HAL plugin reads the shared-memory sampleRate (24000) and runs at 24 kHz.
  • src/core/PipeWireAudioBridge.cpp (Linux) makes the same assumption.

Because the bridge writes ~48000 stereo frames/sec into a ring sized for 24 kHz, the backlog grows and the live-edge trim discards ~50 % of samples each second → periodic chops (the "crackling") and, depending on the consuming app's resampling, low apparent level (the "very quiet at 100%").

This is plausibly a 6000-vs-8000-series difference: the 8000-series PA / DAX path appears to deliver audio at 48 kHz where the 6000-series uses 24 kHz.

Proposed direction

Make the DAX audio rate radio/stream-aware instead of hardcoded 24 kHz, coordinated across the three consumers that must agree on the shared-memory sampleRate:

  1. VirtualAudioBridge.cppsamplesToMs(), backlog frame constants, openShmSegment() sampleRate, feedDaxAudio().
  2. The macOS DAX HAL plugin (reads the shm sampleRate).
  3. PipeWireAudioBridge.cpp (Linux).

Confirm the true 8000-series DAX audio rate (FlexLib / radio-advertised) before wiring it; the shm sampleRate field is the natural carrier so the plugin and app stay in lockstep.

Notes

💻 Filed by Claude Code (Opus 4.8) with architecture by @jensenpat

Metadata

Metadata

Assignees

No one assigned

    Labels

    VITA-49VITA-49 UDP streaming: FFT, waterfall, audio, metersaudioAudio engine and streamingbugSomething isn't workingmaintainer-reviewRequires maintainer review before any action is takenpriority: lowLow priority

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions