Category: Linux

Stopping PipeWire + WirePlumber S/PDIF and Bluetooth Idle Audio Suspension

Introduction

I’m making the move from Windows to Linux ahead of the Windows 10 End of Life this October (2025). For someone who has exclusively used Windows for personal computers and only touched Linux for server applications, this does come with a lot of changes I’ll need to get used to.

Having tried to move a few times before without much luck due to lots of unfixable bugs, I decided to try Fedora. I’m a couple of days in and still nowhere near finished getting things set up, but so far Fedora is proving to be the least buggy KDE based distro I have tried.

It isn’t perfect though. I use an S/PDIF digital audio output to feed an audio transmitter, and under Windows this works perfectly fine. Under Fedora however, where PipeWire and WirePlumber are controlling the audio stack, things don’t work quite as well. After approximately 30 seconds of idle time the interface appears to be suspended entirely, meaning it takes about 250-500ms to wake up again when a sound plays. This is unacceptable as it leads to missed notification sounds and lost words at the start of videos with no intro, which is extremely frustrating.

I just wanted to quickly thank Steven Haigh for their blog post regarding this issue which I used as the basis along with various other forum posts and documentation to figure out how to get this to work with the latest versions of WirePlumber, as Steven’s post is for an older configuration format. Thanks for getting me on the right track Steven!

Fixing the issue

It seems the only way to prevent this issue from occurring is to have some kind of audio playing in the background to prevent the interface from going to sleep. Luckily, WirePlumber provides a method of configuring this for PipeWire natively without having to run a process in the background. The sound produced is completely inaudible so won’t disturb you in periods of silence.

Selecting the correct target device

To find the device you want to apply this fix to, start playing some audio. Open a terminal and run pw-top which will give you a list of your audio devices and the applications currently using them. Here is an example where I am playing Spotify out on my S/PDIF interface:

As you can see above, spotify is a child of alsa_output.pci-0000_2d_00.4.iec958-stereo which is the ALSA name for my S/PDIF audio interface. We’ll need this exact name for the configuration we’re going to create.

It’s also useful to note, once you let the interface idle for a moment the list will look like this:

This is useful because we can see the FORMAT column is blank for our device. This column will never go blank once our configuration has been applied, meaning we can use it as an indicator for whether our configuration is working correctly or not.

Creating the configuration

Here is my exact configuration for this fix. I have saved it as /etc/wireplumber/wireplumber.conf.d/51-spdif-keepalive.conf and I recommend you do the same:

monitor.alsa.rules = [
  {
    matches = [
      {
        node.name = "alsa_output.pci-0000_2d_00.4.iec958-stereo"
      }
    ]
    actions = {
      update-props = {
        session.suspend-timeout-seconds = 0,
        node.pause-on-idle = false,
        node.suspend-on-idle = false,
        dither.method = "wannamaker3",
        dither.noise = 2
      }
    }
  }
]

As you can see, I have placed my device name alsa_output.pci-0000_2d_00.4.iec958-stereo into the matches section of the configuration. You’ll need to adjust this value to the name of your own device.

You may find that setting session.suspend-timeout-seconds alone is enough to fix your issue. I’ll leave it to you, the reader, to experiment with which options are required for your particular setup. The above is a blanket configuration which should fit most scenarios.

The configuration should be owned by the user root in group root which if it is not, you can do with chown root:root 51-spdif-keepalive.conf and you can check with the ls -la command.

The configuration will not be applied immediately and you’ll need to restart the WirePlumber service for it to take effect, which you can do by running systemctl --user restart wireplumber or alternatively by rebooting.

Confirming it works

Once applied, the first sound you play will wake your audio interface up. Once woken up, the interface will be kept alive by the configuration we created.

You can see the interface being kept alive by looking at the FORMAT column as shown below, where there are no children to the interface producing sound but a FORMAT is still selected:

Bluetooth too?

If you experience this same issue on a Bluetooth audio device, which you most likely will, you can apply a similar configuration which affects all bluetooth audio devices simultaneously. I created /etc/wireplumber/wireplumber.conf.d/51-bluetooth-keepalive.conf which fixed my issue with my wireless headphones too:

monitor.bluez.rules = [
  {
    matches = [
      {
        node.name = "~bluez_output.*"
      }
    ]
    actions = {
      update-props = {
        session.suspend-timeout-seconds = 0
      }
    }
  }
]

