I do not know if it is hardware-related, but I am going mad about spurious underrun errors on snd_pcm_writei() calls. The same code runs without issues on my laptop.
I use a blocking setup:
snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
Here is the snd_pcm_dump_sw_setup() output:
tstamp_mode : NONE
tstamp_type : MONOTONIC
period_step : 1
avail_min : 1764
period_event : 0
start_threshold : 1
stop_threshold : 3528
silence_threshold: 0
silence_size : 0
boundary : 1849688064
While setting the hardware parameters, I log the results of the snd_pcm_hw_params_set_rate_near(), snd_pcm_hw_params_set_periods_near(), snd_pcm_hw_params_set_period_size_near() calls:
3719.1287 D [AlsaSound] SOUND: setupWithFreq sampling rate: 44100, dir: 0
3719.1288 D [AlsaSound] SOUND: number of periods: 2, dir: 0
3719.1289 D [AlsaSound] SOUND: period size: 1764 frames, dir: 0
Here is the relevant part from the filling loop, what is called repeatedly:
log.debug("play %d samples", n);
while ((ret = snd_pcm_writei(handle, playBuf, n)) != (long)n) {
if (ret < 0) {
log.warn("ALSA error: %s\n", snd_strerror(ret));
if ((ret = snd_pcm_recover(handle, ret, 0)) < 0) {
log.error("ALSA error after recover: %s\n", snd_strerror(ret));
checkFatalAlsaError(snd_pcm_prepare(handle), "ALSA irrecoverable error: %s");
}
} else {
log.warn("ALSA short write...?\n");
break;
}
}
Here is the log when everything is fine:
3751.3029 D [AlsaSound] Starting square sound, nsamples: 3528, nPeriods: 2, nFrames: 1764
3751.3030 D [AlsaSound] play 1739 samples
3751.3037 D [AlsaSound] play 1739 samples
3751.3046 D [AlsaSound] play 50 samples
3751.3048 D [AlsaSound] Stop sound
And sometimes I get this:
3752.8769 D [AlsaSound] Starting square sound, nsamples: 3528, nPeriods: 2, nFrames: 1764
3752.8770 D [AlsaSound] play 1739 samples
3752.8779 D [AlsaSound] play 1739 samples
3752.8782 W [AlsaSound] ALSA error: Broken pipe
ALSA lib ../../../alsa-lib-1.1.4.1/src/pcm/pcm.c:8323:(snd_pcm_recover) underrun occurred
3752.8792 D [AlsaSound] play 50 samples
3752.8793 D [AlsaSound] Stop sound
From the log timestamps it is visible that the underrun occurs within 2ms of the first write – what writes ~40ms of samples. The two shown examples are identical in any other way, the device is not playing sound and is prepare()'d. The writing thread is renice’d to priority -19.
What can be the problem, and the solution?
Please note that it is intentional that I write fewer samples at once than the period size. Also maybe it counts that I am doing some OpenGL ES work in another thread (running on normal nice value).
OpenEmbedded v2.8b4 - Linux kernel version 4.9.87, libasound2 version 1.1.4.1-r0
Thanks in advance!