]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
mpegts: fix the idle scan (use another idle scan queue - fixes #5548)
authorJaroslav Kysela <perex@perex.cz>
Sat, 2 Mar 2019 20:26:18 +0000 (21:26 +0100)
committerJaroslav Kysela <perex@perex.cz>
Sat, 2 Mar 2019 20:27:40 +0000 (21:27 +0100)
src/input/mpegts.h
src/input/mpegts/mpegts_mux.c
src/input/mpegts/mpegts_network.c
src/input/mpegts/mpegts_network_scan.c

index 51863f1ca9ef9598ac76d518d601e8543f711bec..9636dbaa55071ab1879f63f94a6c6c96d148532f 100644 (file)
@@ -343,6 +343,7 @@ struct mpegts_network
    * Scanning
    */
   mpegts_mux_queue_t mn_scan_pend;    // Pending muxes
+  mpegts_mux_queue_t mn_scan_ipend;   // Pending muxes (idle)
   mpegts_mux_queue_t mn_scan_active;  // Active muxes
   mtimer_t           mn_scan_timer;   // Timer for activity
   mtimer_t           mn_bouquet_timer;
@@ -385,6 +386,7 @@ typedef enum mpegts_mux_scan_state
 {
   MM_SCAN_STATE_IDLE,     // Nothing
   MM_SCAN_STATE_PEND,     // Queue'd pending scan
+  MM_SCAN_STATE_IPEND,    // Queue'd pending scan - idle queue
   MM_SCAN_STATE_ACTIVE,   // Scan is active
 } mpegts_mux_scan_state_t;
 
index c34d8013e802eeb4e3386803cf925a2ecac3e2c8..92dfe22fab893824c2349b137ba010e5ca4567f0 100644 (file)
@@ -94,7 +94,8 @@ mpegts_mux_scan_active
   int t;
 
   /* Setup scan */
-  if (mm->mm_scan_state == MM_SCAN_STATE_PEND) {
+  if (mm->mm_scan_state == MM_SCAN_STATE_PEND ||
+      mm->mm_scan_state == MM_SCAN_STATE_IPEND) {
     mpegts_network_scan_mux_active(mm);
 
     /* Get timeout */
@@ -391,9 +392,10 @@ mpegts_mux_class_get_name ( void *ptr )
 
 static struct strtab
 scan_state_tab[] = {
-  { N_("IDLE"),   MM_SCAN_STATE_IDLE },
-  { N_("PEND"),   MM_SCAN_STATE_PEND },
-  { N_("ACTIVE"), MM_SCAN_STATE_ACTIVE },
+  { N_("IDLE"),        MM_SCAN_STATE_IDLE },
+  { N_("PEND"),        MM_SCAN_STATE_PEND },
+  { N_("IDLE PEND"),   MM_SCAN_STATE_IPEND },
+  { N_("ACTIVE"),      MM_SCAN_STATE_ACTIVE },
 };
 
 static struct strtab
@@ -416,7 +418,9 @@ mpegts_mux_class_scan_state_set ( void *o, const void *p )
     return 0;
   
   /* Start */
-  if (state == MM_SCAN_STATE_PEND || state == MM_SCAN_STATE_ACTIVE) {
+  if (state == MM_SCAN_STATE_PEND ||
+      state == MM_SCAN_STATE_IPEND ||
+      state == MM_SCAN_STATE_ACTIVE) {
 
     /* Start (only if required) */
     mpegts_network_scan_queue_add(mm, SUBSCRIPTION_PRIO_SCAN_USER,
index ab1c4ba3bad9fd3100efcfbe2c4b5121c328bd90..701bad77935e1b454c3aa9f42d560d0bdbd3e3a7 100644 (file)
@@ -558,6 +558,7 @@ mpegts_network_create0
 
   /* Initialise scanning */
   TAILQ_INIT(&mn->mn_scan_pend);
+  TAILQ_INIT(&mn->mn_scan_ipend);
   TAILQ_INIT(&mn->mn_scan_active);
   mtimer_arm_rel(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, 0);
 
index 7a65885db33c2820b54e03bf53bdd5f2475a2673..5a6e2cfd9b1a75076d49bd785f37916ea86aacbe 100644 (file)
@@ -31,6 +31,12 @@ mpegts_network_scan_notify ( mpegts_mux_t *mm )
   idnode_notify_changed(&mm->mm_network->mn_id);
 }
 
+/*
+ * rules:
+ *   1) prefer weight
+ *   2) prefer muxes with the newer timestamp (scan interrupted?)
+ *   3) do standard mux sorting
+ */
 static int
 mm_cmp ( mpegts_mux_t *a, mpegts_mux_t *b )
 {
@@ -44,53 +50,105 @@ mm_cmp ( mpegts_mux_t *a, mpegts_mux_t *b )
   return r;
 }
 
+/*
+ * rules:
+ *   1) prefer weight
+ *   2) prefer muxes with the oldest timestamp
+ *   3) do standard mux sorting
+ */
+static int
+mm_cmp_idle ( mpegts_mux_t *a, mpegts_mux_t *b )
+{
+  int r = b->mm_scan_weight - a->mm_scan_weight;
+  if (r == 0) {
+    int64_t l = a->mm_start_monoclock - b->mm_start_monoclock;
+    if (l == 0)
+      return mpegts_mux_compare(a, b);
+    r = l > 0 ? 1 : -1;
+  }
+  return r;
+}
+
+static void
+mpegts_network_scan_queue_del0 ( mpegts_mux_t *mm )
+{
+  mpegts_network_t *mn = mm->mm_network;
+  if (mm->mm_scan_state == MM_SCAN_STATE_ACTIVE) {
+    TAILQ_REMOVE(&mn->mn_scan_active, mm, mm_scan_link);
+  } else if (mm->mm_scan_state == MM_SCAN_STATE_PEND) {
+    TAILQ_REMOVE(&mn->mn_scan_pend, mm, mm_scan_link);
+  } else if (mm->mm_scan_state == MM_SCAN_STATE_IPEND) {
+    TAILQ_REMOVE(&mn->mn_scan_ipend, mm, mm_scan_link);
+  }
+}
+
+static int
+mpegts_network_scan_do_mux ( mpegts_mux_queue_t *q, mpegts_mux_t *mm )
+{
+  int r, state = mm->mm_scan_state;
+
+  assert(state == MM_SCAN_STATE_PEND ||
+         state == MM_SCAN_STATE_IPEND ||
+         state == MM_SCAN_STATE_ACTIVE);
+
+  /* Don't try to subscribe already tuned muxes */
+  if (mm->mm_active) return 0;
+
+  /* Attempt to tune */
+  r = mpegts_mux_subscribe(mm, NULL, "scan", mm->mm_scan_weight,
+                           mm->mm_scan_flags |
+                           SUBSCRIPTION_ONESHOT |
+                           SUBSCRIPTION_TABLES);
+
+  /* Started */
+  state = mm->mm_scan_state;
+  if (!r) {
+    assert(state == MM_SCAN_STATE_ACTIVE);
+    return 0;
+  }
+  assert(state == MM_SCAN_STATE_PEND ||
+         state == MM_SCAN_STATE_IPEND);
+
+  /* No free tuners - stop */
+  if (r == SM_CODE_NO_FREE_ADAPTER || r == SM_CODE_NO_ADAPTERS)
+    return -1;
+
+  /* No valid tuners (subtly different, might be able to tuner a later
+   * mux)
+   */
+  if (r == SM_CODE_NO_VALID_ADAPTER && mm->mm_is_enabled(mm))
+    return 0;
+
+  /* Failed */
+  TAILQ_REMOVE(q, mm, mm_scan_link);
+  if (mm->mm_scan_result != MM_SCAN_FAIL) {
+    mm->mm_scan_result = MM_SCAN_FAIL;
+    idnode_changed(&mm->mm_id);
+  }
+  mm->mm_scan_state  = MM_SCAN_STATE_IDLE;
+  mm->mm_scan_weight = 0;
+  mpegts_network_scan_notify(mm);
+  return 0;
+}
+
 void
 mpegts_network_scan_timer_cb ( void *p )
 {
   mpegts_network_t *mn = p;
   mpegts_mux_t *mm, *nxt = NULL;
-  int r;
 
-  /* Process Q */
+  /* Process standard Q */
   for (mm = TAILQ_FIRST(&mn->mn_scan_pend); mm != NULL; mm = nxt) {
     nxt = TAILQ_NEXT(mm, mm_scan_link);
-    assert(mm->mm_scan_state == MM_SCAN_STATE_PEND || mm->mm_scan_state == MM_SCAN_STATE_ACTIVE);
-
-    /* Don't try to subscribe already tuned muxes */
-    if (mm->mm_active) continue;
-
-    /* Attempt to tune */
-    r = mpegts_mux_subscribe(mm, NULL, "scan", mm->mm_scan_weight,
-                             mm->mm_scan_flags |
-                             SUBSCRIPTION_ONESHOT |
-                             SUBSCRIPTION_TABLES);
-
-    /* Started */
-    if (!r) {
-      assert(mm->mm_scan_state == MM_SCAN_STATE_ACTIVE);
-      continue;
-    }
-    assert(mm->mm_scan_state == MM_SCAN_STATE_PEND);
-
-    /* No free tuners - stop */
-    if (r == SM_CODE_NO_FREE_ADAPTER || r == SM_CODE_NO_ADAPTERS)
+    if (mpegts_network_scan_do_mux(&mn->mn_scan_pend, mm))
       break;
+  }
 
-    /* No valid tuners (subtly different, might be able to tuner a later
-     * mux)
-     */
-    if (r == SM_CODE_NO_VALID_ADAPTER && mm->mm_is_enabled(mm))
-      continue;
-
-    /* Failed */
-    TAILQ_REMOVE(&mn->mn_scan_pend, mm, mm_scan_link);
-    if (mm->mm_scan_result != MM_SCAN_FAIL) {
-      mm->mm_scan_result = MM_SCAN_FAIL;
-      idnode_changed(&mm->mm_id);
-    }
-    mm->mm_scan_state  = MM_SCAN_STATE_IDLE;
-    mm->mm_scan_weight = 0;
-    mpegts_network_scan_notify(mm);
+  /* Process idle Q */
+  for (mm = TAILQ_FIRST(&mn->mn_scan_ipend); mm != NULL; mm = nxt) {
+    nxt = TAILQ_NEXT(mm, mm_scan_link);
+    if (mpegts_network_scan_do_mux(&mn->mn_scan_ipend, mm))
+      break;
   }
 
   /* Re-arm timer. Really this is just a safety measure as we'd normally
@@ -103,6 +161,25 @@ mpegts_network_scan_timer_cb ( void *p )
  * Mux transition
  *****************************************************************************/
 
+static void
+mpegts_network_scan_mux_add ( mpegts_network_t *mn, mpegts_mux_t *mm )
+{
+  TAILQ_INSERT_SORTED_R(&mn->mn_scan_ipend, mpegts_mux_queue, mm,
+                        mm_scan_link, mm_cmp);
+  mtimer_arm_rel(&mn->mn_scan_timer, mpegts_network_scan_timer_cb,
+                 mn, sec2mono(10));
+}
+
+static void
+mpegts_network_scan_idle_mux_add ( mpegts_network_t *mn, mpegts_mux_t *mm )
+{
+  mm->mm_scan_weight = SUBSCRIPTION_PRIO_SCAN_IDLE;
+  TAILQ_INSERT_SORTED_R(&mn->mn_scan_ipend, mpegts_mux_queue, mm,
+                        mm_scan_link, mm_cmp_idle);
+  mtimer_arm_rel(&mn->mn_scan_timer, mpegts_network_scan_timer_cb,
+                 mn, sec2mono(10));
+}
+
 /* Finished */
 static inline void
 mpegts_network_scan_mux_done0
@@ -124,20 +201,19 @@ mpegts_network_scan_mux_done0
   mpegts_mux_unsubscribe_by_name(mm, "scan");
   mm->mm_scan_state = state;
 
-  if (state == MM_SCAN_STATE_PEND) {
+  if (state == MM_SCAN_STATE_PEND || state == MM_SCAN_STATE_IPEND) {
     if (weight || mn->mn_idlescan) {
-      if (!weight)
-        mm->mm_scan_weight = SUBSCRIPTION_PRIO_SCAN_IDLE;
-      TAILQ_REMOVE(&mn->mn_scan_pend, mm, mm_scan_link);
-      TAILQ_INSERT_SORTED_R(&mn->mn_scan_pend, mpegts_mux_queue,
-                            mm, mm_scan_link, mm_cmp);
-      mtimer_arm_rel(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, sec2mono(10));
+      mpegts_network_scan_queue_del0(mm);
+      if (weight == 0 || weight == SUBSCRIPTION_PRIO_SCAN_IDLE)
+        mpegts_network_scan_idle_mux_add(mn, mm);
+      else
+        mpegts_network_scan_mux_add(mn, mm);
       weight = 0;
     } else {
       mpegts_network_scan_queue_del(mm);
     }
   } else {
-    if (!weight && mn->mn_idlescan)
+    if (weight == 0 && mn->mn_idlescan)
       weight = SUBSCRIPTION_PRIO_SCAN_IDLE;
     mpegts_network_scan_queue_del(mm);
   }
@@ -154,14 +230,14 @@ mpegts_network_scan_mux_done0
 
 /* Failed - couldn't start */
 void
-mpegts_network_scan_mux_fail    ( mpegts_mux_t *mm )
+mpegts_network_scan_mux_fail ( mpegts_mux_t *mm )
 {
   mpegts_network_scan_mux_done0(mm, MM_SCAN_FAIL, 0);
 }
 
 /* Completed succesfully */
 void
-mpegts_network_scan_mux_done    ( mpegts_mux_t *mm )
+mpegts_network_scan_mux_done ( mpegts_mux_t *mm )
 {
   mm->mm_scan_flags = 0;
   mpegts_network_scan_mux_done0(mm, MM_SCAN_OK, 0);
@@ -176,7 +252,7 @@ mpegts_network_scan_mux_partial ( mpegts_mux_t *mm )
 
 /* Interrupted (re-add) */
 void
-mpegts_network_scan_mux_cancel  ( mpegts_mux_t *mm, int reinsert )
+mpegts_network_scan_mux_cancel ( mpegts_mux_t *mm, int reinsert )
 {
   if (reinsert) {
     if (mm->mm_scan_state != MM_SCAN_STATE_ACTIVE)
@@ -196,11 +272,12 @@ void
 mpegts_network_scan_mux_active ( mpegts_mux_t *mm )
 {
   mpegts_network_t *mn = mm->mm_network;
-  if (mm->mm_scan_state != MM_SCAN_STATE_PEND)
+  if (mm->mm_scan_state != MM_SCAN_STATE_PEND &&
+      mm->mm_scan_state != MM_SCAN_STATE_IPEND)
     return;
+  mpegts_network_scan_queue_del0(mm);
   mm->mm_scan_state = MM_SCAN_STATE_ACTIVE;
   mm->mm_scan_init  = 0;
-  TAILQ_REMOVE(&mn->mn_scan_pend, mm, mm_scan_link);
   TAILQ_INSERT_TAIL(&mn->mn_scan_active, mm, mm_scan_link);
 }
 
@@ -211,8 +288,7 @@ mpegts_network_scan_mux_reactivate ( mpegts_mux_t *mm )
   mpegts_network_t *mn = mm->mm_network;
   if (mm->mm_scan_state == MM_SCAN_STATE_ACTIVE)
     return;
-  if (mm->mm_scan_state == MM_SCAN_STATE_PEND)
-    TAILQ_REMOVE(&mn->mn_scan_pend, mm, mm_scan_link);
+  mpegts_network_scan_queue_del0(mm);
   mm->mm_scan_init  = 0;
   mm->mm_scan_state = MM_SCAN_STATE_ACTIVE;
   TAILQ_INSERT_TAIL(&mn->mn_scan_active, mm, mm_scan_link);
@@ -226,12 +302,8 @@ void
 mpegts_network_scan_queue_del ( mpegts_mux_t *mm )
 {
   mpegts_network_t *mn = mm->mm_network;
-  if (mm->mm_scan_state == MM_SCAN_STATE_ACTIVE) {
-    TAILQ_REMOVE(&mn->mn_scan_active, mm, mm_scan_link);
-  } else if (mm->mm_scan_state == MM_SCAN_STATE_PEND) {
-    TAILQ_REMOVE(&mn->mn_scan_pend, mm, mm_scan_link);
-  }
   tvhdebug(LS_MPEGTS, "removing mux %s from scan queue", mm->mm_nicename);
+  mpegts_network_scan_queue_del0(mm);
   mm->mm_scan_state  = MM_SCAN_STATE_IDLE;
   mm->mm_scan_weight = 0;
   mtimer_disarm(&mm->mm_scan_timeout);
@@ -243,7 +315,7 @@ void
 mpegts_network_scan_queue_add
   ( mpegts_mux_t *mm, int weight, int flags, int delay )
 {
-  int reload = 0;
+  int requeue = 0;
   mpegts_network_t *mn = mm->mm_network;
 
   if (!mm->mm_is_enabled(mm)) return;
@@ -252,7 +324,7 @@ mpegts_network_scan_queue_add
 
   if (weight > mm->mm_scan_weight) {
     mm->mm_scan_weight = weight;
-    reload             = 1;
+    requeue = 1;
   }
 
   /* Already active */
@@ -260,22 +332,29 @@ mpegts_network_scan_queue_add
     return;
 
   /* Remove entry (or ignore) */
-  if (mm->mm_scan_state == MM_SCAN_STATE_PEND) {
-    if (!reload)
+  if (mm->mm_scan_state == MM_SCAN_STATE_PEND ||
+      mm->mm_scan_state == MM_SCAN_STATE_IPEND) {
+    if (!requeue)
       return;
-    TAILQ_REMOVE(&mn->mn_scan_pend, mm, mm_scan_link);
+    mpegts_network_scan_queue_del0(mm);
   }
 
   tvhdebug(LS_MPEGTS, "adding mux %s to scan queue weight %d flags %04X",
                       mm->mm_nicename, weight, flags);
 
   /* Add new entry */
-  mm->mm_scan_state  = MM_SCAN_STATE_PEND;
   mm->mm_scan_flags |= flags;
   if (mm->mm_scan_flags == 0)
     mm->mm_scan_flags = SUBSCRIPTION_IDLESCAN;
-  TAILQ_INSERT_SORTED_R(&mn->mn_scan_pend, mpegts_mux_queue,
-                        mm, mm_scan_link, mm_cmp);
+  if (weight == SUBSCRIPTION_PRIO_SCAN_IDLE) {
+    mm->mm_scan_state  = MM_SCAN_STATE_IPEND;
+    TAILQ_INSERT_SORTED_R(&mn->mn_scan_ipend, mpegts_mux_queue,
+                          mm, mm_scan_link, mm_cmp_idle);
+  } else {
+    mm->mm_scan_state  = MM_SCAN_STATE_PEND;
+    TAILQ_INSERT_SORTED_R(&mn->mn_scan_pend, mpegts_mux_queue,
+                          mm, mm_scan_link, mm_cmp);
+  }
   mtimer_arm_rel(&mn->mn_scan_timer, mpegts_network_scan_timer_cb, mn, sec2mono(delay));
   mpegts_network_scan_notify(mm);
 }