Electronics - Radio - Software

Author: tekmanoid

Broadcasting scanner audio with Linux

Imagine being able to listen in on your scanner from any location with internet access, or “on the go” on your mobile device.

This article explains how you can turn your scanner into a web radio, for broadcasting online. In this tutorial we will implement the following features:

  • continous 24/7 streaming
  • voice activated recording on external USB stick
  • daily log with timestamped entries of logged frequencies
  • management of Icecast / monit / webmin through web interfaces

Scanner receiver

Since we will be picking up more than just one frequency, it will be good to know which that frequency is. We need some way to communicate with the scanner, that’s why the serial port is very useful.

There is a simple communications protocol used by Uniden to interact with their radios. A very useful feature is the radio’s ability to inform us whenever the squelch has broken. This will save us from having to poll the radio during regular intervals! And our python script will be event triggered basically by the radio itself to query the radio about the current frequency. This information will then be passed to Icecast’s server metadata information. Streaming players that can handle this information will then display this metadata which is normally used for the current playing song title. We will instead send the currently reported frequency!

Selecting hardware

When selecting a device for a streamer, keep in mind that you will need a integrated sound card, or you will need an external “add on” USB sound card. A serial port is also recommended if possible for reasons that will be explained above.

As a streaming device I chose the DreamPlug from Globalscale, but any other Linux single board computer will do. Here you can see how it compares to other boards out there. DreamPlug has a single core 1.2 GHz ARM processor with a half GB of RAM. As you can see from the pictures below it offers a lot of connectors but of most importance to us is the microphone input and the LAN port.

Since our device will be online 24/7 its important to keep power consumption as low as possible, not only for the electrical bill, but also since we want our setup to be environmentally friendly! Power consumption is an incredible 5 Watt! (1 A @ 5V)

Streaming software

The software we will use is freely available online from open source projects. Configuration does require some more fiddling on your part and doesn’t work straight “out of the box”, but that is also the fun part of putting all the pieces together.

On my setup, audio streaming is performed with the following software:

Icecast2 – streaming server software for streaming multimedia clients to connect to

DarkIce – a live audio streamer. It records audio from an audio interface (e.g. sound card), encodes it and delivers it to a streaming server.

Two programs are therefore involved in audio streaming. The streaming server (IceCast2) accepts connections from two entities. The audio streamer (DarkIce) which provides the source of the audio. And the clients (VLC/Winamp) who connect to the server to access this audio stream. In a home setup, these two usually coexist in the same machine. If you intend to have a large scale deployment though you could outsource the server part (which puts higher demands on hardware and especially bandwidth).

General overview of the setup.

Icecast Configuration

The Icecast service is configured through an XML formatted file /etc/icecast2/icecast.xml
Here you have to pass critical information, such as the credentials for

  • optional password for the audio feeds
  • required password for the sources providing the streams (darkice)
  • required password for the administrator login in through the web interface In my setup the mountpoint is called “/live”.
    I noticed that you can totally omit the mountpoint information, in that case it will be created with whatever information is supplied by darkice (assuming the souce password is correct)

Darkice Configuration

The Darkice client is configured through a normal configuration file. If you don’t find it in /etc/darkice.cfg , create it with contents similar to:

duration = 0 # duration of encoding, in seconds. 0 means forever
bufferSecs = 5 # size of internal slip buffer, in seconds
reconnect = yes # reconnect to the server(s) if disconnected

# this section describes the audio input that will be streamed
device = default
sampleRate = 8000
bitsPerSample = 16
channel = 1     # channels. 1 = mono, 2 = stereo

# this section describes a streaming connection to an IceCast2 server
# there may be up to 8 of these sections, named [icecast2-0] ... [icecast2-7]
# these can be mixed with [icecast-x] and [shoutcast-x] sections
bitrateMode = cbr # average bit rate
format = mp3 # format of the stream
bitrate = 32 # bitrate of the stream sent to the server
server = localhost # host name of the server
port = 8000 # port of the IceCast2 server, usually 8000
password = hackme # source password to the IceCast2 server
mountPoint = live # mount point of this stream on the IceCast2 server
name = GerakiATC # name of the stream
description = Live Air Traffic Control # description of the stream
url = http://www.tekmanoid.com # URL related to the stream
genre = scanner # genre of the stream
public = no # advertise this stream?a

Additional programs used

