Important notes:
1) Tested and confirmed to work on FreeBSD 13.0-RELEASE.
2) Obviously you need to first confirm whether FreeBSD supports the built-in Bluetooth of your laptop/computer.
3) For this guide, we will focus on Intel Bluetooth as that's my case in particular. Hence the use of comms/iwmbt-firmware.
4) Both "hcsecd" and "sdpd" Bluetooth-related services are intentionally not enabled on /etc/rc.conf because they're not really needed in my setup. Nonetheless, adding them shouldn't do any harm.
5) Remember to replace "BD_ADDR" by the real unique address of your Bluetooth device. How to get this address is explained later on.
# First, become superuser and install the programs we need:
# Nowadays, drivers are auto-loaded at system start-up, but installing comms/iwmbt-firmware was still needed, as well as issuing the following command afterwards:
# Next load cuse and make it permanent, for it's needed by virtual_oss:
# Start the Bluetooth stack:
# Now find your Bluetooth headphones (make sure they're on):
# If unsure, find out the human readable name assigned to your remote device:
# Create a connection to your remote device:
# Edit /etc/bluetooth/hosts to assign an alias to your device (replace "98:52:3d:48:3a:51" with your actual address). Example:
# Now create a virtual sound device so you can use your Bluetooth headphones as a sound sink:
*Let's explain a little some of the meaning of the above command:
- I wanted this virtual device to be exposed to other apps, so install entry in /dev/sndstat. ( -T /dev/sndstat)
- Enabled automatic resampling to fix bad sound quality when playing audio with a different sample-rate than default. ( -S)
- The default volume was too high so I set a negative output amplification. ( -a o,-4)
- I chose a sample rate of 44100 Hz but you can use 48000 Hz instead if that's better for your hardware. ( -r 44100)
- I wanted to be able to use my laptop's internal mic simultaneously while using my headphones. ( -R /dev/dsp0)
- You can disable the recording device by setting "-R /dev/null" instead.
All this works great for programs that use OSS as sound backend (the vast majority in FreeBSD). However, other backends need certain workarounds or extra steps:
[sndio]
# To fix applications that use sndio as backend (e.g. Chromium), you need to enable the sndiod service:
[Pulseaudio]
# To fix the ones that use a pulseaudio backend (e.g. Firefox and linux Brave), recording the sound output and immediately redirecting it to /dev/dsp acts as a workaround:
# Also you'd want to mute your computer speakers to avoid hearing double:
# Depending on your particular case, you may need to replace "oss_output.dsp0.monitor" by a different source-output. To list the ones available use:
[OpenAL]
# Sadly, I haven't found yet a workaround to hear sound from Wine games and programs.
# Finally, I created a little script to automate the audio output device switching between Bluetooth headphones and the built-in speakers:
*Note: This script is meant to be run as normal user. Remember to make it executable (chmod +x). Also I suggest to add the commands that need "sudo" to /usr/local/etc/sudoers to allow them running without the need of entering your password. At least I did that.
You can then create a keyboard shortcut to run it easily.
You may also want to increase the
DISCLAIMER: I'm not a coder, so I assume the script above could be greatly improved. All I can say is it works for me Any suggestions and corrections are highly welcome.
Sources:
https://docs.freebsd.org/en/books/handbook/advanced-networking/#network-bluetooth
https://docs.freebsd.org/en/books/handbook/multimedia/#sound-setup
https://wiki.freebsd.org/Sound
https://www.freebsd.org/cgi/man.cgi?query=virtual_oss&sektion=8&format=html
https://forums.ghostbsd.org/viewtopic.php?t=1676
https://gist.github.com/maxrp/fe97f9c84c512536b7876042a14626ba
https://meka.rs/blog/2021/10/12/freebsd-audio/
UPDATE 1 (2021-11-01) :
- Added the
- Mentioned some additional tips regarding the script.
1) Tested and confirmed to work on FreeBSD 13.0-RELEASE.
2) Obviously you need to first confirm whether FreeBSD supports the built-in Bluetooth of your laptop/computer.
3) For this guide, we will focus on Intel Bluetooth as that's my case in particular. Hence the use of comms/iwmbt-firmware.
4) Both "hcsecd" and "sdpd" Bluetooth-related services are intentionally not enabled on /etc/rc.conf because they're not really needed in my setup. Nonetheless, adding them shouldn't do any harm.
5) Remember to replace "BD_ADDR" by the real unique address of your Bluetooth device. How to get this address is explained later on.
# First, become superuser and install the programs we need:
su
pkg install iwmbt-firmware virtual_oss
# If yours isn't Intel, only install audio/virtual_oss.# Nowadays, drivers are auto-loaded at system start-up, but installing comms/iwmbt-firmware was still needed, as well as issuing the following command afterwards:
service devd restart
# This way /etc/devd/iwmbtfw.conf is executed and the required firmware files are downloaded.# Next load cuse and make it permanent, for it's needed by virtual_oss:
kldload cuse
sysrc kld_list+="cuse"
# Start the Bluetooth stack:
service hcsecd onestart
service bluetooth start ubt0
# If this fails, do it again.# Now find your Bluetooth headphones (make sure they're on):
hccontrol -n ubt0hci inquiry
# Take note of the unique address (BD_ADDR) of your Bluetooth device. Example: "98:52:3d:48:3a:51".# If unsure, find out the human readable name assigned to your remote device:
hccontrol -n ubt0hci remote_name_request BD_ADDR
# Replace BD_ADDR by the real unique address of your Bluetooth device.# Create a connection to your remote device:
hccontrol -n ubt0hci create_connection BD_ADDR
# Replace BD_ADDR by the real unique address of your Bluetooth device.# Edit /etc/bluetooth/hosts to assign an alias to your device (replace "98:52:3d:48:3a:51" with your actual address). Example:
Code:
# $Id: hosts,v 1.1 2003/05/21 17:48:40 max Exp $
# $FreeBSD$
#
# Bluetooth Host Database
#
# This file should contain the Bluetooth addresses and aliases for hosts.
#
# BD_ADDR Name [ alias0 alias1 ... ]
# 00:11:22:33:44:55 phone
98:52:3d:48:3a:51 headphones
# Now create a virtual sound device so you can use your Bluetooth headphones as a sound sink:
virtual_oss -T /dev/sndstat -S -a o,-4 -C 2 -c 2 -r 44100 -b 16 -s 1024 -R /dev/dsp0 -P /dev/bluetooth/headphones -d dsp -t vdsp.ctl
*Let's explain a little some of the meaning of the above command:
- I wanted this virtual device to be exposed to other apps, so install entry in /dev/sndstat. ( -T /dev/sndstat)
- Enabled automatic resampling to fix bad sound quality when playing audio with a different sample-rate than default. ( -S)
- The default volume was too high so I set a negative output amplification. ( -a o,-4)
- I chose a sample rate of 44100 Hz but you can use 48000 Hz instead if that's better for your hardware. ( -r 44100)
- I wanted to be able to use my laptop's internal mic simultaneously while using my headphones. ( -R /dev/dsp0)
- You can disable the recording device by setting "-R /dev/null" instead.
All this works great for programs that use OSS as sound backend (the vast majority in FreeBSD). However, other backends need certain workarounds or extra steps:
[sndio]
# To fix applications that use sndio as backend (e.g. Chromium), you need to enable the sndiod service:
sysrc sndiod_enable=YES
service sndiod start
[Pulseaudio]
# To fix the ones that use a pulseaudio backend (e.g. Firefox and linux Brave), recording the sound output and immediately redirecting it to /dev/dsp acts as a workaround:
pacat --record -d oss_output.dsp0.monitor > /dev/dsp &
# It's the only solution I could figure out and it's not perfect, as a very tiny delay can be noticed.# Also you'd want to mute your computer speakers to avoid hearing double:
mixer pcm 0
# Remember to set it back to 100 after disconnecting your headphones, or you won't hear anything.# Depending on your particular case, you may need to replace "oss_output.dsp0.monitor" by a different source-output. To list the ones available use:
pacmd list-sources | grep monitor
[OpenAL]
# Sadly, I haven't found yet a workaround to hear sound from Wine games and programs.
# Finally, I created a little script to automate the audio output device switching between Bluetooth headphones and the built-in speakers:
Code:
#!/bin/sh
if [ "$(cat /dev/sndstat | grep 'Virtual OSS')" = "dsp: <Virtual OSS> (play/rec)" ]; then
killall pacat ; mixer pcm 100 ; sudo /usr/bin/killall virtual_oss ; sudo /sbin/sysctl hw.snd.basename_clone=1 ; notify-send --app-name=Bluetooth --icon=bluetooth -t 5000 'Bluetooth sound device disconnected'
else
notify-send --app-name=Bluetooth --icon=bluetooth -t 5000 'Connecting Bluetooth sound device...'
sudo virtual_oss -T /dev/sndstat -S -a o,-4 -C 2 -c 2 -r 44100 -b 16 -s 1024 -R /dev/dsp0 -P /dev/bluetooth/headphones -d dsp -t vdsp.ctl & sleep 5 && mixer pcm 0 ; pacat --record -d oss_output.dsp0.monitor > /dev/dsp &
fi
*Note: This script is meant to be run as normal user. Remember to make it executable (chmod +x). Also I suggest to add the commands that need "sudo" to /usr/local/etc/sudoers to allow them running without the need of entering your password. At least I did that.
You can then create a keyboard shortcut to run it easily.
You may also want to increase the
sleep
time to 15 seconds or more if your device takes too long to connect. I say this because it's important to run the pacat
command AFTER the device is correctly paired, otherwise the sound will be out of sync. In that case a simple killall pacat ; pacat --record -d oss_output.dsp0.monitor > /dev/dsp &
should suffice to set it right anyway.DISCLAIMER: I'm not a coder, so I assume the script above could be greatly improved. All I can say is it works for me Any suggestions and corrections are highly welcome.
Sources:
https://docs.freebsd.org/en/books/handbook/advanced-networking/#network-bluetooth
https://docs.freebsd.org/en/books/handbook/multimedia/#sound-setup
https://wiki.freebsd.org/Sound
https://www.freebsd.org/cgi/man.cgi?query=virtual_oss&sektion=8&format=html
https://forums.ghostbsd.org/viewtopic.php?t=1676
https://gist.github.com/maxrp/fe97f9c84c512536b7876042a14626ba
https://meka.rs/blog/2021/10/12/freebsd-audio/
UPDATE 1 (2021-11-01) :
- Added the
-S
option to the virtual_oss
command to enable automatic resampling using Project Z. This fixes bad sound quality when playing audio files with a sample rate different than default.- Mentioned some additional tips regarding the script.