hlsdemux: Propagate download errors properly and post error messages if they're fatal
authorSebastian Dröge <sebastian@centricular.com>
Tue, 11 Feb 2014 13:57:16 +0000 (14:57 +0100)
committerSebastian Dröge <sebastian@centricular.com>
Tue, 11 Feb 2014 13:57:16 +0000 (14:57 +0100)
ext/hls/gsthlsdemux.c

index d53fb90..bc8a877 100644 (file)
@@ -108,9 +108,9 @@ static gboolean gst_hls_demux_cache_fragments (GstHLSDemux * demux);
 static gboolean gst_hls_demux_schedule (GstHLSDemux * demux);
 static gboolean gst_hls_demux_switch_playlist (GstHLSDemux * demux);
 static gboolean gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
-    gboolean caching);
+    gboolean caching, GError ** err);
 static gboolean gst_hls_demux_update_playlist (GstHLSDemux * demux,
-    gboolean update);
+    gboolean update, GError ** err);
 static void gst_hls_demux_reset (GstHLSDemux * demux, gboolean dispose);
 static gboolean gst_hls_demux_set_location (GstHLSDemux * demux,
     const gchar * uri);
@@ -883,8 +883,10 @@ gst_hls_demux_updates_loop (GstHLSDemux * demux)
 
     /* fetch the next fragment */
     if (g_queue_get_length (demux->queue) < demux->fragments_cache) {
+      GError *err = NULL;
+
       GST_DEBUG_OBJECT (demux, "queue not full, get next fragment");
-      if (!gst_hls_demux_get_next_fragment (demux, FALSE)) {
+      if (!gst_hls_demux_get_next_fragment (demux, FALSE, &err)) {
         if (demux->cancelled) {
           goto quit;
         } else if (!demux->end_of_playlist) {
@@ -893,8 +895,10 @@ gst_hls_demux_updates_loop (GstHLSDemux * demux)
             GST_WARNING_OBJECT (demux, "Could not fetch the next fragment");
             continue;
           } else {
-            GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND,
-                ("Could not fetch the next fragment"), (NULL));
+            gst_element_post_message (GST_ELEMENT_CAST (demux),
+                gst_message_new_error (GST_OBJECT_CAST (demux), err,
+                    "Could not fetch the next fragment"));
+            g_error_free (err);
             goto error;
           }
         }
@@ -926,7 +930,9 @@ gst_hls_demux_updates_loop (GstHLSDemux * demux)
 
     /* update the playlist for live sources */
     if (gst_m3u8_client_is_live (demux->client)) {
-      if (!gst_hls_demux_update_playlist (demux, TRUE)) {
+      GError *err = NULL;
+
+      if (!gst_hls_demux_update_playlist (demux, TRUE, &err)) {
         if (demux->cancelled)
           goto quit;
         demux->client->update_failed_count++;
@@ -934,8 +940,10 @@ gst_hls_demux_updates_loop (GstHLSDemux * demux)
           GST_WARNING_OBJECT (demux, "Could not update the playlist");
           continue;
         } else {
-          GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND,
-              ("Could not update the playlist"), (NULL));
+          gst_element_post_message (GST_ELEMENT_CAST (demux),
+              gst_message_new_error (GST_OBJECT_CAST (demux), err,
+                  "Could not update the playlist"));
+          g_error_free (err);
           goto error;
         }
       }
@@ -980,6 +988,7 @@ gst_hls_demux_cache_fragments (GstHLSDemux * demux)
    * and update it */
   if (gst_m3u8_client_has_variant_playlist (demux->client)) {
     GstM3U8 *child = NULL;
+    GError *err = NULL;
 
     if (demux->connection_speed == 0) {
 
@@ -994,9 +1003,11 @@ gst_hls_demux_cache_fragments (GstHLSDemux * demux)
     }
 
     gst_m3u8_client_set_current (demux->client, child);
-    if (!gst_hls_demux_update_playlist (demux, FALSE)) {
-      GST_ERROR_OBJECT (demux, "Could not fetch the child playlist %s",
-          child->uri);
+    if (!gst_hls_demux_update_playlist (demux, FALSE, &err)) {
+      gst_element_post_message (GST_ELEMENT_CAST (demux),
+          gst_message_new_error (GST_OBJECT_CAST (demux), err,
+              "Could not fetch the child playlist"));
+      g_error_free (err);
       return FALSE;
     }
   }
@@ -1013,15 +1024,21 @@ gst_hls_demux_cache_fragments (GstHLSDemux * demux)
 
   /* Cache the first fragments */
   for (i = 0; i < demux->fragments_cache; i++) {
+    GError *err = NULL;
+
     gst_element_post_message (GST_ELEMENT (demux),
         gst_message_new_buffering (GST_OBJECT (demux),
             100 * i / demux->fragments_cache));
     demux->next_update = g_get_monotonic_time ();
-    if (!gst_hls_demux_get_next_fragment (demux, TRUE)) {
+    if (!gst_hls_demux_get_next_fragment (demux, TRUE, &err)) {
       if (demux->end_of_playlist)
         break;
-      if (!demux->cancelled)
-        GST_ERROR_OBJECT (demux, "Error caching the first fragments");
+      if (!demux->cancelled) {
+        gst_element_post_message (GST_ELEMENT_CAST (demux),
+            gst_message_new_error (GST_OBJECT_CAST (demux), err,
+                "Error caching the first fragments"));
+        g_error_free (err);
+      }
       return FALSE;
     }
     /* make sure we stop caching fragments if something cancelled it */
@@ -1068,7 +1085,8 @@ map_error:
 }
 
 static gboolean
-gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update)
+gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update,
+    GError ** err)
 {
   GstFragment *download;
   GstBuffer *buf;
@@ -1077,8 +1095,7 @@ gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update)
 
   const gchar *uri = gst_m3u8_client_get_current_uri (demux->client);
 
-  download = gst_uri_downloader_fetch_uri (demux->downloader, uri, NULL);
-
+  download = gst_uri_downloader_fetch_uri (demux->downloader, uri, err);
   if (download == NULL)
     return FALSE;
 
@@ -1087,11 +1104,19 @@ gst_hls_demux_update_playlist (GstHLSDemux * demux, gboolean update)
   g_object_unref (download);
 
   if (playlist == NULL) {
-    GST_WARNING_OBJECT (demux, "Couldn't not validate playlist encoding");
+    GST_WARNING_OBJECT (demux, "Couldn't validate playlist encoding");
+    g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
+        "Couldn't validate playlist encoding");
     return FALSE;
   }
 
   updated = gst_m3u8_client_update (demux->client, playlist);
