Blob Blame History Raw
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