Skip to content

CWNE88/dablast

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dablast

DAB/DAB+ multicast streamer — modelled after dvblast, for digital radio.

Receives a DAB/DAB+ ensemble from an SDR device and streams each radio service as an individual MPEG-TS multicast stream (RTP or raw UDP, chosen per service). Each stream carries a single audio programme with full DVB PSI tables (PAT, PMT, SDT, EIT) and DLS (now-playing text) updates.

How it works

RTL-SDR (or compatible SDR)
         │
         ▼
   OFDM demodulator
   (frequency sync, FFT, Viterbi)
         │
         ▼
   DAB multiplex decoder
   (FIC → ensemble/service info)
   (MSC → subchannel audio data)
         │
         ▼
   DAB+ superframe filter
   (Reed-Solomon FEC, LATM audio)
         │
         ▼
   MPEG-TS packetiser
   (PAT + PMT + SDT + EIT + audio PES)
         │
         ▼
   multicast RTP/UDP  239.x.x.x:port

One stream is sent per configured service. VLC, mplayer, ffmpeg, and IPTV clients can tune each address directly.

Requirements

sudo apt install \
  build-essential cmake \
  librtlsdr-dev \
  libfftw3-dev \
  libfaad-dev \
  libmpg123-dev \
  libtwolame-dev \
  libmp3lame-dev

Optional:

  • libairspy-dev — Airspy HF+ support
  • libSoapySDR-dev — generic SDR support via SoapySDR

Building

cmake -B build -S .
cmake --build build -j$(nproc)

Optional build flags:

Flag Default Description
-DRTLSDR=ON ON RTL-SDR USB dongle support
-DAIRSPY=OFF OFF Airspy HF+ support
-DSOAPYSDR=OFF OFF SoapySDR generic driver
-DKISS_FFT=OFF OFF Use KISS FFT instead of FFTW3

Usage

Step 1 — Find your frequency and service IDs

Scan a single frequency:

./dablast -f 202928000 --scan

Or scan multiple frequencies in one pass using a frequency list file:

./dablast -l /etc/dab-Brisbane.freqs --scan

Example /etc/dab-Brisbane.freqs:

197648000 # 8B
202928000 # 9A
204640000 # 9B
206352000 # 9C
208064000 # 9D

Or skip the frequency file entirely and sweep every channel in dablast's own built-in table (Band III + Band L, 5A..13F/LA..LP — the same list --list-channels prints):

./dablast --scan --all-channels

dablast will scan each frequency in turn, printing results to stdout and progress/status to stderr. Frequencies with no DAB signal are skipped after a 5 s sync timeout (vs. 30 s for a single -f FREQ scan, where a signal is already expected) - a channel with no signal at all produces no other output, so dablast prints a "Still waiting for signal..." heartbeat every 3 s so a multi-frequency sweep never looks indistinguishable from a hung process. This makes scanning every DAB channel in Band III (all 38 of them, e.g. via dablast --list-channels) take a few minutes in the worst case rather than the better part of 20.

Every progress line also shows the global DAB channel designator (e.g. "9A") alongside the frequency when it's a recognized one, e.g. dablast: tuning to 202928000 Hz (9A) ... - useful for matching a scan's progress against a known channel list rather than memorising raw frequencies.

Output example (stderr):

Ensemble found. Collecting service list...
Ensemble: DAB+ Brisbane 1 (9A)  EId 0x1006  202928000 Hz

Output example (stdout), one line per service as name:frequency:sid:codec, where codec is dab (native MPEG-1/2 Layer II) or dab+ (HE-AACv2):

MMM 80s:202928000:0x12A5:dab+
HeartHits:202928000:0x12A7:dab+
Inspire Digital:202928000:0x12CD:dab
Coles CBD:202928000:0x1259:dab+
GOLD 80s:202928000:0x126D:dab+

Step 2 — Create a config file

Each line maps a service to a destination, with four mandatory, comma-separated fields:

# /etc/dablast-202928000.conf
# Format: ADDR:PORT,SID,CODEC,TRANSPORT
239.2.2.1:20000,0x12A5,passthrough,rtp   # MMM 80s
239.2.2.2:20000,0x12A7,passthrough,rtp   # HeartHits
239.2.2.3:20000,0x12CD,mp2,rtp           # Inspire Digital, transcoded to MP2
239.2.2.4:20000,0x1259,passthrough,udp   # Coles CBD, raw UDP instead of RTP

