[input] Make input_resume() not reopen tracks that have finished playing

If playback was paused during the very last part of the track, the rest of the
track would be read into the input buffer and the input would be closed. With
this commit the input will not be reopened.

Also allow input_flush to be called with null argument.
This commit is contained in:
ejurgensen 2019-08-17 01:37:39 +02:00
parent 7dfe4c2b65
commit 86339eee87
2 changed files with 33 additions and 24 deletions

View File

@ -115,7 +115,6 @@ struct input_arg
{ {
uint32_t item_id; uint32_t item_id;
int seek_ms; int seek_ms;
bool resume;
}; };
/* --- Globals --- */ /* --- Globals --- */
@ -344,18 +343,19 @@ clear(struct input_source *source)
} }
static void static void
flush(short *flags) flush(short *flagptr)
{ {
struct marker *marker; struct marker *marker;
short flags;
size_t len; size_t len;
pthread_mutex_lock(&input_buffer.mutex); pthread_mutex_lock(&input_buffer.mutex);
// We will return an OR of all the unread marker flags // We will return an OR of all the unread marker flags
*flags = 0; flags = 0;
for (marker = input_buffer.marker_tail; marker; marker = input_buffer.marker_tail) for (marker = input_buffer.marker_tail; marker; marker = input_buffer.marker_tail)
{ {
*flags |= marker->flag; flags |= marker->flag;
input_buffer.marker_tail = marker->prev; input_buffer.marker_tail = marker->prev;
marker_free(marker); marker_free(marker);
} }
@ -375,14 +375,16 @@ flush(short *flags)
pthread_mutex_unlock(&input_buffer.mutex); pthread_mutex_unlock(&input_buffer.mutex);
#ifdef DEBUG_INPUT #ifdef DEBUG_INPUT
DPRINTF(E_DBG, L_PLAYER, "Flushing %zu bytes with flags %d\n", len, *flags); DPRINTF(E_DBG, L_PLAYER, "Flushing %zu bytes with flags %d\n", len, flags);
#endif #endif
if (flagptr)
*flagptr = flags;
} }
static void static void
stop(void) stop(void)
{ {
short flags;
int type; int type;
event_del(input_open_timeout_ev); event_del(input_open_timeout_ev);
@ -393,7 +395,7 @@ stop(void)
if (inputs[type]->stop && input_now_reading.open) if (inputs[type]->stop && input_now_reading.open)
inputs[type]->stop(&input_now_reading); inputs[type]->stop(&input_now_reading);
flush(&flags); flush(NULL);
clear(&input_now_reading); clear(&input_now_reading);
} }
@ -461,23 +463,12 @@ start(void *arg, int *retval)
{ {
struct input_arg *cmdarg = arg; struct input_arg *cmdarg = arg;
struct db_queue_item *queue_item; struct db_queue_item *queue_item;
short flags;
int ret; int ret;
// If we are asked to start the item that is currently open we can just seek // 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) 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 flush(NULL);
// 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); ret = seek(&input_now_reading, cmdarg->seek_ms);
if (ret < 0) if (ret < 0)
@ -518,6 +509,26 @@ start(void *arg, int *retval)
return COMMAND_END; return COMMAND_END;
} }
// Resume is a no-op if what we are reading now (or just finished reading, hence
// we don't check if input_now_reading.open is true) is the same item as
// requested. We also don't want to flush & seek in this case, since that has
// either already been done, or it is not desired because we just filled the
// buffer after an underrun.
static enum command_state
resume(void *arg, int *retval)
{
struct input_arg *cmdarg = arg;
if (cmdarg->item_id == input_now_reading.item_id)
{
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;
}
return start(arg, retval);
}
static enum command_state static enum command_state
stop_cmd(void *arg, int *retval) stop_cmd(void *arg, int *retval)
{ {
@ -788,7 +799,6 @@ input_seek(uint32_t item_id, int seek_ms)
cmdarg.item_id = item_id; cmdarg.item_id = item_id;
cmdarg.seek_ms = seek_ms; cmdarg.seek_ms = seek_ms;
cmdarg.resume = false;
return commands_exec_sync(cmdbase, start, NULL, &cmdarg); return commands_exec_sync(cmdbase, start, NULL, &cmdarg);
} }
@ -802,9 +812,8 @@ input_resume(uint32_t item_id, int seek_ms)
cmdarg->item_id = item_id; cmdarg->item_id = item_id;
cmdarg->seek_ms = seek_ms; cmdarg->seek_ms = seek_ms;
cmdarg->resume = true;
commands_exec_async(cmdbase, start, cmdarg); commands_exec_async(cmdbase, resume, cmdarg);
} }
void void
@ -816,7 +825,6 @@ input_start(uint32_t item_id)
cmdarg->item_id = item_id; cmdarg->item_id = item_id;
cmdarg->seek_ms = 0; cmdarg->seek_ms = 0;
cmdarg->resume = false;
commands_exec_async(cmdbase, start, cmdarg); commands_exec_async(cmdbase, start, cmdarg);
} }

View File

@ -221,7 +221,8 @@ void
input_stop(void); input_stop(void);
/* /*
* Flush input buffer. Output flags will be the same as input_read(). * Flush input buffer. Output flags will be the same as input_read(). Call with
* null pointer is valid.
*/ */
void void
input_flush(short *flags); input_flush(short *flags);