Version 0.1.0 · free and open source

A trunked radio recorder
in a single program.

Trunk Recorder Pro follows P25, SmartNet and DMR control channels and records every call it hears. It also records conventional analog and digital channels. Calls are saved as WAV files with Trunk Recorder–compatible JSON. It runs on macOS, Windows and Linux with RTL-SDR dongles, with nothing else to install, and it also runs in the browser.

  • 3–7 MB per platform
  • No GNU Radio or OP25
  • GPL-3.0 on GitHub
The recorder's dashboard: control channel decode rate, recorders in use, CPU use, and a live waterfall for each of two RTL-SDR dongles with the active calls marked.
Two RTL-SDRs following a UHF SmartNet system with P25 voice. One waterfall per dongle; the control channel and active calls are marked.

What it records

Trunked systems and single channels, side by side.

Each system or channel is configured separately. All of them share the same radios and recorders.

P25 Phase 1

Control channel and voice, C4FM and CQPSK simulcast. Several receivers run on each channel and the best is kept for every frame.

P25 Phase 2

TDMA voice (H-DQPSK, AMBE+2), descrambled using the system identity read from the control channel. Nothing to set up.

SmartNet / SmartZone

Motorola Type II control channels with standard and custom (OBT) band plans. Voice is P25 or analog FM, depending on the grant.

DMR

Capacity Plus, Linked Capacity Plus, Capacity Max, Connect Plus and Tier III, plus conventional and simplex DMR. Each slot is recorded separately.

Conventional

Analog FM, P25 and DMR channels, with or without a trunked system. Filters by CTCSS/DCS tone, NAC or colour code, and decodes MDC1200 and FleetSync IDs.

Talker aliases

Decodes the names radios send with their unit IDs (Motorola and Harris, Phase 1 and 2). They're shown in place of unit IDs and kept between runs.

Find my system

Start without knowing the frequencies.

Press Scan with a dongle connected. The recorder steps through the land-mobile bands, about 1.3 seconds per 2 MHz, looking for carriers that never key down. It checks each one with its P25, SmartNet and DMR receivers, then listens to the strongest.

  • Finds the system's identity, its control channels, its neighbouring sites and the voice channels it uses
  • Measures your dongle's frequency error (ppm), using the frequency the control channel announces for itself
  • On an RTL-SDR, chooses the lowest gain that doesn't clip
  • For SmartNet systems on VHF/UHF, works out the band plan by watching which carrier comes up when a channel is granted

Also available from the command line: trunk-pro survey --serial 200 --bands 800,700

The Find my system panel: a radio picker, an option to find the best gain, and checkboxes for the bands to scan, from VHF to 900 MHz.
The Systems tab in Setup: a SmartNet system with its control channels, talkgroup CSV, band plan fields and site group, and the list of recent calls beside it.

Several systems and sites

One recorder, many systems.

Each system, or each site of a multi-site system, follows its own control channel and saves calls in its own folder. All of them share the dongles. Each control channel and call is picked up by whichever dongle covers its frequency.

  • Site lock (NAC, WACN, System ID, RFSS, site) keeps each system on its own control channel
  • A call heard on several sites is saved once. Every site's copy is recorded and the cleanest one is kept, so a site that fades mid-call doesn't cost you the call
  • A Preferred Site column in the talkgroup CSV picks which site's copy to keep
  • Neighbouring sites announced by a control channel can be added with one click

Conventional channels

Hundreds of channels cost almost nothing.

Channels are watched in the spectrum the recorder already computes. An idle channel takes about 0.001 % of a CPU core. When a signal rises above the squelch, recording starts a moment before it was detected, so the start of the transmission isn't lost.

  • Squelch is set in dB above the measured noise floor, so it doesn't depend on the dongle or gain
  • Several users of one frequency can be split by CTCSS tone, DCS code, P25 NAC, or DMR colour code, slot and talkgroup
  • Under each frequency, the tones and codes it has carried are listed, each with an Add button
  • Channels can be kept in a CSV file and edited in Excel, Numbers or LibreOffice. Trunk Recorder's channel file works as is
The Conventional tab: import and export CSV, a linked channel file, squelch in dB above noise, and a box for adding frequencies as analog FM, P25 or DMR.
The Radios tab: two RTL-SDR sources with center frequency, sample rate, gain and ppm, each with a bar showing which configured channels fall inside it.

Radios

RTL-SDR with no drivers to install. Other SDRs when you need them.

RTL-SDR dongles are opened directly over USB, so there's no librtlsdr or libusb to install. You can use several at once. Each dongle's card shows which control and voice channels fall inside its range.

  • USRP (UHD), Airspy R2 / Mini and SoapySDR devices, using their makers' drivers if they're installed
  • Recorded IQ files (cu8, cs16, cf32) can be played back through the same engine
  • A dongle left on Auto is tuned to cover the systems the other dongles don't

How it works

One FFT per radio. Every channel is cut from it.

The engine is written in Rust from scratch and doesn't use GNU Radio, OP25 or a block scheduler. A single shared channelizer feeds the control-channel, voice and conventional receivers. The same core is compiled natively for the desktop and to WebAssembly for the browser.

