logo       Dave's Online Memory
A simple WinTV radio server You: 38.107.179.216 Saturday Feb 4, 2012 4:04AM PST
Background

A while back, I purchased a WinTV video/FM tuner card for my home workstation. I love it, but I could barely hear it from the other rooms in the house. The old pc that acts as a router between the home ethernet and the dialup network, also has a wirelss card (for the laptop and the iPaq ). I decided to make the FM radio available over the network.

Rather than reinvent the wheel, and spend a lot of time programming, I decided to make use of existing tools. Fortunately for me (depending on how you look at it), I wasn't aware at the time that the radio's output was sent to /dev/dsp1, and not /dev/dsp, so I had no luck with icecast, or rplay. I dislike the overhead incurred by all of the daemons that get launced by Gnome and KDE, so I wasn't interested in esd or aRTS.

Luckily, I finally happened across the kernel doc's for the btaudio module, and noticed that it referred to /dev/mixer1 and /dev/dsp1. The rest was easy. Stringing together dd, nc (netcat), and sox with a few scripts provided all the functionality I need. Over the course of a few evenings, I added features, and wrapped it all up so that the procedure would be easily reproducible on other systems. Even without the benefit of a tuner, I could still easily stream audio to the network.

The following instructions begin with the basic configuration, and progress to an explanation of all the pieces required to install the setup as a full-blown server on a system.

return.gifTop of page

Requirements
This discussion assumes that one is using a un*x type system. All of the following was developed on linux systems running various distributions - slackware, debian, and redhat. The same methods should work on the BSD's.

Other systems like sun or sgi handle sound differently, so I cannot comment on them. I will update this information with any feedback received.

As was mentioned, only three simple tools are needed to make this work. The first, dd is packaged with the system, almost always in the /bin directory.

The second, netcat, has begun to accompany many distributions. If not installed by default, it can usually be obtained using the package management tools (apt-get install netcat or rpm -i netcat, for example). If not, a quick search of Google should turn up the source code which can be compiled and installed. Touted as a network swiss army knife, netcat is one of those tools that I find indespensible.

The third tool that you'll need is sox, sort of an all-in-one audio toolbox. It's been around for many years, so it usually shows up in the standard distributions, also. Again, if it's not installed on your system, it should be available as a pre-compiled package, and if not, the source is available on the net.

The following instructions assume that the tools are installed in their standard locations (whatever those are). The basic configuration does not require root access as long as one has read access to the audio device. If you can listen to the card, you should be allright. My workstation with the radio card is named ibm on the local net. That is the name that will be used in all the examples.

Assumptions are that the tuner card's output appears as /dev/dsp1, and the network tcp port, 55555, is available. Adjust these to suit your configuration. Choose a different port if 55555 is already in use, for instance. Any unused port will do. If it is above 1024, root priveleges will not be required.

return.gifTop of page

Basic

The easiest way to get the output of the tuner card to another machine is to simply pipe it there through a network socket. First, set up a process to listen on a port and feed it the output of the card:

dd if=/dev/dsp1 | nc -l -p 55555

This says: "pipe the output of the soundcard into netcat which is listening for network connections on tcp port 55555."

Now, on the receiving end (the other computer), connect to netcat using this command:

nc ibm 55555 | play -t raw -r 32000 -s w -f s -c 2 -

Voila! You should hear the output of the radio on the other computer.

What does it all mean? Use netcat to connect to the host named ibm on tcp port 55555, then pipe what you receive into the program named play and tell play the format of the incoming sound data. "Hold on! You never mentioned 'play'!", you say. You're right. It's an alias to the sox program that gets installed when you install the sox package. You can do the same thing with:

nc ibm 55555 | sox -r 32000 -w -s -c 2 -t raw - -t ossdsp /dev/dsp

So, what are all those parameters, and what do they mean? They tell sox about the format of the sound coming from the WinTV card:

-r 32000
The sound rate is 32khz
-w
The data is in word (2 byte) chunks
-s
The data format is signed integers. (unless you're a programmer, believe me, you don't care...)
-c 2
There are 2 channels (stereo).
-t raw
The type is raw. (there is no header as from a .wav file)
-
The input file name. In this case, it is piped in from standard input.
-t ossdsp
The output type. In this case, the sound card.
/dev/dsp
The sound card of the receiving machine. (where to send the output)

