From: Jaroslav Kysela Date: Sat, 2 Mar 2019 20:26:18 +0000 (+0100) Subject: mpegts: fix the idle scan (use another idle scan queue - fixes #5548) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=717030bca5b8087d073a40f45092bc1eb7fdb8bb;p=thirdparty%2Ftvheadend.git mpegts: fix the idle scan (use another idle scan queue - fixes #5548) --- diff --git a/src/input/mpegts.h b/src/input/mpegts.h index 51863f1ca..9636dbaa5 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -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; diff --git a/src/input/mpegts/mpegts_mux.c b/src/input/mpegts/mpegts_mux.c index c34d8013e..92dfe22fa 100644 --- a/src/input/mpegts/mpegts_mux.c +++ b/src/input/mpegts/mpegts_mux.c @@ -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, diff --git a/src/input/mpegts/mpegts_network.c b/src/input/mpegts/mpegts_network.c index ab1c4ba3b..701bad779 100644 --- a/src/input/mpegts/mpegts_network.c +++ b/src/input/mpegts/mpegts_network.c @@ -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); diff --git a/src/input/mpegts/mpegts_network_scan.c b/src/input/mpegts/mpegts_network_scan.c index 7a65885db..5a6e2cfd9 100644 --- a/src/input/mpegts/mpegts_network_scan.c +++ b/src/input/mpegts/mpegts_network_scan.c @@ -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); }