No audio from Pisound in headless mode

Hi there,

I got myself a nice Pisound HAT and have been playing around a bit. I really like it.
(With running Patchbox OS on my Raspberry Pi 4B+)

However, I don’t get any audio output as long as the Raspberry Pi did not load its graphical environment (either automatically from boot, or via startx)

What I try to do is:

  1. Boot the Raspberry Pi in headless mode
  2. Login with ssh (from a different machine)
  3. Play an audio file (with aplay ~/path/to/my_audio.wav)
  4. → No sound is heard.
  5. Leave ssh session open (continue in step 9)
  6. On the Raspberry Pi with keyboard attached, login with user+password
  7. On the Raspberry Pi, start the graphical GUI with startx
  8. In the ssh shell (from the remote machine), try aplay ~/path/to/my_audio.wav again
  9. → Sound is played!!!

(I got the exact same behavior if I use a the following python script in step 3 and step 9. )

import wave
import simpleaudio as sa

path_to_file = "/home/patch/path/to/my_audio.wav"
wave_read = wave.open(path_to_file, 'rb')
wave_obj = sa.WaveObject.from_wave_read(wave_read)
wave_obj.play()

If I re-run the last line wave_obj.play() in step 9 it works!

Question

How can I get the Raspberry+Pisound working before or without running the graphical environment?
Aka: how I use Pisound in headless mode?

Thanks!

@irlabs Welcome to the community!

After you got Patchbox OS installed did you happen to run:

sudo pisound-config

and set the default soundcard to Pisound?

Hi, thanks. I feel welcome already. :blush:

Yes Pisound is the default soundcard.

And I set this as contents of /etc/asound.conf :

pcm.!default {
    type hw card 1
}
ctl.!default {
    type hw card 1
}

Also, the weird thing is, I don’t see any difference in the output of aplay -l or sudo systemctl status jack between before the graphical environment is active (headless) and after I ran startx.

The only difference is I the audio I hear. Before silence. After sound!


The output of aplay -l :

**** List of PLAYBACK Hardware Devices ****
card 0: Headphones [bcm2835 Headphones], device 0: bcm2835 Headphones [bcm2835 Headphones]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7
card 1: pisound [pisound], device 0: PS-0YNDC5D snd-soc-dummy-dai-0 [PS-0YNDC5D snd-soc-dummy-dai-0]
  Subdevices: 0/1
  Subdevice #0: subdevice #0
card 2: vc4hdmi0 [vc4-hdmi-0], device 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 3: vc4hdmi1 [vc4-hdmi-1], device 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

The output of sudo systemctl status jack :

