From 64b0ba6da7975fdde774f188b1647ab6c9024cfa Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 5 Oct 2011 22:37:59 +0200 Subject: decoder_control: add attributes start_ms, end_ms Don't read song.start_ms and song.end_ms, let the player thread manage this logic instead. --- src/player_thread.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/player_thread.c') diff --git a/src/player_thread.c b/src/player_thread.c index be08aa32d..b63758544 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -145,7 +145,9 @@ player_dc_start(struct player *player, struct music_pipe *pipe) assert(player->queued || pc.command == PLAYER_COMMAND_SEEK); assert(pc.next_song != NULL); - dc_start(dc, pc.next_song, player_buffer, pipe); + dc_start(dc, pc.next_song, + pc.next_song->start_ms, pc.next_song->end_ms, + player_buffer, pipe); } /** -- cgit v1.2.3 From 37f026a0a67b9014754e4ab1fcc22229e384fee3 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 5 Oct 2011 22:13:13 +0200 Subject: player_thread: handle SEEK while not playing --- src/player_thread.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/player_thread.c') diff --git a/src/player_thread.c b/src/player_thread.c index b63758544..31bb3d50d 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -145,8 +145,12 @@ player_dc_start(struct player *player, struct music_pipe *pipe) assert(player->queued || pc.command == PLAYER_COMMAND_SEEK); assert(pc.next_song != NULL); + unsigned start_ms = pc.next_song->start_ms; + if (pc.command == PLAYER_COMMAND_SEEK) + start_ms += (unsigned)(pc.seek_where * 1000); + dc_start(dc, pc.next_song, - pc.next_song->start_ms, pc.next_song->end_ms, + start_ms, pc.next_song->end_ms, player_buffer, pipe); } @@ -835,6 +839,10 @@ static void do_play(struct decoder_control *dc) } player_lock(); + + if (pc.command == PLAYER_COMMAND_SEEK) + player.elapsed_time = pc.seek_where; + pc.state = PLAYER_STATE_PLAY; player_command_finished_locked(); @@ -1013,6 +1021,7 @@ static gpointer player_task(G_GNUC_UNUSED gpointer arg) while (1) { switch (pc.command) { + case PLAYER_COMMAND_SEEK: case PLAYER_COMMAND_QUEUE: assert(pc.next_song != NULL); @@ -1026,7 +1035,6 @@ static gpointer player_task(G_GNUC_UNUSED gpointer arg) /* fall through */ - case PLAYER_COMMAND_SEEK: case PLAYER_COMMAND_PAUSE: pc.next_song = NULL; player_command_finished_locked(); -- cgit v1.2.3 From 63b33b6ec584a6730174c45a119a27b4add76777 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 6 Oct 2011 20:55:52 +0200 Subject: player_thread: move code to player_open_output() Common function that manages "player" attributes after audio_output_all_open() has returned. --- src/player_thread.c | 59 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 22 deletions(-) (limited to 'src/player_thread.c') diff --git a/src/player_thread.c b/src/player_thread.c index 31bb3d50d..9a7c917f4 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -276,6 +276,41 @@ real_song_duration(const struct song *song, double decoder_duration) return decoder_duration - song->start_ms / 1000.0; } +/** + * Wrapper for audio_output_all_open(). Upon failure, it pauses the + * player. + * + * @return true on success + */ +static bool +player_open_output(struct player *player) +{ + assert(audio_format_defined(&player->play_audio_format)); + assert(pc.state == PLAYER_STATE_PLAY || + pc.state == PLAYER_STATE_PAUSE); + + if (audio_output_all_open(&player->play_audio_format, player_buffer)) { + player->paused = false; + + player_lock(); + pc.state = PLAYER_STATE_PLAY; + player_unlock(); + + return true; + } else { + /* pause: the user may resume playback as soon as an + audio output becomes available */ + player->paused = true; + + player_lock(); + pc.error = PLAYER_ERROR_AUDIO; + pc.state = PLAYER_STATE_PAUSE; + player_unlock(); + + return false; + } +} + /** * The decoder has acknowledged the "START" command (see * player_wait_for_decoder()). This function checks if the decoder @@ -321,23 +356,12 @@ player_check_decoder_startup(struct player *player) 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)) { + if (!player->paused && !player_open_output(player)) { char *uri = song_get_uri(dc->song); g_warning("problems opening audio device " "while playing \"%s\"", uri); g_free(uri); - 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; } @@ -516,18 +540,9 @@ static void player_process_command(struct player *player) yet - don't open the audio device yet */ player_lock(); - pc.state = PLAYER_STATE_PLAY; - } else if (audio_output_all_open(&player->play_audio_format, player_buffer)) { - /* unpaused, continue playing */ - player_lock(); - pc.state = PLAYER_STATE_PLAY; } else { - /* the audio device has failed - rollback to - pause mode */ - pc.error = PLAYER_ERROR_AUDIO; - - player->paused = true; + player_open_output(player); player_lock(); } -- cgit v1.2.3 From b2f03e76ffd3af918d8eda0968f54c0b81bbff54 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 6 Oct 2011 20:30:46 +0200 Subject: player_thread: add flag "output_open", fixes assertion failure Previously, the condition "defined(play_audio_format)" was used to see if an output device has been opened, but if the device had failed on startup, an assertion failure could occur. This patch adds a separate flag. --- src/player_thread.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'src/player_thread.c') diff --git a/src/player_thread.c b/src/player_thread.c index 9a7c917f4..52788e518 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -73,6 +73,14 @@ struct player { */ bool queued; + /** + * Was any audio output opened successfully? It might have + * failed meanwhile, but was not explicitly closed by the + * player thread. When this flag is unset, some output + * methods must not be called. + */ + bool output_open; + /** * the song currently being played */ @@ -290,6 +298,7 @@ player_open_output(struct player *player) pc.state == PLAYER_STATE_PAUSE); if (audio_output_all_open(&player->play_audio_format, player_buffer)) { + player->output_open = true; player->paused = false; player_lock(); @@ -298,6 +307,8 @@ player_open_output(struct player *player) return true; } else { + player->output_open = false; + /* pause: the user may resume playback as soon as an audio output becomes available */ player->paused = true; @@ -342,7 +353,7 @@ player_check_decoder_startup(struct player *player) decoder_unlock(dc); - if (audio_format_defined(&player->play_audio_format) && + if (player->output_open && !audio_output_all_wait(1)) /* the output devices havn't finished playing all chunks yet - wait for that */ @@ -386,6 +397,7 @@ player_check_decoder_startup(struct player *player) static bool player_send_silence(struct player *player) { + assert(player->output_open); assert(audio_format_defined(&player->play_audio_format)); struct music_chunk *chunk = music_buffer_allocate(player_buffer); @@ -579,8 +591,7 @@ static void player_process_command(struct player *player) break; case PLAYER_COMMAND_REFRESH: - if (audio_format_defined(&player->play_audio_format) && - !player->paused) { + if (player->output_open && !player->paused) { player_unlock(); audio_output_all_check(); player_lock(); @@ -831,6 +842,7 @@ static void do_play(struct decoder_control *dc) .decoder_starting = false, .paused = false, .queued = true, + .output_open = false, .song = NULL, .xfade = XFADE_UNKNOWN, .cross_fading = false, @@ -883,7 +895,7 @@ static void do_play(struct decoder_control *dc) /* not enough decoded buffer space yet */ if (!player.paused && - audio_format_defined(&player.play_audio_format) && + player.output_open && audio_output_all_check() < 4 && !player_send_silence(&player)) break; @@ -988,7 +1000,7 @@ static void do_play(struct decoder_control *dc) audio_output_all_drain(); break; } - } else { + } else if (player.output_open) { /* the decoder is too busy and hasn't provided new PCM data in time: send silence (if the output pipe is empty) */ -- cgit v1.2.3