+  if (!updated) {
+    GST_WARNING_OBJECT (demux, "Couldn't update playlist");
+    g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_FAILED,
+        "Couldn't update playlist");
+    return FALSE;
+  }
 
   /*  If it's a live source, do not let the sequence number go beyond
    * three fragments before the end of the list */
@@ -1148,7 +1173,7 @@ retry_failover_protection:
   GST_INFO_OBJECT (demux, "Client was on %dbps, max allowed is %dbps, switching"
       " to bitrate %dbps", old_bandwidth, max_bitrate, new_bandwidth);
 
-  if (gst_hls_demux_update_playlist (demux, FALSE)) {
+  if (gst_hls_demux_update_playlist (demux, FALSE, NULL)) {
     GstStructure *s;
 
     s = gst_structure_new ("playlist",
@@ -1299,7 +1324,8 @@ out:
 
 static GstFragment *
 gst_hls_demux_decrypt_fragment (GstHLSDemux * demux,
-    GstFragment * encrypted_fragment, const gchar * key, const guint8 * iv)
+    GstFragment * encrypted_fragment, const gchar * key, const guint8 * iv,
+    GError ** err)
 {
   GstFragment *key_fragment, *ret = NULL;
   GstBuffer *key_buffer, *encrypted_buffer, *decrypted_buffer;
@@ -1307,7 +1333,7 @@ gst_hls_demux_decrypt_fragment (GstHLSDemux * demux,
   gsize unpadded_size;
 
   GST_INFO_OBJECT (demux, "Fetching key %s", key);
-  key_fragment = gst_uri_downloader_fetch_uri (demux->downloader, key, NULL);
+  key_fragment = gst_uri_downloader_fetch_uri (demux->downloader, key, err);
   if (key_fragment == NULL)
     goto key_failed;
 
@@ -1348,6 +1374,8 @@ key_failed:
 
 decrypt_error:
   GST_ERROR_OBJECT (demux, "Failed to decrypt fragment");
+  g_set_error (err, GST_STREAM_ERROR, GST_STREAM_ERROR_DECRYPT,
+      "Failed to decrypt fragment");
 
   gst_buffer_unref (key_buffer);
   gst_buffer_unref (encrypted_buffer);
@@ -1362,7 +1390,8 @@ decrypt_error:
 }
 
 static gboolean
-gst_hls_demux_get_next_fragment (GstHLSDemux * demux, gboolean caching)
+gst_hls_demux_get_next_fragment (GstHLSDemux * demux, gboolean caching,
+    GError ** err)
 {
   GstFragment *download;
   const gchar *next_fragment_uri;
@@ -1384,14 +1413,17 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux, gboolean caching)
   GST_INFO_OBJECT (demux, "Fetching next fragment %s", next_fragment_uri);
 
   download = gst_uri_downloader_fetch_uri (demux->downloader,
-      next_fragment_uri, NULL);
-
-  if (download && key)
-    download = gst_hls_demux_decrypt_fragment (demux, download, key, iv);
+      next_fragment_uri, err);
 
   if (download == NULL)
     goto error;
 
+  if (key) {
+    download = gst_hls_demux_decrypt_fragment (demux, download, key, iv, err);
+    if (download == NULL)
+      goto error;
+  }
+
   buf = gst_fragment_get_buffer (download);
 
   GST_BUFFER_DURATION (buf) = duration;