Sudo Rambles
  • Home
  • Privacy Policy
  • About
  • Contact
Categories
  • cheat-sheets (2)
  • guides (15)
  • news (1)
  • ramblings (4)
  • tutorials (11)
  • Uncategorized (10)
Sudo Rambles
Sudo Rambles
  • Home
  • Privacy Policy
  • About
  • Contact
  • guides

Decoding DMR with DSD and a rtl-sdr

  • 24th January 2025

Intro to dsd

Today we’re going to use dsd to decode DMR messages using a rtl-sdr dongle. The main point of this guide is to run everything on Mac OS, as there’re plenty of alternatives for Windows and Linux. I couldn’t really find a proper guide on how to set up everything on OSX, so here it is.

What is DMR?

Before we start, what exactly is DMR? Here’s a quote from an amazing online resource about it:

DMR stands for Digital Mobile Radio and uses the Motorola TRBO protocol for communications. Like other digital modes such as D-Star, C4FM and APCO P25, the TRBO protocol converts your voice into a digital form and sends it out via RF (with other bits of information included) and allows you to communicate to other DMR radios and also DMR repeaters, which are networked together around the world via the internet.

Source: https://www.dmrfordummies.com/library/

How to find one in the wild

You can generally find DMR signals on the following frequencies (EU):

  • 441.0000 MHz
  • 446.5000 MHz
  • 446.0750 MHz
  • 433.4500 MHz
  • 145.7900 MHz
  • 145.5100 MHz

Source: https://www.onesdr.com/dmr-frequency-list/

When scanning these frequencies it’s important to distinguish DMR signals from other digital and encrypted traffic. Here’s an audio example that I recorded of a DMR signal:

Decoding DMRs on MacOS

Now that you have your signal – what can we do to synthesise speech out of these digital signals. The answer – DSD. Let’s set it up

DSD setup

Go ahead and clone/download this repo: https://github.com/szechyjs/dsd. Jared has done an amazing job of creating this port, which works wonderfully under Unix systems.

Before proceeding with the setup, ensure that you’ve installed the pre-requisites. Link: https://github.com/szechyjs/dsd/wiki/Installation#dependency-installation-on-osx
At the time of writing they are listed as:

brew install git cmake libsndfile itpp portaudio
brew install --HEAD mbelib

Once you have the repo cloned follow the instructions he has provided here: https://github.com/szechyjs/dsd/wiki/Installation

Or TL;DR:

  1. cd dsd
  2. mkdir build && cd build
  3. cmake .. && make
  4. sudo make install

Once you’ve done that you should have access to the dsd executable in your terminal. The help output is visualised below:

As you can see both dsd and mbelib are listed at the top with their versions, so we’re good to go.

DSD useful commands

I’ve included several flags here that are super useful.

  1. dsd -h – shows the complete help listing (the image above is trimmed)
  2. dsd -i pa:1 -o pa:2 – example startup with audio input on device #1 and output on device #2
  3. dsd -a – show all audio devices. You should pick the ids for the above command from here

Audio routing

DSD works by audio ingression from a given source. You have several options on how you can set this up. I’ll go through a couple that I’ve tested and are working at the time of writing.

rtl_fm

If you have a compatible dongle you can use the rtl-sdr lib package to pipe audio. Here’s some more info on that

  • Wiki: https://osmocom.org/projects/rtl-sdr/wiki
  • Source code: https://gitea.osmocom.org/sdr/rtl-sdr.git

I won’t go into setup instructions for this, follow the Readme. It’s a basic make-install chain.

Once you have that installed, check what rtl_ executables you have available:

The one we need to get dsd running is rtl_fm. Feel free to explore what the others do, each of them is amazing.

You can test the setup by running:

rtl_fm -f 155862500 -p 49 -s 48000 -g 25 -M fm test.txt

The output should be:

This command tells rtl_fm to tune into 155.862 Mhz in FM mode with 48k sample rate, and to output to a test.txt file.

We’ll look into piping into dsd and decoding in a bit

Alternative – VB Cable

VB Cable is a fairly old piece of software that links the output of a given service to the input of another. Figuratively creating a “cable” connection between the two. The setup on OSX is super simple, just follow the instructions here: https://vb-audio.com/Cable/

Once you have it installed, open the VBCable control panel and you’ll see this UI:

Screenshot

As you can see the link is operational and is awaiting input.

Now just use any sdr software to output to the VBCable. Examples:

SDR++

Screenshot

GQRX

Screenshot

Starting DSD with the audio pipe

No matter how you’ve decided to pipe audio into dsd it’s time to actually set up the workflow. I’ll begin with the VBCable solutions as they are easier to setup and debug.

The VBCable way

Run dsd -a to find the appropriate audio input and output devices. We’re looking for VBCable here for the input and your speakers/headphones as the output. Example:

You can see that the VBCable is on id 3 and my speakers are on id 1.

Running dsd is as simple as:

dsd -i pa:3 -o pa:1 -v99

The in and out flags are clear, just make sure you prefix them with pa:xxx. The -v flag increases the verbosity of the output messages, the default is 0 (this is optional).

You should now see an output like this:

Now simply start your SDR software, make sure to pipe the audio out to the VBCable and start looking for those DMR signals.

The rtl_fm way

In certain ways starting up dsd with the rtl_fm util is easier. Here’s the command:

rtl_fm -f 1681187500 -p 49 -s 48000 -g 25 -M fm | dsd -i - -o pa:1 -v99

It’s the same rtl_fm startup command as before, but we’re now piping the output to dsd directly. When using -i - it tells dsd to use the piped in data as the input. The rest of it is straight forward – -o pa:1 is the output device and -v99 increases the verbosity of the output messages.

Decoding signals

Now that everything is up and running how do you actually decode signals? Well dsd does this automatically. When you find an appropriate signal you’ll see a stream of messages in the output. If the signal is strong enough you’ll also hear voices.

Example of a partial decode in GQRX:

Example of a partial decode in SDR++:

Why do I say partial? You can see the percentage of invalid packets is rather high in both cases. Some invalid packets are okay, but 60-70% is too much. The dsd service does recognise the signal as DMR and tries to decode it, even receiving data headers, but it’s missing too many frames.

You can do several things to try to fix this like:

  1. The signal is too weak, move the antenna, adjust the length (diapole), increase gain, add filters
  2. Try to switch over to WFM and play around with the bandwidth
  3. Use NFW but adjust the bandwidth to one of: 12500, 7000, 4000

Once I get a clear voice recording, I’ll update this guide.

As an example, here’s a video of when everything goes right.
The video is NOT mine!

Happy decoding!

Sudo Rambles
  • LinkedIn
  • GitHub
A programmer's blog

Input your search keywords and press Enter.