Mobile and Embedded Linux Solutions

Home / Blogs / Multithreaded ALSA capture code with overrun debug

I’ve been working on some ASoC multi channel capture drivers lately and was in need of a nice analysis tool to show PCM data throughput and PCM buffering information when writing to slow-ish asynchronous memory cards.

SoC memory card controllers tend to write data in asynchronous bursts and usually compete for SoC CPU IO resources with the audio subsystem. This competition for SoC IO resources between the audio and memory card subsystems can often lead to problems for audio. The two most common audio problems are :-

  1. Audio Controller FIFO overruns.
  2. Audio DMA buffer overruns.

Audio FIFO overruns are caused when the DMA controller cannot empty the audio FIFO before the next incoming audio PCM sample is shifted into the already full FIFO. This ultimately causes the FIFO to lose some audio PCM data and potentially also lose left+right channel alignment. FIFO overruns can be minimised by using the largest FIFO possible and by setting the FIFO DMA IRQ watermark to a value that can tolerate high latency. This should be done by the driver and may depend on number of channels capture and rate.

Audio DMA buffer overruns can be caused when any userspace process reading (capturing) the PCM audio data from the ALSA driver does not manage to completely read the data (from the DMA circular buffer) before it is overwritten by new new data (by the DMA). DMA buffer overruns can be mostly eliminated by making sure our capture program can read from the ALSA driver without any hinderance. This can be achieved by having separate reader and writer threads.

I’ve posted some example ALSA multi threaded capture code here. It’s by no means complete and is a little rough around the edges but should be helpful to anyone debuging overrun or buffering issues. It can be built as follows:-

gcc capture.c -lasound -o capture

The program will capture audio data from the default ALSA device until it receives a CTRL-C signal where it dumps the buffering usage data.

capture.c