Lossless HD Audio over HDMI with PulseAudio under Linux

Today I finally managed to get lossless HD audio working from my Linux media PC over HDMI! I’ll probably update this post as time goes, but for now it’s a quick recipe of what I did:

Configure a PulseAudio ALSA sink to use the HDMI output

Video cards present HDMI audio interfaces in an interesting way. There appears to be one audio device per digital display connector on the GPU (yes, you really can transport audio over a DVI connector!). For some reason, sending audio to any of the output devices on the GPU will work – although you only get two channels unless you select the correct device! I suspect this is related to buffer sharing amongst the output devices, but I digress…

To find the correct output device, run a few iterations of

speaker-test -c8 -twav -D[hdmi:CARD=NVidia,DEV=3]

replacing the part in square brackets with an available output as shown by

aplay -L

Here’s a sample of what the aplay output looks like on my system:

[email protected] ~ $ aplay -L
null
    Discard all samples (playback) or generate zero samples (capture)
pulse
    PulseAudio Sound Server
sysdefault:CARD=PCH
    HDA Intel PCH, ALC892 Analog
    Default Audio Device
front:CARD=PCH,DEV=0
    HDA Intel PCH, ALC892 Analog
    Front speakers
surround40:CARD=PCH,DEV=0
    HDA Intel PCH, ALC892 Analog
    4.0 Surround output to Front and Rear speakers
surround41:CARD=PCH,DEV=0
    HDA Intel PCH, ALC892 Analog
    4.1 Surround output to Front, Rear and Subwoofer speakers
surround50:CARD=PCH,DEV=0
    HDA Intel PCH, ALC892 Analog
    5.0 Surround output to Front, Center and Rear speakers
surround51:CARD=PCH,DEV=0
    HDA Intel PCH, ALC892 Analog
    5.1 Surround output to Front, Center, Rear and Subwoofer speakers
surround71:CARD=PCH,DEV=0
    HDA Intel PCH, ALC892 Analog
    7.1 Surround output to Front, Center, Side, Rear and Woofer speakers
iec958:CARD=PCH,DEV=0
    HDA Intel PCH, ALC892 Digital
    IEC958 (S/PDIF) Digital Audio Output
sysdefault:CARD=pcsp
    pcsp, pcsp
    Default Audio Device
front:CARD=pcsp,DEV=0
    pcsp, pcsp
    Front speakers
hdmi:CARD=NVidia,DEV=0
    HDA NVidia, HDMI 0
    HDMI Audio Output
hdmi:CARD=NVidia,DEV=1
    HDA NVidia, HDMI 1
    HDMI Audio Output
hdmi:CARD=NVidia,DEV=2
    HDA NVidia, HDMI 2
    HDMI Audio Output
hdmi:CARD=NVidia,DEV=3
    HDA NVidia, HDMI 3
    HDMI Audio Output

Turns out the correct device on my system is hdmi:CARD=NVidia,DEV=3. Piece of cake! The hard part is over, right? It is if you’re a PulseAudio guru… which I’m not. After wading around some forums and delving into man pages for a few hours, here’s what I found solved the issue:

Add this line to /etc/pulse/default.pa to create the new sink:

load-module module-alsa-sink device=hw:2,7 rate=192000 channels=8 tsched=0 sink_properties=device.description=HDMI sink_name=HDMI channel_map=front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right

Also, you’ll want to comment out the lines that automatically load other modules. Find the lines below and insert a pound sign to disable them:

#load-module module-udev-detect
#load-module module-detect

Now that the sink is created, configure output settings and sample rates for any PulseAudio instances!

Configure PulseAudio Defaults

Edit the file /etc/pulse/daemon.conf and add a block like this to the end:

default-sample-channels = 8
default-sample-rate = 192000
enable-remixing = no
enable-lfe-remixing = no
flat-volumes = no
resample-method = src-sinc-best-quality

A little explanation is in order – here’s what those parameters do:

  • default-sample-channels – Informs PulseAudio clients that they should prefer 8 channel streams. The default is 2, which is rather bland when you’ve got 6 to spare!
  • default-sample-rate – Informs PulseAudio clients that they should prefer 192,000kHz sample rate, which sounds spectacular. (Sometimes considered “studio quality”!) Be aware that a lot of audio equipment won’t support this sample rate. If yours doesn’t, try 96000 or 48000 instead.
  • enable-remixing – Disables (or enables) up- and down-mixing of source streams. This means that a 2-channel stream would be up-mixed to 7.1 channels, or a 32-channel stream would be down-mixed to 8 channels. I disable this because there is too much bass when a 2-channel signal is duplicated to 7 channels. You should test it both ways to see which you prefer. (I’m hoping a future version of PulseAudio will give more control over this functionality, I’d really like to up-mix post-processed signals with the low end removed to avoid this problem!)
  • enable-lfe-remixing – Basically the same as enable-remixing but PulseAudio will pull the low end of all played channels and route it to the lfe channel. Essentially useless on any system that has crossover functionality in the DSP. (Of course, this might be useful for analog outputs but who does that anymore?)
  • flat-volumes – Causes PulseAudio to adjust the output volume for a particular sink to the highest of all the sources on that sink. I disable this because it’s frustrating for the output volume to change when I don’t expect it.
  • resample-method – Selects what method PulseAudio will use to resample sources on playback. The default is probably okay, but I prefer to use the highest quality option for my home theatre application. You can see what methods are available by running pulseaudio –dump-resample-methods.

Enjoy!

Now that PulseAudio is configured, you can test the setup by running

speaker-test -c8 -twav

Assuming everything is in order, sit back and enjoy! Any application using PulseAudio for output will understand that 8 channels are available and should output properly.