All four fields are mandatory — there are no defaults. ADDR:PORT is the multicast destination (see "Full option reference" below for the exact rules). Any malformed line is a hard error: dablast prints the offending line and exits immediately rather than silently skipping it. Duplicate multicast ADDR:PORT destinations are rejected the same way.

Step 3 — Start streaming

dablast -f 202928000 -c /etc/dablast-202928000.conf

Full option reference

Tuning:
  -f FREQ      Centre frequency in Hz  (e.g. 202928000)
  -l FREQFILE  File of frequencies to scan (one per line)

Hardware:
  -a INDEX   Adapter/device index (default: 0)
  -F DRIVER  Input driver: rtl_sdr (default), rtl_tcp, soapysdr
  -g GAIN    RF gain in tenths of dB, or -1 for AGC (default: -1)

Modes:
  --scan          Scan ensemble and print service list, then exit
  --list-channels Print the built-in DAB channel table (Band III +
                  Band L, 5A..13F/LA..LP) as NAME:FREQ_HZ, then exit.
                  No device or frequency needed - useful for driving
                  a full-spectrum scan across every known channel
                  without needing a region-specific frequency file
                  the way DVB does.
  --all-channels  With --scan: scan every channel in that same
                  built-in table directly, instead of -f or -l - a
                  one-flag full-spectrum scan with no frequency
                  file needed at all.
  -c FILE    Stream config, one service per line, four mandatory
             comma-separated fields: ADDR:PORT,SID,CODEC,TRANSPORT

             ADDR:PORT is the multicast destination.

             CODEC:
               passthrough  HE-AACv2 for DAB+, MP2 for DAB, exactly as
                            broadcast. No decode/encode work at all.
               mp2          Transcode to MPEG-1/2 Audio Layer II; DAB
                            sources are already MP2 and pass through
                            untouched. Costs a decode+encode pass per
                            DAB+ service and a lossy re-encoding
                            generation loss, in exchange for maximum
                            client compatibility (see "Audio quality"
                            below).
               mp3          Transcode to MPEG-1/2 Audio Layer III (via
                            libmp3lame), VBR joint stereo, ~80kbps
                            average. Always a decode+encode pass -
                            DAB itself has no Layer III mode, so
                            there's no untouched-passthrough case the
                            way mp2 has for native DAB sources.

             TRANSPORT:
               rtp          RFC 2250 RTP header + MPEG-TS to the
                            multicast group. Play with rtp://ADDR:PORT
               udp          Raw MPEG-TS, no RTP header, to the
                            multicast group. Play with udp://ADDR:PORT

             Duplicate multicast ADDR:PORT destinations are rejected at
             parse time. Any malformed line is a hard error: dablast
             prints it and exits.

Other:
  -h         Show this help

Multiple ensembles

Run one instance per DAB ensemble (frequency). Each instance uses one SDR device:

dablast -f 197648000 -a 0 -c /etc/dablast-197648000.conf &
dablast -f 202928000 -a 1 -c /etc/dablast-202928000.conf &

Playing a stream

# VLC — a service configured with the rtp transport
vlc rtp://@239.2.2.1:20000

# VLC — a service configured with the udp transport
vlc udp://@239.2.2.4:20000

Or add the multicast addresses to any IPTV playlist (M3U), using the URL scheme that matches the transport column configured for that service.

Audio quality

With the passthrough codec, dablast passes audio through from the DAB multiplex without re-encoding — the audio quality is exactly what the broadcaster transmits.

Service type Codec What you should hear
DAB MPEG-1 Audio Layer II (MP2) Stereo, 48 kHz — universally supported
DAB+ HE-AACv2 (SBR + Parametric Stereo) Stereo, 48 kHz — requires capable decoder

DAB+ requires a specific decoder to play at full quality. Here is what HE-AACv2 actually does and why it can go wrong:

  • The broadcast transmits a mono AAC core at 24 kHz — this is the base layer
  • SBR (Spectral Band Replication) reconstructs the upper frequencies, bringing the output up to 48 kHz
  • Parametric Stereo (PS) reconstructs the stereo image from the mono core, giving full left/right stereo

A decoder that handles all three layers correctly will output full 48 kHz stereo. A decoder that only reads the base layer will output 24 kHz mono — noticeably thin and low quality.

Desktop VLC works correctly because it uses FAAD2, a decoder specifically built for DAB+ that handles 960-sample AAC frames and the full HE-AACv2 chain.

