Starting PipeWire with disabled device, then enabling device in pavucontrol, results in no audio from headphone jacks until device is suspended and waked
- PipeWire version (
pipewire --version
): self-reported 0.3.40, actually c20f2246 - Distribution and distribution version (
PRETTY_NAME
from/etc/os-release
): Arch Linux - Desktop Environment: KDE Plasma 5.23.4 X11
- Kernel version (
uname -r
): 5.15.6-zen2-1-zen
Description of Problem:
When I restart my PipeWire session manager (and/or PipeWire) with onboard audio disabled in pavucontrol[-qt], enabling the device outputs silence through headphone jacks (not speakers), until PipeWire suspends the output (you must pause all streams, then either wait 4 seconds, or restart PipeWire and wait 1 second), or you use pavucontrol-qt to switch ports from headphones to speakers/line-out and back. You are also likely to encounter this bug by disabling a device, logging out and in, then enabling the device and trying to play audio through headphones.
I'm unsure if this is a PipeWire bug in handling instructions from the session manager, or a session manager bug, or a driver/hardware issue.
How Reproducible:
The root bug is always reproducible with both pipewire-media-session and wireplumber. Wireplumber exhibits nondeterministic behavior in some cases, and I can randomly make it enable the left speaker while muting the right (or vice versa).
On my AMD desktop (PipeWire git, wireplumber-git), the bug only occurs on my front headphone port, not my motherboard's rear line out (I think both have device detection). On my Intel laptop (PipeWire 0.3.40, pipewire-media-session), the bug occurs on the headphone jack (on some tests, I heard speaker audio, on others I heard nothing, I think my headphone port is flaky though). No bug occurs when following the same steps, but with no headphones plugged in and audio playing to speakers. So this bug isn't specific to my AMD motherboard alone, but to headphone jacks. I performed most testing on my AMD desktop, but verified the bug is present on my Intel laptop.
I also tested this procedure on a 0d8c:0008 C-Media Electronics, Inc. C-Media USB Audio Device
with a single audio output, but was unable to make the device stop outputting audio. So this might not be the cause for that device not outputting audio in the past.
Steps:
- Quit your music player (eg. Audacious -> pipewire-alsa). Plug in headphones or speakers into your case's front headphone port (not rear line out).
- Open pavucontrol-qt. Click on the Configuration tab, and uncheck all audio devices. Optionally close pavucontrol-qt.
- Wait a few seconds, then run
systemctl --user restart wireplumber
(orpipewire-media-session
).- If you don't wait a few seconds, wireplumber doesn't save the unchecked state to disk.
- Restarting
pipewire.socket pipewire-pulse.socket
as well is not necessary to reproduce the bug.
- Open pavucontrol-qt if necessary. Click on the Configuration tab. Check the desired audio device. Leave pavucontrol-qt open.
Testing:
- Open Audacious and play an audio file. Close Audacious.
- Audacious's current playback timestamp advances, but no audio is played.
- With pavucontrol-qt open, wait 5 seconds. Open Audacious and play an audio file. Close Audacious.
- Still no audio.
- Close pavucontrol-qt. Open Audacious and play an audio file. Pause (or close) Audacious.
- Still no audio.
- Wait >4.1 seconds (<4 seconds doesn't work) for the output to suspend. Resume playback. Close Audacious.
- Audio plays now.
- It usually takes 4.1 seconds for the output to suspend. In one test, it took 1.1 seconds.
It seems like the bug ends when PipeWire suspends the output, which happens when you wait 4 or more seconds with no active audio streams (solid lines in Helvum), or restart WirePlumber with no active streams and wait 1 second. pavucontrol-qt is an active audio stream. Starting Audacious (even paused) is an active audio stream, playing it is an active stream, but subsequently pausing is an inactive stream (a dotted line from Audacious to the audio output).
When the output is suspended, I hear clicking every ~1.1 seconds coming from my speakers. Starting a stream produces sound iff I've heard the first click since I reenabled the output in pavucontrol-qt. This clicking is audible when I plug my speaker amp into my PC case's front headphone port, but not when I plug headphones into the same port. (Thanks, Gigabyte B550M-DS3H chipset with Starship/Matisse HD Audio Controller.) This is undesirable interference, but it's useful since I can tell exactly when pipewire suspends my audio device.
Oddly, wireplumber is setup to suspend the output after 3 seconds of inactivity, and it takes 3 seconds for pipewire to suspend its output:
[I][38583.296385] spa.alsa | [ alsa-pcm.c: 462 spa_alsa_close()] 0x56078a664798: Device 'front:1' closing
[I][38583.296505] pw.node | [ impl-node.c: 377 node_update_state()] (alsa_output.pci-0000_09_00.4.analog-stereo-44) idle -> suspended
But it takes 1.1 more seconds for the clicking to begin, and for subsequent streams to start playing again. And it takes 1.1 second for the clicking to begin (and for subsequent streams to play) when you restart wireplumber with no streams active (which creates the stream in a suspended state):
[I][39353.681974] pw.node | [ impl-node.c: 377 node_update_state()] (alsa_output.pci-0000_09_00.4.analog-stereo-0) creating -> suspended
Wireplumber can mute one speaker but not the other:
- Repeat "Steps", but close pavucontrol-qt.
- Wait 1 second or so, then run
systemctl --user restart wireplumber
. Open Audacious and play. Close Audacious. Rinse and repeat.- The results are random, and may depend on how long you wait before running systemctl (I'm not sure). If you take several seconds, audio plays normally. If you restart wireplumber faster (before output is suspended), sometimes only the left or right speaker plays. I don't think this is due to improperly saving state to disk, since the soloed speaker channel persists when I run
cd ~/.local/state; rm -rf wireplumber; killall wireplumber; wireplumber
.
- The results are random, and may depend on how long you wait before running systemctl (I'm not sure). If you take several seconds, audio plays normally. If you restart wireplumber faster (before output is suspended), sometimes only the left or right speaker plays. I don't think this is due to improperly saving state to disk, since the soloed speaker channel persists when I run
systemctl --user restart pipewire-media-session
doesn't have the same odd effects. If you wait less than 4 seconds between closing pavucontrol-qt/Audacious and opening Audacious, it remains muted. Otherwise you get normal sound.
Broken audio can survive restarting pipewire:
- Repeat "Steps". Close pavucontrol-qt and open Audacious.
- Type
systemctl --user restart pipewire wireplumber pipewire-pulse
but don't press Enter. Close Audacious and immediately press Enter. Open Audacious and play.- The "no audio" state survives all 3 services being restarted.
- Type
systemctl --user disable --now pipewire pipewire.socket; sleep 0.1; systemctl --user enable --now pipewire pipewire.socket
. Close Audacious and press Enter. As soon as the command finishes running (don't wait), run Audacious and play. If you wait too long after restarting Pipewire, the output will suspend (I hear a click) and the muted state ends.- Audio still missing.
- Type
systemctl --user disable --now pipewire pipewire.socket pipewire-pulse pipewire-pulse.socket wireplumber.service; killall pipewire pipewire-pulse wireplumber; sleep 0.1; systemctl --user enable --now pipewire pipewire.socket pipewire-pulse pipewire-pulse.socket wireplumber.service
. Close Audacious and press Enter. As soon as the command finishes running (don't wait), run Audacious and play.- Audio still missing.
Restarting pipewire has the same effect as restarting wireplumber only (usys disable --now wireplumber.service; killall wireplumber; sleep 0.1; usys enable --now wireplumber.service
). Both cause PipeWire to suspend the output immediately (not after 3 seconds), the hardware emits the first click in just 1 second (not 4).
aplay is affected as well
When I Ctrl+C pipewire during the silence, and run aplay /dev/urandom -D front:CARD=Generic,DEV=0 --format=S16_LE --channels=2 --rate=48000
in another terminal, it's silent as well. If I Ctrl+C aplay
and run it again, it produces audio iff I waited over 1.1 seconds for the first click to play. Is this pipewire's fault, or the ALSA drivers malfunctioning, or PipeWire putting the ALSA driver into an incorrect state (perhaps not properly selecting the headphone port)?
Switching from headphones to line out, and back, fixes audio
When Audacious is playing sound, and PipeWire tries playing it into the headphone port (but nothing comes out), if I open pavucontrol-qt and switch "Starship/Matisse HD Audio Controller Analog Stereo" from Headphones to Line Out and back, the headphone port starts working again.
Unplugging and replugging the headphone port only fixes audio on my laptop (which switches to speakers) and not PC.
Expected Results:
Real PulseAudio acts differently:
- Play audio in Audacious (IIRC ALSA pulseaudio-alsa, but I forgot).
- Uncheck the device's configuration profile in pavucontrol-qt.
- Audacious keeps advancing in time, without generating sound. If you did this on pipewire, Audacious stops advancing in time.
- Close and open and play Audacious.
- Audacious pauses for 2 seconds and keeps playing.
- Switch Audacious to PulseAudio. Close and open and play Audacious.
- Audacious keeps playing.
- Close Audacious.
systemctl --user restart pulseaudio
with the device disabled. Open and play Audacious.- Audacious PulseAudio plays silently.
- Re-enable the configuration profile in pavucontrol-qt.
- Audacious's output is heard in the speakers immediately, without having to stop and start the program. In Pipewire's case, even stopping and starting Audacious is insufficient; you have to close pavucontrol-qt and Audacious, and wait 4 seconds (or restart pipewire and wait 1 second).
Theory
My theory is that pipewire or the session managers don't properly setup the port of a device which is initially disabled when the session manager first exposes it to pipewire (doesn't tell ALSA which port to play audio from, or tells ALSA uninitialized memory, or something). This explains why I'm getting no or speaker audio with headphones plugged in, and why switching ports back and forth fixes the issue. It doesn't explain why suspending the device and waiting 1.1 seconds, or spending 1.1 or more seconds between aplay invocations (without pipewire running), causes audio to start playing from the nominally active port.
PipeWire (and WirePlumber) is really janky. On my AMD desktop, when my headphone port is plugged in, plugging a device into "line out" makes PipeWire switch to Line Out... and not actually play any sound into Line Out until I disconnect my headphone port. I think this janky behavior is a combination of underlying ALSA behavior, and PipeWire/WirePlumber logic. When running bare-metal aplay to front:CARD=Generic,DEV=0
(and set the output port beforehand in pavucontrol-qt), it doesn't silence/disable headphones when I plug in line out, but it does silence line out when the headphone port is plugged in.
Additional Info (as attachments):
-
pw-dump > pw-dump.log
: pw-dump_amd.log, pw-dump_intel.log
I took a level-4 pipewire log of me loosely following Steps and Testing (though oddly it only took 1.1 seconds after closing Audacious, not 4.1, for audio to restart): pipewire.log
Possibly related: #1804 (closed), #762, #1826 (closed).