John Tsiombikas nuclear@mutantstargoat.com
11 December 2017
Once again I'm caught between a rock and a stupid place. Mozilla joined Harry Pottering and the eternal september of GNU/Linux, who carries on dead-set on tearing down everything simple and elegant in the userland, replacing it with crude immitations of the beast (MacOS X). So in an inspired move, firefox went bananas and dropped its ALSA audio backend with release 57. And everyone who doesn't fancy spending 10% of their battery life on a byzantine audio contraption, is left with silent southpark, and kung fury without the awesome 80s synths and the buttery voice of David Hasselhoff.
I tried switching to chromium for a month, but I just couldn't stomach it. Now I always maintained that if everyone switches to pulse audio, I can always make a pulse wrapper over alsa, but I really didn't want to have to deal with that. Thankfully, I didn't have to bother, because a guy called Rinat Ibragimov beat me to it, and wrote apulse: a thin libpulse replacment which works with ALSA.
So in theory running apulse firefox should be sufficient to have sound in firefox 57 again. Unfortunately I had to take some more steps, and since I'm certain I'll forget all about them next time I’m trying to do the same on another computer, I'll keep a note here of the extra steps I had to take, to make apulse work with firefox on my computer.
Firefox now runs tabs in their own process with extra security, which by
default disallows ad-hoc filesystem access. In order for apulse to do its job,
it needs to access the ALSA device files under /dev/snd
, and the .asoundrc
configuration file in the user's home directory. Alsa also needs to be able to
call ioctl system calls. To this end we have to modify a few about:config
settings. Specifically:
security.sandbox.content.level
should be lowered from 3 to 2 (edit: this
step might be unnecessary with proper whitelist settings).security.sandbox.content.read_path_whitelist
should be set to /dev/snd/,/home/username/.asoundrc
security.sandbox.content.write_path_whitelist
should be set to /dev/snd/
(the trailing slashes are important)security.sandbox.content.syscall_whitelist
should be set to 16, which is
the syscall number for ioctl (on x86-64, on 32bit x86 systems the ioctl
number is 54).If we don't want apulse to try and use the default alsa device for audio
playback, we need to set the APULSE_PLAYBACK_DEVICE
environment variable. This
is particularly important because firefox tries to output floating point audio
samples, and the dmix
(software mixing) output which is probably the default,
or even worse hw
, doesn't do format conversions. A list of currently available
devices can be obtained by running aplay -L
.
Initially I tried setting APULSE_PLAYBACK_DEVICE=plughw:0,0
which handles
format conversions, but unfortunately then I lost the ability to mix the audio
output of multiple processes, and whenever one firefox tab was playing sound or
even holding the device open for some reason, nothing else in the system (not
even another firefox tab) could. One way to fix this problem is to define
another plug type output (in .asoundrc), which then feeds dmix
instead of hw
as
is the case with plughw
. Here's what I used in my .asoundrc
to achieve that:
pcm.plugdmix {
type plug
slave.pcm "dmix"
}
Then it's only a matter of setting APULSE_PLAYBACK_DEVICE=plugdmix
, and I have
both format conversions and software mixing at the same time.
Less important, but sometimes it's nice to have recording capability in the
browser. I'm using a USB webcam as microphone, so in order to direct apulse to
use it, I need to set APULSE_CAPTURE_DEVICE=plughw:2,0
(0 is the embedded sound
chip, 1 is the nvidia HDMI audio, and 2 is my USB webcam). Actually it might be
preferable to just set this device as the default in .asoundrc
, but I never
bothered, since all programs usually have settings for which device to use.
This was initially posted in my old wordpress blog. Visit the original version to see any comments.