Bluetooth headset with Qubes

NOTE: This was done with a bluetooth USB adapter. If you use your wireless card’s built in bluetooth you should be able to do the same, you’ll just need to do it on sys-net instead of a seperate qube

First, create a fedora ‘bluetooth’ qube that we will attach the USB adapter to

Install required packages:

# dnf install blueman udev-x11 

Add the following to /etc/pulse/qubes-default.pa where 10.137.0.0/24 is your qube network (if different)

load-module module-bluetooth-discover
load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1,10.137.0.0/24 auth-anonymous=1

Add user to audio group

# usermod -a -G audio user

Create /etc/systemd/user/pulseaudio.service

 [Unit]
 After=sound.target network.target avahi-daemon.service
 Requires=sound.target
 Wants=avahi-daemon.service
 Description=PulseAudio Sound System

 [Service]
 Type=dbus
 BusName=org.pulseaudio.Server
 BusName=org.PulseAudio1
 ExecStart=/usr/bin/pulseaudio -vv
 ExecStop=/usr/bin/pulseaudio --kill
 Restart=always 

 [Install]
 WantedBy=default.target 

Reload systemd (or just reboot)

# systemctl daemon-reload 

As user, enable it so pulseaudio is running at startup

# systemctl --user enable pulseaudio.service 

Create a script to handle the blueman-applet in /root/bluetooth.sh

#!/bin/bash
while [ true ]; do
   sudo -u user blueman-applet
   sleep 1
done

Make it executable

# chmod +x /root/bluetooth.sh

Add the following to /rw/config/rc.local

iptables -I INPUT -s <CLIENT IP> -j ACCEPT
/root/bluetooth.sh &

Add firewall rule on sys-firewall qube in /rw/config/qubes-firewall-user-script

iptables -I FORWARD 2 -s <CLIENT IP> -d <BLUETOOTH IP> -j ACCEPT

On each client, add the following to /etc/profile to ensure your applications use your bluetooth qube for audio

export PULSE_SERVER=<BLUETOOTH IP>

Now when you attach the USB bluetooth adapter to the bluetooth qube the applet should appear and you’re good to go.

Leave a Reply

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

Time limit is exhausted. Please reload CAPTCHA.