[input] Pass read errors to the player through the input buffer

This commit is contained in:
ejurgensen 2017-03-11 19:23:49 +01:00
parent 6c94cdd635
commit 5d74c98431
3 changed files with 42 additions and 16 deletions

View File

@ -71,6 +71,8 @@ struct input_buffer
// If non-zero, remaining length of buffer until EOF // If non-zero, remaining length of buffer until EOF
size_t eof; size_t eof;
// If non-zero, remaining length of buffer until read error occurred
size_t error;
// If non-zero, remaining length of buffer until (possible) new metadata // If non-zero, remaining length of buffer until (possible) new metadata
size_t metadata; size_t metadata;
@ -104,6 +106,17 @@ flags_set(size_t len)
{ {
short flags = 0; short flags = 0;
if (input_buffer.error)
{
if (len >= input_buffer.error)
{
flags |= INPUT_FLAG_ERROR;
input_buffer.error = 0;
}
else
input_buffer.error -= len;
}
if (input_buffer.eof) if (input_buffer.eof)
{ {
if (len >= input_buffer.eof) if (len >= input_buffer.eof)
@ -187,22 +200,25 @@ source_check_and_map(struct player_source *ps, const char *action, char check_se
/* ----------------------------- PLAYBACK LOOP ---------------------------- */ /* ----------------------------- PLAYBACK LOOP ---------------------------- */
/* Thread: input */ /* Thread: input */
// TODO Thread safety of ps? Do we need the return of the loop? // TODO Thread safety of ps?
static void * static void *
playback(void *arg) playback(void *arg)
{ {
struct player_source *ps = arg; struct player_source *ps = arg;
int type; int type;
int ret;
type = source_check_and_map(ps, "start", 1); type = source_check_and_map(ps, "start", 1);
if ((type < 0) || (inputs[type]->disabled)) if ((type < 0) || (inputs[type]->disabled))
goto thread_exit; goto thread_exit;
// Loops until input_loop_break is set or no more input, e.g. EOF // Loops until input_loop_break is set or no more input, e.g. EOF
inputs[type]->start(ps); ret = inputs[type]->start(ps);
if (ret < 0)
input_write(NULL, INPUT_FLAG_ERROR);
#ifdef DEBUG #ifdef DEBUG
DPRINTF(E_DBG, L_PLAYER, "Playback loop stopped (break is %d)\n", input_loop_break); DPRINTF(E_DBG, L_PLAYER, "Playback loop stopped (break is %d, ret %d)\n", input_loop_break, ret);
#endif #endif
thread_exit: thread_exit:
@ -231,7 +247,7 @@ input_write(struct evbuffer *evbuf, short flags)
pthread_mutex_lock(&input_buffer.mutex); pthread_mutex_lock(&input_buffer.mutex);
while ( (!input_loop_break) && (evbuffer_get_length(input_buffer.evbuf) > INPUT_BUFFER_THRESHOLD) ) while ( (!input_loop_break) && (evbuffer_get_length(input_buffer.evbuf) > INPUT_BUFFER_THRESHOLD) && evbuf )
{ {
if (input_buffer.full_cb) if (input_buffer.full_cb)
{ {
@ -249,19 +265,26 @@ input_write(struct evbuffer *evbuf, short flags)
pthread_cond_timedwait(&input_buffer.cond, &input_buffer.mutex, &ts); pthread_cond_timedwait(&input_buffer.cond, &input_buffer.mutex, &ts);
} }
if (!input_loop_break) if (input_loop_break)
{ {
pthread_mutex_unlock(&input_buffer.mutex);
return 0;
}
if (evbuf)
ret = evbuffer_add_buffer(input_buffer.evbuf, evbuf); ret = evbuffer_add_buffer(input_buffer.evbuf, evbuf);
else
ret = 0;
if (ret < 0) if (ret < 0)
DPRINTF(E_LOG, L_PLAYER, "Error adding stream data to input buffer\n"); DPRINTF(E_LOG, L_PLAYER, "Error adding stream data to input buffer\n");
if (!input_buffer.error && (flags & INPUT_FLAG_ERROR))
input_buffer.error = evbuffer_get_length(input_buffer.evbuf);
if (!input_buffer.eof && (flags & INPUT_FLAG_EOF)) if (!input_buffer.eof && (flags & INPUT_FLAG_EOF))
input_buffer.eof = evbuffer_get_length(input_buffer.evbuf); input_buffer.eof = evbuffer_get_length(input_buffer.evbuf);
if (!input_buffer.metadata && (flags & INPUT_FLAG_METADATA)) if (!input_buffer.metadata && (flags & INPUT_FLAG_METADATA))
input_buffer.metadata = evbuffer_get_length(input_buffer.evbuf); input_buffer.metadata = evbuffer_get_length(input_buffer.evbuf);
}
else
ret = 0;
pthread_mutex_unlock(&input_buffer.mutex); pthread_mutex_unlock(&input_buffer.mutex);
@ -452,6 +475,7 @@ input_flush(short *flags)
*flags = flags_set(len); *flags = flags_set(len);
input_buffer.error = 0;
input_buffer.eof = 0; input_buffer.eof = 0;
input_buffer.metadata = 0; input_buffer.metadata = 0;
input_buffer.full_cb = NULL; input_buffer.full_cb = NULL;

View File

@ -25,8 +25,10 @@ enum input_flags
INPUT_FLAG_NONBLOCK = (1 << 0), INPUT_FLAG_NONBLOCK = (1 << 0),
// Flags end of file // Flags end of file
INPUT_FLAG_EOF = (1 << 1), INPUT_FLAG_EOF = (1 << 1),
// Flags error reading file
INPUT_FLAG_ERROR = (1 << 2),
// Flags possible new stream metadata // Flags possible new stream metadata
INPUT_FLAG_METADATA = (1 << 2), INPUT_FLAG_METADATA = (1 << 3),
}; };
struct player_source struct player_source
@ -164,7 +166,7 @@ input_wait(void);
* *
* @in data Output buffer * @in data Output buffer
* @in size How much data to move to the output buffer * @in size How much data to move to the output buffer
* @out flags Flags INPUT_FLAG_EOF or INPUT_FLAG_METADATA * @out flags Flags INPUT_FLAG_*
* @return Number of bytes moved, -1 on error * @return Number of bytes moved, -1 on error
*/ */
int int

View File

@ -1058,7 +1058,7 @@ source_read(uint8_t *buf, int len)
} }
nbytes = input_read(buf, len, &flags); nbytes = input_read(buf, len, &flags);
if (nbytes < 0) if ((nbytes < 0) || (flags & INPUT_FLAG_ERROR))
{ {
DPRINTF(E_LOG, L_PLAYER, "Error reading source %d\n", cur_streaming->id); DPRINTF(E_LOG, L_PLAYER, "Error reading source %d\n", cur_streaming->id);