I recently decided to learn FreeBSD 😈. As a long time Linux user I have been curious about BSDs, and understood that MacOS/Darwin had grown out of BSD in some way, but beyond that it was *just another nux in my mind. That concept in itself was a bit hazy to me as well, I understood there was some forking and history behind all of them but I didn’t understand the relevance.
Below I’m documenting things I found to be confusing or I found myself to be the exception to the status quo throughout my journey to understanding FreeBSD. It is by no means an install guide, nor is it comprehensive in its presentation of the FreeBSD OS. I’m documenting this mostly for myself, for the next time I need to run through this, or in the case someone else stumbles in and finds solidarity.
Table of contents
Open Table of contents
Primer
BSD vs Linux
If you’re like me and curious about FreeBSD, you undoubtably have stumbled on Matthew Fuller’s BSD vs Linux already. In the case you haven’t, I highly recommend a read through if you’re coming from Linux. Matthew covers some of the philosophical differences that are actually relevant to end users.
System Configuration
FreeBSD install is a breeze for any enthusiast who has installed Linux before. There is nothing scary in the installation process, I found myself breezing through without even needing to read much from the Handbook 📕. Though once you are up and running… it might surprise you in some ways.
Hardware Support
Xonar Drivers
I thought my cursory review of the supported hardware list was sufficient. Well, I was wrong 😀, there is no support for my ASUS Xonar soundcard out of the box. Luckily I was able to switch over to my RealTek onboard soundcard and carry on. However, I did stumble on polachok/xonar-freebsd in my search and I plan to give that a try very soon. I’m not convinced I didn’t miss something, given the popularity of ASUS cards and the high probability that it uses a common chip. If I don’t update this section, neither of those options panned out and you should plan not to use your ASUS soundcard.
In BSD things were different, and I was suddenly in uncharted water. The handbook’s coverage of Multimedia was brief. This was a good introduction to how BSD loads kernel modules. For some reason adding snd_hda_load="YES"
to my /boot/loader.conf
felt more ✨magical✨ than using modprobe
and /etc/modules-load.d
and /etc/modprobe.d
. I suppose that’s absurd given how similar of a process it is but it felt so cohesive to find everything centered around /etc/rc.conf
and /boot/loader.conf
; even the service
command used to start and stop daemons read from rc.conf
making it extremely easy for me to test options.
USB Microphone (Blue Yeti)
As a Linux veteran I was not at all intimidated by my microphone not working right out of the box. I have grown accustomed 🤕 to some form of tweaking PulseAudio or Alsa configuration to get things working as expected. In recent years, if I chose to install some out of the box distribution, like Ubuntu or SuSE, with Gnome or KDE as a display manager these things have actually sorted themselves out without my intervention.
Long story short, the built in sound manager for BSD, OSS and the canonical soundcard mixer, which is a spartan little utility in terms of capabilities and documentation, are not able to combine multiple sound providers. You either can select your soundcard for playback, or your USB device for recording. You must create a virtual device that combines the two via virtual_oss. Some general directions are provided in the context of a Bluetooth device a bit further down in the Handbook in subsection 7.2.3.
I wound up with the following which works reasonably well so far, though is no doubt imperfect.
#/etc/rc.conf
virtual_oss_enable="YES"
virtual_oss_dsp="-T /dev/sndstat -S -i 8 -C 8 -c 8 -r 96000 -b 24 -s 1024 -O /dev/dsp5 -R /dev/dsp8 -d dsp -t vdsp.ctl"
This combines the (O)utput device /dev/dsp5
with the (R)ecording device /dev/dsp8
into /dev/dsp
which acts as the default soundcard.
USB Video Capture Device (Webcam)
I smirked 😏 when my webcam didn’t immediately work. It had taken me countless hours of effort to get it working well in Linux as it was, and that was an OS where webcams and capture cards have become relatively common place given the recent viability of Linux gaming and the post pandemic remote work world we now live in in 2022.
The issue is I use a cheap USB Video capture device that is about as generic as it gets.
uhid0: <MACROSILICON USB Video, class 239/2, rev 2.00/21.00, addr 2> on usbus0
There is hope though, as someone has come along to solve this problem for us and the solution is called webcamd. Well most of the solution in my case anyway…
#/etc/rc.conf
webcamd_enable="YES"
webcamd_0_flags="-B -N MACROSILICON-USB-Video -d ugen0.3"
These flags instruct the process to bind to my USB capture device and it generally works. I have a Sony Alpha mirrorless camera plugged into it, which is capable of some very high resolutions and frame rates. Unfortunately the capture device only streams in at an oddly small resolution and 5 fps.
I was prepared for this! I have had this same issue in Linux and resolved it through the v4l2loopback
module. The trick of it is this creates a dummy video device of which we have total control of how it reports its specifications to applications. The trouble is, there is no v4l2loopback
for BSD.
webcamd
depends on a port of v4l2loopback
but it does not install it as a module. The installation instructions are well documented and the man
page does its job well.
I was able to create a v4l2loopback device by updating the configuration as follows.
#/etc/rc.conf
webcamd_0_flags="-B -N MACROSILICON-USB-Video -d ugen0.3 -m v4l2loopback.devices=1"
This creates the devices I need for the typical solution to work.
crw-rw---- webcamd webcamd 0 B Thu Sep 15 15:52:43 2022 /dev/video0
crw-rw---- webcamd webcamd 0 B Wed Sep 14 22:57:50 2022 /dev/video1
crw-rw---- webcamd webcamd 0 B Wed Sep 14 22:57:50 2022 /dev/video2
From there it’s usually a matter of streaming data from the capture card to the dummy device using ffmpeg
. I typically add the following to my .xinitrc
.
$ ffmpeg -f v4l2 -input_format mjpeg -framerate 30 -video_size 1920x1080 -i /dev/video1 -r 30 -vsync cfr -c:v copy -an -f v4l2 /dev/video0 &
This works by instructing the device to copy data in the mjpeg
format rather than the default yuyv422p
format. For my camera, or capture device, I’m not really sure why it defaults the way it does. In the above my capture device /dev/video1
which was created by webcamd
and /dev/video0
is the dummy device created by v4l2loopback
. Both devices are interfaced with using v4l2
and the data is copied rather than decoded and re-encoded. This means the processing overhead is negligible.
That is typically all you need to do, but not in this case. I found that my dummy video device was not appearing where I expected it, namely in Chrome on Discord or Zoom. So I dug into the logs and found that chrome was only finding /dev/video1
when enumerating my devices. I recalled from my Linux setup that I had to pass a specific option to the module, exclusive_caps=1
, the option actually takes an array so you can flip the bit for more than one device if need be. The flag was a relatively new addition to v4l2 and it is a fix for the issue of Chrome not detecting CAPTURE devices. It’s explained well at umlaeute/v4l2loopback in the OPTIONS section.
The difficulty is, exclusive_caps
is not exposed via webcamd
and since v4l2loopback
is not loaded as a module there is no way to turn it on. When I looked more deeply at hselasky/webcamd I found that it was building swills/v4loopback which is a fork of umlaeute/v4l2loopback, I’m not sure the rationale but I suspect it’s related to the process of porting to BSD. Luckily the fork already had exclusive_caps
support in it, albeit unexposed in the host application webcamd
.
All that remained now was removing the version of webcamd
I had installed using pkg
, FreeBSD’s excellent package manager, and instead build it from source using ports. It was exceedingly simple to get the ports hierarchy downloaded. This meant when I ran make
the source was downloaded and I was free to make a modest change.
// /usr/ports/multimedia/webcamd/work/webcamd-5.17.1.2/contrib/v4l2loopback/v4l2loopback.c
#define V4L2LOOPBACK_DEFAULT_EXCLUSIVECAPS 1 // Previously 0
I simply defaulted to always use the exclusive_caps
option. A quick rebuild and make install
and I was on my way. Chrome now found the /dev/video0/
Dummy Video Device.
After I was sure this was working I decided to pkg lock webcamd
to prevent pkg upgrade
from stomping on my change. I know there is a better way to go about this, using port patches, and I’ll get there someday.
Other quirks & notable reminders
Chrome
The package repository doesn’t have a port of ungoogled-chromium which has been my browser of choice recently.
There is a FreeBSD ungoogled-chromium package available here. It is easy to install the binary in this form with pkg install ungoogled-chromium-<version>.pkg
dbus
While adding the following enables dbus, it doesn’t export DBUS_SESSION_BUS_ADDRESS
.
#/etc/rc.conf
dbus_enable="YES"
I needed to make this explicit before launching X.
#~/.xinitrc
export $(dbus-launch)
This removed some error messages in the Chrome logs and probably other issues quietly lurking.
Appendix
Thank you to the members of the FreeBSD Discord #helpdesk channel. Special thanks to Alexander88207 in the ❓ Help & Support
channels for their friendliness and quick help.