diff options
author | waker <wakeroid@gmail.com> | 2012-05-03 19:22:39 +0200 |
---|---|---|
committer | waker <wakeroid@gmail.com> | 2012-05-03 19:23:08 +0200 |
commit | 52be1f66c294caeb628d4d46d0045473403841d5 (patch) | |
tree | 9b410132a6679e54205f24c39c32bf451cebe127 /plugins | |
parent | ef1c07cc3bbd19b9f75f3a7d962c619a3952ce8a (diff) |
[by Martin Panter <vadmium à gmail·com>]
Retry with the same data after recovering from an underrun or other error
The palsa_callback() function seems to limit the rate it returns data, and if
a buffer of data is dropped because snd_pcm_writei() failed, the data rate is
not fast enough to keep up with ALSA and another buffer underrun occurs. This
could cause an indefinite cycle, and the audio would sound slighly choppy and
sped up. If the original data is retried, the ALSA buffer eventually tends to
become full; perhaps the rate limit is a little faster than real time.
When playback continues on to an MP3 file cued in the playlist, the MP3 seems
to be scanned before it starts playing. If the scanning takes too long, in my
case because the MP3 file is mounted with SSHFS over wifi, it causes a buffer
underrun.
The code below could also be inserted, just before the snd_pcm_writei() call,
to artificially cause an underrun a few seconds into playback:
static int n = 0;
++n;
if (n >= 200 && n < 300) {
trace ("dropping %i\n", n);
err = 0;
}
else
err = snd_pcm_writei (...);
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/alsa/alsa.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/plugins/alsa/alsa.c b/plugins/alsa/alsa.c index 618465b7..08fbc9b8 100644 --- a/plugins/alsa/alsa.c +++ b/plugins/alsa/alsa.c @@ -613,6 +613,9 @@ palsa_thread (void *context) { continue; } LOCK; + char buf[period_size * (plugin.fmt.bps>>3) * plugin.fmt.channels]; + int bytes_to_write = 0; + /* find out how much space is available for playback data */ snd_pcm_sframes_t frames_to_deliver = snd_pcm_avail_update (audio); @@ -624,12 +627,13 @@ palsa_thread (void *context) { break; } err = 0; - char buf[period_size * (plugin.fmt.bps>>3) * plugin.fmt.channels]; - UNLOCK; // holding a lock here may cause deadlock in the streamer - int bytes_to_write = palsa_callback (buf, period_size * (plugin.fmt.bps>>3) * plugin.fmt.channels); - LOCK; - if (alsa_terminate) { - break; + if (!bytes_to_write) { + UNLOCK; // holding a lock here may cause deadlock in the streamer + bytes_to_write = palsa_callback (buf, period_size * (plugin.fmt.bps>>3) * plugin.fmt.channels); + LOCK; + if (OUTPUT_STATE_PLAYING != state || alsa_terminate) { + break; + } } if (bytes_to_write >= (plugin.fmt.bps>>3) * plugin.fmt.channels) { @@ -643,6 +647,7 @@ palsa_thread (void *context) { else { UNLOCK; usleep (10000); + bytes_to_write = 0; LOCK; continue; } @@ -669,9 +674,10 @@ palsa_thread (void *context) { //} snd_pcm_prepare (audio); snd_pcm_start (audio); - continue; } + continue; } + bytes_to_write = 0; frames_to_deliver = snd_pcm_avail_update (audio); } UNLOCK; |