mirror of
https://github.com/owntone/owntone-server.git
synced 2025-04-14 00:10:10 -04:00
Spotify: When track ends, empty buffer before stopping. Also some
safeguards against indefinite waits and null pointer dereferencing.
This commit is contained in:
parent
5c40b2344c
commit
c3f05671b2
@ -66,6 +66,7 @@ enum spotify_event
|
|||||||
SPOTIFY_EVENT_LIBCB,
|
SPOTIFY_EVENT_LIBCB,
|
||||||
SPOTIFY_EVENT_PLAY,
|
SPOTIFY_EVENT_PLAY,
|
||||||
SPOTIFY_EVENT_PAUSE,
|
SPOTIFY_EVENT_PAUSE,
|
||||||
|
SPOTIFY_EVENT_EOT,
|
||||||
SPOTIFY_EVENT_STOP,
|
SPOTIFY_EVENT_STOP,
|
||||||
SPOTIFY_EVENT_SEEK,
|
SPOTIFY_EVENT_SEEK,
|
||||||
SPOTIFY_EVENT_EXIT,
|
SPOTIFY_EVENT_EXIT,
|
||||||
@ -78,6 +79,7 @@ enum spotify_state
|
|||||||
SPOTIFY_STATE_WAIT,
|
SPOTIFY_STATE_WAIT,
|
||||||
SPOTIFY_STATE_PLAYING,
|
SPOTIFY_STATE_PLAYING,
|
||||||
SPOTIFY_STATE_PAUSED,
|
SPOTIFY_STATE_PAUSED,
|
||||||
|
SPOTIFY_STATE_STOPPING,
|
||||||
SPOTIFY_STATE_STOPPED,
|
SPOTIFY_STATE_STOPPED,
|
||||||
SPOTIFY_STATE_SEEKED,
|
SPOTIFY_STATE_SEEKED,
|
||||||
SPOTIFY_STATE_EXITING,
|
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");
|
DPRINTF(E_DBG, L_SPOTIFY, "Play token lost - init\n");
|
||||||
pthread_mutex_lock(&g_notify_mutex);
|
pthread_mutex_lock(&g_notify_mutex);
|
||||||
g_event = SPOTIFY_EVENT_STOP;
|
g_event = SPOTIFY_EVENT_EOT;
|
||||||
pthread_cond_signal(&g_notify_cond);
|
pthread_cond_signal(&g_notify_cond);
|
||||||
pthread_mutex_unlock(&g_notify_mutex);
|
pthread_mutex_unlock(&g_notify_mutex);
|
||||||
DPRINTF(E_DBG, L_SPOTIFY, "Play token lost - done\n");
|
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");
|
DPRINTF(E_DBG, L_SPOTIFY, "End of track - init\n");
|
||||||
pthread_mutex_lock(&g_notify_mutex);
|
pthread_mutex_lock(&g_notify_mutex);
|
||||||
g_event = SPOTIFY_EVENT_STOP;
|
g_event = SPOTIFY_EVENT_EOT;
|
||||||
pthread_cond_signal(&g_notify_cond);
|
pthread_cond_signal(&g_notify_cond);
|
||||||
pthread_mutex_unlock(&g_notify_mutex);
|
pthread_mutex_unlock(&g_notify_mutex);
|
||||||
DPRINTF(E_DBG, L_SPOTIFY, "End of track - done\n");
|
DPRINTF(E_DBG, L_SPOTIFY, "End of track - done\n");
|
||||||
@ -1063,6 +1065,11 @@ spotify(void *arg)
|
|||||||
state = SPOTIFY_STATE_PAUSED;
|
state = SPOTIFY_STATE_PAUSED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SPOTIFY_EVENT_EOT:
|
||||||
|
playback_stop();
|
||||||
|
state = SPOTIFY_STATE_STOPPING;
|
||||||
|
break;
|
||||||
|
|
||||||
case SPOTIFY_EVENT_STOP:
|
case SPOTIFY_EVENT_STOP:
|
||||||
if ((ret = playback_stop()) == 0)
|
if ((ret = playback_stop()) == 0)
|
||||||
state = SPOTIFY_STATE_STOPPED;
|
state = SPOTIFY_STATE_STOPPED;
|
||||||
@ -1240,6 +1247,7 @@ spotify_playback_seek(int ms)
|
|||||||
int
|
int
|
||||||
spotify_audio_get(struct evbuffer *evbuf, int wanted)
|
spotify_audio_get(struct evbuffer *evbuf, int wanted)
|
||||||
{
|
{
|
||||||
|
struct timespec ts;
|
||||||
audio_fifo_data_t *afd;
|
audio_fifo_data_t *afd;
|
||||||
int processed;
|
int processed;
|
||||||
int ret;
|
int ret;
|
||||||
@ -1260,30 +1268,51 @@ spotify_audio_get(struct evbuffer *evbuf, int wanted)
|
|||||||
pthread_mutex_lock(&g_audio_fifo->mutex);
|
pthread_mutex_lock(&g_audio_fifo->mutex);
|
||||||
|
|
||||||
while ((processed < wanted) && (g_state != SPOTIFY_STATE_STOPPED))
|
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))
|
||||||
DPRINTF(E_DBG, L_SPOTIFY, "Audio get is blocking now\n");
|
g_state = SPOTIFY_STATE_STOPPED;
|
||||||
pthread_cond_wait(&g_audio_fifo->cond, &g_audio_fifo->mutex); // TODO protect against indefinite wait
|
|
||||||
DPRINTF(E_DBG, L_SPOTIFY, "Audio get is released now\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
TAILQ_REMOVE(&g_audio_fifo->q, afd, link);
|
// If buffer is empty wait for audio, but use timed wait so we don't
|
||||||
g_audio_fifo->qlen -= afd->nsamples;
|
// 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");
|
||||||
|
#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;
|
||||||
|
|
||||||
s = afd->nsamples * sizeof(int16_t) * 2;
|
pthread_cond_timedwait(&g_audio_fifo->cond, &g_audio_fifo->mutex, &ts);
|
||||||
|
DPRINTF(E_DBG, L_SPOTIFY, "Audio get is released now\n");
|
||||||
|
}
|
||||||
|
|
||||||
ret = evbuffer_add(evbuf, afd->samples, s);
|
if (!afd)
|
||||||
free(afd);
|
break;
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
DPRINTF(E_LOG, L_SPOTIFY, "Out of memory for evbuffer (tried to add %d bytes)\n", s);
|
|
||||||
pthread_mutex_unlock(&g_audio_fifo->mutex);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
processed += s;
|
TAILQ_REMOVE(&g_audio_fifo->q, afd, link);
|
||||||
}
|
g_audio_fifo->qlen -= afd->nsamples;
|
||||||
|
|
||||||
|
s = afd->nsamples * sizeof(int16_t) * 2;
|
||||||
|
|
||||||
|
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);
|
||||||
|
pthread_mutex_unlock(&g_audio_fifo->mutex);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
processed += s;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&g_audio_fifo->mutex);
|
pthread_mutex_unlock(&g_audio_fifo->mutex);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user