diff options
Diffstat (limited to 'src/player.c')
-rw-r--r-- | src/player.c | 275 |
1 files changed, 79 insertions, 196 deletions
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)); |