diff options
-rw-r--r-- | src/decode.c | 243 | ||||
-rw-r--r-- | src/decode.h | 9 | ||||
-rw-r--r-- | src/directory.c | 1 | ||||
-rw-r--r-- | src/inputPlugins/aac_plugin.c | 2 | ||||
-rw-r--r-- | src/inputPlugins/audiofile_plugin.c | 1 | ||||
-rw-r--r-- | src/inputPlugins/flac_plugin.c | 1 | ||||
-rw-r--r-- | src/inputPlugins/mod_plugin.c | 1 | ||||
-rw-r--r-- | src/inputPlugins/mp3_plugin.c | 4 | ||||
-rw-r--r-- | src/inputPlugins/mp4_plugin.c | 2 | ||||
-rw-r--r-- | src/inputPlugins/mpc_plugin.c | 1 | ||||
-rw-r--r-- | src/inputPlugins/oggflac_plugin.c | 1 | ||||
-rw-r--r-- | src/inputPlugins/oggvorbis_plugin.c | 1 | ||||
-rw-r--r-- | src/inputPlugins/wavpack_plugin.c | 1 | ||||
-rw-r--r-- | src/main.c | 2 | ||||
-rw-r--r-- | src/outputBuffer.c | 6 | ||||
-rw-r--r-- | src/outputBuffer.h | 2 | ||||
-rw-r--r-- | src/player.c | 275 | ||||
-rw-r--r-- | src/player.h | 13 | ||||
-rw-r--r-- | src/playerData.c | 2 | ||||
-rw-r--r-- | src/sig_handlers.c | 19 | ||||
-rw-r--r-- | src/sig_handlers.h | 2 |
21 files changed, 212 insertions, 377 deletions
diff --git a/src/decode.c b/src/decode.c index c8e9fd9cf..caf29849a 100644 --- a/src/decode.c +++ b/src/decode.c @@ -30,63 +30,50 @@ #include "utf8.h" #include "os_compat.h" -static int decode_pid; +static pthread_cond_t decoder_wakeup_cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t decoder_wakeup_mutex = PTHREAD_MUTEX_INITIALIZER; -void decodeSigHandler(int sig, siginfo_t * si, void *v) +/* called inside decoder_task (inputPlugins) */ +void decoder_wakeup_player(void) { - if (sig == SIGCHLD) { - int status; - if (decode_pid == wait3(&status, WNOHANG, NULL)) { - /* - if (WIFSIGNALED(status)) { - if (WTERMSIG(status) != SIGTERM) { - ERROR("decode process died from " - "signal: %i\n", WTERMSIG(status)); - } - } - */ - decode_pid = 0; - getPlayerData()->playerControl.decode_pid = 0; - } - } else if (sig == SIGTERM) { - int pid = decode_pid; - if (pid > 0) { - /* DEBUG("player (or child) got SIGTERM\n"); */ - kill(pid, SIGCONT); - kill(pid, SIGTERM); - } /* else - DEBUG("decoder (or child) got SIGTERM\n"); */ - exit(EXIT_SUCCESS); - } + wakeup_player_nb(); +} + +void decoder_sleep(void) +{ + pthread_cond_wait(&decoder_wakeup_cond, &decoder_wakeup_mutex); + wakeup_player_nb(); +} + +static void player_wakeup_decoder_nb(void) +{ + pthread_cond_signal(&decoder_wakeup_cond); +} + +/* called from player_task */ +static void player_wakeup_decoder(void) +{ + pthread_cond_signal(&decoder_wakeup_cond); + player_sleep(); } static void stopDecode(DecoderControl * dc) { - if (decode_pid > 0 && (dc->start || dc->state != DECODE_STATE_STOP)) { + if (dc->start || dc->state != DECODE_STATE_STOP) { dc->stop = 1; - kill(decode_pid, SIGCONT); - signalNotify(&(getPlayerData()->buffer.notify)); - while (decode_pid > 0 && dc->stop) - my_usleep(10000); + do { player_wakeup_decoder_nb(); } while (dc->stop); } } static void quitDecode(PlayerControl * pc, DecoderControl * dc) { - int pid; - stopDecode(dc); pc->state = PLAYER_STATE_STOP; dc->seek = 0; pc->play = 0; pc->stop = 0; pc->pause = 0; - - pid = decode_pid; - if (pid > 0) - kill(pid, SIGSTOP); - - kill(getppid(), SIGUSR1); + wakeup_main_task(); } static int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) @@ -111,7 +98,7 @@ static int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) #define handleDecodeStart() \ if(decodeWaitedOn) { \ - if(dc->state!=DECODE_STATE_START && decode_pid > 0 && \ + if(dc->state!=DECODE_STATE_START && \ dc->error==DECODE_ERROR_NOERROR) \ { \ decodeWaitedOn = 0; \ @@ -121,8 +108,9 @@ static int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) ERROR("problems opening audio device while playing \"%s\"\n", pc->utf8url); \ quitDecode(pc,dc); \ return; \ - } else if (decode_pid > 0) { \ - kill(decode_pid, SIGCONT); }\ + } else { \ + player_wakeup_decoder(); \ + } \ if (pause) { \ dropBufferedAudio(); \ closeAudioDevice(); \ @@ -135,14 +123,14 @@ static int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) cb->audioFormat.channels/ \ cb->audioFormat.sampleRate; \ } \ - else if(dc->state!=DECODE_STATE_START || decode_pid <= 0) { \ + else if(dc->state!=DECODE_STATE_START) { \ pathcpy_trunc(pc->erroredUrl, pc->utf8url); \ pc->error = PLAYER_ERROR_FILE; \ quitDecode(pc,dc); \ return; \ } \ else { \ - my_usleep(10000); \ + player_sleep(); \ continue; \ } \ } @@ -153,8 +141,8 @@ static int waitOnDecode(PlayerControl * pc, DecoderControl * dc, MpdTag *tag = NULL; pathcpy_trunc(pc->currentUrl, pc->utf8url); - while (decode_pid > 0 && dc->start) - my_usleep(10000); + while (dc->start) + player_wakeup_decoder(); if (dc->start || dc->error != DECODE_ERROR_NOERROR) { pathcpy_trunc(pc->erroredUrl, pc->utf8url); @@ -183,52 +171,45 @@ static int decodeSeek(PlayerControl * pc, DecoderControl * dc, { int ret = -1; - if (decode_pid > 0) { - if (dc->state == DECODE_STATE_STOP || dc->error || - strcmp(dc->utf8url, pc->utf8url) != 0) { - stopDecode(dc); - *next = -1; - cb->begin = 0; - cb->end = 0; - dc->error = 0; - dc->start = 1; - waitOnDecode(pc, dc, cb, decodeWaitedOn); - } - if (decode_pid > 0 && dc->state != DECODE_STATE_STOP && - dc->seekable) { - *next = -1; - dc->seekWhere = pc->seekWhere > pc->totalTime - 0.1 ? - pc->totalTime - 0.1 : pc->seekWhere; - dc->seekWhere = 0 > dc->seekWhere ? 0 : dc->seekWhere; - dc->seekError = 0; - dc->seek = 1; - kill(decode_pid, SIGCONT); - signalNotify(&(getPlayerData()->buffer.notify)); - while (decode_pid > 0 && dc->seek) - my_usleep(10000); - if (!dc->seekError) { - pc->elapsedTime = dc->seekWhere; - ret = 0; - } + if (dc->state == DECODE_STATE_STOP || dc->error || + strcmp(dc->utf8url, pc->utf8url) != 0) { + stopDecode(dc); + *next = -1; + cb->begin = 0; + cb->end = 0; + dc->error = 0; + dc->start = 1; + waitOnDecode(pc, dc, cb, decodeWaitedOn); + } + if (dc->state != DECODE_STATE_STOP && dc->seekable) { + *next = -1; + dc->seekWhere = pc->seekWhere > pc->totalTime - 0.1 ? + pc->totalTime - 0.1 : pc->seekWhere; + dc->seekWhere = 0 > dc->seekWhere ? 0 : dc->seekWhere; + dc->seekError = 0; + dc->seek = 1; + do { player_wakeup_decoder(); } while (dc->seek); + if (!dc->seekError) { + pc->elapsedTime = dc->seekWhere; + ret = 0; } } pc->seek = 0; + wakeup_main_task(); return ret; } #define processDecodeInput() \ - if(pc->cycleLogFiles) { \ - cycle_log_files(); \ - pc->cycleLogFiles = 0; \ - } \ if(pc->lockQueue) { \ pc->queueLockState = PLAYER_QUEUE_LOCKED; \ pc->lockQueue = 0; \ + wakeup_main_task(); \ } \ if(pc->unlockQueue) { \ pc->queueLockState = PLAYER_QUEUE_UNLOCKED; \ pc->unlockQueue = 0; \ + wakeup_main_task(); \ } \ if(pc->pause) { \ pause = !pause; \ @@ -236,8 +217,6 @@ static int decodeSeek(PlayerControl * pc, DecoderControl * dc, pc->state = PLAYER_STATE_PAUSE; \ } else { \ if (openAudioDevice(NULL) >= 0) { \ - if (decode_pid > 0) \ - kill(decode_pid, SIGCONT); \ pc->state = PLAYER_STATE_PLAY; \ } else { \ pathcpy_trunc(pc->erroredUrl, pc->utf8url); \ @@ -247,7 +226,7 @@ static int decodeSeek(PlayerControl * pc, DecoderControl * dc, } \ } \ pc->pause = 0; \ - kill(getppid(), SIGUSR1); \ + wakeup_main_task(); \ if (pause == -1) { \ pause = 1; \ } else if (pause) { \ @@ -303,7 +282,7 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb, while (!inputStreamAtEOF(&inStream) && bufferInputStream(&inStream) < 0 && !dc->stop) { /* sleep so we don't consume 100% of the cpu */ - my_usleep(1000); + my_usleep(10000); } /* for http streams, seekable is determined in bufferInputStream */ @@ -353,8 +332,10 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb, if (plugin == NULL) { /* we already know our mp3Plugin supports streams, no * need to check for stream{Types,DecodeFunc} */ - if ((plugin = getInputPluginFromName("mp3"))) - ret = plugin->streamDecodeFunc(cb, dc, &inStream); + if ((plugin = getInputPluginFromName("mp3"))) { + ret = plugin->streamDecodeFunc(cb, dc, + &inStream); + } } } else { unsigned int next = 0; @@ -397,51 +378,34 @@ stop_no_close: dc->stop = 0; } -static int decoderInit(PlayerControl * pc, OutputBuffer * cb, - DecoderControl * dc) +static void * decoder_task(mpd_unused void *unused) { - int pid; - - pid = decode_pid; - if (pid > 0) { - kill(pid, SIGCONT); - return 0; - } - - blockSignals(); - getPlayerData()->playerControl.decode_pid = 0; - decode_pid = fork(); - - if (decode_pid == 0) { - /* CHILD */ - unblockSignals(); - - while (1) { - if (dc->cycleLogFiles) { - cycle_log_files(); - dc->cycleLogFiles = 0; - } else if (dc->start || dc->seek) - decodeStart(pc, cb, dc); - else if (dc->stop) { - dc->state = DECODE_STATE_STOP; - dc->stop = 0; - } else - my_usleep(10000); + OutputBuffer *cb = &(getPlayerData()->buffer); + PlayerControl *pc = &(getPlayerData()->playerControl); + DecoderControl *dc = &(getPlayerData()->decoderControl); + + while (1) { + if (dc->start || dc->seek) { + decodeStart(pc, cb, dc); + } else if (dc->stop) { + dc->state = DECODE_STATE_STOP; + dc->stop = 0; + decoder_wakeup_player(); + } else { + decoder_sleep(); } - - exit(EXIT_SUCCESS); - /* END OF CHILD */ - } else if (decode_pid < 0) { - unblockSignals(); - pathcpy_trunc(pc->erroredUrl, pc->utf8url); - pc->error = PLAYER_ERROR_SYSTEM; - return -1; } - DEBUG("decoder PID: %d\n", decode_pid); - getPlayerData()->playerControl.decode_pid = decode_pid; - unblockSignals(); +} - return 0; +void decoderInit(void) +{ + pthread_attr_t attr; + pthread_t decoder_thread; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (pthread_create(&decoder_thread, &attr, decoder_task, NULL)) + FATAL("Failed to spawn decoder task: %s\n", strerror(errno)); } static void handleMetadata(OutputBuffer * cb, PlayerControl * pc, int *previous, @@ -519,14 +483,13 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * pc->elapsedTime = 0; pc->state = PLAYER_STATE_PLAY; pc->play = 0; - kill(getppid(), SIGUSR1); + wakeup_main_task(); - while (decode_pid > 0 && - (unsigned)(cb->end - cb->begin) < bbp && + while ((unsigned)cb->end - cb->begin < bbp && cb->end != buffered_chunks - 1 && dc->state != DECODE_STATE_STOP) { processDecodeInput(); - my_usleep(1000); + player_sleep(); } while (!quit) { @@ -540,7 +503,8 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * next = cb->end; dc->start = 1; pc->queueState = PLAYER_QUEUE_DECODE; - kill(getppid(), SIGUSR1); + wakeup_main_task(); + player_wakeup_decoder_nb(); } if (next >= 0 && doCrossFade == 0 && !dc->start && dc->state != DECODE_STATE_START) { @@ -563,11 +527,9 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * race conditions and weirdness */ end = cb->end; - if (pause) { - if (decode_pid) - kill(decode_pid, SIGSTOP); - kill(getpid(), SIGSTOP); - } else if (cb->begin != end && cb->begin != next) { + if (pause) + player_sleep(); + else if (cb->begin != end && cb->begin != next) { if (doCrossFade == 1 && next >= 0 && ((next > cb->begin && (fadePosition = next - cb->begin) @@ -625,7 +587,7 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb->begin = 0; } else cb->begin++; - signalNotify(&cb->notify); + player_wakeup_decoder_nb(); } else if (cb->begin != end && cb->begin == next) { if (doCrossFade == 1 && nextChunk >= 0) { nextChunk = cb->begin + crossFadeChunks; @@ -646,7 +608,7 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * while (pc->queueState == PLAYER_QUEUE_DECODE || pc->queueLockState == PLAYER_QUEUE_LOCKED) { processDecodeInput(); - my_usleep(10000); + player_sleep(); } if (pc->queueState != PLAYER_QUEUE_PLAY) { quit = 1; @@ -661,10 +623,9 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * doCrossFade = 0; crossFadeChunks = 0; pc->queueState = PLAYER_QUEUE_EMPTY; - kill(getppid(), SIGUSR1); + wakeup_main_task(); } - } else if (decode_pid <= 0 || - (dc->state == DECODE_STATE_STOP && !dc->start)) { + } else if (dc->state == DECODE_STATE_STOP && !dc->start) { quit = 1; break; } else { @@ -699,9 +660,7 @@ void decode(void) dc->seek = 0; dc->stop = 0; dc->start = 1; - - if (decoderInit(pc, cb, dc) < 0) - return; + do { player_wakeup_decoder(); } while (dc->start); decodeParent(pc, dc, cb); } diff --git a/src/decode.h b/src/decode.h index 14dc0e8ee..1d90dced4 100644 --- a/src/decode.h +++ b/src/decode.h @@ -47,15 +47,18 @@ typedef struct _DecoderControl { volatile mpd_sint8 seek; volatile mpd_sint8 seekError; volatile mpd_sint8 seekable; - volatile mpd_sint8 cycleLogFiles; volatile double seekWhere; AudioFormat audioFormat; char utf8url[MPD_PATH_MAX]; volatile float totalTime; } DecoderControl; -void decodeSigHandler(int sig, siginfo_t * siginfo, void *v); - void decode(void); +void decoder_wakeup_player(void); + +void decoder_sleep(void); + +void decoderInit(void); + #endif diff --git a/src/directory.c b/src/directory.c index 3bb18bf59..fa517cba6 100644 --- a/src/directory.c +++ b/src/directory.c @@ -175,7 +175,6 @@ int updateInit(int fd, List * pathList) if (directory_updatePid == 0) { /* child */ int dbUpdated = 0; - clearPlayerPid(); unblockSignals(); diff --git a/src/inputPlugins/aac_plugin.c b/src/inputPlugins/aac_plugin.c index 0091b396e..de442acf7 100644 --- a/src/inputPlugins/aac_plugin.c +++ b/src/inputPlugins/aac_plugin.c @@ -400,6 +400,7 @@ static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char *path) if (dc->seek) { dc->seekError = 1; dc->seek = 0; + decoder_wakeup_player(); } else if (dc->stop) { eof = 1; break; @@ -418,6 +419,7 @@ static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char *path) if (dc->seek) { dc->seekError = 1; dc->seek = 0; + decoder_wakeup_player(); } return 0; diff --git a/src/inputPlugins/audiofile_plugin.c b/src/inputPlugins/audiofile_plugin.c index 1c94a8589..33ea54df9 100644 --- a/src/inputPlugins/audiofile_plugin.c +++ b/src/inputPlugins/audiofile_plugin.c @@ -102,6 +102,7 @@ static int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char *path) dc->audioFormat.sampleRate; afSeekFrame(af_fp, AF_DEFAULT_TRACK, current); dc->seek = 0; + decoder_wakeup_player(); } ret = diff --git a/src/inputPlugins/flac_plugin.c b/src/inputPlugins/flac_plugin.c index 7dab78922..23d61e805 100644 --- a/src/inputPlugins/flac_plugin.c +++ b/src/inputPlugins/flac_plugin.c @@ -394,6 +394,7 @@ static int flac_decode_internal(OutputBuffer * cb, DecoderControl * dc, } else dc->seekError = 1; dc->seek = 0; + decoder_wakeup_player(); } } if (!dc->stop) { diff --git a/src/inputPlugins/mod_plugin.c b/src/inputPlugins/mod_plugin.c index 22c364d70..25cedf04b 100644 --- a/src/inputPlugins/mod_plugin.c +++ b/src/inputPlugins/mod_plugin.c @@ -194,6 +194,7 @@ static int mod_decode(OutputBuffer * cb, DecoderControl * dc, char *path) if (dc->seek) { dc->seekError = 1; dc->seek = 0; + decoder_wakeup_player(); } if (dc->stop) diff --git a/src/inputPlugins/mp3_plugin.c b/src/inputPlugins/mp3_plugin.c index b008a1dd9..76d226b00 100644 --- a/src/inputPlugins/mp3_plugin.c +++ b/src/inputPlugins/mp3_plugin.c @@ -857,6 +857,7 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc, clearOutputBuffer(cb); data->muteFrame = 0; dc->seek = 0; + decoder_wakeup_player(); } break; default: @@ -972,10 +973,12 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc, dc->seekError = 1; data->muteFrame = 0; dc->seek = 0; + decoder_wakeup_player(); } } else if (dc->seek && !data->inStream->seekable) { dc->seek = 0; dc->seekError = 1; + decoder_wakeup_player(); } } @@ -1082,6 +1085,7 @@ static int mp3_decode(OutputBuffer * cb, DecoderControl * dc, if (dc->seek && data.muteFrame == MUTEFRAME_SEEK) { clearOutputBuffer(cb); dc->seek = 0; + decoder_wakeup_player(); } flushOutputBuffer(cb); diff --git a/src/inputPlugins/mp4_plugin.c b/src/inputPlugins/mp4_plugin.c index 2e3dd18ae..0484e9993 100644 --- a/src/inputPlugins/mp4_plugin.c +++ b/src/inputPlugins/mp4_plugin.c @@ -221,6 +221,7 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, clearOutputBuffer(cb); seeking = 0; dc->seek = 0; + decoder_wakeup_player(); } if (seeking) @@ -296,6 +297,7 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, if (dc->seek && seeking) { clearOutputBuffer(cb); dc->seek = 0; + decoder_wakeup_player(); } flushOutputBuffer(cb); diff --git a/src/inputPlugins/mpc_plugin.c b/src/inputPlugins/mpc_plugin.c index 49142aaed..9b6e862ff 100644 --- a/src/inputPlugins/mpc_plugin.c +++ b/src/inputPlugins/mpc_plugin.c @@ -194,6 +194,7 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc, } else dc->seekError = 1; dc->seek = 0; + decoder_wakeup_player(); } vbrUpdateAcc = 0; diff --git a/src/inputPlugins/oggflac_plugin.c b/src/inputPlugins/oggflac_plugin.c index 4e56a554a..6638362b6 100644 --- a/src/inputPlugins/oggflac_plugin.c +++ b/src/inputPlugins/oggflac_plugin.c @@ -370,6 +370,7 @@ static int oggflac_decode(OutputBuffer * cb, DecoderControl * dc, } else dc->seekError = 1; dc->seek = 0; + decoder_wakeup_player(); } } diff --git a/src/inputPlugins/oggvorbis_plugin.c b/src/inputPlugins/oggvorbis_plugin.c index 539dc55b7..8eb075336 100644 --- a/src/inputPlugins/oggvorbis_plugin.c +++ b/src/inputPlugins/oggvorbis_plugin.c @@ -285,6 +285,7 @@ static int oggvorbis_decode(OutputBuffer * cb, DecoderControl * dc, } else dc->seekError = 1; dc->seek = 0; + decoder_wakeup_player(); } ret = ov_read(&vf, chunk + chunkpos, OGG_CHUNK_SIZE - chunkpos, diff --git a/src/inputPlugins/wavpack_plugin.c b/src/inputPlugins/wavpack_plugin.c index e25b5099c..37dc4f3d0 100644 --- a/src/inputPlugins/wavpack_plugin.c +++ b/src/inputPlugins/wavpack_plugin.c @@ -192,6 +192,7 @@ static void wavpack_decode(OutputBuffer *cb, DecoderControl *dc, } dc->seek = 0; + decoder_wakeup_player(); } if (dc->stop) diff --git a/src/main.c b/src/main.c index 671363b97..428ef2a91 100644 --- a/src/main.c +++ b/src/main.c @@ -429,6 +429,8 @@ int main(int argc, char *argv[]) initZeroconf(); openVolumeDevice(); + decoderInit(); + playerInit(); read_state_file(); while (COMMAND_RETURN_KILL != doIOForInterfaces() && diff --git a/src/outputBuffer.c b/src/outputBuffer.c index dab233668..7a47a44e7 100644 --- a/src/outputBuffer.c +++ b/src/outputBuffer.c @@ -45,8 +45,6 @@ void initOutputBuffer(OutputBuffer * cb, char *chunks) (float *)(((char *)cb->metaChunk) + buffered_chunks * sizeof(mpd_sint8)); cb->acceptMetadata = 0; - - initNotify(&cb->notify); } void clearAllMetaChunkSets(OutputBuffer * cb) @@ -129,11 +127,12 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, } else { dc->seekError = 1; dc->seek = 0; + decoder_wakeup_player(); } } if (!inStream || bufferInputStream(inStream) <= 0) { - waitNotify(&cb->notify); + decoder_sleep(); } } if (dc->stop) @@ -163,6 +162,7 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, flushOutputBuffer(cb); } } + decoder_wakeup_player(); return 0; } diff --git a/src/outputBuffer.h b/src/outputBuffer.h index ab4ccc893..563c1904b 100644 --- a/src/outputBuffer.h +++ b/src/outputBuffer.h @@ -26,7 +26,6 @@ #include "inputStream.h" #include "metadataChunk.h" #include "replayGain.h" -#include "notify.h" #define OUTPUT_BUFFER_DC_STOP -1 #define OUTPUT_BUFFER_DC_SEEK -2 @@ -46,7 +45,6 @@ typedef struct _OutputBuffer { mpd_sint8 metaChunkSet[BUFFERED_METACHUNKS]; mpd_sint8 *volatile metaChunk; volatile mpd_sint8 acceptMetadata; - Notify notify; } OutputBuffer; void initOutputBuffer(OutputBuffer * cb, char *chunks); diff --git a/src/player.c b/src/player.c index 3312a23e1..4071b5a57 100644 --- a/src/player.c +++ b/src/player.c @@ -33,167 +33,95 @@ #include "sig_handlers.h" #include "os_compat.h" +static pthread_cond_t player_wakeup = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t player_wakeup_mutex = PTHREAD_MUTEX_INITIALIZER; + +static pthread_cond_t main_wakeup = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t main_wakeup_mutex = PTHREAD_MUTEX_INITIALIZER; + static void playerCloseAudio(void); -volatile int player_pid = 0; +void wakeup_player_nb(void) +{ + pthread_cond_signal(&player_wakeup); +} -void clearPlayerPid(void) +static void wakeup_player(void) { - player_pid = 0; + pthread_cond_signal(&player_wakeup); + pthread_cond_wait(&main_wakeup, &main_wakeup_mutex); } -static void resetPlayerMetadata(void) +void wakeup_main_task(void) { - PlayerControl *pc = &(getPlayerData()->playerControl); + pthread_cond_signal(&main_wakeup); +} - if (pc->metadataState == PLAYER_METADATA_STATE_READ) { - pc->metadataState = PLAYER_METADATA_STATE_WRITE; - } +void player_sleep(void) +{ + pthread_cond_wait(&player_wakeup, &player_wakeup_mutex); } -static void resetPlayer(void) -{ - int pid; - - clearPlayerPid(); - getPlayerData()->playerControl.stop = 0; - getPlayerData()->playerControl.play = 0; - getPlayerData()->playerControl.pause = 0; - getPlayerData()->playerControl.lockQueue = 0; - getPlayerData()->playerControl.unlockQueue = 0; - getPlayerData()->playerControl.state = PLAYER_STATE_STOP; - getPlayerData()->playerControl.queueState = PLAYER_QUEUE_UNLOCKED; - getPlayerData()->playerControl.seek = 0; - getPlayerData()->playerControl.metadataState = - PLAYER_METADATA_STATE_WRITE; - pid = getPlayerData()->playerControl.decode_pid; - if (pid > 0) - kill(pid, SIGTERM); - getPlayerData()->playerControl.decode_pid = 0; -} - -void player_sigChldHandler(int pid, int status) -{ - if (player_pid == pid) - { - /* - DEBUG("SIGCHLD caused by player process\n"); - if (WIFSIGNALED(status) && - WTERMSIG(status) != SIGTERM && - WTERMSIG(status) != SIGINT) - { - ERROR("player process died from signal: %i\n", - WTERMSIG(status)); - } - */ - resetPlayer(); - } - else if (pid == getPlayerData()->playerControl.decode_pid && - player_pid <= 0) - { - /* - if (WIFSIGNALED(status) && WTERMSIG(status) != SIGTERM) - { - ERROR("(caught by master parent) " - "decode process died from a " - "non-TERM signal: %i\n", WTERMSIG(status)); +static void * player_task(mpd_unused void *unused) +{ + PlayerControl *pc = &(getPlayerData()->playerControl); + + while (1) { + if (pc->play) { + decode(); + continue; /* decode() calls wakeup_main_task */ + } else if (pc->stop) { + pc->stop = 0; + } else if (pc->seek) { + pc->seek = 0; + } else if (pc->pause) { + pc->pause = 0; + } else if (pc->closeAudio) { + closeAudioDevice(); + pc->closeAudio = 0; + } else if (pc->lockQueue) { + pc->queueLockState = PLAYER_QUEUE_LOCKED; + pc->lockQueue = 0; + } else if (pc->unlockQueue) { + pc->queueLockState = PLAYER_QUEUE_UNLOCKED; + pc->unlockQueue = 0; + } else { + player_sleep(); + continue; } - */ - getPlayerData()->playerControl.decode_pid = 0; + /* we did something, tell the main task about it */ + wakeup_main_task(); } + return NULL; } -static int playerInit(void) +static void resetPlayerMetadata(void) { PlayerControl *pc = &(getPlayerData()->playerControl); - int pid; - - pid = player_pid; - if (pid > 0) { - kill(pid, SIGCONT); - pc->wait = 0; - return 0; - } - blockSignals(); - player_pid = fork(); - if (player_pid==0) - { - clock_t start = clock(); - - unblockSignals(); - - setSigHandlersForDecoder(); - - closeAllListenSockets(); - freeAllInterfaces(); - finishPlaylist(); - closeMp3Directory(); - finishPermissions(); - finishCommands(); - finishVolume(); - - DEBUG("took %f to init player\n", - (float)(clock()-start)/CLOCKS_PER_SEC); - - while (1) { - if (pc->play) - decode(); - else if (pc->stop) - pc->stop = 0; - else if (pc->seek) - pc->seek = 0; - else if (pc->pause) - pc->pause = 0; - else if (pc->closeAudio) { - closeAudioDevice(); - pc->closeAudio = 0; - kill(getppid(), SIGUSR1); - } else if (pc->lockQueue) { - pc->queueLockState = PLAYER_QUEUE_LOCKED; - pc->lockQueue = 0; - } else if (pc->unlockQueue) { - pc->queueLockState = PLAYER_QUEUE_UNLOCKED; - pc->unlockQueue = 0; - } else if (pc->cycleLogFiles) { - cycle_log_files(); - pc->cycleLogFiles = 0; - } else - my_usleep(10000); - } - } - else if (player_pid < 0) - { - unblockSignals(); - ERROR("player Problems fork()'ing\n"); - player_pid = 0; - return -1; + if (pc->metadataState == PLAYER_METADATA_STATE_READ) { + pc->metadataState = PLAYER_METADATA_STATE_WRITE; } +} - unblockSignals(); +void playerInit(void) +{ + pthread_attr_t attr; + pthread_t player_thread; - return 0; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (pthread_create(&player_thread, &attr, player_task, NULL)) + FATAL("Failed to spawn player task: %s\n", strerror(errno)); } int playerWait(int fd) { - PlayerControl *pc = &(getPlayerData()->playerControl); - int pid; - - if (pc->wait) - return 0; - if (playerStop(fd) < 0) return -1; playerCloseAudio(); - pid = player_pid; - if (pid > 0) { - pc->wait = 1; - kill(pid, SIGSTOP); - } - return 0; } @@ -215,17 +143,10 @@ int playerPlay(int fd, Song * song) set_current_song(song); - pc->play = 1; - if (playerInit() < 0) { - pc->play = 0; - return -1; - } - resetPlayerMetadata(); - if (player_pid > 0 && pc->state == PLAYER_STATE_PAUSE) - kill(player_pid, SIGCONT); - while (player_pid > 0 && pc->play) - my_usleep(1000); + pc->play = 1; + /* FIXME: _nb() variant is probably wrong here, and everywhere... */ + do { wakeup_player_nb(); } while (pc->play); return 0; } @@ -234,12 +155,9 @@ int playerStop(int fd) { PlayerControl *pc = &(getPlayerData()->playerControl); - if (player_pid > 0 && pc->state != PLAYER_STATE_STOP) { + if (pc->state != PLAYER_STATE_STOP) { pc->stop = 1; - if (pc->state == PLAYER_STATE_PAUSE) - kill(player_pid, SIGCONT); - while (player_pid > 0 && pc->stop) - my_usleep(1000); + do { wakeup_player(); } while (pc->stop); } pc->queueState = PLAYER_QUEUE_BLANK; @@ -248,27 +166,18 @@ int playerStop(int fd) return 0; } -void playerKill(void) +void playerKill(void) /* deprecated */ { - int pid; - - pid = player_pid; - if (pid > 0) { - kill(pid, SIGCONT); - kill(pid, SIGTERM); - } + playerPause(STDERR_FILENO); } int playerPause(int fd) { PlayerControl *pc = &(getPlayerData()->playerControl); - if (player_pid > 0 && pc->state != PLAYER_STATE_STOP) { + if (pc->state != PLAYER_STATE_STOP) { pc->pause = 1; - if (player_pid > 0 && pc->state == PLAYER_STATE_PAUSE) - kill(player_pid, SIGCONT); - while (player_pid > 0 && pc->pause) - my_usleep(1000); + do { wakeup_player(); } while (pc->pause); } return 0; @@ -278,9 +187,6 @@ int playerSetPause(int fd, int pause_flag) { PlayerControl *pc = &(getPlayerData()->playerControl); - if (player_pid <= 0) - return 0; - switch (pc->state) { case PLAYER_STATE_PLAY: if (pause_flag) @@ -370,15 +276,10 @@ static void playerCloseAudio(void) { PlayerControl *pc = &(getPlayerData()->playerControl); - if (player_pid > 0) { - if (playerStop(STDERR_FILENO) < 0) - return; - pc->closeAudio = 1; - if (pc->state == PLAYER_STATE_PAUSE) - kill(player_pid, SIGCONT); - while (player_pid > 0 && pc->closeAudio) - my_usleep(1000); - } + if (playerStop(STDERR_FILENO) < 0) + return; + pc->closeAudio = 1; + do { wakeup_player(); } while (pc->closeAudio); } int queueSong(Song * song) @@ -412,12 +313,9 @@ void playerQueueLock(void) { PlayerControl *pc = &(getPlayerData()->playerControl); - if (player_pid > 0 && pc->queueLockState == PLAYER_QUEUE_UNLOCKED) { - if (pc->state == PLAYER_STATE_PAUSE) - kill(player_pid, SIGCONT); + if (pc->queueLockState == PLAYER_QUEUE_UNLOCKED) { pc->lockQueue = 1; - while (player_pid > 0 && pc->lockQueue) - my_usleep(1000); + do { wakeup_player(); } while (pc->lockQueue); } } @@ -425,12 +323,9 @@ void playerQueueUnlock(void) { PlayerControl *pc = &(getPlayerData()->playerControl); - if (player_pid > 0 && pc->queueLockState == PLAYER_QUEUE_LOCKED) { - if (pc->state == PLAYER_STATE_PAUSE) - kill(player_pid, SIGCONT); + if (pc->queueLockState == PLAYER_QUEUE_LOCKED) { pc->unlockQueue = 1; - while (player_pid > 0 && pc->unlockQueue) - my_usleep(1000); + do { wakeup_player(); } while (pc->unlockQueue); } } @@ -454,10 +349,8 @@ int playerSeek(int fd, Song * song, float seek_time) resetPlayerMetadata(); pc->seekWhere = seek_time; pc->seek = 1; - if (player_pid > 0 && pc->state == PLAYER_STATE_PAUSE) - kill(player_pid, SIGCONT); - while (player_pid > 0 && pc->seek) - my_usleep(1000); + /* FIXME: _nb() is probably wrong here, too */ + do { wakeup_player_nb(); } while (pc->seek); } return 0; @@ -519,15 +412,6 @@ int getPlayerChannels(void) return pc->channels; } -void playerCycleLogFiles(void) -{ - PlayerControl *pc = &(getPlayerData()->playerControl); - DecoderControl *dc = &(getPlayerData()->decoderControl); - - pc->cycleLogFiles = 1; - dc->cycleLogFiles = 1; -} - /* this actually creates a dupe of the current metadata */ Song *playerCurrentDecodeSong(void) { @@ -537,7 +421,6 @@ Song *playerCurrentDecodeSong(void) PlayerControl *pc = &(getPlayerData()->playerControl); if (pc->metadataState == PLAYER_METADATA_STATE_READ) { - DEBUG("playerCurrentDecodeSong: caught new metadata!\n"); if (prev) free(prev); prev = xmalloc(sizeof(MetadataChunk)); diff --git a/src/player.h b/src/player.h index 48a87227f..71b0e9094 100644 --- a/src/player.h +++ b/src/player.h @@ -55,7 +55,6 @@ #define PLAYER_METADATA_STATE_WRITE 2 typedef struct _PlayerControl { - volatile mpd_sint8 wait; volatile mpd_sint8 stop; volatile mpd_sint8 play; volatile mpd_sint8 pause; @@ -81,16 +80,16 @@ typedef struct _PlayerControl { volatile float crossFade; volatile mpd_uint16 softwareVolume; volatile double totalPlayTime; - volatile int decode_pid; - volatile mpd_sint8 cycleLogFiles; volatile mpd_sint8 metadataState; MetadataChunk metadataChunk; MetadataChunk fileMetadataChunk; } PlayerControl; -void clearPlayerPid(void); +void wakeup_main_task(void); -void player_sigChldHandler(int pid, int status); +void wakeup_player_nb(void); + +void player_sleep(void); int playerPlay(int fd, Song * song); @@ -144,8 +143,8 @@ int getPlayerBits(void); int getPlayerChannels(void); -void playerCycleLogFiles(void); - Song *playerCurrentDecodeSong(void); +void playerInit(void); + #endif diff --git a/src/playerData.c b/src/playerData.c index 3c92fde52..31a3bbd94 100644 --- a/src/playerData.c +++ b/src/playerData.c @@ -97,7 +97,6 @@ void initPlayerData(void) initOutputBuffer(&(playerData_pd->buffer), ((char *)playerData_pd) + sizeof(PlayerData)); - playerData_pd->playerControl.wait = 0; playerData_pd->playerControl.stop = 0; playerData_pd->playerControl.pause = 0; playerData_pd->playerControl.play = 0; @@ -115,7 +114,6 @@ void initPlayerData(void) playerData_pd->playerControl.crossFade = crossfade; playerData_pd->playerControl.softwareVolume = 1000; playerData_pd->playerControl.totalPlayTime = 0; - playerData_pd->playerControl.decode_pid = 0; playerData_pd->playerControl.metadataState = PLAYER_METADATA_STATE_WRITE; diff --git a/src/sig_handlers.c b/src/sig_handlers.c index 111ce9775..af664f182 100644 --- a/src/sig_handlers.c +++ b/src/sig_handlers.c @@ -45,7 +45,6 @@ int handlePendingSignals(void) } if (cycle_log_files() < 0) return COMMAND_RETURN_KILL; - playerCycleLogFiles(); } return 0; @@ -63,7 +62,6 @@ static void chldSigHandler(int sig) else break; } - player_sigChldHandler(pid, status); directory_sigChldHandler(pid, status); } } @@ -92,23 +90,6 @@ void finishSigHandlers(void) signal_unhandle(SIGHUP); } -void setSigHandlersForDecoder(void) -{ - struct sigaction sa; - - finishSigHandlers(); - - sa.sa_flags = 0; - sigemptyset(&sa.sa_mask); - sa.sa_handler = SIG_IGN; - while (sigaction(SIGHUP, &sa, NULL) < 0 && errno == EINTR) ; - while (sigaction(SIGINT, &sa, NULL) < 0 && errno == EINTR) ; - sa.sa_flags = SA_SIGINFO; - sa.sa_sigaction = decodeSigHandler; - while (sigaction(SIGCHLD, &sa, NULL) < 0 && errno == EINTR) ; - while (sigaction(SIGTERM, &sa, NULL) < 0 && errno == EINTR) ; -} - void ignoreSignals(void) { struct sigaction sa; diff --git a/src/sig_handlers.h b/src/sig_handlers.h index 15fa181ee..a9438cac1 100644 --- a/src/sig_handlers.h +++ b/src/sig_handlers.h @@ -27,8 +27,6 @@ void initSigHandlers(void); void finishSigHandlers(void); -void setSigHandlersForDecoder(void); - void ignoreSignals(void); void blockSignals(void); |