Monit is program that monitors the “health” of deamon processes / servers by keeping an eye on CPU / memory usage, response or the lack of it to a service port. In my configuration its used to monitor the IceCast / DarkIce processes.

  • Icecast: check that port 8000 responds to HTTP request and that process is up and running -else, report and restart process.
  • DarkIce: check that process is up and running. DarkIce is configured as a process that depends on IceCast and restarts BOTH if one has failed.

Additionally I added the option to be informed by email whenever the state of these programs change. You have to know the SMTP server settings for this.

screen is a “window manager”. In this project it is used to start the Python scripts and let them output to stdout. It allows the user to execute the program and then “detach” from the screen while the program is still running in the background.

serproxy  is a program that redirects serial ports to network ports. Most programming languages have well defined ways of creating sockets for connecting to network interfaces. Serial ports can be more challenging. That is where serproxy comes in to simplify things. Configuration file /etc/serproxy.cfg

root@dreamplug:~# cat /etc/serproxy.cfg 
# Config file for serproxy
# See serproxy 's README file for documentation

# Comm ports used

# Default settings

# Idle time out in seconds

# Port 1 settings (ttyS0)

ddclient is a deamon program used to update DNS entries whenever it detects a change in the assigned public IP. Most home routers allow this configuration through their own interface, and you can select that option if you want.

# Configuration file for ddclient generated by debconf
# /etc/ddclient.conf

use=web, web=checkip.dyndns.com/, web-skip='IP Address'

usbmount used to automatically and safely mount and unmount pen-drives, used here as external media for storing our voice activated recordings. USB devices will be assigned the following mountpoints /media/usbX where X is a digit from 0 to 7.

Free serial port connected to console, for connection to radio’s COM port

The COM port is already internally “wired” to the linux console, as a last resort connection mechanism in case the SSH service should fail for some reason, ban you, or any other reason. NOTE: For communicating with Dreamplug (or any other “plug PC” for that matter) using another PC port, you will have to connect the two using a null-modem cable, and not a classic serial port extension cable.

Lets assume now that nothing will ever go wrong with our SSH connections and “disconnect” our COM port from the console and use it like we please.

First check the current settings of the COM port:
stty < /dev/ttyS0
Check also whether a process is already using the COM port:

 ps -ef | grep tty
 root  2061  ttyS0    00:00:00 /sbin/getty -L ttyS0 115200 linux

This process is started during system startup from the /etc/inittab file. In it we find indeed the following line:

# Example how to put a getty on a serial line (for a terminal)
 T0:23:respawn:/sbin/getty -L ttyS0 115200 linux

All we need to do now is comment out this line and reboot.

Running automatically on startup

The sole purpose of this device will be to act as an streaming server. This device should be purely “plug and play”, therefore we have to fire all required services right after startup in an automated fashion. We will use: /etc/rc.local  As it says in the comment section, “this file is executed at the end of each multiuser runlevel”. We will add a call to our startup bash script located in /root/scripts/startup.sh that will initiate all necessary services and programs for our streaming server.

#icecast auto started by init.d
#start darkice
/usr/bin/screen -S darkice -d -m /usr/local/bin/darkice

#seems to be required for serial port
/bin/stty -F /dev/ttyS0 19200 time 5 ignbrk -brkint -icrnl -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke
#start serproxy
/usr/bin/screen -S serproxy -d -m /usr/local/bin/serproxy

#start python script
/usr/bin/screen -S ubc780 -d -m python /root/scripts/ubc780.py

#set blue LED on Dreamplug to indicate all services running
echo 1 > /sys/class/leds/guruplug\:green\:wmode/brightness

IceCast & Darkice

Alternatively, these services can be set to run automatically on startup by setting their configuration file in /etc/default

root@dreamplug:~# cat /etc/default/darkice 
# Defaults for darkice initscript
# sourced by /etc/init.d/darkice
# installed at /etc/default/darkice by the maintainer scripts

# This is a POSIX shell fragment
# Additional options that are passed to the Daemon.

The Icecast / Darkice init scripts did not seem to work with the start/stop/status commands. For some reason the init scripts darkice.pid and icecast2.pid did not  the pid files with the current process IDs. To fix I added the “–make-pidfile” flag to the start-stop-deamon command below

 start-stop-daemon --start --quiet --pidfile $PIDFILE \
 --background --chuid $USER:$GROUP --exec $DAEMON --make-pidfile

and similarly for Icecast

