From 3e9f8effa06e8855b79937f1a7c2d7b1b4e98d58 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Fri, 12 Jul 2019 19:11:48 +0200 Subject: [PATCH] [player] Better fix for resuming playback af long pause (issue #766) The fix in commit 3928ab6 broke resuming from an underrun, since it meant that pb_resume() would flush the input buffer. With this fix it is possible to call input_resume(), which will not flush the buffer if the source is already open. Also renamed some functions in player.c for consistency. --- src/input.c | 26 +++++++++++++++++++++++++- src/input.h | 11 +++++++++++ src/player.c | 45 ++++++++++++++++++++++++++++++--------------- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/src/input.c b/src/input.c index c98bdeb6..e13fe9a4 100644 --- a/src/input.c +++ b/src/input.c @@ -113,7 +113,7 @@ struct input_arg { uint32_t item_id; int seek_ms; - struct input_metadata *metadata; + bool resume; }; /* --- Globals --- */ @@ -462,6 +462,16 @@ start(void *arg, int *retval) // If we are asked to start the item that is currently open we can just seek if (input_now_reading.open && cmdarg->item_id == input_now_reading.item_id) { + // When we resume we don't want to flush & seek, since that has either + // already been done, or it is not desired because we just filled the + // buffer after an underrun. + if (cmdarg->resume) + { + DPRINTF(E_DBG, L_PLAYER, "Resuming input read loop for item '%s' (item id %" PRIu32 ")\n", input_now_reading.path, input_now_reading.item_id); + *retval = cmdarg->seek_ms; + return COMMAND_END; + } + flush(&flags); ret = seek(&input_now_reading, cmdarg->seek_ms); @@ -763,6 +773,19 @@ input_seek(uint32_t item_id, int seek_ms) cmdarg.item_id = item_id; cmdarg.seek_ms = seek_ms; + cmdarg.resume = false; + + return commands_exec_sync(cmdbase, start, NULL, &cmdarg); +} + +int +input_resume(uint32_t item_id, int seek_ms) +{ + struct input_arg cmdarg; + + cmdarg.item_id = item_id; + cmdarg.seek_ms = seek_ms; + cmdarg.resume = true; return commands_exec_sync(cmdbase, start, NULL, &cmdarg); } @@ -776,6 +799,7 @@ input_start(uint32_t item_id) cmdarg->item_id = item_id; cmdarg->seek_ms = 0; + cmdarg->resume = false; commands_exec_async(cmdbase, start, cmdarg); } diff --git a/src/input.h b/src/input.h index 18407f6d..fb8cb82a 100644 --- a/src/input.h +++ b/src/input.h @@ -196,6 +196,17 @@ input_buffer_full_cb(input_cb cb); int input_seek(uint32_t item_id, int seek_ms); +/* + * Same as input_seek(), except if the item is already being read we don't do + * anything (no flush & seek) + * + * @in item_id Queue item id to start playing + * @in seek_ms Position to start playing + * @return Actual seek position if seekable, 0 otherwise, -1 on error + */ +int +input_resume(uint32_t item_id, int seek_ms); + /* * Same as input_seek(), just non-blocking and does not offer seek. * diff --git a/src/player.c b/src/player.c index ff219d1f..9d704e89 100644 --- a/src/player.c +++ b/src/player.c @@ -612,19 +612,8 @@ source_stop(void) input_stop(); } -static void -source_start(struct player_source *ps) -{ - if (!ps) - return; - - DPRINTF(E_DBG, L_PLAYER, "Opening next track: '%s' (id=%d)\n", ps->path, ps->item_id); - - input_start(ps->item_id); -} - static int -source_restart(struct player_source *ps) +source_start(struct player_source *ps) { short flags; @@ -638,6 +627,32 @@ source_restart(struct player_source *ps) return input_seek(ps->item_id, (int)ps->seek_ms); } +static void +source_next(struct player_source *ps) +{ + if (!ps) + return; + + DPRINTF(E_DBG, L_PLAYER, "Opening next track: '%s' (id=%d)\n", ps->path, ps->item_id); + + input_start(ps->item_id); +} + +static int +source_restart(void) +{ + if (!pb_session.playing_now) + { + DPRINTF(E_LOG, L_PLAYER, "Bug! source_restart called, but playing_now is null\n"); + return -1; + } + + DPRINTF(E_DBG, L_PLAYER, "Restarting track: '%s' (id=%d, pos=%d)\n", pb_session.playing_now->path, pb_session.playing_now->item_id, pb_session.playing_now->pos_ms); + + input_resume(pb_session.playing_now->item_id, pb_session.playing_now->pos_ms); + + return 0; +} /* ------------------------ Playback session upkeep ------------------------- */ @@ -910,7 +925,7 @@ event_read_start_next() session_update_read_next(ps); // Starts the input read loop - source_start(pb_session.source_list); + source_next(pb_session.source_list); } static void @@ -1604,7 +1619,7 @@ pb_session_start(struct db_queue_item *queue_item, uint32_t seek_ms) session_start(ps); // Sets of opening of the new source - while ( (ret = source_restart(ps)) < 0) + while ( (ret = source_start(ps)) < 0) { // Couldn't start requested item, skip to next and remove failed item from queue item_id = ps->item_id; @@ -1665,7 +1680,7 @@ pb_resume(void) { int ret; - ret = source_restart(pb_session.playing_now); + ret = source_restart(); if (ret < 0) { pb_abort();