Broadcast-quality OBs with Raspberry Pis

OpenOB‘s been ticking along nicely but it’s historically needed a bit of oomph and capital in the form of two computers running Linux. This isn’t often what you’ve got on your PC and it’s not something you can easily chuck in your reporter’s rucksack to take along to an event.

This limits its usefulness somewhat. So what you need instead is something cheap, small, and lightweight, that can run Linux and do everything you need it to with regards to OpenOB and network management.

Enter the Raspberry Pi, the £25 wonder-SBC. It’s got audio out (not in), runs Linux off an SD card, is small, runs off 5V power supplied via USB, and did I mention it’s £25? Okay, £30 if you buy from Farnell with shipping thrown in, and probably more like £60 when you’ve bought a power supply, sound card, SD card, etc. But we’re still talking an outside broadcast remote and receiver for a grand total of around £200. Compare that with the £1,500 per end of the current cheapest commercial solution, or the £5,000+ an end and up boxes found in most professional OB trucks. Sure, you don’t get their slickness or polish or even all their features, but you can move audio and you can do it well with OpenOB. With Opus, now from 16kbps all the way to 384kbps or linear PCM.

The primary OS supported for the Pi is Raspbian, a Debian derivative, which is awesome – because Debian/Ubuntu is the standard platform on which I develop OpenOB.

So can we actually make this perfect storm come to pass?

Update, 3rd Apr 2014: This post has been superseded by the OpenOB documentation. Please don’t try and use this post to configure your Pi – it is wrong in places as a result of updates and is not being maintained.

Update, 11th Nov 2013: The Raspberry Pi is as of this moment not capable of doing high quality audio while also using its network interface due to the USB bus being shared between audio cards and network interface, combined with a firmware regression. Substituting a Raspberry Pi for a Beaglebone Black in the below guide will work better but it is not flawless. Please see the OpenOB documentation (which includes an updated version of most of this guide)  and openob-users mailing list for more information – OpenOB on embedded devices is a work in progress. The new Pi Audio Shield may solve the USB contention issue but will not be available until Nov 20th at the earliest.

Hardware required

You’ll need some bits and pieces to pull this off. If you’ve got a Raspberry Pi rig working already you’re most of the way there.

  • 2 x Raspberry Pi (tested with 512MB Model B Revision 2 boards from Farnell, rev1/256MB boards should work fine too)
  • 2 x MicroUSB to USB cables (I’m using these)
  • 2 x USB power supply (the Portapow 2A seems to work well)
  • 2 x SD card (2GB minimum, I’d recommend these, faster is better)
  • 2 x USB sound card (You can get away with one if you’re okay with using the onboard 3.5mm jack output on the Pi – this seems okay so far as a cheap option with analogue and SPDIF)
  • 1 x Pair of headphones for testing
  • 1 x Audio source – I use an old Android mobile I have lying around and a 3.5mm jack to jack lead
  • (Optional) 2 x Cases for the RPis (Just good practice, really)
  • (Optional) 1 x Battery for the mobile RPi, some form of USB battery pack. This guy seems okay so far, though is undervolting the board a teensy bit (4.77v)

The USB sound cards can be as nice or as cheap as you like. For phono I/O, Behringer (shudder) make the UCA202 which is cheap and should work fine, though I’ve not tested it. You can use any high-end USB card you like so long as it can either be bus powered by the RPi (which can be dodgy) or, preferably, it has its own power supply. If you’re trying to rig a battery system together, bear this in mind. Also of reference for battery rigs: You’ll need to provide up to 700mA of current, probably anywhere from 200-500mA constantly, at 5V. You can find more on supported/tested hardware at the eLinux wiki.

Installing prerequisites

Install and set up your Raspberry Pis with Raspbian as normal – I’d recommend the 1GHz turbo mode overclock, give the system all the RAM, and disable desktop on boot. You’ll probably want to enable SSH so you can work on these from your desktop to set up/test, and change your password. Once that’s all done, reboot and shell in to your Pis. You might want to run a quick apt-get update/apt-get upgrade to make sure your system is up to date and running the latest everything before your proceed, and reboot again if required. On both ends run the following:

sudo apt-get install git python-gst0.10 python-redis \
gstreamer0.10-plugins-base gstreamer0.10-plugins-bad \
gstreamer0.10-plugins-good gstreamer0.10-plugins-ugly \
gstreamer0.10-tools python-gobject python-gobject-2 gstreamer0.10-alsa python-setuptools