Though this method works, and it's great for testing and for one-offs, there are some drawbacks. For instance, every time you want to connect, you first have to launch the server. That means typing the entire command line for a ssh connection. The server also has the annoying habit of dying after every single connection. (Well, that's what we told it to do, after all.) It also won't work for multiple connections because the second server will complain that the port's already in use and die. We'll address the second issue in a minute, but first, let's make it easier to launch these programs. I don't know about you, but I'd need a cheat sheet to remember all those command line switches a couple of weeks down the road...

return.gifTop of page

Scripts

Ok, for the next step, let's automate all this just a little and save our memory for more important tasks. We can wrap the server in a script that contains a loop so that it will launch a new listener whenever a client disconnects with a shell script like so:

#!/bin/sh
PATH=/bin:/usr/bin
while true ; do dd if=/dev/dsp1 | nc -l -p 55555 done

Save this somewhere in your path with a meaningful name like $HOME/bin/radiod. Change the permissions to make it executible (chmod +x $HOME/bin/radiod), and you can now launch the server, by simply typing radiod. Note that the PATH statement has been added for a modicum of enhanced security.

Something similar for the client would look like:

#!/bin/sh
PATH=/bin:/usr/bin

if [ "$1" = "-k" ] ; then
	killall sox
	exit
fi

exec nc ibm 55555 | sox -r 8000 -w -s -c 1 -t raw - -t ossdsp /dev/dsp vol 1.5 &

Same thing; put it in your path and make it executible so that you can launch the client with something simple like radio.

There are a couple of niceties added to this script. The line
if [ "$1" = "-k" ] ; then
checks whether the program was called with a command line argument of -k, and if so, kills the client and exits. The last line, the one that actually launches the client, does an exec and launches the client in the background. This keeps us from having a spare terminal window hanging around just to run the client.

"But, I can just background it from my current session.", you say. Sure you can, but what happens when you log out of that window? This method keeps the client running even if you log out of that session.

The vol 1.5 argument on the end as added to boost the volume. The output wasn't very loud on my laptop. The parameters might need some adjustment; this arrangement tends to make radio announcers talk with a lisp.

return.gifTop of page

Bandwidth

If you've tried the methods above, you'll soon notice that though the music has pretty good fidelity, there's quite a bit of network traffic, and the cpu of the receiving machine keeps pretty busy just to play our music. My gkrellm display hovered at 94% to 99% cpu utilization, and the sound dropped out with almost every disk access.

Since the workstation with the tuner card has a 600mhz processor, I decided to let it work a little harder to reduce the amount of data getting sent to the network. That way, the pc acting as a router doesn't work as hard, network utilization is reduced (more important over wireless where the connection is more like 2mbs than the theorectical 11mbs), and the poor little laptop with a 133mhz cpu doesn't turn the battery into a lap warmer (burner).

To accomplish this, sox is pressed into service on the server side before sending the signal to the netcat daemon. By using sox to convert the sound from stereo to mono, we cut the data rate in half. By dropping the data rate from 32khz to 8khz, we cut it by another fourth. Admittedly, 8khz is more suited for voice than music, but the speakers on my laptop aren't exactly studio monitor quality, so I opted for the additional reduction over signal fidelity. All references to 8000 can be changed to 16000 in the following to improve the sound quality with an associated increase in network traffic.

Here is what the server looks like with these changes:

#!/bin/sh
PATH=/bin:/usr/bin
while true ; do
  dd if=/dev/dsp1 | sox -r 32000 -c 2 -s -w -t raw - -t raw -r 8000 -c 1 - rate
done

The client would now be:

#!/bin/sh
PATH=/bin:/usr/bin

if [ "$1" = "-k" ] ; then
	killall sox
	exit
fi

exec nc ibm 55555 | sox -r 8000 -w -s -c 1 -t raw - -t ossdsp /dev/dsp vol 1.5 &

return.gifTop of page

inetd and xinetd

Ok, this reduces traffic and client overhead, but can't we make this act like a real internet server? Sure, piece of cake. W'ell use the internet super server, inetd (nowadays, xinetd seems to be a popular replacement). This will require a change to the server script to remove the loop, and an addition to the /etc/inetd.conf file. For xinetd, we'll create a file to put into the /etc/xinetd.d directory.

