While PCs still usually provide a full set of analog jacks capable of outputting a 5.1 audio, other modern hardware (such as TVs) is usually limited to digital audio outputs (and sometimes analog outputs limited to stereo sound). These outputs are either S/PDIF (coaxial or optical) or HDMI. When the PC is connected to a TV, a pretty logical setup is to carry the sound via HDMI to the TV, and from there via S/PDIF or HDMI ARC to a 5.1 amplifier. However, it isn’t always as simple as it sounds.
For a start, S/PDIF is a pretty antiquated interface originally designed to carry stereo PCM audio. The modern versions of the interface have sufficient bandwidth for up to 192 kHz sampling rate and up to 24 bit audio depth. However, in order to support more than two audio channels, the transmitted sound needs to be compressed. S/PDIF hardware usually supports MPEG, AC3 and DTS formats.
HDMI is better there. HDMI 1.2 technically supports up to 8 channels of PCM audio, 2.0 up to 32 channels. However, not all hardware actually supports that. In particular, my TV seems to only support stereo PCM input, and ignores additional channels when passed 5.1 audio. Fortunately, additional audio channels work when compressed input is used. HDMI supports more audio formats, including DTS-HD MA and TrueHD.
In this post, I’d like to shortly explore our options for making a PulseAudio-enabled Linux system output compressed 5.1 over S/PDIF or HDMI (apparently both are treated the same from ALSA/PulseAudio perspective).
Enabling S/PDIF / HDMI passthrough in mpv
It’s rather unlikely that you’ll be playing uncompressed audio these days. When playing movies, you’ll often find that the audio tracks are encoded using one of the formats supported by S/PDIF or HDMI. Rather than having mpv decode them just to have ALSA compress them again (naturally with a quality loss), why not pass the encoded audio through to the output?
If you’re using HDMI, the first prerequisite is to set the PulseAudio’s configuration profile to digital stereo
(found on Configuration
tab of pavucontrol). This could be a bit confusing but it actually enables you to transfer compressed surround sound. Of course, this implies that you’ll no longer be able to output surround PCM sound via HDMI but if you’re going to enable compressed audio output anyway, it doesn’t matter.
Then, you need to enable support for additional output formats. If you’re using pavucontrol, the relevant checkboxes can be found on Output Devices
tab, hidden under Advanced
. Tick off all that your connected device supports (usually all).
Finally, you have to enable S/PDIF passthrough (the same option is used for HDMI) in mpv, via ~/.config/mpv/mpv.conf:
audio-spdif=ac3,dts,eac3
audio-channels=5.1
The full list of formats can be found in mpv(1) manpage.
If everything works fine, you’re going to see something like the following in mpv output:
AO: [alsa] 48000Hz stereo 2ch spdif-ac3
(ignore the stereo part, it is shown like this when passing compressed surround sound through)
Note that audio passthrough requires exclusive access to the sound card, i.e. you won’t be able to use it simultaneously with sound from other apps.
Enabling transparent AC3/DTS compression of audio output
While passthrough is often good enough for watching movies, it is not a universal solution. If, say, you’d like to play a game with surround sound, you need the regular audio output to support it. Fortunately, there is a relatively easy way to use ALSA plugins to enable transparent compression and make your S/PDIF / HDMI output 5.1-friendly.
For a start, you need to install an appropriate ALSA plugin. If you’d like to use AC3 audio, the plugin is found in media-plugins/alsa-plugins[ffmpeg]. For DTS audio, the package is media-sound/dcaenc[alsa].
The next step is adding the appropriate configuration to /etc/asound.conf. The snippet for AC3 is:
pcm.a52 {
@args [CARD]
@args.CARD {
type string
}
type rate
slave {
pcm {
type a52
bitrate 448
channels 6
card $CARD
}
rate 48000
}
}
The version modified for DTS is:
pcm.dca {
@args [CARD]
@args.CARD {
type string
}
type rate
slave {
pcm {
type dca
channels 6
card $CARD
}
rate 48000
}
}
Honestly, it’s some black magic how it works but somehow PulseAudio just picks it up and starts accepting 5.1 sound, and the TV happily plays it.
Finally, the Ubuntu Community wiki suggests explicitly setting sampling rate in PA to avoid compatibility issues. In /etc/pulse/daemon.conf:
default-sample-rate = 48000
Does anyone know a similar solution using VLC?
I find MPV a bit too simple (e.g. no subtitles?).
I can’t help you with VLC but I can tell you that mpv definitely has subtitle support, both for in-file and external subtitles. Note that at some point they’ve stopped autoloading .txt-suffixed subtitles, so you need to either name them .sub or .srt, or pass -sub-file explicitly.
On VLC for passthrough, you can select in the Audio settings (translated from french, may be different):
Output: Alsa audio output
Check: Use S/PDIF
Device (something similar depending on your setup): HD-Audio Generic, HDMI 1 HDMI Audio Output
Nice walkthrough by the way!
Thanks for the write up. Gentoo needs more mini guides like this.
I never managed to get a52 encoding to work on ubuntu.
I tried the DTS alternative that worked very rapidly for me:
https://github.com/darealshinji/dcaenc