# Defaults for icecast2 initscript
# sourced by /etc/init.d/icecast2
# installed at /etc/default/icecast2 by the maintainer scripts

# This is a POSIX shell fragment

# Full path to the server configuration file

# Name or ID of the user and group the daemon should run under

# Edit /etc/icecast2/icecast.xml and change at least the passwords.
# Change this to true when done to enable the init.d script

Open ports on router

The result of the netstat -ntlp command gives us a quick look at what services are running and on which ports. This is no guarantee that they are running correctly, but still a first indication.

nestat -ntlp, showing listening ports and corresponding services

As you can see, a number of ports are used, that need to be port-forwarded correctly through the router in order for our services to be visible and available to the “outside world”.

  • 8000 – IceCast2
  • 2812 – Monit
  • 5331 – Serproxy
  • 10000 – Webmin

You will have to port forward the streaming port 8000 to the same or another external port of your choice in the routers application / port configuration page. Besides the 8000 port you might want to forward also other services.

Port forwarding page on Linksys router. Internal ports can be mapped to any external port of your choice. Beware that this setup shown  above expects the IP of the streaming device to be static on

Set static IP on streaming device

By default these devices have DHCP enabled in /etc/network/interfaces configuration file. It would be a good advice to alter these settings and use a static IP like in the example below, were IP is used.

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static

auto eth1
iface eth1 inet dhcp

Register a domain name on a Dynamic DNS service

Since anyone running a similar setup will most likely be behind a dynamic IP assignment by the Internet provider, we need  a domain name with which the service can be reached. There are a number of dynamic IP registers out there, some of them are free and might require the host-name to be confirmed during regular (monthly) periods. You will have to set the appropriate information in /etc/ddclient.conf configuration file! See section above on ddclient.

Screenshot from the dynamic DNS service provider  showing the current mapping between host-name and dynamic IP

Python script automation

  • looprecorder.py – Voice Activated (VOX) recorder. Records audio that surpasses a minimal threshold. The recordings are saved to an external USB device. I would recommend getting one with a LED indicator, to have visual feedback of whenever a “read/write” is taking place. The recording are saved as raw WAV files. At midnight these files are re-encoded to MP3 files and the process terminates. This script has been added to a daily crontab at 00.00 every night for automatic startup. At the end of the day you end up with a daily recording with the date stamp as the filename.
  • bc780.py – Radio interface. Connects to the serial port of the radio. Activates the “Squelch report” option (QUN command) that sends (asynchronously) a “+” character whenever the squelch on the radio is broken, which means that a reception is being made.


Run alsamixer to set the microphone levels to an adequate amount around 30% on my system and with the “autogain” set to disabled (press M)


There are a number of players out there that support streaming audio, but we should prefer the ones that have metadata support so we can see the tuned frequency baked into the stream!
A personal favourite that dates back to the Napster era is Winamp. Enter your server’s URL as such:

Winamp’s Open URL (CTRL + L)

Hopefully you should see the player starting to buffer and connecting to the stream successfully.

Winamp: Excellent player with metadata support. Note the tuned channel and frequency displayed!

Listening behind a proxy

If you plan to connect with your client from a corporate environment you will most likely be sitting behind a proxy. You will have to know the proxy IP address and configure this in the client player’s configuration.

Configuring the proxy on Winamp

That’s all folks! Enjoy listening to your scanner online!

Raspberry FM radio from an old PCI-tv card

Going through some old electronics I discovered I had an old PCI tv card for analog TV. These are preety much useless now that DVB-T has turned TV broadcasts to a digital format. I remembered though that it had a classic FM radio tuner as well. So I hooked it up to the PC and after downloading a bunch of drivers I still couldn’t get it to work, most probably because the Win OS I was using was unsupported after so many years. So…in frustration and in lack of better things to do I decided to proceed with the following hack…

I removed the tuner module from the card. But before doing that, while it was still plugged into the powered PC, I measured the voltages on the pins between the tuner module and the PCB. My suspicion was that this module, like many others, communicate via a serial protocol. Most times the protocol is I2C, which is an “inter-chip” communication bus consisting of just clock and data lines. All chips are connected to the same I2C bus, so each device is selected by refering to it with a special address that it responds to. Compare this to the SPI protocol were no addresses are used, but the desired chip is selected with an extra pin, the “chip select” (CS) pin.