Many other players (Android apps, hardware IPTV boxes, some media servers) use hardware AAC decoders or general-purpose software decoders that do not support the 960-sample frame size used by DAB+. These will fall back to the 24 kHz mono base layer regardless of how the stream is signalled. This is a decoder limitation, not a problem with the stream itself — the stream content is correct.

Transcoding to MP2 (codec config column)

To sidestep the DAB+ decoder-compatibility problem above, dablast can decode DAB+ (HE-AACv2) audio and re-encode it to plain MP2 — a format every player, hardware IPTV box, and Android app already decodes correctly at full quality. Choose this per service via the codec column in the config file:

239.2.2.3:20000,0x12CD,mp2,rtp   # Inspire Digital, transcoded to MP2
Codec column Output codec DAB (native MP2) services DAB+ (HE-AACv2) services
passthrough native MP2 passthrough HE-AACv2 passthrough
mp2 MP2 passthrough (already MP2, untouched) decoded + re-encoded to MP2
mp3 MP3 decoded + re-encoded to MP3 decoded + re-encoded to MP3

Trade-offs of mp2 versus passthrough:

  • CPU cost: DAB+ services now require a real decode+encode per service instead of a byte copy. Fine for a handful of services on a modern PC; budget accordingly on something like a Raspberry Pi — only enable transcoding on the services that actually need it, since each transcoded service adds real-time CPU load and too many at once can starve the OFDM demodulator and cause dropouts.
  • Quality: re-encoding DAB+ audio is a second lossy generation (AAC → PCM → MP2), on top of whatever the broadcaster already lost encoding to AAC. It fixes the 24 kHz-mono-fallback problem, but isn't bit-identical to the broadcast.
  • Compatibility gain: MP2 output plays at full quality (48 kHz, stereo) on literally anything, with no dependence on the client having a DAB+-aware AAC decoder.

There's no way to transcode a DAB (MP2) source up to HE-AACv2 — dablast only has an MP2 encoder, not an AAC one — so a DAB service configured with mp2 is always a passthrough. This is a deliberate scope limit rather than a gap: nobody has needed it, and a compliant HE-AACv2 encoder is a real licensing/dependency burden to carry for a corner case.

Transcoding to MP3 (codec config column)

mp3 behaves like mp2 (same decode step for DAB+, same untouched-vs- transcode split doesn't apply — MP3 isn't a DAB native format at all, so every service, DAB or DAB+, goes through a decode+encode pass) but targets MPEG-1/2 Audio Layer III via libmp3lame instead, VBR joint stereo at roughly 80kbps average:

239.2.2.5:20000,0x126D,mp3,rtp   # GOLD 80s, transcoded to MP3

Same CPU-cost caveat as mp2 applies — budget accordingly, and only transcode the services that actually need it. Choose mp3 over mp2 for smaller output at a given perceptual quality (Layer III's usual advantage over Layer II); choose mp2 where the client specifically expects it, since it's the more universally-supported IPTV/broadcast format of the two.

Transport: RTP vs raw UDP (transport config column)

dablast is multicast-only — the transport column just picks how each service's packets are framed on the wire:

Transport column Wire format Play with
rtp 12-byte RTP header (RFC 2250, PT=33) + MPEG-TS rtp://ADDR:PORT
udp Raw MPEG-TS, no header udp://ADDR:PORT
239.2.2.4:20000,0x1259,passthrough,udp   # Coles CBD, raw UDP instead of RTP

Unicast delivery, if you need it, is a job for an external UDP-to-TCP proxy sitting in front of the multicast stream — not something dablast does itself.

Supported hardware

  • RTL-SDR — any RTL2832U-based USB dongle (default, tested)

The following drivers are included from the welle.io backend and should work in principle, but have not been tested with dablast:

  • Airspy HF+ — compile with -DAIRSPY=ON
  • SoapySDR — any SoapySDR-supported device, compile with -DSOAPYSDR=ON
  • rtl_tcp — network-attached RTL-SDR via rtl_tcp server, use -F rtl_tcp
  • Raw IQ file — for testing, use -F rawfile

License

Copyright (C) 2026 Paul Stanley paul.stanley@tutanota.com

GNU General Public License v3.0 or later — see LICENSE.md.

This project incorporates code from welle.io, SDR-J, DABlin, and third-party libraries. See LICENSE.md for details.

About

DAB/DAB+ multicast streamer

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages