Repository navigation
Code map
How the OnAir repository is organised, and where things live.
OnAir is a C++20 program in two layers: a receiver library (core/) that knows nothing about windows, and a graphical app (app/) that draws what the library reports. The command-line tools in tools/ and the Android app use the same library. Source: https://github.com/adswill/OnAir.
| Folder | What is in it |
|---|---|
core/ |
the receiver library: core/include/dect2/ (public headers) and core/src/ (one folder per mode and topic) |
app/ |
the desktop window (Dear ImGui): the frame loop, panels and one folder of screens per mode |
tests/ |
unit tests, benchmarks and a fuzzer; most use synthetic signals from the generators in core/, so they need no radio. Run with ctest --test-dir build
|
rust/ |
Rust protocol layers (one crate per protocol, built into one static library libonair_rs.a; 27 crates in 0.2.7), switched on per module in CMake |
tools/ |
dect2cli (the onair-cli receiver on the command line), dect2scan (channel scanner), one small tool per mode, package/ (installer scripts) and dev/ (helpers) |
web/ |
Cloudflare Worker code: web/map (the live map, https://map.on-air.dev) and web/discord (the Discord /map and /stats bot) |
docs/ |
CODECS.md, TRANSMIT.md, research notes and the project log |
packaging/ |
icons, the Windows installer script and toolchain file, Linux resources |
third_party/ |
Dear ImGui and miniaudio, with their licences (codec2 is built as a separate shared library) |
The text below is ARCHITECTURE.md of the 0.2.7 development branch. In the released 0.2.6 the core/src and app folders are flat (all files side by side); 0.2.7 sorts them into the folders listed here and changes no behaviour.
OnAir is a C++20 program in two layers: a receiver library (core/) that knows nothing about windows, and a graphical app (app/) that draws what the library reports. The command-line tools in tools/ use the same library.
radio ──► ring buffer ──► Engine ──► standard receiver ──► transport stream ──► Player ──► screen and speakers
(source) (ring.h) (analysis T2 / DVB-T / ATSC / DAB (ts.cpp) (player.cpp)
thread)
-
Sources (
core/src/source*.cpp) deliver complex samples from a radio or a file: HackRF natively, other radios through their own library (source_native.cpp) or SoapySDR (source_soapy.cpp), recordings and a built-in synthetic signal. -
Engine (
engine.cpp) owns the source, runs the analysis thread, feeds the spectrum analyser and the receiver that matches the chosen standard, watches the radio (unplug and reconnect), and publishes snapshots for the interface. -
Receivers: DVB-T2 (
t2rx.cppfinds the P1 preamble, tracks symbols, equalises;t2l1.cppreads the signalling;t2plp.cppruns the error correction), DVB-T (dvbt_rx.cpp), ATSC (atsc_rx.cpp), ATSC 3.0 (theatsc3_*.cppfiles:atsc3_sync.cppfinds the bootstrap and cuts frames,atsc3_frame.cppdecodes a frame, then ALP, IP, ROUTE andatsc3_remux.cppturn it into a transport stream), ISDB-T (isdbt_rx.cppfinds the mode and guard interval, tracks carrier and clock and reads the TMCC;isdbt_demod.cppdoes the channel estimate, the interleavers, Viterbi and Reed-Solomon per layer;isdbt.cppandisdbt_tables_data.cpphold the carrier layout and TMCC coding,isdbt_gen.cppis the transmitter used for the tests andisdbtgen), DAB (dab_rx.cpp), DVB-S/S2, DTMB, analog TV, DMR, DRM and ADS-B (one set of files per mode,core/src/<mode>_*.cpp, each with a test-signal generator;modes.cpplists their tuning and test signals), FM radio (fm_rx.cpp: a channel filter brings the station to 500 kHz, a discriminator gives the multiplex, a pilot PLL drives the stereo decoder and the RDS decoder;fm_gen.cppis the transmitter used for the tests). The error correction (LDPC, BCH, Viterbi, Reed-Solomon) lives inldpc.cpp,t2fec.cpp,dvbt_fec.cpp,dab_fec.cpp. The LDPC decoder can run on the GPU (Metal ingpu_ldpc.mm, Direct3D 11 ingpu_ldpc_d3d11.cpp), with a self-test and the CPU as fallback. -
Transport stream (
ts.cpp,bbunpack.cpp): turns baseband frames into packets, parses the service list, guide and subtitles. -
Player (
player.cpp) decodes video and audio with FFmpeg, keeps the audio clock, and repairs short gaps (conceal*.cpp: Apple's model on macOS, a Direct3D 11 version on Windows, a CPU motion search elsewhere). -
Outputs (
tsout.cpp,nettuner.cpp): recording, UDP/RTP, and the built-in network tuner (HDHomeRun-style, M3U and XMLTV).
Threads: the analysis thread runs the receiver (it must never wait for the interface), the error-correction work runs on helper threads or the GPU, the player has its own reader thread and audio callback, and the interface runs on the main thread.
| Folder | What is in it |
|---|---|
core/include/dect2/<folder>/ |
public headers, same folder names as core/src (#include "dect2/<folder>/<name>.h") |
core/src/<mode>/ |
one folder per decoder mode (DVB-T2 is t2/, AIS is ais/ ...) |
core/src/engine/ |
the engine thread, mode table and tuning, scanner, quality, wide-capture helpers |
core/src/source/ |
radios and drivers (source_*.cpp), Hamlib, rotator, IQ files, gain |
core/src/audio/ |
audio and video input/output, AC-4, encoders, shared ham audio front end |
core/src/tv/ |
transport stream, player, concealment, HLS, subtitles, teletext |
core/src/dsp/ |
FFT and SIMD kernels, resamplers, LDPC (CPU, GPU), IQ correction, spectrum |
core/src/net/ |
remote API, share server, network tuner and radio, data feeds, PSKReporter, WSPRnet |
core/src/geo/ |
Maidenhead, satellite passes, map layers, tile cache, MBTiles |
core/src/channels/ |
channel database and lookup |
core/src/results/ |
results serialiser and telemetry JSON (the Android bridge reads these) |
core/src/tx/ |
transmit |
core/src/common/ |
ring buffer, XML, inflate, PNG, character sets, platform headers |
app/ |
the window: main.cpp (loop and layout), app.h (state and shared declarations); app/<mode>/ has a mode's screens; topical folders: ui/, gfx/, panels/, map/, scan/, state/, platform/, i18n/
|
tools/ |
dect2cli (receiver on the command line), dect2scan (channel scanner), package/ (installer scripts), dev/ (developer helpers) |
tests/<folder>/ |
unit tests, benchmarks and a fuzzer, in the same folders as core/src (tests/<mode>/test_<mode>_*.cpp is picked up by a glob); tests/app/ tests the window code, tests/bench/ has the benchmarks; run with ctest
|
packaging/ |
icons, Windows installer script and toolchain file, Linux resources |
third_party/ |
Dear ImGui and miniaudio, with their licences |
app/app.h holds the App struct (all interface state) and the list of panels. main.cpp has the frame loop (the window and fonts are in main_window.cpp, start-up and the developer flags in main_start.cpp, the classic layout in ui/draw_ui.cpp and ui/main_tabs.cpp). The panels are grouped: toolbar.cpp with toolbar_source.cpp, toolbar_rig.cpp, statusbar.cpp (top bar, source options, the network and Hamlib rig windows, status bar), mode_table.cpp (the one-row-per-mode table) and mode_select.cpp (the mode selector), ui_common.h (helpers several screens share), plots.cpp, plot.cpp (our own plotting library on ImGui's draw lists: axes, lines, dots, bars, images, heat maps, panning and zooming), analysis_tabs.cpp (receiver analysis tabs), tv.cpp (player and guide), scan_outputs.cpp, antenna.cpp, dab_ui.cpp, fm_ui.cpp, ui2.cpp, ui2_theme.cpp, ui2_widgets.cpp, ui2_shell.cpp, ui2_faces.cpp (the new interface: palettes, small widgets, menu bar and top bar, and the Panel / Sidebar / Scope / Tiles layouts; the classic shell stays in ui/draw_ui.cpp and is one click away under View), wizard.cpp (first-run tour), and widgets.cpp (small shared pieces). Drawing goes through gfx.h (Metal on macOS, OpenGL elsewhere), and platform.h hides file dialogs and settings storage per operating system.
- macOS: Accelerate (vDSP) for the signal processing, Metal for LDPC, CoreAudio, Apple's frame interpolation (macOS 15.4+, left out when building with an older SDK). Apple silicon uses NEON code; Intel builds use AVX2 and refuse to start on a processor without it.
- Windows: built for AVX2 (no run-time dispatch), Direct3D 11 for LDPC and picture repair, D3D11VA for video, miniaudio (WASAPI) for sound.
- Linux: the vector kernels exist twice (AVX2 and baseline) and the loader picks one; the GPU decoder is a stub, so error correction runs on the CPU.
ctest --test-dir build runs the unit tests. Most use synthetic signals produced by the generators in the library (t2gen.cpp, dvbt_gen.cpp, atsc_gen.cpp), so they need no radio. test_gpu_ldpc compares the GPU decoder with the CPU one, test_native loads fake radio libraries, test_conceal checks the picture repair against known pictures. test_fm_rx sends a stereo station with RDS and noise through the FM receiver and checks the sound, the stereo separation and the decoded station name and text.
The Android bridge (onair-android/native, outside this repo) includes headers as dect2/<name>.h. Since 0.2.7 the headers live in folders: dect2/remote_api.h is dect2/net/remote_api.h, dect2/modes.h is dect2/engine/modes.h, dect2/rx_json.h is dect2/results/rx_json.h, dect2/adsb_tel.h is dect2/adsb/adsb_tel.h, and so on (mode headers go to their mode folder). tools/dev/path_moves_0.2.7.txt lists every old and new path. The bridge only needs core/include and the dect2core target, so its CMake does not change.
A mode is one row in the mode table (kModes: name, group, blurb, tip, short label and search keys; in 0.2.6 it is in app/toolbar.cpp, in 0.2.7 in app/mode_table.cpp), its receiver in core/src/<mode>/ with a xxxTuning() function that describes the usual frequency and sample rate (core/include/dect2/mode_tuning.h), and its screens in app/<mode>/. Add tests under tests/<mode>/ and, where possible, a signal generator.
See also Contributing, Build from source and Command line.
Getting started
Using OnAir
Tools and guides (0.2.7)
- Band survey
- Message database
- Watchlists
- TV recorder
- Time machine
- Pass scheduler
- Plugin SDK
- Headless server
- All guides
Radios
Modes by group
- TV
- Broadcast radio
- Aviation
- Maritime
- Satellite & navigation
- Two-way radio
- Cellular & rail
- Pagers
- IoT & sensors
- Weather & science
- Amateur: digital
- Amateur: voice & packet
- HF utility
- General & tools
Tutorials
- DVB-T2 TV with a HackRF
- FM radio with RDS
- Aircraft with ADS-B and the map
- Ships with AIS
- DAB+ digital radio
- Weather satellite images
- HF digital: FT8 and WSPR
- Digital voice: DMR, D-STAR, P25
- Pagers: POCSAG and FLEX
- Time stations and the clock
- Record IQ, then the Signal workbench
- The signal sample library
- Control a rig with Hamlib
- Two receivers and the multi-decoder
Reference
Help
Legal and privacy
More