Configuring a Fedora Media Server

I was trying to configure our file server to be a media server, specifically to play music with MPD and to make its speakers available as a PulseAudio output for laptops on the wireless network. This wound up being far harder than it seems like it should have been, and involved learning (among other things) that SELinux has failure modes I didn't even know existed. And it let me explore the wonders of systemd some more.

So, here's how I did it. All of this is on Fedora 17 with RPMFusion (for MPD). The goals are:

  • PulseAudio running as a system service on the server (this configuration is discouraged, but the use case of configuring a network audio appliance seems to be the sort of use case where it makes sense).
  • PulseAudio device advertised via Zeroconf, so the laptops can just find them.
  • MPD playing via PulseAudio and discoverable via Zeroconf.
  • Two laptops capable (also running Fedora 17) capable of discovering and using the server's audio sink.

Installing the Software

To start, install the following packages with yum:

  • pulseaudio (obviously)
  • pulseaudio-module-zeroconf (for ZeroConf discovery)
  • mpd
  • checkpolicy and policycoreutils (because yes, we need to adjust SELinux configuration)

Running PulseAudio System-Wide

Since PulseAudio's system-wide mode is strongly discouraged, the Fedora packages do not ship with support for it. Therefore, we need to write our own systemd unit to start it. On other platforms, you could write an init script or Upstart job, but that's kinda annoying.

Here's my unit, saved as /etc/systemd/system/pulseaudio.service:

[Unit]
Description=PulseAudio Daemon

[Install]
WantedBy=multi-user.target

[Service]
Type=simple
PrivateTmp=true
ExecStart=/usr/bin/pulseaudio --system --disallow-module-loading --disallow-exit

Some of the arguments in the ExecStart line might be redundant; I don't know. But it works.

We won't start PulseAudio quite yet, because there's still some configuration to do.

SELinux configuration

By default, SELinux blocks a few operations we need to get all this working:

  • PulseAudio and MPD need to send messages to Avahi via D-Bus to publish themselves on the network.
  • PulseAudio does some directory setup before dropping privileges. By default, this is blocked.

So, we need a new SELinux policy module. Here's the module code; save it in a file called audio_server.te (location doesn't matter, as we'll use SELinux tools to install it):

module audio_server 1.0;

require {
    type mpd_t;
    type pulseaudio_t;
    type avahi_t;
    class capability { dac_read_search dac_override };
    class dbus send_msg;
}

# Allow PulseAudio to set up dirs before dropping privileges
allow pulseaudio_t self:capability { dac_read_search dac_override };

# Allow PulseAudio and Avahi to send each other DBus messages
allow avahi_t pulseaudio_t:dbus send_msg;
allow pulseaudio_t avahi_t:dbus send_msg;

# Ditto for MPD
allow avahi_t mpd_t:dbus send_msg;
allow mpd_t avahi_t:dbus send_msg;

Then compile the module and install it in SELinux:

checkmodule -M -m audio_server.te -o audio_server.mod
semodule_package -o audio_server.pp -m audio_server.mod
sudo semodule -i audio_server.pp

As a brief aside, the failure mode I was unfamiliar with is USER_AVC. Typically, when SELinux denies a request, you get an AVC denial in the audit log. This can be found by running ausearch -m AVC. However, when D-Bus SELinux denials are done as USER_AVC denials rather than AVC, so they don't show up with this search. It took me quite some time to figure out that USER_AVC even existed; once I searched for those denials, though, I found the D-Bus denials and was able to get network publishing working.

Firewall Configuration

Right now, I have the firewall completely turned off on the server. However, if you want the firewall on, you just need to open the following ports:

  • 4713/tcp (PulseAudio)
  • 6600/tcp (MPD)
  • 5353/tcp and 5353/udp (mDNS/Zeroconf)

Enabling PulseAudio Zeroconf

This is fortunately easy. Add the following line at the end of /etc/pulse/system.pa:

load-module module-zeroconf-publish

That loads the ZeroConf publication module so the laptop can find PulseAudio.

Configuring MPD

There are a few configuration tweaks I did in /etc/mpd.conf. First was to uncomment the PulseAudio output definition (just search for pulse in the file). I also set log_file to “syslog” so that log messages go to syslog (or the systemd journal — really nice).

Starting everything

Now we are ready to start the servers. Fortunately, everything is nice and easy with systemd:

sudo systemctl enable pulseaudio.service
sudo systemctl enable mpd.service
sudo systemctl start pulseaudio.service
sudo systemctl start mpd.service

Now, clients on the network should be able to see the audio sinks and MPD server.

Configuring Clients

There is a bit of work to do on the laptop to make everything work well.

First, mDNS needs to be allowed through the firewall. Fedora's firewall config tools make this easy, as it's a pre-defined service. So just run system-config-firewall and open up mDNS.

Then install paprefs (to easily configure PulseAudio) and pulseaudio-module-zeroconf with yum, PackageKit, or whatever you use to install your packages. You might also want gmpc to control the music server.

Finally, run paprefs (while logged in) and tell it to “Make discoverable PulseAudio network sound devices available locally”. I think there's a way to do this in a config file, without needing to install paprefs (or involve GConf), but I haven't taken the time to get that working.

You might need to log out to get everything working. But once you have, you should see the server's audio device(s) in the GNOME Sound control panel (or whatever sound settings system you use). You might also want the Extended Volume Indicator shell extension to select audio sinks from the sound menu in the shell.