Giocoso and Pipewire
The Linux audio stack is a convoluted mess!
In the beginning, Linux used OSS (the Open Sound System). This was replaced in the late 1990s by ALSA, the Advanced Linux Sound Architecture. ALSA is a kernel-level sound architecture that has no support for mixing multiple audio streams (so two programs cann't play simultaneously and one would block the other: some of us think this is what playing classical music ought to be like!) and no per-application volume control, because the kernel doesn't concern itself with the details as to what programs users might be running.
Along came PulseAudio, in the mid-2000s. It provided a wrapper around ALSA that allowed multiple programs to sound simultaneously and provided per-application volume control. It also added network audio streaming. By sitting on top of ALSA, however, PulseAudio added complexity to the sound stack and made working out why sound didn't work properly more complex, not less. It also was a high-latency layer, that made real-time audio tricky and started to fail, with jitter and dropouts, when the CPU was stressed enough.
So finally, in around 2015, PipeWire was invented. It replaces PulseAudio with a lower-latency and better real-time performance that's more immune to CPU load than PulseAudio ever was. PipeWire still sits on top of ALSA (ALSA is the kernel-level audio stuff, so both PulseAudio and PipeWire are the user-layer interface to ALSA). Amusingly, PipeWire runs a PulseAudio compatibility layer, so applications designed to run with PulseAudio can (allegedly) work seamlessly with PipeWire. I say 'amusingly' with venom because it now means you run an application and you haven't necessarily got a clue how it's talking to ALSA: it might be using the PulseAudio interface, or the PipeWire. Everything still works either way, so you're left a bit in the dark!
My music player PC (an ancient Mac Mini) runs Linux Mint. Linux Mint switched to using PipeWire as the default audio interface in the Wilma release (which is approximately late last year). I hadn't been aware of any of that… until I did a big software update the other day and things got “interesting”!
The issue is Giocoso's pause/resume functionality. Giocoso tells the process running the ffmpeg audio stream handler either to pause itself or resume itself. Under PulseAudio (or direct ALSA) doing this is not a problem: neither cared if the process was frozen or not, so resuming a frozen playback was without drama.
But PipeWire seeks to be modern and more efficient… which, of course, means it messes with the tried and true! When it detects that audio process has stalled, it suspends audio nodes to save power, marks the stream node as inactive and all its resources are freed. This poses a problem on playback resumption: the audio buffer behind the paused process will have been cleared, meaning that when the audio stream is resumed, it does so with invalid timestamps… and that manifests itself in garbled or 'scratchy' sound.
So guess what happened to my Giocoso setup after I foolishly subjected the Mac Mini in question to a recent software update? Pausing playback worked fine, but resuming it sounded like a Dalek with laryngitis had entered the room. Or maybe a Dalek attempting to sing Tristan und Isolde from the bottom of a swimming pool. It wasn't pleasant, put it that way.
Basically, the punchline is this: if your Linux distro uses PipeWire as its default audio stream handler, Giocoso's Pause/Resume is probably broken.
There is allegedly a fix. If you are able to tell PipeWire, “Do not treat a suspended audio device as being dead”, then the auto-cleanup of resources doesn't take place and the resumption of the playback should work as it used to. To do that, you need to create a new file:
~/.config/pipewire/pipewire.conf.d/99-nosuspend.conf
In that file, you type the following:
context.properties = {
suspend-timeout-seconds = 0
}
Finally, you re-start PipeWire to get the new setting picked up and applied:
systemctl --user restart pipewire
Once these textual fixes are in-place, you'll find that Giocoso pauses and resumes cleanly once more.
This will be a problem for many modern Linux distros, because they've all been switching over to PipeWire by default quietly in recent months. The same fix should apply to them all. A new release of Giocoso will eventually be produced that applies this fix automatically, if PipeWire is detected on your system… but for now, the fix has to be applied manually.
My apologies for any inconvenience: this is what happens when the technological rug is tugged from underneath one! Giocoso development is, frankly, just a question of keeping up with what other Linux developers are… er, breaking!
Update 1: It turns out that this “fix” doesn't really work very reliably. Fiddling with the PipeWire suspend timeout doesn't appear to have fixed the garbled sound problem if the music playback is paused for a very long time (such as overnight): the resumed playback still sounds awful in that case. I shall attempt to get Giocoso working on different hardware to see if that resolves the issue, though why hardware which worked fine at the beginning of the week suddenly decides to misbehave after a software update is a bit of a mystery!
Update 2: Well, after much fiddling with other hardware, I ended up issuing the following commands on the original PC:
systemctl --user --now disable pipewire pipewire-pulse wireplumber systemctl --user mask pipewire pipewire-pulse wireplumber
…to stop and disable pipewire. Then I issued this command:
sudo apt remove --purge pipewire pipewire-audio-client-libraries wireplumber
…to remove pipewire and PulseAudio from the Linux Mint 22 system completely. That means this PC is now going to be using ALSA directly (which Giocoso is happy doing). Finally, I issued this command:
sudo apt-mark hold pulseaudio pipewire
…to prevent Linux Mint “accidentally” re-installing either PulseAudio or PipeWire. A reboot followed at this point and, once the PC was back up, I issued the command:
aplay /usr/share/sounds/alsa/Front_Center.wav
…to directly play some sound… and heard everything just fine. The command:
aplay -l
…reassured me that the operating system could still see and enumerate audio devices correctly:
**** List of PLAYBACK Hardware Devices ****
card 0: HDMI [HDA Intel HDMI], device 3: HDMI 0 [HDMI 0]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 7: HDMI 1 [HDMI 1]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 8: HDMI 2 [HDMI 2]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 1: PCH [HDA Intel PCH], device 0: CS4208 Analog [CS4208 Analog]
Subdevices: 1/1
Subdevice #0: subdevice #0
card 1: PCH [HDA Intel PCH], device 1: CS4208 Digital [CS4208 Digital]
Subdevices: 0/1
Subdevice #0: subdevice #0
I was thus able to configure Giocoso to use the “plughw:1,1” device (the digital, optical output) and music playback was fine. I then paused a piece of music in mid-play overnight. On waking, music playback was able to be resumed without any garbling or distortion.
The short take on this is, therefore, that Giocoso works fine with PipeWire so long as you don't pause or resume; that it works fine with PipeWire for short pauses and resumes if you set the suspend-timeout-seconds parameter; but that it does not work at all well with PipeWire if you intend to pause for lengthy periods (say, a half hour or more). My advice is therefore to run Giocoso on systems that do not have PipeWire installed at all (such as Alpine Linux); to remove it if it is installed; and to avoid even PulseAudio unless you intend to route Giocoso's playback over your home network. Use ALSA directly, as Giocoso was always intended to do, basically.
It is possible that I shall nevertheless re-write Giocoso's pause/resume functionality to avoid stopping and resuming audio playback at the per-process level. Giocoso already has a pause/resume functionality that involves launching a completely new playback process when music playback is resumed: the Giocoso Pro 'Global Resume' functionality. If that were employed as the sole pause/resume functionality, the garbled sound issue would be resolved even in the presence of PipeWire. It's a lot of work, however, and I wouldn't hold my breath!
Giocoso over a dodgy network
I recently had trouble talking from me desktop PC to my music-playing PC, running Giocoso. I'd launch a remote ssh session to the player PC, kick off some music playback …and the ssh connection would die, stopping the music playback as it did so. Very annoying if, say, you'd played 1.75 hours of a 2 hour opera: when the ssh session dies, the partial play is essentially regarded as never having happened, so you have to start from scratch next time you connect.
My first thought on fixing this was: screen. It's a utility you launch on the music-playing PC immediately after you've ssh'd into it from the desktop PC, and then within screen, you can launch Giocoso. If the ssh connection dies between desktop and player PCs, screen and anything launched from within it continues to run regardless. Brilliant! But, unfortunately, this is what launching Giocoso inside screen looks like:
Complete gibberish, of course! I mean, you can just about make out menu options and navigation aids and the thing will actually play music.. but it's obviously not ideal! It probably has something to do with the way Screen handles terminal emulation: I did try fiddling with the value of the TERM environment variable before launching Giocoso, but it really didn't make any difference.
So my second thought was tmux, which does the same sort of thing as Screen: provide an environment in which programs can be launched such that, should the network die, the running program doesn't.
So I tweaked my desktop PC's launcher for 'remote Giocoso'. It's application remained unchanged from before:
/usr/bin/uxterm
…that is, everything continues to run inside a local session of the 'uxterm' console program. What's different is the “arguments” that you pass to that uxterm session as it begins. Mine used to read:
-T 'Giocoso - A Digital Music Player' -xrm 'xterm*iconHint: /home/hjr/.local/share/giocoso3/art/giocosoico.xpm' -bg black -fg green -geometry 103x28+0+0 -fa 'Luxi Mono:style=Regular' -fs 12 -ti 340 -tn xterm-256color -e 'trap "" HUP; ssh -Y -t [email protected] /usr/bin/giocoso3.sh'
…which is “give the terminal a name and a thumbnail icon, set it to be black with green text, make it 103 columns wide and 28 rows high, positioning it in the top left of my desktop PC's monitor; set the font to something nice, and then ssh over to the music-player PC and launch Giocoso”. Looks messy, but it worked (or did if the network stayed up)!
The new “arguments” however now read as follows:
-T 'Giocoso - A Digital Music Player' -xrm 'xterm*iconHint: /home/hjr/.local/share/giocoso3/art/giocosoico.xpm' -bg black -fg green -geometry 103x28+0+0 -fa 'Luxi Mono:style=Regular' -fs 12 -ti 340 -tn xterm-256color -e "ssh -Y -t [email protected] \"tmux new-session -A -s giocoso '/usr/bin/giocoso3.sh'\""
Most of that starts off exactly as it used to. The new feature is that having ssh'd to the remote PC, it doesn't directly launch Giocoso, but launches tmux and creates a new session (called 'giocoso') and, within that session, runs the giocoso3.sh executable. This appears on my desktop PC almost exactly the same as it used to… except that I can now physically close the Giocoso window, thereby manually terminating the ssh session… and the music previously playing will continue playing without interruption. If my network dies of its own accord, the player PC will similarly continue playing without a murmur. Especially nice is that if I re-launch Giocoso on my desktop, it will automatically re-connect to the remote tmux session and display it exactly where I left it, album art and all.
The only slight fly in the ointment is that, by default, tmux likes to display a status bar at the bottom of the terminal window it's running in:
That glowing green bar at the bottom of the screen rather throws off my geometry calculations: Giocoso needs to run in a 103×28 terminal window… but if one of the vertical lines is taken up by tmux's status bar, Giocoso gets muddled:
None of the lines actually appear where they should and text over-writes them in places. The fix for this is relatively straightforward. One possible fix is to retain the status bar and just amend the “arguments” for my launcher to launch at 103×2*9* rather than 103×28. That's a client-side fix, of course. The fix I decided to adopt is a server-side one: on the remote PC, I create the file $HOME/.tmux.conf and type the following code into it:
set -g status off
Once a new tmux session starts, it picks up this new setting… and the result is:
The title bar of that terminal tells you that the session is running tmux… but now there's no bright green bar at the bottom of the screen. The status bar is off!
All of which means that no matter how dodgy my network connection to different parts of my home might be, I can be confident that Giocoso will play things through to completion, every time: no more getting 4.5 hours through Götterdämmerung and then having the rug pulled out from under me yet again! A future Giocoso installer may implement this tmux configuration tweak directly, though I haven't decided on it yet. Obviously: it only affects people who use Giocoso via a network/ssh connection, so it is maybe a bit niche to start making sweeping configuration changes to other programs at this point!
RVW Journal now out!
Just announcing that the latest edition of the Journal of the Ralph Vaughan Williams Society has been published and is available for purchase from the Society's website. It happens to have been edited by my own good self!
I encourage you to become a member of the Society, for the princely sum of £25.
Something new is coming
Just wanted to announce that I'm planning a complete re-vamp of the website, into something more performant, less cluttered, much smaller and quite a lot simpler to configure and maintain!




Some Code Comments
This website's “sidebar” (it's main menu, effectively) will refresh every five minutes, because of this code it contains:
<script type="text/javascript"> (function() { window.onload = function() { setTimeout(function() { location.reload(); }, 300000); }; })(); </script>…which triggers a refresh every three hundred thousand milliseconds (which is therefore every three hundred seconds… or every five minutes).
The purpose of this auto-refresh is to ensure the 'currently playing…' icon more-or-less accurately reflects the music I'm actually listening to, rather than a recording I was listening to several hours ago. A manual selection of any of the sidebar menu items will also trigger a refresh and thereby 'reset the clock' for the auto-refresh functionality.