Hey, remember when I used ESD to play music across my network? Well ESD is only for playing back on one computer. And sometimes it lags. And sometimes it causes Amarok to stutter. And it is really old.
PulseAudio is the new ESD. ESD is (or was) basically a single daemon that did only one thing — listen on port 16001 and mix inputs to be piped out through ALSA. PulseAudio is a fancy-pants framework that takes any number of inputs and routes them through some independent modules (much like JACK does). PulseAudio doesn’t even need to give any sound output, as you could set it up to output through a fifo or to a .wav file. Thats silly though. I used it to play awesome music on more than one computers at the same time at my openhouse.
Ok, so here’s the setup: On my desktop computer (Pluto) I have Amarok installed with a very nice dynamic playlist aptly dubbed ‘Awesome’. I’ll explain that playlist some other day, but it plays just what it is titled. The openhouse spanned across the whole house, which included the living room, the garage, and the pool/patio area. In the living room we have Cosmo who mostly runs my MythTV frontend. In the garage I put Charon (and hooked it up to a monitor to use pluto’s Digikam to provide a slideshow). Out back by the pool I placed Callisto and hooked up some speakers. On callisto I ssh’d into Pluto to bring up Amarok’s window. This would let me stay outside and ‘mingle’ while still having access to the music controls. Using Amarok’s xine engine I selected the PulseAudio subengine to connect to the PulseAudio daemon on Pluto.
In PulseAudio, there are two important concepts. Sinks and sources. Sinks are where you send audio to. The name has no connotation of destination, because a ‘sink’ is just something you ‘dump’ stuff into. It doesn’t matter where it goes. Sources are like sinks, but they are where sound comes from, such as a microphone. A third important concept is that of the ‘client’. A client is a program that connects to the server and interacts with the sinks and sources. Protocol modules provide clients. Some modules (such as protocol-cli) provide for a text-based interface to configure/script the daemon. Others (like esound) simply work with audio data. Yet others (native) do both.
From clients, come audio streams. They are not to be confused with sources. In PulseAudio, moving a client’s stream to a different source/sink will cause PA to remember that client goes to that sink/source. New streams from that client are routed as memory serves. Clients can be considered anchors because thats where all the data comes from. Endpoints (where the data finally ends up) can really be anything that the module wants. Some modules (esound-sink/native-sink) send their data out over the network to other servers. Other modules (alsa-sink/oss-sink) work with the hardware. Another module (combine) lets you do some ‘real’ routing, by duplexing one input into several outputs (to send to multiple computers for instance).
I had been playing around with PulseAudio the week before, so I already had a nice /etc/pulse/default.pa written up in advance:
## Load protocols load-module module-esound-protocol-unix load-module module-native-protocol-unix ### Network access load-module module-esound-protocol-tcp load-module module-native-protocol-tcp load-module module-zeroconf-publish ### Automatically restore the volume of playback streams load-module module-volume-restore ### Automatically move streams to the default sink if the sink they are ### connected to dies, similar for sources load-module module-rescue-streams ### load the default sink load-module module-alsa-sink sink_name=local device=hw:0 ### Autoload my MythTV clients add-autoload-sink cosmo module-esound-sink server=cosmo sink_name=cosmo add-autoload-sink saturn module-esound-sink server=saturn sink_name=saturn add-autoload-sink neptune module-esound-sink server=neptune sink_name=neptune add-autoload-sink mythtv module-combine sink_name=mythtv master=cosmo slaves=saturn,neptune set-default-sink local set-default-source local ### HAL creates ugly sink names. #load-module module-hal-detect .nofail ### Load something to the sample cache #load-sample x11-bell /usr/share/sounds/gtk-events/activate.wav #load-sample-dir-lazy /usr/share/sounds/*.wav ### Load X11 bell module load-module module-x11-bell sample=x11-bell ### Publish connection data in the X11 root window load-module module-x11-publish
Let’s go through this piece by piece. First, I load up the two most basic modules. I load the esound module so that older programs such as mplayer can still playback audio. The native protocol is the one PulseAudio uses instead of ESD’s old and busted protocol. The next two loaded modules provide the same protocols but over the network instead of unix sockets. My network is pretty much hands-free, thanks to Zeroconf/Bonjour/UPnP, so I throw that in as well. That module announces the PulseAudio server on the network.
The next two modules (volume-restore and rescue-streams) do simple tasks. volume-restore is similar to alsactl save which saves your volume settings between boots, except PulseAudio lets you have a different volume for each input and output (and everything in between). rescue-streams is a fallback module. If I have my local hardware output as the default, but I have amarok piped out to Cosmo and Cosmo suddenly dies (as it tends to do in important moments), Amarok is moved back to local output.
PulseAudio has two autodetection modules. The first is very rudimentary and basic. It simply pokes around in /dev/ to see what might be available. That one is called detect. The second uses HAL to determine what hardware is installed, but it creates ugly names like alsa_output.pci_1106_3059_alsa_playback_0. Blech. I’ll stick with something easy to remember, like ‘local’ or ‘hardware’. Thats what the alsa-sink module there does. detect and hal-detect autoload alsa-sink modules as needed with appropriate parameters.
The next four lines load modules on-demand. At the server’s startup, there are no esound-sink modules loaded. When I type move-sink-input
Now I assign the default sink and source (removed from my example is the ‘local’ source, which just doesn’t seem to agree with me right now. PA has no problem ignoring an invalid source as the default). I have the hal module commented out for reasons above.
I load up a bunch of sound caches next. Apparently GNOME is supposed to use them to play application events, but they don’t yet. I load one named ‘x11-bell’ for the x11-bell module. That module listens to your X server for XBell events and then plays the given sample.
With ESD, you needed to supply the ESPEAKER variable for everything you wanted to do that wasn’t local. With PulseAudio started on a remote server with X11 forwarding enabled, PA will publish the connection information in the root window which allows local apps to automagically ‘realize’ where the PulseAudio server is.
Previously, I had ESD set up as a system-wide daemon for each of my computers. PulseAudio has entirely superseeded it on Pluto and Callisto. I’ve added a file in /etc/X11/xinit/xinitrc.d/ that runs pulseaudio -D on user login, allowing each user to have their own seperate sound system. Amarok doesn’t lag anymore, nor does it have random static. Overall, I can’t wait for PA to reach version 1.0 where things should be even better (like a GUI admin interface, DBUS, KDE’s Phonon system using PA by that time, etc)
One Final Note
A few people have been googling how exactly you specify what pulseaudio server to connect to. If you have X11 and tunneling set up as explained above, the whole thing happens automagically. If you don’t, and are just using some futuristic mplayer output plugin that fully supports PulseAudio (or don’t have the x11-publish module loaded), you can use the PULSE_SERVER enviroment variable. Explained simply, you just put the address of the server into it. A more complex explanation (that seems silly to me) is found on their wiki.