I am working on an embedded audio device, it is using kernel-5.10, and ALSA-LIB to play audio.
When I am trying to call snd_pcm_writei()
to play audio, I got a little confused on what is the right way to set its input parameters and handle its return value.
Here is my code.
/* Get periodsize from system */
snd_pcm_hw_params_get_period_size(hw_params, &periodsize, NULL);
left = frames;
sent = 0;
while (left > 0) {
sent = (left > periodsize) ? periodsize : left;
rc = snd_pcm_writei(pcm_handle, buf, sent);
if (rc < 0) {
if (rc == -EAGAIN) {
usleep(1000);
}
rc = snd_pcm_recover(pcm_handle, rc, 0);
if (rc < 0) {
snd_pcm_prepare(pcm_handle);
}
} else if (rc == 0) {
/* How to handle this case ?*/
} else {
/* Samples less than were sent to audio-card */
left -= rc;
buf += rc * frame_size;
}
}
In my testing, the frames is 820, and periodsize
is got from system, now it is 400. I am trying to sent data to audio-card upto the size of periodsize
, is it correct?
Should I send data with frames
of 820 directly to the audio card to play?
snd_pcm_writei(pcm_handle, buf, frames);
Updated with testing codes and testing results.
#ifdef TEST_APLAY
frame_size = chan * 2;
buf = databuf;
left = data_frames;
sent = 0;
while (left > 0) {
sent = (left > periodsize) ? periodsize : left;
rc = snd_pcm_writei(hah->pcm_handle, buf, sent);
if (rc == -EAGAIN || (rc >= 0 && (size_t)rc < sent)) {
snd_pcm_wait(hah->pcm_handle, 10);
} else if (rc == -EPIPE) {
snd_pcm_recover(hah->pcm_handle, rc, 0);
//// snd_pcm_prepare(hah->pcm_handle);
} else if (rc < 0) {
break;
}
if (rc > 0) {
left -= rc;
buf += rc * frame_size;
}
}
#endif
And I got the following results (start and stop playing 10 times).
Playing/stoping quickly for times, pid: 3168
Got end of media, breaking
Got end of media, breaking
ALSA lib pcm.c:8526:(snd_pcm_recover) underrun occurred
Got end of media, breaking
ALSA lib pcm.c:8526:(snd_pcm_recover) underrun occurred
ALSA lib pcm.c:8526:(snd_pcm_recover) underrun occurred
Got end of media, breaking
ALSA lib pcm.c:8526:(snd_pcm_recover) underrun occurred
ALSA lib pcm.c:8526:(snd_pcm_recover) underrun occurred
ALSA lib pcm.c:8526:(snd_pcm_recover) underrun occurred
ALSA lib pcm.c:8526:(snd_pcm_recover) underrun occurred
ALSA lib pcm.c:8526:(snd_pcm_recover) underrun occurred
Got end of media, breaking
Above is tested in Ubuntu-20.04 X86_64 VM, with AC97 sound card.
aplay
sources?aplay
source codes and the discussion in the link stark provided. I think I got 2 different answers.aplay
seemed to feed sound card with date length ofchunk_size
, and send samples in a loop. But the SO link said I just need to writeeverything
in one go. So which one should I follow?aplay
is "semi-interactive", it can be interrupted by user. When you write entire buffer, the process callingsnd_pcm_writei()
is blocked until [almost] all buffer content is played.