Use Alt-Shift for keyboard layout switching in GNOME 40

Since GNOME 40 the keyboard layout indicator doesn’t work if the keyboard is switched using a key combination defined in GNOME Tweaks. The indicator does work for key combinations defined through GNOME Setting’s Keyboard Shortcut settings. However, GNOME Settings doesn’t allow one to set Alt+Shift as the key combination layout switching, as it seems to require at least one non-modifier key in every shortcut. This limitation only exists in GNOME Settings GUI and you can work around it by defining the shortcut using gsettings:

$ gsettings set org.gnome.desktop.wm.keybindings switch-input-source "['<Shift>Alt_L']"
$ gsettings set org.gnome.desktop.wm.keybindings switch-input-source-backward "['<Alt>Shift_L']"

Downgrade PipeWire 0.3.39 to 0.3.38

PipeWire 0.3.39 on Debian deprecates pipewire-media-session in favor of WirePlumber. The main issue I found with the new version is that it doesn’t support Bluetooth profile autoswitching, as it is unimplemented in WirePlumber. The best solution until this is resolved is simply holding back upgrading to 0.3.39. If you already upgraded, downgrading is a bit of hassle.

The first step is to retrieve all the necessary packages in the last working version, which is 0.3.38-2.

$ cd `mktemp -d`
$ debsnap -a amd64 --binary -d . gstreamer1.0-pipewire 0.3.38-2
$ debsnap -a amd64 --binary -d . libpipewire-0.3-0 0.3.38-2
$ debsnap -a all --binary -d . libpipewire-0.3-common 0.3.38-2
$ debsnap -a amd64 --binary -d . libpipewire-0.3-modules 0.3.38-2
$ debsnap -a amd64 --binary -d . pipewire-audio-client-libraries 0.3.38-2
$ debsnap -a amd64 --binary -d . pipewire-bin 0.3.38-2
$ debsnap -a amd64 --binary -d . pipewire-pulse 0.3.38-2
$ debsnap -a amd64 --binary -d . pipewire 0.3.38-2
$ debsnap -a amd64 --binary -d . pipewire-media-session 0.3.38-2
$ debsnap -a amd64 --binary -d . libspa-0.2-modules 0.3.38-2
$ debsnap -a amd64 --binary -d . libspa-0.2-bluetooth 0.3.38-2

Install all the retrieved packages and mark some of the packages back as automatically installed.

