aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2008-09-23 23:59:54 +0200
committerMax Kellermann <max@duempel.org>2008-09-23 23:59:54 +0200
commite4f5d6bdf47c96dc9c0b5fe287598bc10b168a71 (patch)
tree2229953464549c10559a458879cd33678f1c704e
parent9899ab5ac2d572fbfa430b59f8bf6f917477b6f1 (diff)
downloadmpd-e4f5d6bdf47c96dc9c0b5fe287598bc10b168a71.tar.gz
mpd-e4f5d6bdf47c96dc9c0b5fe287598bc10b168a71.tar.xz
mpd-e4f5d6bdf47c96dc9c0b5fe287598bc10b168a71.zip
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).
-rw-r--r--src/audioOutputs/audioOutput_alsa.c17
1 files changed, 10 insertions, 7 deletions
diff --git a/src/audioOutputs/audioOutput_alsa.c b/src/audioOutputs/audioOutput_alsa.c
index 8149917c4..83c4f228c 100644
--- a/src/audioOutputs/audioOutput_alsa.c
+++ b/src/audioOutputs/audioOutput_alsa.c
@@ -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) {