On Wed, Dec 27, 2023 at 07:53 PM, Steve Beckman wrote:
I found that the PCM Playback audio channel was frequently reporting buffer under-runs. To understand what was going on, I wrote a small test program to experiment with ALSA audio. It ran perfectly on a desktop Linux box, but would generate buffer under-runs on the Raspberry Pi. The solution was to run all the audio queues in a blocking mode. The queues actually don't block until the queues are totally filled up, which won't happen in the sBitx since the PCM Capture channel paces the entire audio system.
On Thu, Dec 28, 2023 at 02:02 PM, Steve Beckman wrote:
What really clued me in to what was going on was the test program I created to try some simple ALSA experiments. The program is set up to play sound for 10 seconds. It ran perfectly on a Linux PC. On the Raspberry Pi 4 in my sBitx, however, the program played 10 seconds of sound in 7 seconds!!? Somehow the audio samples in the output queue were either getting lost or getting overwritten. I was able to fix that problem by changing the buffer write mode from non-blocking to blocking. I then applied that change to the two output buffers being used by the sbitx.
I uploaded that test program to the bitx20 groups.io files section a short while ago if you want to play with it.
I am taking you up on that offer.?
I used Audacity to convert some known audio (ok, an Allman Brothers song!) to the right format for the program to play.? It worked just like your experiments, nonblocking mode was faster.?
Then I wanted to understand the difference between "hw:0,0" and "plughw:0,0".? ?This is because the sbitx install.txt talks about using hw:0,0 and not about using plughw:0,0.? I know they are similar but not the same thing.
The program worked with device="hw:0,0" and mode=0 but not mode=SND_PCM_NONBLOCK.?
Googling told me that if you use "plughw" you are using the "plug" plugin which does a bunch of things, one of which is rebuffering i.e. matching the rate of the sender (us) and the receiver (the codec).? When you use "hw" you are writing directly to the sound device.
If you use blocking mode you don't need this, the sender is blocked so it runs no faster than the rate of the codec, but as you suggest if the sender stalls for too long we get underruns i.e. we didn't deliver data to the codec on time.
If you use non-blocking mode and no plug plugin, I see 'short write' messages and I hear distorted sound.? I would expect this to mean we overrun i.e. we're writing faster than the codec can read and there's nothing to rebuffer so the audio gets distorted.? ?Yet I don't hear crackling, what I hear is the audio playing real slooow.? I don't have a good explanation for what is going on.
If we use non-blocking with the plug plugin the plugin will save the data (re-buffering if needed) till the right time to play it back.? ?As you say, this works because it's the codec that paces the system.? It's kind of a "dump and run" strategy.? The user mode code delivers samples as fast as it can and the plugin is playing them out at the right rate.? It seems the writer is never getting too far ahead of the codec, its rate is determined by the rate of the audio it is creating/playing.? It seems the writer does occasionally get behind if we use blocking mode.? It's better to let the writer deliver the data, for the kernel to rebuffer it as needed, and release the writer to get ready for the next block of samples instead of blocking it till the block plays.
Below is what the early part of the C code now looks like on my system.? I think we might consider making room for it in Git either in the sbitx repo or in an adjacent one.??

I've also written up how to use Audacity to make the audio the program wants:

More later...
--
Regards,
Dave, N1AI
?
--
Regards,
Dave, N1AI