]> git.sesse.net Git - vlc/commitdiff
Bug fix: HLS module does not block until data is available. As a result live streams...
authorAvishay Spitzer <savishay@gmail.com>
Mon, 19 Aug 2013 07:08:33 +0000 (03:08 -0400)
committerIlkka Ollakka <ileoo@videolan.org>
Mon, 26 Aug 2013 13:39:49 +0000 (16:39 +0300)
Signed-off-by: Ilkka Ollakka <ileoo@videolan.org>
modules/stream_filter/httplive.c

index cc1c0b73d99ee3a7d2740cd9e41934e2ba73dd99..6577a81675fe57fe56a35b7a4245c8ea12287fe3 100644 (file)
@@ -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;