Buffer period, ALSA vs. JACK

Hi all. This may not strictly be JUCE-related, but I’d be interested to get the views of any Linux audio people on why I’m witnessing the following phenomenon.

I’m writing a networked audio server. Taking the naive approach of sending packets directly from AudioAppComponent::getNextAudioBlock I observed a lot of jitter at the client side. I moved my calls to DatagramSocket::write to a dedicated thread, using wait and notify and observed the same thing.

I used Time::getMillisecondCounterHiRes to report the buffer period in ms:

...
0.026
0.027
0.027
0.028
10.413
0.088
0.061
0.042
0.044
0.043
...

Wireshark reported comparable figures in the UDP timestamp deltas.

I’m using a buffer size of 32 frames, so I’d expect to see figures around 0.726 @ 44.1 kHz.

So this is with ALSA as the audio host, and the default device, which is “Playback/recording through the PulseAudio sound server.” I have JACK installed, and switching to “JACK Audio Connection Kit” I see intervals of:

...
0.041
1.402
0.035
1.463
0.065
1.339
0.034
1.417
...

Finally, selecting JACK as the host, and “system” as the output device, the expected ~726 µs:

...
0.709
0.747
0.725
0.703
0.732
0.716
...

I imagined that using ALSA as the host, calls to getNextAudioBlock would be driven by audio hardware, and thus very evenly distributed in time. I can glimpse that pulseaudio might not be the most reliable output device for timing-critical purposes. How JACK can be used as an ALSA device, when it is itself a host backed up by ALSA, is a mystery to me. So is why I can’t see any device that both looks like a system soundcard and provides output channels in AudioIODeviceType::getDeviceNames (e.g. “HD-Audio Generic, ALC294 Analog; Front output / input”, looks promising but has no channels). Given JACK is a host with ALSA as its driver (that’s how I have it configured anyway) it’s surprising to me that it’s the most temporally reliable here (particularly if, by default, ALSA is actually using pulseaudio at the backend). It’s not clear why JUCE finds the particular list of ALSA output devices, which differs from the lists I see in Audacity or Reaper, for example.

There are a lot of factors at play here – hardware, drivers, kernel perhaps, how pulseaudio/JACK/ALSA work, etc. – and a lot that I don’t know; if anyone can shed some light on the reasons for what I’m seeing I’d really appreciate it.

Not sure why this happens, maybe because jack is supposed to give its audio thread high priority ? See Realtime scheduling and additional resources section of the Archwiki.
Btw I recall a discussion around here where it was mentioned that thread’s notify() were not reliable for uses where timing is important.

Thanks for your reply, @faidideq. I’m running JACK (JACK2 specifically) with the -R flag, so that could be it. It’s very strange to me that ALSA appears to default to some much lower priority. Reading between the lines of this page from the jackaudio wiki, it sounds like JACK handles the potentially hazardous side of elevating audio priority, so there’s no need to flirt with chrt, etc.

Re. notify() do you remember whether anyone suggested any preferable approaches for timing-critical applications? Alternatively, if you can find a link to that thread it’d be very much appreciated!

I think I confused it with a discussion about the message thread events and the timers, sorry. Looking at the Thread class code, it seems to be doing the following, which is reliable if your thread handling network i/o is available:

No apology required! Thanks for providing further detail.

I guess if my network thread isn’t waiting, that could cause a problem. That’s something I’ll have to bear in mind.