vlc | branch: master | Avishay Spitzer <[email protected]> | Mon Aug 19 03:08:33 2013 -0400| [50d7d0c9c470ccec4d48212221aaecd822928c96] | committer: Ilkka Ollakka
Bug fix: HLS module does not block until data is available. As a result live streams may end unexpectedly in case of short playlists or slow connections. Problem was fixed by blocking on a condition variable in the "read" function in case data is not available until Download thread signals (when new data is available) or a timeout of 10 seconds is reached. Blocking is done with a timed wait in order to avoid deadlocks since the thread that calls read is also responsible for calling close. Signed-off-by: Ilkka Ollakka <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=50d7d0c9c470ccec4d48212221aaecd822928c96 --- modules/stream_filter/httplive.c | 74 ++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 6 deletions(-) diff --git a/modules/stream_filter/httplive.c b/modules/stream_filter/httplive.c index cc1c0b7..6577a81 100644 --- a/modules/stream_filter/httplive.c +++ b/modules/stream_filter/httplive.c @@ -135,6 +135,12 @@ struct stream_sys_t int tries; /* times it was not changed */ } playlist; + struct hls_read_s + { + vlc_mutex_t lock_wait; /* used by read condition variable */ + vlc_cond_t wait; /* some condition to wait on during read */ + } read; + /* state */ bool b_cache; /* can cache files */ bool b_meta; /* meta playlist */ @@ -1672,6 +1678,11 @@ static void* hls_Thread(void *p_this) p_sys->download.segment++; vlc_cond_signal(&p_sys->download.wait); vlc_mutex_unlock(&p_sys->download.lock_wait); + + // In case of a successful download signal the read thread that data is available + vlc_mutex_lock(&p_sys->read.lock_wait); + vlc_cond_signal(&p_sys->read.wait); + vlc_mutex_unlock(&p_sys->read.lock_wait); } vlc_restorecancel(canc); @@ -2029,6 +2040,9 @@ static int Open(vlc_object_t *p_this) vlc_mutex_init(&p_sys->download.lock_wait); vlc_cond_init(&p_sys->download.wait); + vlc_mutex_init(&p_sys->read.lock_wait); + vlc_cond_init(&p_sys->read.wait); + /* Initialize HLS live stream */ if (p_sys->b_live) { @@ -2056,6 +2070,9 @@ fail_thread: vlc_mutex_destroy(&p_sys->download.lock_wait); vlc_cond_destroy(&p_sys->download.wait); + vlc_mutex_destroy(&p_sys->read.lock_wait); + vlc_cond_destroy(&p_sys->read.wait); + fail: /* Free hls streams */ for (int i = 0; i < vlc_array_count(p_sys->hls_stream); i++) @@ -2096,6 +2113,9 @@ static void Close(vlc_object_t *p_this) vlc_mutex_destroy(&p_sys->download.lock_wait); vlc_cond_destroy(&p_sys->download.wait); + vlc_mutex_destroy(&p_sys->read.lock_wait); + vlc_cond_destroy(&p_sys->read.wait); + /* Free hls streams */ for (int i = 0; i < vlc_array_count(p_sys->hls_stream); i++) { @@ -2284,13 +2304,55 @@ static int Read(stream_t *s, void *buffer, unsigned int i_read) assert(p_sys->hls_stream); - if (p_sys->b_error) - return 0; + while (length == 0) + { + // In case an error occurred or the stream was closed return 0 + if (p_sys->b_error || !vlc_object_alive(s)) + return 0; - /* NOTE: buffer might be NULL if caller wants to skip data */ - length = hls_Read(s, (uint8_t*) buffer, i_read); - if (length < 0) - return 0; + // Lock the mutex before trying to read to avoid a race condition with the download thread + vlc_mutex_lock(&p_sys->read.lock_wait); + + /* NOTE: buffer might be NULL if caller wants to skip data */ + length = hls_Read(s, (uint8_t*) buffer, i_read); + + // An error has occurred in hls_Read + if (length < 0) + { + vlc_mutex_unlock(&p_sys->read.lock_wait); + + return 0; + } + + // There is no data available yet for the demuxer so we need to wait until reload and + // download operation are over. + // Download thread will signal once download is finished. + // A timed wait is used to avoid deadlock in case data never arrives since the thread + // running this read operation is also responsible for closing the stream + if (length == 0) + { + mtime_t start = mdate(); + + // Wait for 10 seconds + mtime_t timeout_limit = start + (10 * UINT64_C(1000000)); + + int res = vlc_cond_timedwait(&p_sys->read.wait, &p_sys->read.lock_wait, timeout_limit); + + // Error - reached a timeout of 10 seconds without data arriving - kill the stream + if (res == ETIMEDOUT) + { + msg_Info(s, "timeout limit reached!"); + + vlc_mutex_unlock(&p_sys->read.lock_wait); + + return 0; + } + else if (res == EINVAL) + return 0; // Error - lock is not locked so we can just return + } + + vlc_mutex_unlock(&p_sys->read.lock_wait); + } p_sys->playback.offset += length; return length; _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
