Reading Microphone Data by Polling Using Alsa [Or V4L2]

Reading Microphone Data by Polling using ALSA [or V4L2]

To prevent the snd_pcm_read*() calls from blocking, enable non-blocking mode with snd_pcm_nonblock().

To get pollable file descriptors, call snd_pcm_poll_descriptors_count() and snd_pcm_poll_descriptors().
It is possible to have multiple descriptors because some plugins might implement notifications differently.
To translate the result of a poll() on those descriptors back into a POLLIN/POLLOUT value, call snd_pcm_poll_descriptors_revents().

How to fill ALSA buffer in timely manner

When the PCM device is in blocking mode (the default), snd_pcm_write*() will wait until all bytes have actually been written to the buffer. Unplayed samples never are overwritten.

When the PCM device is in non-blocking mode, snd_pcm_write*() will return how many frames have actually been written (or return -EAGAIN if the buffer is completely full). To wait for some space to become available, use poll(), which allows to use an event loop that waits for multiple types of events. (See that answer for details.)

Java Sound API: Attempt to Do Live Microphone Input Monitoring is Slow

There is more than one buffer involved!

When you open the SourceDataLine and TargetDataLine, I'd recommend using the form where you specify the buffer size. But I don't know what size to recommend. I haven't played around with this enough to know what the optimum size is for safely piping microphone input--my experience is more with real-time synthesis.

Anyway, how about this: define the length of data[] and use the same length in your line opening methods. Try numbers like 1024 or multiples (while making sure the number of bytes can be evenly divided by the per-frame number of bytes which looks to be 4 according to the format you are using).

int bufferLen = 1024 * 4;  // experiment with buffer size here

byte[] data = new byte[bufferLen];
sourceLine.open(bufferLen);
targetLine.open(bufferLen);

Also, maybe code in your run() would be better placed elsewhere so as not to add to the required processing before the piping can even start. The array data[] and int readBytes could be instance variables and ready to roll rather than being dinked with in the run(), potentially adding to the latency.

Those are things I'd try, anyway.

How to fill ALSA buffer in timely manner

When the PCM device is in blocking mode (the default), snd_pcm_write*() will wait until all bytes have actually been written to the buffer. Unplayed samples never are overwritten.

When the PCM device is in non-blocking mode, snd_pcm_write*() will return how many frames have actually been written (or return -EAGAIN if the buffer is completely full). To wait for some space to become available, use poll(), which allows to use an event loop that waits for multiple types of events. (See that answer for details.)

Alsa full duplex communication

When the application has to wait for a PCM device, it goes to sleep and gets woken up at the next period boundary. Therefore, the optimal size to read/write is one period (or a multiple of that).

You should read/write sample data as soon as some frames are available.

To reduce the chances of an over/underrun, increase the buffer size.
(On capture devices, increasing the buffer size does not increase latency.)



Related Topics



Leave a reply



Submit