December 11, 2017 — Nuclear

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.

Sandbox security settings

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).

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

should be set to security.sandbox.content.write_path_whitelist should be set to /dev/snd/ (the trailing slashes are important)

should be set to (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).

Selecting the correct playback device

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.

Selecting the correct recording device

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.

Edit: Later versions of firefox also restrict ioctl calls, which makes ALSA fail with an error message about “seccomp sandbox violation”. This can be fixed by adding ioctls to the syscall whitelist by setting security.sandbox.content.syscall_whitelist to 16 for 64bit x86 systems, or to 54 for 32bit x86 systems.