$ sudo apt install ./*.deb
$ sudo apt-mark auto gstreamer1.0-pipewire libpipewire-0.3-0 libpipewire-0.3-common libpipewire-0.3-modules pipewire-bin pipewire libspa-0.2-modules

Mark pipewire-media-session as held so it won’t get accidentally removed again.

$ sudo apt-mark hold pipewire-media-session

Finally, restart PipeWire.

$ systemctl --user daemon-reload
$ systemctl --user restart pipewire pipewire-pulse

Removing PulseAudio after migrating to PipeWire

After migrating to PipeWire you would want to fully remove PulseAudio. The problem is that certain packages, for example libcanberra-pulse, depend on pulseaudio even though they would work just as well if pipewire-pulse is installed. There are several relevant bugs to solve this issue, but meanwhile we could use equivs to generate a fake package that provides pulseaudio.

Copy the following file locally as pulseaudio-fake:

Section: misc
Priority: optional
Standards-Version: 3.9.2

Package: pulseaudio-fake
Provides: pulseaudio
Description: Fake pulseaudio package to satisfy depdendencies.
 This solves depdendencies for packages like libcanberra-pulse when actually using PipeWire instead of PulseAudio.

Build a package from it using equivs and install it:

$ equivs-build ./pulseaudio-fake
$ sudo apt install ./pulseaudio-fake_1.0_all.deb

Now you can safely remove pulseaudio.

GNOME 40 on Debian Unstable

These are the steps I took to install (most of) GNOME 40 Debian Unstable:

$ sudo apt install -t experimental gnome-shell gjs mutter gnome-control-center gnome-desktop3-data
$ sudo apt-mark auto gjs mutter

Failing to install gjs 1.68 from experimental will result in white or blue desktop backgrounds regardless of the wallpaper you choose. This bug was reported in Arch.

Most of GNOME 40 functionality should now work, including the updated activities overview.

What doesn’t work? Settings->About still display GNOME’s version as 3.38. I suspect it’s because gnome-session is still at 3.38.

Update 2021-08-24: I upgraded to gnome-session 40.1.1 and it didn’t solve the version string issue.

Update 2021-08-31: Following a comment by Jeremy, I installed gnome-desktop3-data from experimental and it fixed the version string issue.

Autostart rclone mount using systemd

Create the following file under ~/.config/systemd/user/rclone-dropbox.service:

[Unit]
Description=Dropbox (rclone)
AssertPathIsDirectory=%h/Dropbox
# Make sure we have network enabled
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/rclone mount --vfs-cache-mode full Dropbox: Dropbox
# Perform lazy unmount
ExecStop=/usr/bin/fusermount -zu %h/Dropbox
# Restart the service whenever rclone exists with non-zero exit code
Restart=on-failure
RestartSec=15
[Install]
# Autostart after reboot
WantedBy=default.target

Reload the user services, enable and start the new service:

$ systemctl --user daemon-reload
$ systemctl --user enable --now rclone-dropbox

Replacing PulseAudio with PipeWire 0.3.30

Replacing PulseAudio with Pipewire became much simpler recently with PipeWire 0.3.30 and requires less configuration. I’m going to go through the updated routine. You can read the original post for more explanations.

The new version is still only available in experimental as of today.

$ sudo apt install -t experimental pipewire-pulse pipewire-audio-client-libraries libspa-0.2-bluetooth

The pipewire-pulse package takes care of most of the configuration that was previously needed, like touching with-pulseaudio or manually creating the systemd service files.

$ systemctl --user daemon-reload
$ systemctl --user disable pulseaudio.socket pulseaudio.service
$ systemctl --user stop pulseaudio.socket pulseaudio.service
$ systemctl --user mask pulseaudio.service pulseaudio.socket
$ systemctl --user enable --now pipewire pipewire-pulse pipewire-media-session

Don’t remove the PulseAudio packages yet. While not being used, some packages still depend specifically on PulseAudio and might break. See the original post for more details.

Enable mSBC and SBC XQ

One of the main advantages of PipeWire is proper support for better sounding bluetooth audio profiles, and specifically mSBC and SBC XQ. Copy /usr/share/pipewire/media-session.d/bluez-monitor.conf to ~/.config/pipewire/media-session.d/bluez-monitor.conf (or to /etc/pipewire/media-session.d/bluez-monitor.conf) and in the properties section add the following lines:

bluez5.msbc-support   = true
bluez5.sbc-xq-support = true

Replacing PulseAudio with PipeWire

PipeWire is a multimedia server, best known for it’s video support in Wayland. It also provides an audio server which can replace PulseAudio. The appeal, for me at least, to switch over from PulseAudio to PipeWire stems from PipeWire’s better support of bluetooth audio, and especially support for modern A2DP codecs such as AptX, AptX HD and LDAC.

Starting with PipeWire 0.3.20 introduced native mSBC support. This profile support mSBC codec versus CSVD supported by the older HSP/HFP profiles. The difference is significant, as the CSVD only supported narrow band speech (NBS, 8kHz) compared with mSBC support for wide band speech (WBS, 16kHz). That is the difference between 90’s era call quality sound and modern call quality sound.

Update: PipeWire-0.3.30 made the replacement process simpler. See my updated post.

Installing PipeWire 0.3.23

As of writing this post, Debian Unstable only has PipeWire 0.3.19. We are going to install PipeWire from the experimental repo so we get the PipeWire 0.3.23 with the support for mSBC.

We start by enabling the experimental repo

$ sudo apt-add-repository "deb http://deb.debian.org/debian experimental main
$ sudo apt update

Install PipeWire from experimental:

$ sudo apt install -t experimental pipewire-audio-client-libraries libspa-0.2-bluetooth

(pipewire-audio-client-libraries will pull pipewire itself as a dependency)

Substituting PipeWire for PulseAudio

These instructions are based on the ones from Debian Wiki, Arch Wiki and Gentoo Wiki. Create the file

$ sudo touch /etc/pipewire/media-session.d/with-pulseaudio

It will instruct PipeWire to handle Bluetooth audio devices.

Copy the pipewire-pulse systemd service:

$ sudo cp /usr/share/doc/pipewire/examples/systemd/user/pipewire-pulse.{service,socket} /etc/systemd/user

Disable PulseAudio services and enable the PipeWire ones

$ systemctl --user disable pulseaudio.socket pulseaudio.service
$ systemctl --user stop pulseaudio.socket pulseaudio.service
$ systemctl --user enable pipewire pipewire-pulse
$ systemctl --user start pipewire pipewire-pulse

If everything worked well pactl info should report Server Name: PulseAudio (on PipeWire 0.3.23):

$ pactl info | grep "Server Name"
Server Name: PulseAudio (on PipeWire 0.3.23)

If not, you might need to restart (PulseAudio tends to be rather persistent). In case PulseAudio still doesn’t play nicely, you should mask it:

$ systemctl --user mask pulseaudio.service pulseaudio.socket
$ systemctl --user stop pulseaudio.service pulseaudio.socket

Removing PulseAudio completely is not a good move at this point in time. Some packages depend on it, although they could work with PipeWire just as well. For example, when I remvoed PipeWire libcanberra-pulse got removed as well which caused system notification sounds to break. Alternatively you could try to replace the PulseAudio package with a dummy using equivs but that seems like more effort than keeping the package.

Enabling mSBC and SBC XQ

Edit /etc/pipewire/media-session.d/bluez-monitor.conf and uncomment the following lines:

bluez5.msbc-support   = true
bluez5.sbc-xq-support = true

This will enable both mSBC and SBC XQ.

You can test that you’re headset is connected via mSBC using pw-cli info:

$ guyru@gdebian3:~$ pw-cli info all | grep bluez
info: unsupported type PipeWire:Interface:Profiler
info: unsupported type PipeWire:Interface:Metadata
info: unsupported type PipeWire:Interface:Metadata
*		device.api = "bluez5"
*		device.name = "bluez_card.94_DB_56_AC_36_52"
*		api.bluez5.path = "/org/bluez/hci0/dev_94_DB_56_AC_36_52"
*		api.bluez5.address = "94:DB:56:AC:36:52"
*		api.bluez5.device = ""
*		api.bluez5.class = "0x240404"
*		api.bluez5.transport = ""
*		api.bluez5.profile = "headset-head-unit"
*		api.bluez5.codec = "mSBC"
*		api.bluez5.address = "94:DB:56:AC:36:52"
*		node.name = "bluez_input.94_DB_56_AC_36_52.headset-head-unit"
*		factory.name = "api.bluez5.sco.source"
*		device.api = "bluez5"
*		api.bluez5.transport = ""
*		api.bluez5.profile = "headset-head-unit"
*		api.bluez5.codec = "mSBC"
*		api.bluez5.address = "94:DB:56:AC:36:52"
*		node.name = "bluez_output.94_DB_56_AC_36_52.headset-head-unit"
*		factory.name = "api.bluez5.sco.sink"
*		device.api = "bluez5"

In case mSBC is not supported you’ll see api.bluez5.codec = "CSVD" (and you’lll probably hear the difference).

Errors

Problem: Connecting to bluetooth headset fails, and the following error appears in journalctl:

bluetoothd[41893]: src/service.c:btd_service_connect() a2dp-sink profile connect failed for 94:DB:56:AC:36:52: Protocol not available

Solution: You’re missing the libspa-0.2-bluetooth package. Install it and restart PipeWire:

$ sudo apt install -t experimental libspa-0.2-bluetooth
$ systemctl --user restart pipewire pipewire-pulse

Problem: ALSA programs fail with the following error:

ALSA lib pcm_dmix.c:1075:(snd_pcm_dmix_open) unable to open slave
aplay: main:830: audio open error: Device or resource busy

Solution: You need to enable the ALSA backend for PipeWire:

$ sudo touch /etc/pipewire/media-session.d/with-alsa
$ systemctl --user restart pipewire pipewire-pulse

Rename Debian packages according to version

This is a small bash utility function to allow renaming deb archives according to their version.

rename-deb () 
{ 
    base="${1%.deb}";
    version="$(dpkg-deb -f $1 Version)" || return 1;
    new="$base-$version.deb";
    mv -i "$1" "$new";
    echo "$1 -> $new"
}

You can either run it one time in your shell, or define it in your ~/.bash_aliases.

Example:

$ rename-deb zoom_amd64.deb
zoom_amd64.deb -> zoom_amd64-5.5.7011.0206.deb