Thursday, March 27, 2014

Network Audio Streaming with PulseAudio

I had been trying to come up with a way to get sound from my PC (and laptop) to a stereo for awhile. Recently, when the onboard audio on my desktop's motherboard died (thanks Gigabyte!), the situation became somewhat more urgent.

As I grabbed a USB audio interface as a temporary solution to my desktop's now dead audio, a thought came to my mind. Why don't I take one of the ARM boxes I have sitting in a junk drawer, hook this USB interface to it, and stream my desktop's sound to it using PulseAudio? So that's what I did.




The ARM box I'm using is a GuruPlug Server Plus (don't buy one, the second Google hit is titled "don't waste your money", they aren't wrong). I used to run Fedora on it and use it as a router but one day the interfaces stopped coming up, so I switched to a consumer router and threw the GuruPlug in a drawer. Fedora no longer supports the GuruPlug, so I threw in a leftover MicroSD card (8 GB) and installed Debian following this guide.

The GuruPlug has no built in audio support. So I'm using a USB audio interface. Of the two I have available, I picked a Behringer UCA-202 (which actually tests pretty well as far as USB DACs go).

After getting Debian installed and configuring SSH so I didn't have to be connected to the silly USB->Serial adapter, it was time to get PulseAudio sorted.

Enough of story time, now for some 'howto'. I'm going to assume the 'source' (where you'll be streaming from) is a Linux box of some sort with a GTK compatible environment (Gnome 3, Unity, whatever) with PulseAudio already running as the sound server. I'm going to assume the 'sink' (where you'll be streaming to) is already networked, with some kind of package management running, and the sound hardware properly enumerated (it appears when you do lspci, or lsusb, or lswhateveryoupluggeditinto).

On the sink, install PulseAudio if not already done. For my Debian box, I followed the instructions in the Debian Wiki.

To make this easy on ourselves. We're going to make PulseAudio discoverable over Zeroconf. Set up Zeroconf (often interchangeably called Avahi) on the sink, again, I followed a guide from the Debian Wiki.

We also need the PulseAudio Zeroconf module installed on both the source and the sink. In the case of both Debian and Fedora, the package is called 'pulseaudio-module-zeroconf'.

Now we need to configure the sink to both start PulseAudio in system mode (I don't fully understand why this is necessary, but I was unable to make this work with PulseAudio running on the sink as a per-session daemon [likely because no session exists...]), and make PulseAudio discoverable via Zeroconf.

To make PulseAudio start in system mode on the sink, edit the file '/etc/default/pulseaudio' to contain:

PULSEAUDIO_SYSTEM_START=1

Now, to make the sink appear over Zeroconf, edit '/etc/pulse/system.pa' to contain:

load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;192.168.0.0/16
load-module module-zeroconf-publish

Depending on your network configuration, you may need to massage the above slightly. I'll include my complete files at the end of this post.

We're done working on the sink at this point. Restart the sink (or just PulseAudio).

Now, for the source. If you didn't install 'pulseaudio-module-zeroconf' on the source as mentioned above, do so now. Also install 'paprefs'. Restart PulseAudio (or sign off and back on again, or reboot) so the module is available to load.

Open 'paprefs', and check the box for "Make discoverable PulseAudio network sound devices available locally" as shown below. No other options should be required.

Screenshot from 'paprefs' showing "Make discoverable PulseAudio network sound devices available locally" checked

At this point, the network connected PulseAudio sink should appear in your sound manager, as seen below:

Screenshot showing networked sink appearing in Gnome 3's Sound preferences dialog

The hostname for my remote sink is Elizabeth, hence "pulse@Elizabeth". Simply select your networked sink, and all audio should be routed there.

A few oddities to note. On my laptop, the network sink always appears. On my desktop, I often have to uncheck and recheck "Make discoverable PulseAudio network sound devices available locally" in paprefs to make the networked sink appear. On my desktop, audio from Flash videos sometimes 'breathes', but when played from my laptop, it will instead occasionally stutter. All other content streams fine from both devices. I attribute it to usual Flash crappiness.

Sink '/etc/default/pulseaudio':

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# Start the PulseAudio sound server in system mode.
# (enables the pulseaudio init script - requires that users be in the
# pulse-access group)
# System mode is not the recommended way to run PulseAudio as it has some
# limitations (such as no shared memory access) and could potentially allow
# users to disconnect or redirect each others' audio streams. The
# recommended way to run PulseAudio is as a per-session daemon. For GNOME/KDE/
# Xfce sessions in Ubuntu Lucid/10.04, /etc/xdg/autostart/pulseaudio.desktop
# handles this function of automatically starting PulseAudio on login, and for
# it to work correctly your user must *not* have "autospawn = no" set in
# ~/.pulse/client.conf (or in /etc/pulse/client.conf). By default, autospawn
# is enabled. For other sessions, you can simply start PulseAudio with
# "pulseaudio --daemonize".
# 0 = don't start in system mode, 1 = start in system mode
PULSEAUDIO_SYSTEM_START=1

# Prevent users from dynamically loading modules into the PulseAudio sound
# server. Dynamic module loading enhances the flexibility of the PulseAudio
# system, but may pose a security risk.
# 0 = no, 1 = yes
DISALLOW_MODULE_LOADING=1

Sink '/etc/pulse/system.pa':

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/usr/bin/pulseaudio -nF
#
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# PulseAudio is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PulseAudio; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.

# This startup script is used only if PulseAudio is started in system
# mode.

### Automatically load driver modules depending on the hardware available
.ifexists module-udev-detect.so
load-module module-udev-detect
.else
### Use the static hardware detection module (for systems that lack udev/hal support)
load-module module-detect
.endif

### Load several protocols
.ifexists module-esound-protocol-unix.so
load-module module-esound-protocol-unix
.endif
load-module module-native-protocol-unix

### Automatically restore the volume of streams and devices
load-module module-stream-restore
load-module module-device-restore

### Automatically restore the default sink/source when changed by the user
### during runtime
### NOTE: This should be loaded as early as possible so that subsequent modules
### that look up the default sink/source get the right value
load-module module-default-device-restore

.ifexists module-dbus-protocol.so
### If you want to allow TCP connections, set access to "remote" or "local,remote".
load-module module-dbus-protocol access=local
.endif

### Automatically move streams to the default sink if the sink they are
### connected to dies, similar for sources
load-module module-rescue-streams

### Make sure we always have a sink around, even if it is a null sink.
load-module module-always-sink

### Automatically suspend sinks/sources that become idle for too long
load-module module-suspend-on-idle

### Enable positioned event sounds
load-module module-position-event-sounds

### Make the device network discoverable
load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1;192.168.0.0/16
load-module module-zeroconf-publish

No comments:

Post a Comment