The position of the SDA, SCL lines was determined by opening the metalic cover of the tuner and making notes of the chip numbers, especially the ones close to the pins. Some of the chips noted were:

TDA9809 – Single standard multimedia IF-PLL and FM radio demodulator

(T)SA5523-1.4 GHz I2C-bus controlled multimedia synthesizer (pin3/4 are SDA,SCL)

TDA5737 – hyperband and UHF mixers/oscillators for TV and VCR 3-band tuners

TDA7040 – Low voltage PLL stereo decoder (MPX pin 8, pin 5/6 are left/right audio)

The existence of a chip capable of I2C was the guarantee that the tuner module is indeed controlled by this protocol. By following the PCB lines from SA5523 above it was relatively easy to determine what pins were connected to the tuner module and made accessible to the outside world.

The pin numbers of the tuner module were determined to be as follows. The ones marked with bold are the ones actually used for something on our project:

The pin numbers of the tuner module were determined to be as follows. The ones marked with bold are the ones actually used for something on our project:

  • (NC)
  • (NC)
  • VT (Tuning voltage readout?)
  • 5V
  • SCL – Serial CLock
  • SDA – Serial DAta
  • AS – Address Select
  • (NC)
  • Right Audio channel
  • Left Audio channel
  • 2nd IF AF
  • Video out
  • 5V
  • Multiplexed stereo + RDS etc

In order to make the tuner module usable for this project we had to establish communication with it. First we need to know what I2C address this tuner module “listens to”. For this the Raspberry PI was used which as native support for I2C.

So by hooking up the Raspberry to the tuner module and the now known I2C lines( SDA, SCL) and 5V, GND we were ready to do that. Recall that Raspberry’s GPIO section has a pair of pins specially dedicated to I2C.

There is a very useful command available through the Raspberry terminal command line called i2cdetect which allows us to discover the address of any such chip on the lines. The tuner responded with “61“!

So now that we established the address, we can continue to determine the commands that will actually place the tuner in various modes, select desired frequency etc. Beware that pin number 7 (Address Select) can be set low or high to change the tuner I2C address in case there happens to be another device using exactly this one (since they are not unique).

The master (Raspberry) is initially in master transmit mode by sending a START followed by the 7-bit address of the slave it wishes to communicate with, which is finally followed by a single bit representing whether it wishes to write (0) to or read (1) from the slave.

Example: Suppose we want to tune to 101.300 MHz. We do 101.3 + 10.7 = 112.000.
Divide this with 0.050 = 2240 or ….0x8c0 in hexadecimal.
The byte sequence to command the tuner would be:

<address><freq upper byte><freq lower byte><controlbyte1><controlbyte2>

The address byte 0x61 is actually shifted left to fit the write(0) bit, so 0xC2 is actually sent.

The control bytes set various things like internal mixers, stereo/mono settings etc. They were found with a bit of experimentation and consulting online documentation for similar modules.

Extra functions for FM tuner mode are :

FM Stereo/Mono toggling mode by toggling bit 2 of controlbyte 2

Mute on/off toggling by toggling bit 4 of controlbyte 2

For displaying the currently tuned frequency a 7 segment, 4 digit display is used. Internally this module is made up of a pair of 74HC595 shift registers.
Beware that this code is written for the variant with just TWO such chips for the 4 digit segments. The code required to run the FOUR chip version is different. These buttons will trigger our code on the falling edge, so to prevent spurious interrupts by noise etc each one will be pulled up by a 10k resistor.

The SPI protocol will be used to talk to this unit.

For tuning up and tuning down we need at least two buttons, I decided to add two more in order to control Stereo/Mono and Mute/Unmute functions. That is a total of 4 buttons that will be configured as interrupt driven. We could use simple polling but I decided to use interrupts.

In the tune up/down callback functions the frequency global variable will be checked that it is within bounds (87.5-108) and tuning below 87.5 will take you immediately to 108. Similarly if you surpass 108 MHz, you will find yourself at 87.5 MHz.

The left and right channel pins from the tuner will be connected to a normal 3.5mm jack (dont forget ground pin) and we will use a 3.5mm audio jack cable to feed this to an existing pair of speakers, or existing WIFI with AUX/LineIn input.

Dont forget to connect the tuner module to an external antenna, preferably an FM antenna for best reception!

Tune your favorite station now and enjoy the music!

© 2022 Tekmanoid

Theme by Anders NorenUp ↑