diff options
Diffstat (limited to 'src/player_thread.c')
-rw-r--r-- | src/player_thread.c | 108 |
1 files changed, 71 insertions, 37 deletions
diff --git a/src/player_thread.c b/src/player_thread.c index 32d35f309..5cb73a3ee 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -124,6 +124,22 @@ static void player_command_finished(void) } /** + * Start the decoder. + * + * Player lock is not held. + */ +static void +player_dc_start(struct player *player, struct music_pipe *pipe) +{ + struct decoder_control *dc = player->dc; + + assert(player->queued); + assert(pc.next_song != NULL); + + dc_start(dc, pc.next_song, player_buffer, pipe); +} + +/** * Stop the decoder and clears (and frees) its music pipe. * * Player lock is not held. @@ -148,6 +164,17 @@ player_dc_stop(struct player *player) } /** + * Returns true if the decoder is decoding the next song (or has begun + * decoding it, or has finished doing it), and the player hasn't + * switched to that song yet. + */ +static bool +decoding_next_song(const struct player *player) +{ + return player->dc->pipe != NULL && player->dc->pipe != player->pipe; +} + +/** * After the decoder has been started asynchronously, wait for the * "START" command to finish. The decoder may not be initialized yet, * i.e. there is no audio_format information yet. @@ -159,34 +186,40 @@ player_wait_for_decoder(struct player *player) { struct decoder_control *dc = player->dc; - dc_command_wait(dc); + assert(player->queued); + assert(pc.next_song != NULL); - if (decoder_lock_has_failed(dc)) { - assert(dc->next_song == NULL || dc->next_song->uri != NULL); + player->queued = false; + if (decoder_lock_has_failed(dc)) { player_lock(); - pc.errored_song = dc->next_song; + pc.errored_song = dc->song; pc.error = PLAYER_ERROR_FILE; pc.next_song = NULL; player_unlock(); - player->queued = false; return false; } + player->song = pc.next_song; + player->elapsed_time = 0.0; + + /* set the "starting" flag, which will be cleared by + player_check_decoder_startup() */ + player->decoder_starting = true; + + player_lock(); + + /* update player_control's song information */ pc.total_time = pc.next_song->tag != NULL ? pc.next_song->tag->time : 0; pc.bit_rate = 0; audio_format_clear(&pc.audio_format); - player->song = pc.next_song; + /* clear the queued song */ pc.next_song = NULL; - player->queued = false; - player->elapsed_time = 0.0; - /* set the "starting" flag, which will be cleared by - player_check_decoder_startup() */ - player->decoder_starting = true; + player_unlock(); /* call syncPlaylistWithQueue() in the main thread */ event_pipe_emit(PIPE_EVENT_PLAYLIST); @@ -212,12 +245,12 @@ player_check_decoder_startup(struct player *player) if (decoder_has_failed(dc)) { /* the decoder failed */ - assert(dc->next_song == NULL || dc->next_song->uri != NULL); - decoder_unlock(dc); - pc.errored_song = dc->next_song; + player_lock(); + pc.errored_song = dc->song; pc.error = PLAYER_ERROR_FILE; + player_unlock(); return false; } else if (!decoder_is_starting(dc)) { @@ -231,26 +264,30 @@ player_check_decoder_startup(struct player *player) all chunks yet - wait for that */ return true; + player_lock(); pc.total_time = dc->total_time; pc.audio_format = dc->in_audio_format; + player_unlock(); + player->play_audio_format = dc->out_audio_format; player->decoder_starting = false; if (!player->paused && !audio_output_all_open(&dc->out_audio_format, player_buffer)) { - char *uri = song_get_uri(dc->next_song); + char *uri = song_get_uri(dc->song); g_warning("problems opening audio device " "while playing \"%s\"", uri); g_free(uri); - assert(dc->next_song == NULL || dc->next_song->uri != NULL); - pc.errored_song = dc->next_song; + player_lock(); pc.error = PLAYER_ERROR_AUDIO; /* pause: the user may resume playback as soon as an audio output becomes available */ pc.state = PLAYER_STATE_PAUSE; + player_unlock(); + player->paused = true; return true; } @@ -328,10 +365,9 @@ static bool player_seek_decoder(struct player *player) /* clear music chunks which might still reside in the pipe */ music_pipe_clear(player->pipe, player_buffer); - dc->pipe = player->pipe; /* re-start the decoder */ - dc_start_async(dc, pc.next_song); + player_dc_start(player, player->pipe); ret = player_wait_for_decoder(player); if (!ret) { /* decoder failure */ @@ -436,8 +472,6 @@ static void player_process_command(struct player *player) } else { /* the audio device has failed - rollback to pause mode */ - assert(dc->next_song == NULL || dc->next_song->uri != NULL); - pc.errored_song = dc->next_song; pc.error = PLAYER_ERROR_AUDIO; player->paused = true; @@ -463,7 +497,7 @@ static void player_process_command(struct player *player) return; } - if (dc->pipe != NULL && dc->pipe != player->pipe) { + if (decoding_next_song(player)) { /* the decoder is already decoding the song - stop it and reset the position */ player_unlock(); @@ -571,7 +605,7 @@ play_next_chunk(struct player *player) return true; if (player->xfade == XFADE_ENABLED && - dc->pipe != NULL && dc->pipe != player->pipe && + decoding_next_song(player) && (cross_fade_position = music_pipe_size(player->pipe)) <= player->cross_fade_chunks) { /* perform cross fade */ @@ -698,7 +732,7 @@ static void do_play(struct decoder_control *dc) .buffering = true, .decoder_starting = false, .paused = false, - .queued = false, + .queued = true, .song = NULL, .xfade = XFADE_UNKNOWN, .cross_fading = false, @@ -710,9 +744,7 @@ static void do_play(struct decoder_control *dc) player.pipe = music_pipe_new(); - dc->buffer = player_buffer; - dc->pipe = player.pipe; - dc_start(dc, pc.next_song); + player_dc_start(&player, player.pipe); if (!player_wait_for_decoder(&player)) { player_dc_stop(&player); player_command_finished(); @@ -785,18 +817,16 @@ static void do_play(struct decoder_control *dc) */ #endif - if (decoder_lock_is_idle(dc) && player.queued) { + if (decoder_lock_is_idle(dc) && player.queued && + dc->pipe == player.pipe) { /* the decoder has finished the current song; make it decode the next song */ - assert(pc.next_song != NULL); assert(dc->pipe == NULL || dc->pipe == player.pipe); - player.queued = false; - dc->pipe = music_pipe_new(); - dc_start_async(dc, pc.next_song); + player_dc_start(&player, music_pipe_new()); } - if (dc->pipe != NULL && dc->pipe != player.pipe && + if (decoding_next_song(&player) && player.xfade == XFADE_UNKNOWN && !decoder_lock_is_starting(dc)) { /* enable cross fading in this song? if yes, @@ -835,7 +865,7 @@ static void do_play(struct decoder_control *dc) /* XXX synchronize in a better way */ g_usleep(10000); - } else if (dc->pipe != NULL && dc->pipe != player.pipe) { + } else if (decoding_next_song(&player)) { /* at the beginning of a new song */ if (!player_song_border(&player)) @@ -859,14 +889,18 @@ static void do_play(struct decoder_control *dc) player_dc_stop(&player); - assert(!player.queued || pc.next_song != NULL); - pc.next_song = NULL; - music_pipe_clear(player.pipe, player_buffer); music_pipe_free(player.pipe); player_lock(); + + if (player.queued) { + assert(pc.next_song != NULL); + pc.next_song = NULL; + } + pc.state = PLAYER_STATE_STOP; + player_unlock(); event_pipe_emit(PIPE_EVENT_PLAYLIST); |