ALSA PCM Recovery on Embedded Linux: Distinguish an XRUN from a Suspended Stream

An embedded audio application should not classify every failed PCM transfer as an underrun. An XRUN and a suspended stream follow different recovery paths. More importantly, a helper returning success means it handled a stream-state error; it does not mean the failed transfer delivered its requested frames.

This guide reads the implementation in alsa-lib v1.2.13. The worked example is a hypothetical embedded recorder or HMI audio task using interleaved transfers. No audio device, suspend operation or recovery loop was exercised.

Preserve the transfer result before recovery

Use the signed return value from the transfer API. A positive result counts frames actually transferred. A negative result is an error code. Do not overwrite the original result with a recovery helper’s return value and then interpret zero as a successful full-buffer transfer.

For example, suppose an application requests 256 frames and receives 96. Its accounting advances by 96 frames, leaving 256 - 96 = 160 frames under the application’s pending-transfer policy. If the next transfer fails, recovery does not retroactively supply those remaining frames. In capture, a discontinuity may make a logical recording block incomplete; in playback, the product must decide whether stale queued audio is still appropriate.

Keep that policy separate from the PCM handle state. A restored handle can be usable while the application’s frame sequence still contains a gap.

Follow the implementation’s error branches

In the tagged PCM source, snd_pcm_recover() handles -EPIPE by preparing the stream. That error denotes playback underrun or capture overrun. For -ESTRPIPE, it attempts resume, repeats while resume returns -EAGAIN, and falls back to preparation if resume ends with another negative result.

The distinction matters for diagnosis. The first case says the streaming schedule failed to keep up. The second says the stream was suspended and requires the corresponding recovery path. Labeling both “buffer too small” discards evidence before investigating the cause.

The helper also treats -EINTR as handled without preparing the stream. Errors it does not handle, including -EAGAIN supplied directly to the helper, remain negative. An application should not put every negative result into an immediate retry loop with no classification or wait policy.

The ALSA recovery helper prepares on EPIPE, retries resume on ESTRPIPE while EAGAIN persists, and handles EINTR without preparing.
Original implementation branch map. Suspend recovery has no overall timeout, and recovery success is not a transferred-frame count.

Original branch map of the pinned helper. The repeated suspend-resume branch has no overall deadline in this implementation.

Do not put an unbounded recovery wait in the UI owner

The suspend branch uses poll(NULL, 0, 1000) between resume attempts that return -EAGAIN. There is no total attempt or elapsed-time limit in that helper. The requested wait is not a promise that recovery completes within one second, and a nonblocking PCM transfer mode does not turn this helper into a deadline-bounded operation.

For an HMI with audio, that makes thread ownership consequential. A UI callback that invokes this recovery path can stop servicing display and input work for much longer than one iteration. Give PCM operations one clearly defined owner and decide how the product reports prolonged suspension without blocking unrelated user interaction.

If a product requires cancellation or a recovery deadline, design and qualify that behavior around the lower-level operations and the selected PCM backend. Do not advertise a timeout merely because a surrounding loop checks a clock after a potentially unbounded helper returns. Avoid concurrent “rescue” calls on the same handle without a reviewed ownership protocol.

Resolve the source’s misleading prose

The same source file’s introductory error documentation contains an inequality in its resume-loop description that does not match the implementation. The actual loop repeats on equality with -EAGAIN. The snd_pcm_resume() return documentation likewise identifies that result as inability to resume immediately.

For this release-specific behavior, the article follows the function body and return contract. This is why copying one error-description sentence without inspecting the helper can produce the opposite retry condition.

Review recovery and continuity separately

A proposed software-level review can feed the owner synthetic outcomes: a short positive transfer, an XRUN, a suspend sequence with repeated retry-later results, a successful resume, and an unhandled device error. This is a design fixture, not a claim that arbitrary ALSA backends can be forced into those states identically.

Require separate fields for transferred frames, stream-state recovery outcome and audio discontinuity. A zero recovery result must not advance the frame counter. An unhandled negative result must leave the busy retry path and become visible to the owner.

Target qualification should then use the product’s supported audio route, suspend policy and disconnect behavior. Preserve the exact library and plugin configuration. The acceptance question is whether the application handles each state transition and its audio consequences coherently, rather than whether one call to a helper eventually returned zero.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *