Node-red-contrib-sox-utils - sox WARN alsa: under-run and other problems

Hi,

i'm using a raspberry pi with Raspberry Pi OS Lite installed. I have installed the node-red environment and am using node-red-contrib-sox-utils. I tried to start streaming audio from an external USB sound card using sox-record node and at the same time play it back in the speakers. In general everything works fine, but from time to time i get the error: sox WARN alsa: under-run and i hear crackling in the speakers. Besides, there is some delay between the input (microphone) and output (speakers). When I set the sample-rate in sox-record to 16000, the delay is about 1s, but when I change it to 48000, there is practically no delay what i want. It probably has to do with some ALSA / SOX buffer. Is it possible to somehow set it up so that at the sample-rate 16000 there was not such a long delay?

If i set the number of channels to 1 in sox-record, then after starting the flow in the debug output it receives the information that the number of channels is 2

Input File : 'plughw:1,0' (alsa)
Channels : 2
Sample Rate : 48000
Precision : 16-bit
Sample Encoding: 16-bit Signed Integer PCM

would it be possible to use node sox-convert to convert the stream from the microphone (obtained with node sox-record) to the format, for example mp3 on the fly and then play it in the speakers so that there is the shortest possible delay between input and output?

Which version of node-red-contrib-sox-utils are you using?
What Pi are you using?

I am currently using Raspberry pi 4 with 4GB RAM, but also tested on Raspberry pi 3 - same problems

node-red-contrib-sox-utils 0.4.9

i wanted to add that I tried on two different external USB sound cards and there are the same problems

Hmmm I just tested the latest version on my Mac the other day and fed the recording right to the output and it worked fine. Give me a bit to find the version

@jgkk any thoughts on this?

Thank you for your help. I've been sitting on it for a long time, but I'm stuck

here's what i did from the beginning:

on Raspberry pi3 or 4:

  1. installed Raspberry PI OS Lite (32bit) (Released 2021-01-11) with Raspberry Pi Imager v1.4
  2. sudo apt-get update and sudo apt-get upgrade
  3. installing node-red bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
  4. sudo apt-get install git sox
  5. cd ~/.node-red and npm install johanneskropf/node-red-contrib-sox-utils
  6. sudo reboot
  7. test this flow:1
  8. sox-record settings:
  9. sox-play settings

and when I start the flow in debug output i have:

Input File : 'plughw:1,0' (alsa)
Channels : 2
Sample Rate : 16000
Precision : 16-bit
Sample Encoding: 16-bit Signed Integer PCM

i have Channels:2, but I chose one channel in sex-record

The flow works and i hear my voice in the speakers when i speak into the microphone, while at 16000 there is a long delay (over 1s) between what i say and what i hear in the speakers. Interestingly, when i change to 48000 then this delay is very short. I would like to achieve the shortest possible delay at 16000. This is probably related to the alsa or sox buffer but i don't know where it is configured,

but no matter if I set 16000 or 48000, from time to time the debug displays: error: sox WARN alsa: under-run which results in a short click in the speakers.

In this very special use case where I think you might be better of using an exec node to achieve this directly with Unix pipes.

This is nothing to worry about and you can safely ignore it.

Yes this has to do with the default buffer size. If you use an exec node you could try define a smaller buffer size. The reason that the delay is shorter with a higher Bitrate is that you will have much less audio length in one buffer of the same size. But this also equals to more buffers a second and a much higher load unfortunately.

The explanation above, use a custom command and try defining a smaller buffer size but you might run into limits imposed by the underlying alsa architecture.

This is the native number of channels and format of the chosen input device sox shows you, this is what gets converted to the settings in the node. So the output data will be in the format that you set.

No not possible unfortunately as sox can’t do streaming conversions and the play node can only handle pcm streams. Encoding like that would only add more latency anyways.

This happens as the node.js process will add varying latency when handling the buffers and so the timing of how they arrive at the play node can shift from how the record send them leading to a to big pause between two buffers. Again only way to solve this would be to use a all in one command with pipes in an exec node.

I hope this explains some things,
Johannes

1 Like

Thanks for the advice and answers, i also thought about using exec node when creating a command, setting buffers etc, but i don't know how to do it yet. Can you help me where to start? maybe you can provide some example for the test? I figured buffers could be set in some alsa or sox configuration file...

If i remember correctly there is a buffer argument you can add to a sox command but you would have to look it up in the documentation.
You are running into the reason why most hardware audio interfaces supply a hardware solution for listening in on yourself as the delay /latency when running through software quickly adds up.
An exec command would look something like this i think (of course you need to edit it to your input output device, here for example it plays from the default configured recording device to the built in Headphone port of the raspberry):

sox --buffer 512 -t alsa default -t alsa plughw:Headphones

This should straight up play the input from one source to a chosen output (not testes though).

1 Like

it works: sox --buffer 256 -t alsa plughw: 1.0 -t alsa plughw: 1.0

but now i am wondering about one more thing. I wanted to send the stream using a UDP_OUT node to another raspberry pi on the network. On the second raspberry pi i wanted to use the UDP_IN node and listen on the port. This worked fine with node-red-contrib-sox-utils nodes, but how do you do that with an exec node now?

it's going to be a long night...

For streaming audio over a network you should really look at solutions like snapcast or gstreamer.
Those specialized solutions will be much better for this as nodered will not be the best tool for something like low latency audio streaming.

1 Like