From 53306659a71bd4b49a560a7197f2fd0a7ba71ca0 Mon Sep 17 00:00:00 2001
From: Hans de Goede <j.w.r.degoede@hhs.nl>
Date: Fri, 8 May 2009 11:59:33 +0200
Subject: [PATCH 6/9] alsa plugin: Fix last second(s) of songs getting lost
There are 2 problems with the alsa plugin, which cause the end of a song
to get lost:
1) alsa_playing contains the following check:
get_thread_buffer_filled() > hw_period_size_in
This will cause alsa_playing to return 0 when there are still
frames left in the thread buffer, and once the input plugin then calls
alsa_close, these frames will get lost.
2) alsa_close_pcm() calls snd_pcm_drop() which will cause all the frames
still in the buffers of the card to be dropped
Fixing this:
1) Can be fixed by replacing the check with just:
get_thread_buffer_filled()
2) However is harder to fix, one could replace snd_pcm_drop() with
snd_pcm_drain(), but this will cause delays when we want to
close immediately (stop/prev song/next song)
After some fiddling I've come the conclusing that 2 is not really a problem,
the problem is that alsa_playing should return 1 as long as there is data
in either the thread buffer or in the hardware buffer of the card.
For this to work we also need to change the:
get_thread_buffer_filled() > hw_period_size_in
check in alsa_loop with just get_thread_buffer_filled()
Last this patch also removes the write max hw_period_size_in at a time
bytes check, if there is more then one period_size worth of data available
in the cards buffers its quite alright to write multiple periods at a time.
---
src/alsa/audio.c | 13 +++++--------
1 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/src/alsa/audio.c b/src/alsa/audio.c
index 8dacdf2..80b92a5 100644
--- a/src/alsa/audio.c
+++ b/src/alsa/audio.c
@@ -131,13 +131,11 @@ static void debug(char *str, ...)
int alsa_playing(void)
{
- if (!going || paused || alsa_pcm == NULL)
+ if (!going || paused || prebuffer || alsa_pcm == NULL)
return FALSE;
- return snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING &&
- !paused &&
- !prebuffer &&
- get_thread_buffer_filled() > hw_period_size_in;
+ return snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING ||
+ get_thread_buffer_filled();
}
static int
@@ -637,7 +635,7 @@ static void alsa_write_out_thread_data(void)
{
gint length, cnt, avail;
- length = MIN(hw_period_size_in, get_thread_buffer_filled());
+ length = get_thread_buffer_filled();
avail = snd_pcm_frames_to_bytes(alsa_pcm, alsa_get_avail());
length = MIN(length, avail);
while (length > 0)
@@ -667,8 +665,7 @@ static void *alsa_loop(void *arg)
{
if (get_thread_buffer_filled() > prebuffer_size)
prebuffer = FALSE;
- if (!paused && !prebuffer &&
- get_thread_buffer_filled() > hw_period_size_in)
+ if (!paused && !prebuffer && get_thread_buffer_filled())
{
wr = snd_pcm_wait(alsa_pcm, 10);
if (wr > 0)
--
1.6.2.2