diff options
Diffstat (limited to 'src/player.c')
-rw-r--r-- | src/player.c | 135 |
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; } |