DIY remote kit for the IC-706 part 6: A simple audio server and client

It has been a few weeks since my last update about the IC-706 remote rig project so here is a new one.

I have been working on and off on the audio client and server part, which is pretty much the last piece I need before I can do some realistic field tests. To that end, I have decided that the first iteration of the audio client and server is going to be as follows:

  • Uses the Gstreamer multimedia processing framework.
  • Uses the Opus audio codec.
  • Uses TCP network connection between client and server.

Few weeks ago I started implementing my own client and server code, including interfacing to the ALSA audio system. After some time I thought, ok, this is going to take time to learn and get it right. So I decided to start with gstreamer because it allows building a client and server in a matter of minutes. On the downside, gstreamer is a rather large framework with many dependencies, so implementing a dedicated client and server applications will still make sense later.

The opus codec is a quite amazing audio codec useful for both music and speech. For AM, FM and SSB voice it can provide excellent audio quality with no more than 12 kbps. It can also run at very low latency. The default frame length is 20 millisecond and can be adjusted down to 2.5 milliseconds.

Although I chose the opus codec, gstreamer allows experimenting with a large variety of audio codecs, including raw uncompressed samples. The following gstreamer pipeline reads audio samples from a sound card and sends the raw samples to a TCP socket, if a client is connected:

$ gst-launch-1.0 -v alsasrc device="hw:1" ! 
audio/x-raw, format=(string)S16LE, channels=1, rate=48000 !
tcpserversink host=localhost port=12345

A corresponding client that reads the samples from the TCP socket and sends them to a different sound card is like follows:

$ gst-launch-1.0 -v tcpclientsrc host=localhost port=12345 ! 
audio/x-raw, format=(string)S16LE, channels=1, rate=48000 !
alsasink device="hw:2"

The above client and server runs on the same machine using locashost as client and server. To run them on different machines simply replace localhost at both ends with the IP address of the server.

In order to encode the audio using opus codec, we simply add an opus encoder with suitable parameters to the server and a decoder to the client. Unfortunately, the only way I could get the pipelines to work in gstreamer 1.x was to pack the opus encoded audio into RTP:

$ gst-launch-1.0 -v alsasrc device=hw:3 ! 
audio/x-raw, format=(string)S16LE, channels=1, rate=48000 !
opusenc bandwidth=1102 bitrate=12000 audio=true complexity=5 !
rtpopuspay ! tcpserversink host=localhost port=12345
$ gst-launch-1.0 -v tcpclientsrc host=localhost port=12345 ! 
application/x-rtp, media=audio, clock-rate=48000, payload=96 !
rtpopusdepay ! opusdec ! alsasink device=hw:1

It should be possible to send opus or otherwise encoded audio without wrapping it into RTP and since it is indeed possible in gstreamer 0.10 I presume it is a error introduced in gstreamer 1.x.

If your client has a global IP or is on the same network as the server, you can also try to use RTP over UDP instead of TCP. THis is indeed the normal use case for RTP. The corresponding client and server would look something like this:

$ gst-launch-1.0 -v alsasrc device=hw:3 ! 
audio/x-raw, format=(string)S16LE, channels=1, rate=48000 !
opusenc bandwidth=1102 bitrate=12000 audio=true complexity=5 !
rtpopuspay ! udpsink host=localhost port=12345
$ gst-launch-1.0 -v udpsrc port=12345 ! 
application/x-rtp, media=audio, clock-rate=48000, payload=96 !
rtpopusdepay ! opusdec ! alsasink device=hw:1

UDP is generally better suited for real time streaming of audio and video because lost packets are dropped instead of being retransmitted. But it requires the client to have a global IP or otherwise visible to the server. Therefore I will focus on using TCP connection between the client and the server and implement some sort of connection reset if it turns out to be necessary.

More background information about using RTP in gstreamer is available here.

Up until now I have only tested the audio client and server on a PC using gstreamer 1.4.3. The next item on the list is to move over to the Beaglebones and have the applications start up automatically.