summaryrefslogtreecommitdiff
path: root/src/player.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/player.c')
-rw-r--r--src/player.c135
1 files changed, 61 insertions, 74 deletions
diff --git a/src/player.c b/src/player.c
index b743ee8..733a315 100644
--- a/src/player.c
+++ b/src/player.c
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2012
+Copyright (c) 2008-2011
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -23,17 +23,12 @@ THE SOFTWARE.
/* receive/play audio stream */
-#ifndef __FreeBSD__
-#define _POSIX_C_SOURCE 1 /* sigaction() */
-#endif
-
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <stdint.h>
#include <limits.h>
#include <arpa/inet.h>
-#include <signal.h>
#include "player.h"
#include "config.h"
@@ -42,6 +37,16 @@ THE SOFTWARE.
#define bigToHostEndian32(x) ntohl(x)
+/* wait while locked, but don't slow down main thread by keeping
+ * locks too long */
+#define QUIT_PAUSE_CHECK \
+ pthread_mutex_lock (&player->pauseMutex); \
+ pthread_mutex_unlock (&player->pauseMutex); \
+ if (player->doQuit) { \
+ /* err => abort playback */ \
+ return WAITRESS_CB_RET_ERR; \
+ }
+
/* pandora uses float values with 2 digits precision. Scale them by 100 to get
* a "nice" integer */
#define RG_SCALE_FACTOR 100
@@ -74,20 +79,6 @@ static inline signed short int applyReplayGain (const signed short int value,
}
}
-/* handles bogus signal BAR_PLAYER_SIGCONT
- */
-static void BarPlayerNullHandler (int sig) {
-}
-
-/* handler signal BAR_PLAYER_SIGSTOP and pauses player thread
- */
-static void BarPlayerPauseHandler (int sig) {
- /* for a reason I don’t know sigsuspend does not work here, so we use
- * pause, which should be fine as there are no other (expected) signals
- * than SIGCONT */
- pause ();
-}
-
/* Refill player's buffer with dataSize of data
* @param player structure
* @param new data
@@ -133,6 +124,8 @@ static WaitressCbReturn_t BarPlayerAACCb (void *ptr, size_t size,
const char *data = ptr;
struct audioPlayer *player = stream;
+ QUIT_PAUSE_CHECK;
+
if (!BarPlayerBufferFill (player, data, size)) {
return WAITRESS_CB_RET_ERR;
}
@@ -166,6 +159,9 @@ static WaitressCbReturn_t BarPlayerAACCb (void *ptr, size_t size,
(unsigned long long int) player->channels;
player->bufferRead += frameInfo.bytesconsumed;
player->sampleSizeCurr++;
+ /* going through this loop can take up to a few seconds =>
+ * allow earlier thread abort */
+ QUIT_PAUSE_CHECK;
}
} else {
if (player->mode == PLAYER_INITIALIZED) {
@@ -209,7 +205,7 @@ static WaitressCbReturn_t BarPlayerAACCb (void *ptr, size_t size,
if ((player->audioOutDevice = ao_open_live (audioOutDriver,
&format, NULL)) == NULL) {
/* we're not interested in the errno */
- player->ret = PLAYER_RET_ERR;
+ player->aoError = 1;
BarUiMsg (player->settings, MSG_ERR,
"Cannot open audio device\n");
return WAITRESS_CB_RET_ERR;
@@ -318,6 +314,8 @@ static WaitressCbReturn_t BarPlayerMp3Cb (void *ptr, size_t size,
struct audioPlayer *player = stream;
size_t i;
+ QUIT_PAUSE_CHECK;
+
if (!BarPlayerBufferFill (player, data, size)) {
return WAITRESS_CB_RET_ERR;
}
@@ -370,7 +368,7 @@ static WaitressCbReturn_t BarPlayerMp3Cb (void *ptr, size_t size,
format.byte_format = AO_FMT_NATIVE;
if ((player->audioOutDevice = ao_open_live (audioOutDriver,
&format, NULL)) == NULL) {
- player->ret = PLAYER_RET_ERR;
+ player->aoError = 1;
BarUiMsg (player->settings, MSG_ERR,
"Cannot open audio device\n");
return WAITRESS_CB_RET_ERR;
@@ -397,6 +395,8 @@ static WaitressCbReturn_t BarPlayerMp3Cb (void *ptr, size_t size,
(unsigned long long int) BAR_PLAYER_MS_TO_S_FACTOR /
(unsigned long long int) player->samplerate;
}
+
+ QUIT_PAUSE_CHECK;
} while (player->mp3Stream.error != MAD_ERROR_BUFLEN);
player->bufferRead += player->mp3Stream.next_frame - player->buffer;
@@ -407,42 +407,6 @@ static WaitressCbReturn_t BarPlayerMp3Cb (void *ptr, size_t size,
}
#endif /* ENABLE_MAD */
-/* player cleanup function
- * @param player structure
- */
-static void BarPlayerCleanup (void *data) {
- struct audioPlayer *player = data;
-
- switch (player->audioFormat) {
- #ifdef ENABLE_FAAD
- case PIANO_AF_AACPLUS_LO:
- case PIANO_AF_AACPLUS:
- NeAACDecClose(player->aacHandle);
- free (player->sampleSize);
- break;
- #endif /* ENABLE_FAAD */
-
- #ifdef ENABLE_MAD
- case PIANO_AF_MP3:
- case PIANO_AF_MP3_HI:
- mad_synth_finish (&player->mp3Synth);
- mad_frame_finish (&player->mp3Frame);
- mad_stream_finish (&player->mp3Stream);
- break;
- #endif /* ENABLE_MAD */
-
- default:
- /* this should never happen */
- break;
- }
-
- ao_close(player->audioOutDevice);
- WaitressFree (&player->waith);
- free (player->buffer);
-
- player->mode = PLAYER_FINISHED_PLAYBACK;
-}
-
/* player thread; for every song a new thread is started
* @param audioPlayer structure
* @return PLAYER_RET_*
@@ -450,28 +414,18 @@ static void BarPlayerCleanup (void *data) {
void *BarPlayerThread (void *data) {
struct audioPlayer *player = data;
char extraHeaders[32];
+ void *ret = PLAYER_RET_OK;
#ifdef ENABLE_FAAD
NeAACDecConfigurationPtr conf;
#endif
WaitressReturn_t wRet = WAITRESS_RET_ERR;
- struct sigaction sa;
-
- /* set up pause signals */
- memset (&sa, 0, sizeof (sa));
- sa.sa_handler = BarPlayerPauseHandler;
- sigaction (BAR_PLAYER_SIGSTOP, &sa, NULL);
- memset (&sa, 0, sizeof (sa));
- sa.sa_handler = BarPlayerNullHandler;
- sigaction (BAR_PLAYER_SIGCONT, &sa, NULL);
- /* set up cleanup function */
- pthread_cleanup_push (BarPlayerCleanup, data);
/* init handles */
+ pthread_mutex_init (&player->pauseMutex, NULL);
player->waith.data = (void *) player;
/* extraHeaders will be initialized later */
player->waith.extraHeaders = extraHeaders;
player->buffer = malloc (BAR_PLAYER_BUFSIZE);
- player->ret = PLAYER_RET_OK;
switch (player->audioFormat) {
#ifdef ENABLE_FAAD
@@ -500,8 +454,9 @@ void *BarPlayerThread (void *data) {
#endif /* ENABLE_MAD */
default:
+ /* FIXME: leaks memory */
BarUiMsg (player->settings, MSG_ERR, "Unsupported audio format!\n");
- pthread_exit (PLAYER_RET_OK);
+ return PLAYER_RET_OK;
break;
}
@@ -516,7 +471,39 @@ void *BarPlayerThread (void *data) {
} while (wRet == WAITRESS_RET_PARTIAL_FILE || wRet == WAITRESS_RET_TIMEOUT
|| wRet == WAITRESS_RET_READ_ERR);
- /* cleanup */
- pthread_cleanup_pop (!0);
- return NULL;
+ switch (player->audioFormat) {
+ #ifdef ENABLE_FAAD
+ case PIANO_AF_AACPLUS_LO:
+ case PIANO_AF_AACPLUS:
+ NeAACDecClose(player->aacHandle);
+ free (player->sampleSize);
+ break;
+ #endif /* ENABLE_FAAD */
+
+ #ifdef ENABLE_MAD
+ case PIANO_AF_MP3:
+ case PIANO_AF_MP3_HI:
+ mad_synth_finish (&player->mp3Synth);
+ mad_frame_finish (&player->mp3Frame);
+ mad_stream_finish (&player->mp3Stream);
+ break;
+ #endif /* ENABLE_MAD */
+
+ default:
+ /* this should never happen: thread is aborted above */
+ break;
+ }
+
+ if (player->aoError) {
+ ret = (void *) PLAYER_RET_ERR;
+ }
+
+ ao_close(player->audioOutDevice);
+ WaitressFree (&player->waith);
+ pthread_mutex_destroy (&player->pauseMutex);
+ free (player->buffer);
+
+ player->mode = PLAYER_FINISHED_PLAYBACK;
+
+ return ret;
}