But first... just to be thorough... We'll add our server to the list of internet servers that is kept in the file /etc/services. This is a a necessity for inetd, not for xinetd. Do this by adding the following line to the end of the file (must be root):

radio 55555/tcp # my radio server

If your system uses inetd, add this line to the /etc/inetd.conf file:

radio stream tcp nowait root /usr/sbin/tcpd /PATH_SPEC/radiod

Two things to notice - this assumes that tcp wrappers are installed on your machine. Hopefully, they are. If so, don't forget to update /etc/hosts.allow to allow connections to the server. PATH_SPEC must be changed to match the full path to the program.

This is the configuration file that I use for xinetd:

# default: on
# description: my radio server for the wintv fm tuner - dwc - 7/11/02

service radio
{
	type		= UNLISTED
	port		= 55555
	socket_type	= stream
	protocol	= tcp
	wait		= no
	disable		= no
  server		 = /home/dave/bin/radiod
  user     = root
#	only_from	= 127.0.0.1
}                                                                               

Note that you can limit the hosts who can connect to this server by adjusting the only_from directive. Also notice that the full path specification is required for the server program.

Whether using inetd or xinetd, some consideration might be given to the fact that I run these as root. I see no problem with it since there is no input to the daemon. There are those, however, who would argue that it is dangerous to run any server as root. I tend to be rather paranoid, but perhaps I'm not sufficiently paranoid. As with many of these things, Your Mileage May Vary...

Don't forget to launch/relaunch the inetd server:

killall -HUP inetd
or
service xinetd restart
or - whatever is appropriate for your system...

Since we're now launching out of the super server, we no longer want the loop in the server script. If we incorporate the throttling via sox, the server script now looks like:

#!/bin/sh
PATH=/bin:/usr/bin
dd if=/dev/dsp1 | sox -r 32000 -c 2 -s -w -t raw - -t raw -r 8000 -c 1 - rate

return.gifTop of page

tkradio - a gui interface for windows

All these features now make the server run automatically at boot, and the client is easy to start and stop via radio or radio -k. Of course, this is not enough for today's windowed environments. To that end, I created a simple gui wrapper for the client using the Tk scripting language. It's a little long, so I won't list it. Just click on the screenshot to download it. tkradio.png

Note that this program sports a couple of extra features. I use the radio command line program to control the tuner. Since I have my internal network configured to allow ssh connections using RSA/DSA authentication without passwords, I added the ability to tune the radio card across the network. This works by assigning the list of stations and their frequencies to the drop-down menu, and including them in the command sent via ssh to the machine with the tuner card. This saves an extra ssh connection just to change the station. It also allows me to control the speaker output on the remote box. I don't usually need the sound output in the kitchen if I'm sitting on the front porch with my laptop. The command invoked looks like:

ssh ibm radio -q -m -f 89.7

This sends the command via ssh to the host with the tuner (ibm), and tells the radio program to change the station to 89.7mhz, mute the speaker, and quit.

The program can be used without the remote tuner features. The On, Off, and Exit buttons toggle the radio reception and quit the program.

return.gifTop of page

License and Warranty

This web page, all of these programs and source code are copyright by
dave w capella © 2002 All Rights Reserved
and are released under the terms of the GNU Public License.

Generally, these may be freely distributed and used as long as all headers are are retained, and all modifications are clearly indicated.

The author makes no promise of technical support. However, bug reports, suggestions, questions, and comments are welcome. All will be answered via electronic mail as time allows.

THE  SOFTWARE  IS  PROVIDED  "AS  IS",  WITHOUT  WARRANTY OF ANY KIND,
EXPRESS  OR  IMPLIED,  INCLUDING  BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN  NO EVENT SHALL DAVE CAPELLA OR ANY OTHER CONTRIBUTOR BE LIABLE FOR
ANY  CLAIM,  DAMAGES  OR  OTHER  LIABILITY,  WHETHER  IN  AN ACTION OF
CONTRACT,  TORT  OR  OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

...dave


silly cat image Top of Page FEEDBACK      Comments, Corrections & Questions welcome