That’s our GStreamer and Redis dependencies installed, along with git to let you grab the OpenOB project. On one end (this will be your ‘receiver’ and sit in your studio/rack/etc), install redis:

sudo apt-get install redis-server

Install OpenOB

Now we’re good to install OpenOB on both ends:

sudo easy_install OpenOB

Now we’ve got OpenOB installed! (If you’re using pip, which you can install with “sudo apt-get install python-pip”, just “sudo pip install OpenOB”) Let’s get started. Note at this point we’re basically following the guide on the OpenOB homepage – nothing deviates away from Debian here, happily. On a side note before we continue – you can image the SD card you’re using fairly trivially and save it to disk. Once you get the setup right you can just image the card, and use it to duplicate your setup onto many Pis. If you want a little fleet of RPi devices, this can make life easier. Alternatively you should be able to fairly trivially script much of this.

Configure Redis

Next we need to tell the receiver’s Redis server to listen outside of localhost. Either edit /etc/redis/redis.conf and modify the bind line to bind to 0.0.0.0 then restart redis, or run this magic incantation to have your system do that for you:

sudo sed -i.bak ‘s/bind 127.*/bind 0.0.0.0/’ /etc/redis/redis.conf && sudo service redis restart

Audio Devices and Settings

Got that? Good! Let’s check your audio settings on the transmitter. The Pi comes with one ALSA sound card, hw:0, which is output-only and is the onboard sound card output. This isn’t too interesting so we’ll probably be working with your external card. Happily, OpenOB supports multiple sound cards with ease. Let’s look at what the Pi makes of our setup with aplay/arecord:

pi@raspberrypi ~/openob $ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
 Subdevices: 8/8
 Subdevice #0: subdevice #0
 Subdevice #1: subdevice #1
 Subdevice #2: subdevice #2
 Subdevice #3: subdevice #3
 Subdevice #4: subdevice #4
 Subdevice #5: subdevice #5
 Subdevice #6: subdevice #6
 Subdevice #7: subdevice #7
card 1: Device [USB Sound Device], device 0: USB Audio [USB Audio]
 Subdevices: 1/1
 Subdevice #0: subdevice #0
pi@raspberrypi ~/openob $ arecord -l
**** List of CAPTURE Hardware Devices ****
card 1: Device [USB Sound Device], device 0: USB Audio [USB Audio]
 Subdevices: 1/1
 Subdevice #0: subdevice #0

We’ve got a capture source and two playback sinks. We’re going to use the external here so we want to specify card 1, subdevice 0. This maps to hw:1,0 in ALSA-speak. Let’s have a look at alsamixer and check we’re doing okay – pass in the card we’re interested in (from that list) as an argument.

alsamixer -c 1 -V capture

On most cheap cards, especially with more than one port, you get a lot of stuff rolled into one audio device to the PC with control via alsamixer. Hit space and arrow keys to disable inputs you don’t want or tweak volumes. We’ll use OpenOB to verify we have audio. Let’s crack on and get these guys talking to each other. Run ifconfig on the receiver to find out the IP address of that Pi, and set up the transmitter. The first run of OpenOB will take a few seconds while Python files get compiled down nicely. We don’t need to set up the receiver yet, since we’re still verifying we have audio coming into the Pi where we expect it for now.

openob 192.168.0.213 test-link tx 192.168.0.213 -d hw:1,0

Change your IP address of the receiving Pi to suit. If you get a connection refused error, check Redis is set up properly and you’ve restarted it. If all goes well you should see something like this:

-- OpenOB Audio Link
 -- Starting Up
 -- Parameters: Namespace(audio_input='alsa', bitrate=96, config_host='192.168.0.213', device='hw:1,0', encoding='opus', jitter_buffer=150, link_name='test-link', mode='tx', port=3000, receiver_host='192.168.0.213')
 -- Connected to configuration server
 -- Configured receiver with:
 - Base Port: 3000
 - Jitter Buffer: 150 ms
 - Encoding: opus
 - Bitrate: 96 kbit/s
(<enum GST_STATE_CHANGE_SUCCESS of type GstStateChangeReturn>, <enum GST_STATE_PLAYING of type GstState>, <enum GST_STATE_VOID_PENDING of type GstState>)
 -- Waiting for caps - if you get this a lot, you probably can't access the requested audio device.
 - Caps: application/x-rtp, media=(string)audio, clock-rate=(int)48000, encoding-name=(string)X-GST-OPUS-DRAFT-SPITTKA-00, ssrc=(uint)1273910127, payload=(int)96, clock-base=(uint)1805896953, seqnum-base=(uint)33228
 -- Transmitting: L -700.00 R -700.00 (Peak L -350.00 R -350.00)

