alsa: re-enable-nonblocking, but sleep if busy

Instead of letting ALSA block for us (and potentially allowing
something stupid on certain hardware or drivers), we do the
sleeping ourselves.  We calculate the sleep to be a fraction of
period_time to avoid oversleeping (and thus audible skipping).
This commit is contained in:
Eric Wong 2008-09-23 23:59:54 +02:00 committed by Max Kellermann
parent 9899ab5ac2
commit e4f5d6bdf4
1 changed files with 10 additions and 7 deletions

View File

@ -37,9 +37,6 @@ static const char default_device[] = "default";
#include <alsa/asoundlib.h>
/* #define MPD_SND_PCM_NONBLOCK SND_PCM_NONBLOCK */
#define MPD_SND_PCM_NONBLOCK 0
typedef snd_pcm_sframes_t alsa_writei_t(snd_pcm_t * pcm, const void *buffer,
snd_pcm_uframes_t size);
@ -49,6 +46,7 @@ typedef struct _AlsaData {
alsa_writei_t *writei;
unsigned int buffer_time;
unsigned int period_time;
unsigned int period_sleep;
int sampleSize;
int useMmap;
} AlsaData;
@ -160,18 +158,16 @@ static int alsa_openDevice(struct audio_output *audioOutput)
ad->device, audioFormat->bits);
err = snd_pcm_open(&ad->pcmHandle, ad->device,
SND_PCM_STREAM_PLAYBACK, MPD_SND_PCM_NONBLOCK);
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
if (err < 0) {
ad->pcmHandle = NULL;
goto error;
}
#if MPD_SND_PCM_NONBLOCK == SND_PCM_NONBLOCK
cmd = "snd_pcm_nonblock";
err = snd_pcm_nonblock(ad->pcmHandle, 0);
if (err < 0)
goto error;
#endif /* MPD_SND_PCM_NONBLOCK == SND_PCM_NONBLOCK */
period_time_ro = period_time = ad->period_time;
configure_hw:
@ -254,6 +250,8 @@ configure_hw:
if (retry != MPD_ALSA_RETRY_NR)
DEBUG("ALSA period_time set to %d\n", period_time);
ad->period_sleep = period_time >> 1;
cmd = "snd_pcm_hw_params_get_buffer_size";
err = snd_pcm_hw_params_get_buffer_size(hwparams, &alsa_buffer_size);
if (err < 0)
@ -388,7 +386,12 @@ static int alsa_playAudio(struct audio_output *audioOutput,
while (size > 0) {
ret = ad->writei(ad->pcmHandle, playChunk, size);
if (ret == -EAGAIN || ret == -EINTR)
if (ret == -EAGAIN) {
DEBUG("ALSA busy, sleeping %d\n", ad->period_sleep);
my_usleep(ad->period_sleep);
continue;
}
if (ret == -EINTR)
continue;
if (ret < 0) {