Spotify: When track ends, empty buffer before stopping. Also some

safeguards against indefinite waits and null pointer dereferencing.
This commit is contained in:
ejurgensen 2014-03-17 22:25:47 +01:00
parent 5c40b2344c
commit c3f05671b2

View File

@ -66,6 +66,7 @@ enum spotify_event
SPOTIFY_EVENT_LIBCB,
SPOTIFY_EVENT_PLAY,
SPOTIFY_EVENT_PAUSE,
SPOTIFY_EVENT_EOT,
SPOTIFY_EVENT_STOP,
SPOTIFY_EVENT_SEEK,
SPOTIFY_EVENT_EXIT,
@ -78,6 +79,7 @@ enum spotify_state
SPOTIFY_STATE_WAIT,
SPOTIFY_STATE_PLAYING,
SPOTIFY_STATE_PAUSED,
SPOTIFY_STATE_STOPPING,
SPOTIFY_STATE_STOPPED,
SPOTIFY_STATE_SEEKED,
SPOTIFY_STATE_EXITING,
@ -815,7 +817,7 @@ static void play_token_lost(sp_session *sess)
{
DPRINTF(E_DBG, L_SPOTIFY, "Play token lost - init\n");
pthread_mutex_lock(&g_notify_mutex);
g_event = SPOTIFY_EVENT_STOP;
g_event = SPOTIFY_EVENT_EOT;
pthread_cond_signal(&g_notify_cond);
pthread_mutex_unlock(&g_notify_mutex);
DPRINTF(E_DBG, L_SPOTIFY, "Play token lost - done\n");
@ -830,7 +832,7 @@ static void end_of_track(sp_session *sess)
{
DPRINTF(E_DBG, L_SPOTIFY, "End of track - init\n");
pthread_mutex_lock(&g_notify_mutex);
g_event = SPOTIFY_EVENT_STOP;
g_event = SPOTIFY_EVENT_EOT;
pthread_cond_signal(&g_notify_cond);
pthread_mutex_unlock(&g_notify_mutex);
DPRINTF(E_DBG, L_SPOTIFY, "End of track - done\n");
@ -1063,6 +1065,11 @@ spotify(void *arg)
state = SPOTIFY_STATE_PAUSED;
break;
case SPOTIFY_EVENT_EOT:
playback_stop();
state = SPOTIFY_STATE_STOPPING;
break;
case SPOTIFY_EVENT_STOP:
if ((ret = playback_stop()) == 0)
state = SPOTIFY_STATE_STOPPED;
@ -1240,6 +1247,7 @@ spotify_playback_seek(int ms)
int
spotify_audio_get(struct evbuffer *evbuf, int wanted)
{
struct timespec ts;
audio_fifo_data_t *afd;
int processed;
int ret;
@ -1261,13 +1269,33 @@ spotify_audio_get(struct evbuffer *evbuf, int wanted)
while ((processed < wanted) && (g_state != SPOTIFY_STATE_STOPPED))
{
while ((g_state != SPOTIFY_STATE_STOPPED) && !(afd = TAILQ_FIRST(&g_audio_fifo->q)))
// If track has ended and buffer is empty
if ((g_state == SPOTIFY_STATE_STOPPING) && (g_audio_fifo->qlen <= 0))
g_state = SPOTIFY_STATE_STOPPED;
// If buffer is empty wait for audio, but use timed wait so we don't
// risk waiting forever (maybe the player stopped while we were waiting)
while ( !(afd = TAILQ_FIRST(&g_audio_fifo->q)) &&
(g_state != SPOTIFY_STATE_STOPPED) &&
(g_state != SPOTIFY_STATE_STOPPING) )
{
DPRINTF(E_DBG, L_SPOTIFY, "Audio get is blocking now\n");
pthread_cond_wait(&g_audio_fifo->cond, &g_audio_fifo->mutex); // TODO protect against indefinite wait
#if _POSIX_TIMERS > 0
clock_gettime(CLOCK_REALTIME, &ts);
#else
struct timeval tv;
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, &ts);
#endif
ts.tv_sec += 5;
pthread_cond_timedwait(&g_audio_fifo->cond, &g_audio_fifo->mutex, &ts);
DPRINTF(E_DBG, L_SPOTIFY, "Audio get is released now\n");
}
if (!afd)
break;
TAILQ_REMOVE(&g_audio_fifo->q, afd, link);
g_audio_fifo->qlen -= afd->nsamples;
@ -1275,6 +1303,7 @@ spotify_audio_get(struct evbuffer *evbuf, int wanted)
ret = evbuffer_add(evbuf, afd->samples, s);
free(afd);
afd = NULL;
if (ret < 0)
{
DPRINTF(E_LOG, L_SPOTIFY, "Out of memory for evbuffer (tried to add %d bytes)\n", s);