Also known as: voice_taps, wideband DDC taps, virtual voice tuners
Wideband voice taps are per-call digital down-converter
channels carved out of one SDR’s IQ capture, so a single dongle can decode a trunked
control channel and record the voice
grants it issues. On a trunked system the control channel and
each voice call sit on different frequencies, so one tuner cannot do both jobs by retuning —
either you add a second SDR with role: voice, or you channelize: give the dongle
role: wideband, point center_freq_hz at the middle of the site’s frequency cluster, and
set voice_taps: N. Each grant whose frequency lands inside the capture window then gets its
own on-demand DDC tap on the same IQ stream, no extra hardware needed
(#379).
The window math
A tap can only be created where there is capture to tap. The validated rule is:
- Every tapped frequency must fall within
center_freq_hz ± sample_rate/2, with a 5% guard band at each edge (the channelizer and DDC filters need clean skirts). voice_taps: 0disables the feature; there is no hard upper bound, but CPU scales roughly linearly per tap and the daemon warns above 16.- Grants that fall outside the window spill over to a physical
role: voiceSDR when one is configured, and otherwise drop with the standardno voice device availablelog.
So a 2.4 MS/s RTL-SDR capture gives a usable span of about ±1.1 MHz around center — plan the center frequency around where the voice channels actually are, not just the control channel.
Misleading messages and the bugs behind them
| Symptom | Looks like | Actually | Fix / check |
|---|---|---|---|
voice pool full but no actives |
Pool exhausted by traffic | The pool was empty — the message fired only when the daemon had zero voice devices (a control-only config), the exact opposite of “full” (#379) | Add voice_taps to the wideband entry or a role: voice SDR; current builds emit an actionable warning instead |
| Wideband-only setup drops every grant as “no voice SDR” | Grants out of window | Init ordering: the virtual voice tuners were created after the voice pool was built, so the pool had zero devices; a physical voice SDR would have masked it entirely (#422) | Fixed; on old builds, adding any physical voice SDR hid the bug |
composer: p25p2 voice chain started trellis=0 |
Config problem on your side | The wideband path never forwarded the p25_phase2_* FEC options to the decoder, even though the config read back correctly through the API (#882) |
Fixed; trellis=1 in that line is the confirmation the options arrived |
| Wideband P25 voice garbled on a CQPSK site | Weak signal | The wideband path stamped no demod mode onto its grants, so voice always ran the C4FM chain regardless of the setting (#882, #935) | Fixed; set the per-channel p25_phase1_demod_mode override where needed |
The middle two rows are the same lesson twice: the wideband engine is a second, parallel pipeline, and “the config is accepted and echoed back by the API” does not prove the value ever reached the decoder. The observable tell is always a decoder-side log line, not the config surface.
Per-channel demod mode
Each channels: entry on a wideband dongle can carry its own p25_phase1_demod_mode:
override, inheriting the system default when absent. The override is keyed by frequency,
not by RFSS/site identity, for a structural reason: the symbol-recovery path must be chosen
before the control channel locks (it is what lets it lock), but the RFSS and site numbers
are only known after that control channel decodes — a chicken-and-egg the config resolves
by using the channel frequency, the one place site identity exists at config time
(#935). See
P25 demod-mode selection for how to choose the value.
Related knobs
signalling_taps: Nallocates signalling-only taps that harvest P25 Phase 2 talker aliases off granted traffic channels without following the call as voice — useful where voice taps rarely win a grant.- A multi-tap wideband dongle usually wants
gain: "auto"; a single fixed gain cannot serve sites of differing strength, and overload has its own signature — see SDR gain and overload.
Provenance
- #379 — the backwards “voice pool full” message and the one-SDR-can’t-do-both explanation that motivated
voice_taps. - #422 — wideband-only topology dropped every grant because the virtual voice tuners were built after the pool.
- #882 — wideband pipeline silently dropped the P25 Phase 2 FEC options; the
trellis=0tell. - #935 — per-channel demod-mode override and why it is keyed by frequency rather than site.