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

Reply via email to