Signal chain: IQ samples from each radio go into one shared FFT channelizer with one second of pre-roll. It feeds three paths: control channels to the trunking logic, voice channels to the vocoders, and conventional channels detected by energy. All three produce WAV and JSON files and the live interface. Radios IQ samples Channelizer one shared FFT 1 s pre-roll history Control channels receivers → framer → Viterbi Voice channels soft FEC → IMBE / AMBE+2 Conventional energy → FM / P25 / DMR Call manager grants, sites, dedupe Calls WAV + Trunk Recorder JSON live interface · plugins opens voice channels
98–99%

of P25 control messages decoded on a CQPSK simulcast site, where OP25's decoder gets 62 %.

1.6%

of one CPU core for a 2.4 MSPS P25 site (control channel and two voice channels). About 6 % at 8 MSPS with 16 calls at once.

90–99%

of SmartNet control messages on a UHF system where Trunk Recorder decodes 40–60 %.

~6dB

less signal needed than before for the same P25 C4FM voice decoding (8 dB on DMR). The receivers use matched filtering and multi-symbol detection.

Measured on captures and live systems in the Washington, DC area using RTL-SDR and USRP B200 receivers, on an Apple-silicon Mac. Your results will depend on your site, antenna and hardware. The methods and raw results are in the repository.

Works with your existing setup

Uses Trunk Recorder's file layout and formats.

Calls are saved in Trunk Recorder's folder layout with its JSON fields, so tools that read Trunk Recorder's output can read these files too. Your existing configuration can be imported.

  • Import Trunk Recorder config… brings in P25, SmartNet, DMR and conventional systems
  • Talkgroup CSVs, channel files, unitTagsOTA files and lcnTable are read as is
  • Plugins are separate programs that receive each call. Ports of the OpenMHz, Broadcastify Calls, Rdio Scanner, simplestream and upload-script plugins are in progress
~/TrunkRecorderPro
dcfd/2026/10/1/
  1201-1790865823_857237500.wav
  1201-1790865823_857237500.json
  1307-1790865861_770106250.1.wav   # Phase 2, slot 1
capmax/2026/10/1/
  201-1790865902_452275000.0.wav   # DMR, slot 0
conv/2026/10/1/
  154430-1790865940_154430000.wav # talkgroup = kHz

Install

Download one file and run it.

Each download is a single program with the interface built in. When it runs, it opens its interface in your browser at http://localhost:8080. Downloads are on the GitHub releases page, with a SHA256SUMS file for checking them.

macOS 11 or later · Apple silicon and Intel (one universal app)

  1. Download trunk-pro-<version>-macos.dmg

    Open it and drag Trunk Recorder Pro to Applications.

  2. Allow the first launch

    Releases aren't signed with an Apple Developer ID yet, so macOS blocks the first launch. Open the app once, then go to System Settings → Privacy & Security → Open Anyway.

  3. Plug in a dongle and set up a system

    The app has no Dock icon. It opens its interface in your browser. To get back to the interface, open the app again. To stop it, use Quit in the interface.

Command-line version

trunk-pro-<version>-macos-universal.tar.gz contains the same program without the app bundle:

tar xzf trunk-pro-*-macos-universal.tar.gz
./trunk-pro

Optional: USRP and Airspy drivers

RTL-SDRs need nothing extra. For other radios, install the maker's driver. The recorder finds it at startup and offers it as a source type. trunk-pro devices shows which drivers it found.

macOSDebian / Ubuntu / Pi OSWindows
USRPbrew install uhdsudo apt install libuhd-dev uhd-hostEttus's UHD installer
Airspybrew install airspysudo apt install libairspy0airspy.dll next to trunk-pro.exe

In the browser

Try it without installing anything.

The browser version runs the same Rust engine, compiled to WebAssembly. On a test capture it recorded the same calls as the desktop build, using about 7 % of a CPU core in real time. It's a quick way to see whether your dongle can hear a system.

For several dongles or long unattended runs, use the desktop app. A browser tab can be suspended or closed, and WebUSB is only available in Chromium-based browsers.

Open the web app

Status

What's tested and what isn't.

This is the first release of a new engine. Here's the current state.

Verified

  • Live recording on macOS with one or several RTL-SDRs. A public SmartNet feed now runs on it
  • P25 Phase 1 and Phase 2, SmartNet and DMR decoding on real-air captures. P25 and SmartNet were compared with Trunk Recorder on the same air
  • USRP B200, live at 8 MSPS with no dropped samples
  • The browser build on captures, giving the same calls as the native build

Not yet tested on hardware

  • Linux and Windows builds with live dongles (the builds are made, but haven't been run with hardware yet)
  • Airspy streaming
  • Live WebUSB in the browser version
  • Conventional channels on live air (verified on synthetic signals)

Not built yet

  • Signed and notarized macOS builds
  • A plugin store (plugins can be added from a file for now)
  • Login for the web interface. Keep it on localhost or a network you trust

Found a problem or have a system it doesn't handle? Open an issue on GitHub.