QAudioSink buffer size changes
-
I'm one of the authors of Square Desk an open source music player application targeted at square dance callers (niche audience). The other author recently changed our audio processing chain from LibBass to a more complex one that uses the Qt API with KFR and SountTouch to better work on M1 Macs, which is great, but I'm on Linux, and we had the usual QAudioSink latency issues. Particularly, that it looks like on the Mac, ->bytesFree() is giving us a fraction of a second of buffer (yay), on Linux it lets us write tens of seconds, if not minutes, of data ahead (boo).
His approach has a thread doing the audio processing, checking for output space on the QAudioOutput device, filling that, sleeping for a few milliseconds, repeat. Not perfect, but it works as long as the buffer isn't larger than what you'd expect from clicking stop and start or munging controls. A tenth or even a quarter of a second is fine.
So on Linux, on the first play, I call ->bytesFree(), set a variable to that minus the latency I'm looking for (eg: 44.1KHz * 8 byte samples / 100ms), and subtract that number from all subsequent calls to ->bytesFree().
Which mostly works fantastically. Until something happens and suddenly I'm apparently getting a much larger number back and all my buffers overrun. I've fixed this with some defensive coding, but I don't trust it, especially when I'm behind a mic looking out over a crowd and trying to not panic about when my technology is going to misbehave.
I've seen discussion threads about using a QIODevice subclass to write when the QAudioSink requests data for better latency handling, and I've played a little bit with that, but I'm not totally sure how that solves my latency issues if I can't trust the buffer size, and it started to be a pretty complex rewrite of my co-author's buffer management.
Anyone have experience with this sort of approach and give me some better notions of what to be looking for? Example code for mid-latency Qt audio processing that I should be looking at?
-
I'm one of the authors of Square Desk an open source music player application targeted at square dance callers (niche audience). The other author recently changed our audio processing chain from LibBass to a more complex one that uses the Qt API with KFR and SountTouch to better work on M1 Macs, which is great, but I'm on Linux, and we had the usual QAudioSink latency issues. Particularly, that it looks like on the Mac, ->bytesFree() is giving us a fraction of a second of buffer (yay), on Linux it lets us write tens of seconds, if not minutes, of data ahead (boo).
His approach has a thread doing the audio processing, checking for output space on the QAudioOutput device, filling that, sleeping for a few milliseconds, repeat. Not perfect, but it works as long as the buffer isn't larger than what you'd expect from clicking stop and start or munging controls. A tenth or even a quarter of a second is fine.
So on Linux, on the first play, I call ->bytesFree(), set a variable to that minus the latency I'm looking for (eg: 44.1KHz * 8 byte samples / 100ms), and subtract that number from all subsequent calls to ->bytesFree().
Which mostly works fantastically. Until something happens and suddenly I'm apparently getting a much larger number back and all my buffers overrun. I've fixed this with some defensive coding, but I don't trust it, especially when I'm behind a mic looking out over a crowd and trying to not panic about when my technology is going to misbehave.
I've seen discussion threads about using a QIODevice subclass to write when the QAudioSink requests data for better latency handling, and I've played a little bit with that, but I'm not totally sure how that solves my latency issues if I can't trust the buffer size, and it started to be a pretty complex rewrite of my co-author's buffer management.
Anyone have experience with this sort of approach and give me some better notions of what to be looking for? Example code for mid-latency Qt audio processing that I should be looking at?
Hi and welcome to devnet,
Which version of Qt are you using ?
-
@Dan-Lyke a quick look at your code reminded me of another project where latency was crucial and I wrote a QIODevice subclass on top of PortAudio which might be better suited for your use case.
On a side note, your custom mutex locker class is not necessary since there's QMutexLocker.