Note that we’ve got no audio. Okay! Let’s fix that. Back to alsamixer, try another input. Start it up again and hopefully you’ll get something like this:

 -- Transmitting: L -19.85 R -19.59 (Peak L -7.27 R -7.56)

Result! We’ve got audio coming in. Let’s send it and see if we can receive, too.

Running a link

Leave the command running on the transmitter and go to the receiver:

openob 192.168.0.213 test-link rx
-- OpenOB Audio Link
 -- Starting Up
 -- Parameters: Namespace(audio_output='alsa', config_host='192.168.0.213', device='hw:0', link_name='test-link', mode='rx')
 -- Connected to configuration server
 -- Configured from transmitter with:
 - Base Port: 3000
 - Jitter Buffer: 150 ms
 - Encoding: opus
 - Bitrate: 96 kbit/s
 - Caps: application/x-rtp, media=(string)audio, clock-rate=(int)48000, encoding-name=(string)X-GST-OPUS-DRAFT-SPITTKA-00, ssrc=(uint)1959599910, payload=(int)96, clock-base=(uint)1877854339, seqnum-base=(uint)21406
 -- Receiving: L -18.17 R -17.92 (Peak L -5.91 R -4.71)

We have now got audio coming over! Stick some cans in your onboard output and you should hear whatever you’re feeding the other sound card. If you have a USB sound card on the receiver, don’t forget to append -d hw:1,0.

4 thoughts on “Broadcast-quality OBs with Raspberry Pis”

  1. The sudo/sed/redis magic incantation can be written in a far simpler way!

    sudo sed -i.bak ‘s/bind 127.*/bind 0.0.0.0/’ /etc/redis/redis.conf && sudo service redis restart

    The -i flag to sed will edit in-place, optionally creating a backup file with the given suffix (just use -i to create no backup). It also keeps things like SELinux contents in place, which would otherwise get lost.

  2. Hi James, I’m having a bit of trouble setting up an Ubuntu 12.04 Desktop Machine as the receiver to my Raspberry Pi transmitter and wondered if you’d be able to point me in the right direction?

    I’m seeing this message and I’m not sure how to proceed from here:

    — Unhandled exception occured, please report this as a bug!
    Traceback (most recent call last):
    File “/usr/local/bin/openob”, line 5, in
    pkg_resources.run_script(‘OpenOB==2.3.2′, ‘openob’)
    File “/usr/lib/python2.7/dist-packages/pkg_resources.py”, line 499, in run_script
    self.require(requires)[0].run_script(script_name, ns)
    File “/usr/lib/python2.7/dist-packages/pkg_resources.py”, line 1235, in run_script
    execfile(script_filename, namespace, namespace)
    File “/usr/local/lib/python2.7/dist-packages/OpenOB-2.3.2-py2.7.egg/EGG-INFO/scripts/openob”, line 29, in
    manager.run(opts)
    File “/usr/local/lib/python2.7/dist-packages/OpenOB-2.3.2-py2.7.egg/openob/manager.py”, line 94, in run
    receiver = RTPReceiver(audio_output=opts.audio_output, audio_device=opts.device, base_port=port, encoding=encoding, caps=caps, bitrate=bitrate, jitter_buffer=jitter_buffer, jack_name=(“openob_tx_%s” % opts.link_name) )
    File “/usr/local/lib/python2.7/dist-packages/OpenOB-2.3.2-py2.7.egg/openob/rtp/rx.py”, line 35, in __init__
    self.decoder = gst.element_factory_make(“opusdec”,”decoder”)
    gst.ElementNotFoundError: opusdec

    As far as I can see I’ve fulfilled all the dependencies for 12.04 following the guide on the front page of the OpenOB project on GitHub, a similar message is displayed when transmitting from the same machine “Couldn’t fulfill our gstreamer module dependencies! You don’t have the following element available: opusenc”

    Any help would be much appreciated,
    Thanks in advance,
    Gary

    1. Well, as the (more recent) OpenOB says, you’ve not got the opusenc or opusdec GStreamer element available. On 12.04 this is because the GStreamer package version is too old. Debian Wheezy certainly supports Opus if you really want that, but CELT works well on 12.04 – just start the transmitter with -e celt and you should be good to go. I’m not sure on 12.10’s support for Opus but it may have a recent enough package version – I’d be interested if anyone’s tried this out.

      I’m aware the documentation is sub-par on this and I’ll fix it shortly.

Comments are closed.