Like with the other configuration, a restart of WirePlumber is required for this to take effect. I needed to disconnect and reconnect my wireless headphones to stop them from behaving strangely after this config change too.

How to Factory Reset and Skip Nook SimpleTouch (and other) Registration, then Root Your Nook

I do not find there to be a lot of results online regarding how to skip the Nook setup screen if you factory reset your device (for example, with NookManager).

I decided to make a simple post which explains this process in the hopes it will get on Google and help others.

Factory Reset

If you haven’t already Factory Reset your device, you may be struggling to do so, as for some reason, Factory Resets require a network connection to the Nook servers, which no longer exist.

To Factory Reset your Nook, you will want NookManager, which is a third-party Nook rooting and backup/restore/reset tool.

https://forum.xda-developers.com/t/root-nookmanager-graphical-rooter-for-1-2-x-and-beyond.2040351/

Download NookManager and write it to an SD card. Please note, writing NookManager to an SD card will erase the card. Also, you will need to use a tool like Win32DiskImager or Balena Etcher to write the img file to the card.

Insert the card into your Nook and reboot it by holding the Power button and switching it off, then back on again.

You will be presented with a display like below:

You do not need Wireless at this time, so select No, continue without wireless. You will then want to go through a Backup procedure (whether you want to keep the contents of your Nook or not, you should do this!)

From the NookManager Main Menu, select Rescue:

Then select Backup:

And start the backup:

Once the backup is complete, go Back to the Rescue menu:

Then select Restore Factory.zip:

Continue with the Restore, and you will be presented with the NookManager exit and reboot screens (upon SD card ejection):

The Nook will now start up and reset:

Skipping Registration (OOBE/Out Of Box Experience)

To skip the Registration process, which no longer works because the Nook servers are now, we will need to use a hidden Factory menu. To start, select your language and get to the Welcome screen, but do not continue:

From this welcome menu, hold the right hand, top physical button, then swipe (whilst still holding the button) the top Nook logo pattern from left to right, which will reveal the Factory menu button on top of the pattern:

This will take you into the Factory menu:

In the Factory menu, hold the same physical button again and then tap the blank spot to the left of HW Test to reveal the Skip OOBE button. Press it and you will be launched straight into your Nook:

Rooting

Rooting the Nook can also be done incredibly easily from NookManager. Simply insert the SD card and reboot your device to get back into NookManager, then select Root:

Select Root my device and then you will then observe the root run and complete in a minute or less:

Click Back and then Exit and remove the SD card, then the rooted Nook will reboot:

Building Barebones Linux

I do not intend to make this particular post a tutorial, demonstration, or any kind of reference or guideline, though it may end up looking like one.

Introduction

Here I will be exploring the assembly of Linux from zero to functioning system. By the end of this, in an ideal world, I’d like to be able to do some bare minimum things such as multiuser, SSH, a webserver, networking, disk access, NFS, etc.

For my first experiments, I will be using QEMU to test due to its convenient bootloader functionality, and the fact I don’t want to be wasting time booting a physical machine to a broken OS every time I do a tweak.

Observations and Explanations

This section will be where I stick my observations, and where applicable, explanations in a Q&A style.

O1: When booting the kernel, /dev contains one node, /dev/console without any intervention. Mounting a tmpfs to /dev removes /dev/console .

E: Because of the mknod major and minor numbers, it seems the kernel already knows what the devices are called (seemingly from their driver’s name) and console is just populated by default, sort of like /root . A tmpfs is pretty useless, but if we mount a devtmpfs to /dev (as long as it is supported by the kernel) the kernel appears to populate /dev with all devices it knows exists already.

O2: It appears /root is created automatically?

E: None yet

O3: Kernel cmdline lets you specify ttyS0 when that node isn’t even created at /dev/ttyS0 as we aren’t even at init yet. Then when init is complete, /dev/ttyS0 doesn’t exist unless init creates it, we also haven’t chosen the name to be ttyS0 either!

E: See O1‘s explanation

Building the Kernel

I am building the Linux kernel from source code using x86_64_defconfig. My procedure for preparing and proceeding with a kernel build is as follows:

#Install compilation dependencies
sudo apt-get install git make gcc libssl-dev libelf-dev libncurses-dev flex bison -y

