PulseAudio with a VNC Terminal Server

I have an Arch Linux VNC terminal server, serving Raspberry Pi 4 clients running Manjaro ARM on a local trusted network. The following guide allowed me to get the audio of the terminal server connected to the Pi’s.

This works both ways, both for forwarding audio from the terminal server to either the audio jack or HDMI on the Pi’s, and conversely, audio from a USB microphone connected to the Pi is also forwarded to the terminal server.

Multiple users can log in to the terminal server simultaneously without their audio getting mixed up with that of another user.

It’s a messy hack, but works surprisingly well.

Terminal Configuration

While I have used Manjaro Arm as the operating system on the Raspberry Pi’s, likely the steps are similar for Raspberry Pi OS of another operating system.

Install Pulseaudio on the Pi (unless it’s already on there)

pacman -Sy pulseaudio

Edit the global configuration file at /etc/pulse/default.pa, adding or uncommenting the following, to enable network support in PulseAudio.

load-module module-native-protocol-tcp auth-anonymous=1

Optionally, for a little extra security (or even not accidentally forwarding sound to the wrong terminal in a trusted environment), an identical cookie can be placed on the client and server, with auth-anonymous=1 removed from the config file. In the interests of simplicity, I’ve decided against this for my situation.

Terminal Server Configuration

The terminal server is set up according to the Arch Linux TigerVNC wiki guide, and specifically, using on demand sessions, and with LightDM as the display manager.

Install PulseAudio on the terminal server. No special configuration of PulseAudio on the terminal server is required, though I find pavucontrol essential for controlling the volume levels etc.

pacman -Syu pulseaudio pavucontrol

Create a cron job to keep /var/log/lightdm/lightdm.log readable by any user. Note that this is a messy hack and possibly untrusted in an insecure environment. The file will revert to becoming unreadable to users if this is not done.

* * * * * chmod o+r /var/log/lightdm/lightdm.log

Next, create a script, owned by root but executable by users, located at /etc/profile.d/userclient.sh, that is run by any user at login.

This script exists to find out which terminal the user is logging in from, and set the user’s environment variable to tell Pulse to connect the audio to that terminal. It achieves this by filtering /var/log/lightdm/lightdm.log for lines showing that a user has logged in (this gives the user) and lines showing the xdmcp seat they are on.

LightDM needs to have DEBUG level logging enabled for this to work, but I don’t believe it’s possible to change this anyway.

This is tested with lightdm-1:1.30.0-4. Future versions may need changes made to the script, if the log output is worded or arranged differently.

#!/bin/sh

/etc/profile.d/userclient.sh
USER=`whoami`
DISP=`cat /var/log/lightdm/lightdm.log \
        | grep -e "User .* authorized" -e "Stopping greeter; display server will be re-used for user session" \
        | sed -z 's/authorized\n/,/g' \
        | grep "$USER" \
        | tail -n 1 \
        | sed 's/Seat/,/g' \
        | sed 's/:/,/g' \
        | sed 's/User/,/g' \
        | cut -d ',' -f 6 \
        | sed 's/ xdmcp//g' `

if [ "$DISP" ];
then
        # Find the IP address of the VNC client
        ADDR=`systemctl status xvnc.socket | sed 's/Triggers://g'  | grep "xvnc@$DISP" | cut -d ':' -f 2 | cut -d '-' -f 2`
        # Add to user's profile
        export PULSE_SERVER="$ADDR"
fi

You should now be able to access audio over the network.

Leave a comment

Your email address will not be published. Required fields are marked *