● jack.service - JACK Server
     Loaded: loaded (/lib/systemd/system/jack.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2024-01-17 21:17:56 CET; 6min ago
   Main PID: 550 (jackd)
      Tasks: 5 (limit: 4915)
        CPU: 15.163s
     CGroup: /system.slice/jack.service
             └─550 /usr/bin/jackd -t 2000 -R -P 95 -d alsa -d hw:pisound -r 96000 -p 128 -n 2 -X seq -s -S

Jan 17 21:17:58 pi02 jackdrc[550]: ALSA: final selected sample format for capture: 16bit little-endian
Jan 17 21:17:58 pi02 jackdrc[550]: ALSA: use 2 periods for capture
Jan 17 21:17:58 pi02 jackdrc[550]: ALSA: final selected sample format for playback: 16bit little-endian
Jan 17 21:17:58 pi02 jackdrc[550]: ALSA: use 2 periods for playback
Jan 17 21:17:58 pi02 jackdrc[550]: port created: Midi-Through:midi/playback_1
Jan 17 21:17:58 pi02 jackdrc[550]: port created: Midi-Through:midi/capture_1
Jan 17 21:17:58 pi02 jackdrc[550]: port created: pisound:midi/playback_1
Jan 17 21:17:58 pi02 jackdrc[550]: port created: pisound:midi/capture_1
Jan 17 21:20:06 pi02 jackdrc[550]: port created: pisound-ctl:midi/playback_1
Jan 17 21:20:06 pi02 jackdrc[550]: port created: pisound-ctl:midi/capture_1

@irlabs great detail provided! I’m not sure what your problem might be here. I’m going to summon the @Giedrius to assist. :smiley:

1 Like

If Jack is running, ALSA utilities should receive ‘device is busy’ errors when trying to play audio (ALSA usually provides direct access to audio hardware, Jack backend is the one that shares it with other software, as long as the software is configured to use Jack). Most likely the ALSA utilities end up sending audio either to the headphone jack on the Pi itself or via its HDMI connections.

Try to explicitly specify -D hw:pisound for aplay.

If you get ‘device is busy’ error, temporarily stop Jack and try again: sudo systemctl stop jack

Hi, thanks for the help.

But it doesn’t solve my problem. Still no audio in headless morde. And it makes me understand it even less. I have a couple of questions and observations now.

1. Should jack run or not?

Observation 1

Indeed, if I specify the pisound card with

aplay -D hw:pisound ~/path/to/my_audio.wav

It gives me this error: aplay: main:830: audio open error: Device or resource busy

And indeed, if I kill jack with sudo systemctl stop jack, the error is gone, but I still get no sound out!

Observation 2

When, while running the graphical environment, (with startx), the same command (explicitly specifying the pisound card), gives me the exact same error:

aplay -D hw:pisound ~/path/to/my_audio.wav

yields → aplay: main:830: audio open error: Device or resource busy

But without specifying it (while the graphical environment is running), there is full audio from the pisound card!

aplay ~/path/to/my_audio.wav

works!

Observation 3

Furthermore, if I start the graphical environment with jack stopped, or when the graphical environment is already running and I kill jack, none of my python scripts (using the simpleaudio module) is producing any sound. Also the simple aplay ~/path/to/my_audio.wav isn’t working (no errors, but also no sound).

So, I get the feeling I shouldn’t try to mess with the jack server, and just leave it running

2. Is always necessary to specify the sound card?

I’m assuming Jack takes care of specifying which audio card to use as default. Because if I don’t specify it with aplay or with the python script, (and it is not running headless), it works.

Observation 4

If the graphical environment is running and jack server is stopped, the only way to get audio out, is to use aplay and specify the card:

aplay -D hw:pisound ~/path/to/my_audio.wav

yields → Playing WAVE '/home/patch/path/to/my_audio.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo

and actually plays the sound.

But when not specifying the card:

aplay ~/path/to/my_audio.wav

it yields the same → Playing WAVE '/home/patch/path/to/my_audio.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo.

Thus no error, but also no sound.

And I don’t know how I can specify the audio card with the simpleaudio python module. So it seems I need the Jack server to run for that reason.

3. Deeper in the rabbit hole: What is the difference between specifying the card and not specifying it?

Observation 5

This is with a different audio file. (The one above was 16bit, 48kHz. This one is 24bit)

Environment: graphical OS running + Jack server stopped.

aplay ~/path/to/otherfile48kHz24bit.wav

yields → Playing WAVE '/home/patch/path/to/otherfile48kHz24bit.wav' : Signed 24 bit Little Endian in 3bytes, Rate 48000 Hz, Stereo

yet produces no audio.

When specifying the sound card:

aplay -D hw:pisound ~/path/to/otherfile48kHz24bit.wav

yields this error:

Playing WAVE '/home/patch/path/to/otherfile48kHz24bit.wav' : Signed 24 bit Little Endian in 3bytes, Rate 48000 Hz, Stereo
aplay: set_params:1343: Sample format non available
Available formats:
- S16_LE
- S24_LE
- S32_LE

What does this error mean and why do I get it?

As far as I know, and as far as I can create or convert (with sox), this file is 24 bit signed, little endian.
Also, when Jack server is running in the graphical OS,

aplay ~/path/to/otherfile48kHz24bit.wav

is playing the audio just fine. So it is not a problem with aplay or with the audio format. (Or at least that is how it seems.) This error only is displayed when specifying the audio card.


I feel I am still tumbling and tumbling down the rabbit hole, with aplay, -D hw:pisound, the Jack server and 24bit audio formats.

But my initial question how to get audio from the pisound without firing up the graphical OS, gets further away.

Hi,

one more observation.

I have difficulty to find a command line message or status which displays or explains the difference between:

  • headless : no audio
  • graphical OS : audio

(The only difference is the audio I hear, or silence for that matter)

But now I saw this LED light up when I play audio.

The LED only lights up in graphical OS mode, only when I actually hear audio

The red led means you’re overloading the input, need to turn down the gain.

Ah! Thanks! The input gain.
(That is because I hooked up the input to the AUX (FX) SEND of my mix panel)

Sorry for the confusion. This has nothing to do with the audio output

Jack is an efficient audio backend for Linux that allows multiple software to route their virtual audio inputs and outputs around, and finally to the hardware I/O ports. If the software you intend to use supports Jack, you should use it.

Linux has multiple audio APIs that programs can use, some programs support more than one. The ALSA utilities you’re using are intended only for ALSA. There might be some automatic Jack adapter that’s managing to bridge between the APIs, but usually such model is inefficient and should be avoided, in favor of using audio software configured to use Jack directly, or ALSA only. (this might be the reason why some ALSA utils manage to work while Jack is running)

ALSA gives exclusive access to the audio hardware, that means only one program can output audio at a time. There’s some software mixer plugins out there, but they’re less efficient than using Jack.

So in short - configure and use only software that’s capable of using the Jack backend, or if you need to use ALSA in some software directly, stop all Jack software and the server itself, and then run the ALSA based ones. There’s usually equivalent Jack utilities available for playing and recording .wav files.

The Jack backend gets configured to use a particular sound card. For other utilities, I’d recommend always specifying the card anyway, as otherwise, the OS can see the 3.5mm audio port on the Pi itself, the HDMI audio, and Pisound - it has no idea on its own which output device you intend to use at that time, it may even have a ‘fallback’ logic, in case one device is busy, try the next, etc… So no guarantee to get the result that you actually intend to if you’re not specific.

This is covered in the first 2 answers I think. :slight_smile:


Try this in headless mode:

sudo systemctl stop jack
speaker-test -c2 -r48000 -Dhw:pisound

It should produce white noise, alternating on left and right channels. Does it work for you?

Hi, thanks for the detailed explanation of Jack and ALSA!

Try this in headless mode:
[…]
It should produce white noise, alternating on left and right channels. Does it work for you?

Yes!
Finally some audio from the PiSound in headless mode.

But still no sound in headless when Jack is running with

/usr/bin/jackd -t 2000 -R -P 95 -d alsa -d hw:pisound -r 96000 -p 128 -n 2 -X seq -s -S

So, I am about to give up the headless attempt, and accept that the Raspberry Pi will be running a full fledged Desktop GUI in the background without the need for it. Just hope that is not causing too much extra latency.

It is most likely some sort of configuration error, we have Jack running headless on Patchbox OS without any issues.

Are you trying to start Jack by yourself?

No, it is starting automatically on boot.


But I have been investigating further –– and investigating the obvious, which I discarded earlier :see_no_evil: –– and now I am getting much further:

  1. If in headless mode, I run
aplay ~/path/to/my_audio48kHz16bit.wav

or

aplay -D default ~/path/to/my_audio48kHz16bit.wav

There is no audio from the pisound card, but there is audio from the 3.5 mm jack on the Raspberry!
(I did not realize this until I plugged in a set of headphones until today :see_no_evil: :hear_no_evil: :see_no_evil:)

  1. If I try
aplay -D hw:pisound ~/path/to/my_audio48kHz16bit.wav

it tells me : audio open error: Device or resource busy

So

  1. So I disable Jack (because I am assuming that Jack keeps the hw:pisound “busy”)
sudo systemctl stop jack
aplay -D hw:pisound ~/path/to/my_audio48kHz16bit.wav

And that actually works! :tada: Sound is coming from the pisound card in headless mode.

However,

aplay -D default ~/path/to/my_audio48kHz16bit.wav

is still playing through the 3.5 mm jack on the Raspberry Pi.

And for my use case, I digged a little deeper into the python audio lib that I intend to use, and its C code appears to use ALSA’s “default” device hardcoded: static char *device = "default";
I don’t intend to fork that library or modify it,


so now my simple question is:
Q: how to set the pisound card as the “default” ALSA audio device?

Thanks

https://www.alsa-project.org/wiki/Setting_the_default_device

Also check ~/.asoundrc as it may be overriding the default.

Pisound is probably card number 2 or 3, it depends on your system configuration.

Normally you should prefer using the Jack backend for audio software, as it allows sharing audio resources with multiple programs. In case this option is unavailable, then disable Jack backend and use ALSA.

sudo systemctl disable --now jack

Thanks @Giedrius,
you have been helping me tremendously. Just disabling jack and having

defaults.ctl.card 1
defaults.pcm.card 1

in /etc/asound.conf was not enough to set the pisound card (card 1) as default.

aplay -D default ~/path/to/my_audio48kHz16bit.wav

would still be playing the audio through the 3.5 mm headphone jack.


I investigated further and read on the Raspberry StackExchange a lengthy post about how to Set an external USB as default ALSA device. And assured by your comment from 6,5 years ago, as an experiment, I removed PulseAudio

sudo apt-get remove pulseaudio

Only then, after a reboot, the default ALSA device really is the pisound card.

aplay -D default ~/path/to/my_audio48kHz16bit.wav

is finally playing from the pisound card. :relieved: :tada:


However, … this is still not a solution for my problem :exploding_head: :cold_sweat:

(I want to play multiple .wav files simultaneously using the python simpleaudio library )

Because if I remove PulseAudio, the python script is only playing the first note. When it attempts to play the second note it crashes:

Traceback (most recent call last):
   [...]
    play_id = _sa._play_buffer(audio_data, num_channels, bytes_per_sample,
_simpleaudio.SimpleaudioError: Error opening PCM device. -- CODE: -16 -- MSG: Device or resource busy

So this Device or resource busy tells me that indeed, like you wrote

And it seems not just one program exclusively (it is one python script), but even only one play call invocation at a time. This is clearly not the way to go for my sequencer/sampler.

So I think I do need PulseAudio, and the pulseaudio-module-jack if I want to use this python library.

After more investigation, I think I understand the system now. And it seems for my setup, I need ALSA, Jack and PulseAudio. (The graphical GUI desktop gives me this setup).

from the jackaudio.github Wiki :

  1. Redirect all ALSA output to PulseAudio
  2. Redirect PulseAudio to JACK

However in headless mode, Jack was not available as module for PulseAudio.

the command pacmd stat reported:

[...]
Default sink name: alsa_output.platform-bcm2835_audio.analog-stereo
Default source name: alsa_output.platform-bcm2835_audio.analog-stereo.monitor
[...]

And pacmd list-sinks didn’t include Jack:

1 sink(s) available.
	index: 0
		name: <alsa_output.platform-bcm2835_audio.analog-stereo>
		[...]
			alsa.name = "bcm2835 Headphones"

While in Desktop mode, pacmd stat gave me:

Default sink name: jack_out
Default source name: jack_in

and pacmd list-sinks :

2 sink(s) available.
	index: 0
		name: <alsa_output.platform-bcm2835_audio.analog-stereo>
		[...]
	index: 1
		name: <jack_out>

So finally I fixed my issue, and can now run my python simpleaudio headless in the way I intend to use it, playing multiple sounds simultaneously

pactl load-module module-jack-source
pactl load-module module-jack-sink
pacmd set-default-sink jack_out
pacmd set-default-source jack_in

:white_check_mark:

Thanks all!