#Clean directory to work in
mkdir linuxdev
cd linuxdev

#Download and expand kernel, then enter its directory
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.14.10.tar.xz
tar -xf linux-5.14.10.tar.xz
cd linux-5.14.10

#Set up default config and then begin compilation
make x86_64_defconfig
make

Setting up Directories and Scripts

I will now set up the directory in which I will build my linux system, and I will start my creating some directories and scripts to make repetitive things quicker:

#Assuming we just finished the kernel build, so are still in the kernel folder
cd ..

#Make our system directory and enter it
mkdir linuxsystem
cd linuxsystem

#Make our initrd directory
mkdir myrd

Lets make a simple script to package a directory as our initrd called mkinitrd.sh with the following contents:

#!/bin/bash
cd myrd
find . | cpio -v -H newc -o -F ../myrd.cpio
cd ..
cat myrd.cpio | xz --check=crc32 -9 > myrd.cpio.xz

Lets also make another script called launchrd.sh which just defines our qemu startup parameters:

#!/bin/bash

qemu-system-x86_64 -kernel my.knl -initrd myrd.cpio.xz -nographic -no-reboot -m 128 -append "panic=1 console=ttyS0 noapic"

The contents of the launch script will likely change throughout this. If I use different parameters, I will specify the full startup line.

We also need to actually install qemu and also make these scripts executable, install the execution environment and copy our compiled kernel locally:

#Install QEMU
sudo apt-get install qemu qemu-kvm -y

#Make scripts executable
chmod +x mkinitrd.sh
chmod +x launchrd.sh

#Copy kernel
cp ../linux-5.14.10/arch/x86_64/boot/bzImage ./my.knl

Building Busybox

As the basis of this system, I’d like to use Busybox. For this, I will also compile it myself. Lets clone it:

#Assuming we just finished creating the two scripts, so are still in our system's folder
cd ..

#Clone Busybox
git clone https://github.com/mirror/busybox

Now we have busybox cloned, let’s set up a default config. We will also need to do a quick tweak to produce a statically linked binary, as dependency libraries will not be included in our Linux system:

#Go into Busybox's cloned directory
cd busybox

#Make a default config
make defconfig

#Enable static linking
make menuconfig

Now you are in the menuconfig, you need to go to Settings -> Build Options -> Build static binary (no shared libs) and make sure it is switched on. Then exit menuconfig and choose Yes to saving. Now we can run the compile:

#Run the compiler
make

Laying out the initrd

Go into the myrd directory we created inside of the linuxsystem directory earlier:

#Assuming we just finished making Busybox, head down to linuxsystem then down to myrd
cd ../linuxsystem/myrd

We will now lay out some very basic folders and set up Busybox and init.

Create some important directories familiar in Linux:

mkdir usr
mkdir bin
mkdir sbin
mkdir usr/bin
mkdir usr/sbin
mkdir etc
mkdir etc/init.d

We will now copy the Busybox binary we created earlier into the initrd and link it as the init also:

#Copy Buxybox in
cp ../../busybox/busybox bin/busybox

#Make it also the init executable by symlinking it. Remember, symlinks are relative to the mounted rootfs
ln -s /bin/busybox init

We will now make the script which will initialise the system. Busybox, as it is linked to /init , will initialise the system and then run the initialisation script we create. Open the init script with nano etc/init.d/rcS and fill it with the following contents:

#!/bin/busybox sh

#Set the PATH environment variable
PATH=/bin:/sbin:/usr/bin:/usr/sbin

#Let Busybox set itself up to make all executables it contains available nativelt
/bin/busybox --install

#Mount the kernel's virtual filesystems
mkdir /proc
mkdir /sys
mount -t proc none /proc
mount -t sysfs none /sys
mount -t devtmpfs none /dev

Save and exit, then mark the script as executable with chmod +x rcS .

We now need to set the file permissions correct for the initrd. Change the owner of all files to root with chown -R root:root ./* .

Build and Launch Your System

Finally, pack your initrd using the script we created earlier, then launch your QEMU VM to demo your system:

#Assuming you're still in mrd whilst we were setting it up
cd ..

#Pack your initrd
./mkinitrd.sh

#Launch your QEMU VM
./launchrd.sh

To be continued