diff --git a/src/input.c b/src/input.c index e13fe9a4..5e92a023 100644 --- a/src/input.c +++ b/src/input.c @@ -50,6 +50,8 @@ #define INPUT_OPEN_TIMEOUT 600 //#define DEBUG_INPUT 1 +// For testing http stream underruns +//#define DEBUG_UNDERRUN 1 extern struct input_definition input_file; extern struct input_definition input_http; @@ -142,6 +144,9 @@ static struct event *input_open_timeout_ev; #ifdef DEBUG_INPUT static size_t debug_elapsed; #endif +#ifdef DEBUG_UNDERRUN +int debug_underrun_trigger; +#endif /* ------------------------------- MISC HELPERS ----------------------------- */ @@ -578,6 +583,16 @@ input_write(struct evbuffer *evbuf, struct media_quality *quality, short flags) if (evbuf) { len = evbuffer_get_length(evbuf); +#ifdef DEBUG_UNDERRUN + // Starves the player so it underruns after a few minutes + debug_underrun_trigger++; + if (debug_underrun_trigger % 10 == 0) + { + DPRINTF(E_DBG, L_PLAYER, "Underrun debug mode: Dropping audio buffer length %zu\n", len); + evbuffer_drain(evbuf, len); + len = 0; + } +#endif input_buffer.bytes_written += len; ret = evbuffer_add_buffer(input_buffer.evbuf, evbuf); if (ret < 0) @@ -778,16 +793,18 @@ input_seek(uint32_t item_id, int seek_ms) return commands_exec_sync(cmdbase, start, NULL, &cmdarg); } -int +void input_resume(uint32_t item_id, int seek_ms) { - struct input_arg cmdarg; + struct input_arg *cmdarg; - cmdarg.item_id = item_id; - cmdarg.seek_ms = seek_ms; - cmdarg.resume = true; + CHECK_NULL(L_PLAYER, cmdarg = malloc(sizeof(struct input_arg))); - return commands_exec_sync(cmdbase, start, NULL, &cmdarg); + cmdarg->item_id = item_id; + cmdarg->seek_ms = seek_ms; + cmdarg->resume = true; + + commands_exec_async(cmdbase, start, cmdarg); } void diff --git a/src/input.h b/src/input.h index fb8cb82a..4c3294a6 100644 --- a/src/input.h +++ b/src/input.h @@ -196,17 +196,6 @@ 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. * @@ -215,6 +204,16 @@ input_resume(uint32_t item_id, int seek_ms); void input_start(uint32_t item_id); +/* + * Same as input_seek(), but non-blocking and 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 + */ +void +input_resume(uint32_t item_id, int seek_ms); + /* * Stops the input and clears everything. Flushes the input buffer. */ diff --git a/src/player.c b/src/player.c index 9d704e89..66d6c63f 100644 --- a/src/player.c +++ b/src/player.c @@ -649,6 +649,9 @@ source_restart(void) 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); + // Must be non-blocking, because otherwise we get a deadlock via the input + // thread making a sync call to player_playback_start() -> pb_resume() -> + // source_restart() -> input_resume() input_resume(pb_session.playing_now->item_id, pb_session.playing_now->pos_ms); return 0;