From 35a939e3e766975776ecaf99e0e46f8a3a68faf2 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 12 Oct 2008 00:07:54 +0200 Subject: player: added commands QUEUE and CANCEL QUEUE adds a new song to the player's queue. CANCEL clears the queue. These two commands replace the old and complex queueState and queueLockState code. --- src/player_control.c | 46 +++++-------------------------- src/player_control.h | 57 ++++++++++---------------------------- src/player_thread.c | 77 ++++++++++++++++++++++++++++++++-------------------- src/playlist.c | 49 +++------------------------------ 4 files changed, 74 insertions(+), 155 deletions(-) diff --git a/src/player_control.c b/src/player_control.c index 8ba215ae1..e7935f80f 100644 --- a/src/player_control.c +++ b/src/player_control.c @@ -33,8 +33,6 @@ void pc_init(unsigned int buffered_before_play) pc.command = PLAYER_COMMAND_NONE; pc.error = PLAYER_ERROR_NOERROR; pc.state = PLAYER_STATE_STOP; - pc.queueState = PLAYER_QUEUE_BLANK; - pc.queueLockState = PLAYER_QUEUE_UNLOCKED; pc.crossFade = 0; pc.softwareVolume = 1000; } @@ -57,26 +55,22 @@ void playerPlay(struct song *song) { assert(song != NULL); - assert(pc.queueLockState == PLAYER_QUEUE_UNLOCKED); if (pc.state != PLAYER_STATE_STOP) player_command(PLAYER_COMMAND_STOP); - pc.queueState = PLAYER_QUEUE_BLANK; - pc.next_song = song; player_command(PLAYER_COMMAND_PLAY); } -void playerWait(void) +void pc_cancel(void) { - player_command(PLAYER_COMMAND_CLOSE_AUDIO); - - assert(pc.queueLockState == PLAYER_QUEUE_UNLOCKED); + player_command(PLAYER_COMMAND_CANCEL); +} +void playerWait(void) +{ player_command(PLAYER_COMMAND_CLOSE_AUDIO); - - pc.queueState = PLAYER_QUEUE_BLANK; } void playerKill(void) @@ -172,36 +166,10 @@ void queueSong(struct song *song) { assert(song != NULL); - assert(pc.queueState == PLAYER_QUEUE_BLANK); + assert(pc.next_song == NULL); pc.next_song = song; - pc.queueState = PLAYER_QUEUE_FULL; -} - -enum player_queue_state getPlayerQueueState(void) -{ - return pc.queueState; -} - -void setQueueState(enum player_queue_state queueState) -{ - pc.queueState = queueState; - notify_signal(&pc.notify); -} - -void playerQueueLock(void) -{ - assert(pc.queueLockState == PLAYER_QUEUE_UNLOCKED); - player_command(PLAYER_COMMAND_LOCK_QUEUE); - assert(pc.queueLockState == PLAYER_QUEUE_LOCKED); -} - -void playerQueueUnlock(void) -{ - if (pc.queueLockState == PLAYER_QUEUE_LOCKED) - player_command(PLAYER_COMMAND_UNLOCK_QUEUE); - - assert(pc.queueLockState == PLAYER_QUEUE_UNLOCKED); + player_command(PLAYER_COMMAND_QUEUE); } int diff --git a/src/player_control.h b/src/player_control.h index 179a9c2ab..bd557ce57 100644 --- a/src/player_control.h +++ b/src/player_control.h @@ -38,8 +38,16 @@ enum player_command { PLAYER_COMMAND_PAUSE, PLAYER_COMMAND_SEEK, PLAYER_COMMAND_CLOSE_AUDIO, - PLAYER_COMMAND_LOCK_QUEUE, - PLAYER_COMMAND_UNLOCK_QUEUE + + /** player_control.next_song has been updated */ + PLAYER_COMMAND_QUEUE, + + /** + * cancel pre-decoding player_control.next_song; if the player + * has already started playing this song, it will completely + * stop + */ + PLAYER_COMMAND_CANCEL, }; #define PLAYER_ERROR_NOERROR 0 @@ -49,36 +57,6 @@ enum player_command { #define PLAYER_ERROR_UNKTYPE 4 #define PLAYER_ERROR_FILENOTFOUND 5 -/* 0->1->2->3->5 regular playback - * ->4->0 don't play queued song - */ -enum player_queue_state { - /** there is no queued song */ - PLAYER_QUEUE_BLANK = 0, - - /** there is a queued song */ - PLAYER_QUEUE_FULL = 1, - - /** the player thread has forwarded the queued song to the - decoder; it waits for PLAY or STOP */ - PLAYER_QUEUE_DECODE = 2, - - /** tells the player thread to start playing the queued song; - this is a response to DECODE */ - PLAYER_QUEUE_PLAY = 3, - - /** tells the player thread to stop before playing the queued - song; this is a response to DECODE */ - PLAYER_QUEUE_STOP = 4, - - /** the player thread has begun playing the queued song, and - thus its queue is empty */ - PLAYER_QUEUE_EMPTY = 5 -}; - -#define PLAYER_QUEUE_UNLOCKED 0 -#define PLAYER_QUEUE_LOCKED 1 - struct player_control { unsigned int buffered_before_play; @@ -92,8 +70,6 @@ struct player_control { volatile float elapsedTime; struct song *volatile next_song; struct song *errored_song; - volatile enum player_queue_state queueState; - volatile int8_t queueLockState; volatile double seekWhere; volatile float crossFade; volatile uint16_t softwareVolume; @@ -109,6 +85,11 @@ void pc_deinit(void); void playerPlay(struct song *song); +/** + * see PLAYER_COMMAND_CANCEL + */ +void pc_cancel(void); + void playerSetPause(int pause_flag); void playerPause(void); @@ -134,14 +115,6 @@ void playerWait(void); void queueSong(struct song *song); -enum player_queue_state getPlayerQueueState(void); - -void setQueueState(enum player_queue_state queueState); - -void playerQueueLock(void); - -void playerQueueUnlock(void); - int playerSeek(struct song *song, float seek_time); diff --git a/src/player_thread.c b/src/player_thread.c index f6cecb5a2..10b9a8769 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -51,6 +51,11 @@ struct player { */ bool paused; + /** + * is there a new song in pc.next_song? + */ + bool queued; + /** * is cross fading enabled? */ @@ -94,6 +99,9 @@ static int waitOnDecode(struct player *player) ? pc.next_song->tag->time : 0; pc.bitRate = 0; audio_format_clear(&pc.audio_format); + + pc.next_song = NULL; + player->queued = false; player->decoder_starting = true; return 0; @@ -137,13 +145,9 @@ static void processDecodeInput(struct player *player) case PLAYER_COMMAND_CLOSE_AUDIO: break; - case PLAYER_COMMAND_LOCK_QUEUE: - pc.queueLockState = PLAYER_QUEUE_LOCKED; - player_command_finished(); - break; - - case PLAYER_COMMAND_UNLOCK_QUEUE: - pc.queueLockState = PLAYER_QUEUE_UNLOCKED; + case PLAYER_COMMAND_QUEUE: + assert(pc.next_song != NULL); + player->queued = true; player_command_finished(); break; @@ -177,6 +181,27 @@ static void processDecodeInput(struct player *player) player->buffered_before_play = 0; } break; + + case PLAYER_COMMAND_CANCEL: + if (pc.next_song == NULL) { + /* the cancel request arrived too later, we're + already playing the queued song... stop + everything now */ + pc.command = PLAYER_COMMAND_STOP; + return; + } + + if (player->next_song_chunk != -1) { + /* the decoder is already decoding the song - + stop it and reset the position */ + dc_stop(&pc.notify); + player->next_song_chunk = -1; + } + + pc.next_song = NULL; + player->queued = false; + player_command_finished(); + break; } } @@ -203,6 +228,7 @@ static void do_play(void) .buffered_before_play = pc.buffered_before_play, .decoder_starting = false, .paused = false, + .queued = false, .xfade = XFADE_UNKNOWN, .next_song_chunk = -1, }; @@ -286,15 +312,22 @@ static void do_play(void) } } - if (decoder_is_idle() && - pc.queueState == PLAYER_QUEUE_FULL && - pc.queueLockState == PLAYER_QUEUE_UNLOCKED) { + if (decoder_is_idle() && !player.queued && + pc.next_song != NULL) { + /* the decoder has finished the current song; + request the next song from the playlist */ + pc.next_song = NULL; + wakeup_main_task(); + } + + if (decoder_is_idle() && player.queued) { /* the decoder has finished the current song; make it decode the next song */ + assert(pc.next_song != NULL); + + player.queued = false; player.next_song_chunk = ob.end; dc_start_async(pc.next_song); - pc.queueState = PLAYER_QUEUE_DECODE; - wakeup_main_task(); } if (player.next_song_chunk >= 0 && player.xfade == XFADE_UNKNOWN && @@ -386,20 +419,10 @@ static void do_play(void) player.xfade = XFADE_UNKNOWN; - /* wait for a signal from the playlist */ - if (pc.queueState == PLAYER_QUEUE_DECODE || - pc.queueLockState == PLAYER_QUEUE_LOCKED) { - notify_wait(&pc.notify); - continue; - } - if (pc.queueState != PLAYER_QUEUE_PLAY) - break; - player.next_song_chunk = -1; if (waitOnDecode(&player) < 0) return; - pc.queueState = PLAYER_QUEUE_EMPTY; wakeup_main_task(); } else if (decoder_is_idle()) { break; @@ -418,6 +441,7 @@ static void * player_task(mpd_unused void *arg) while (1) { switch (pc.command) { case PLAYER_COMMAND_PLAY: + case PLAYER_COMMAND_QUEUE: do_play(); break; @@ -438,13 +462,8 @@ static void * player_task(mpd_unused void *arg) pthread_exit(NULL); break; - case PLAYER_COMMAND_LOCK_QUEUE: - pc.queueLockState = PLAYER_QUEUE_LOCKED; - player_command_finished(); - break; - - case PLAYER_COMMAND_UNLOCK_QUEUE: - pc.queueLockState = PLAYER_QUEUE_UNLOCKED; + case PLAYER_COMMAND_CANCEL: + pc.next_song = NULL; player_command_finished(); break; diff --git a/src/playlist.c b/src/playlist.c index 74b2d60d2..840c9c6b5 100644 --- a/src/playlist.c +++ b/src/playlist.c @@ -499,28 +499,9 @@ static void queueNextSongInPlaylist(void) static void syncPlaylistWithQueue(void) { - switch (getPlayerQueueState()) { - case PLAYER_QUEUE_EMPTY: - setQueueState(PLAYER_QUEUE_BLANK); - if (playlist.queued >= 0) { - DEBUG("playlist: now playing queued song\n"); - playlist.current = playlist.queued; - } + if (pc.next_song == NULL && playlist.queued != -1) { + playlist.current = playlist.queued; playlist.queued = -1; - break; - - case PLAYER_QUEUE_DECODE: - if (playlist.queued != -1) - setQueueState(PLAYER_QUEUE_PLAY); - else - setQueueState(PLAYER_QUEUE_STOP); - break; - - case PLAYER_QUEUE_FULL: - case PLAYER_QUEUE_PLAY: - case PLAYER_QUEUE_STOP: - case PLAYER_QUEUE_BLANK: - break; } } @@ -528,31 +509,9 @@ static void clearPlayerQueue(void) { assert(playlist.queued >= 0); - if (getPlayerQueueState() == PLAYER_QUEUE_PLAY || - getPlayerQueueState() == PLAYER_QUEUE_FULL) { - playerQueueLock(); - syncPlaylistWithQueue(); - } - playlist.queued = -1; - switch (getPlayerQueueState()) { - case PLAYER_QUEUE_BLANK: - case PLAYER_QUEUE_DECODE: - case PLAYER_QUEUE_STOP: - case PLAYER_QUEUE_EMPTY: - break; - - case PLAYER_QUEUE_FULL: - DEBUG("playlist: dequeue song\n"); - setQueueState(PLAYER_QUEUE_BLANK); - break; - case PLAYER_QUEUE_PLAY: - DEBUG("playlist: stop decoding queued song\n"); - setQueueState(PLAYER_QUEUE_STOP); - break; - } - playerQueueUnlock(); + pc_cancel(); } enum playlist_result addToPlaylist(const char *url, int *added_id) @@ -907,7 +866,7 @@ void syncPlayerAndPlaylist(void) playPlaylistIfPlayerStopped(); else { syncPlaylistWithQueue(); - if (getPlayerQueueState() == PLAYER_QUEUE_BLANK) + if (pc.next_song == NULL) queueNextSongInPlaylist(); } -- cgit v1.2.3