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, 74 insertions, 61 deletions
diff --git a/src/player.c b/src/player.c
index 733a315..b743ee8 100644
--- a/src/player.c
+++ b/src/player.c
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2008-2011
+Copyright (c) 2008-2012
Lars-Dominik Braun <lars@6xq.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -23,12 +23,17 @@ 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"
@@ -37,16 +42,6 @@ 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
@@ -79,6 +74,20 @@ 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
@@ -124,8 +133,6 @@ 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;
}
@@ -159,9 +166,6 @@ 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) {
@@ -205,7 +209,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->aoError = 1;
+ player->ret = PLAYER_RET_ERR;
BarUiMsg (player->settings, MSG_ERR,
"Cannot open audio device\n");
return WAITRESS_CB_RET_ERR;
@@ -314,8 +318,6 @@ 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;
}
@@ -368,7 +370,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->aoError = 1;
+ player->ret = PLAYER_RET_ERR;
BarUiMsg (player->settings, MSG_ERR,
"Cannot open audio device\n");
return WAITRESS_CB_RET_ERR;
@@ -395,8 +397,6 @@ 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,6 +407,42 @@ 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_*
@@ -414,18 +450,28 @@ static WaitressCbReturn_t BarPlayerMp3Cb (void *ptr, size_t size,
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
@@ -454,9 +500,8 @@ void *BarPlayerThread (void *data) {
#endif /* ENABLE_MAD */
default:
- /* FIXME: leaks memory */
BarUiMsg (player->settings, MSG_ERR, "Unsupported audio format!\n");
- return PLAYER_RET_OK;
+ pthread_exit (PLAYER_RET_OK);
break;
}
@@ -471,39 +516,7 @@ void *BarPlayerThread (void *data) {
} while (wRet == WAITRESS_RET_PARTIAL_FILE || wRet == WAITRESS_RET_TIMEOUT
|| wRet == WAITRESS_RET_READ_ERR);
- 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;
+ /* cleanup */
+ pthread_cleanup_pop (!0);
+ return NULL;
}