int tdmi_tune_failed; // Adapter failed to tune this frequency
// Don't try again
- int tdmi_weight;
-
struct th_subscription_list tdmi_subscriptions;
} th_dvb_mux_instance_t;
typedef struct th_dvb_adapter {
+ int tda_instance;
+
+
TAILQ_ENTRY(th_dvb_adapter) tda_global_link;
dvb_network_t *tda_dn;
void dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src);
-void dvb_adapter_clean(th_dvb_adapter_t *tda);
-
int dvb_adapter_destroy(th_dvb_adapter_t *tda);
void dvb_adapter_notify(th_dvb_adapter_t *tda);
uint16_t tsid, int enabled);
+void dvb_mux_stop(th_dvb_mux_instance_t *tdmi);
+
void dvb_mux_initial_scan_done(dvb_mux_t *dm);
-int dvb_fe_tune_tdmi(th_dvb_mux_instance_t *tdmi);
+int dvb_fe_tune_tdmi(th_dvb_mux_instance_t *tdmi, const char *reason);
+
+void dvb_create_tdmis(dvb_mux_t *dm);
+
+int tdmi_current_weight(const th_dvb_mux_instance_t *tdmi);
/**
struct th_dvb_adapter_queue dvb_adapters;
static void *dvb_adapter_input_dvr(void *aux);
-
+static int dvb_adapter_instance_generator;
/**
*
pthread_mutex_init(&tda->tda_delivery_mutex, NULL);
TAILQ_INIT(&tda->tda_satconfs);
streaming_pad_init(&tda->tda_streaming_pad);
+ tda->tda_instance = ++dvb_adapter_instance_generator;
return tda;
}
}
}
-#if 0
-/**
- * If nobody is subscribing, cycle thru all muxes to get some stats
- * and EIT updates
- */
-void
-dvb_adapter_mux_scanner(void *aux)
-{
- th_dvb_adapter_t *tda = aux;
- th_dvb_mux_instance_t *tdmi;
-
- if(tda->tda_rootpath == NULL)
- return; // No hardware
-
- // default period
- gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 20);
-
- /* No muxes */
- if(LIST_FIRST(&tda->tda_dn->dn_mux_instances) == NULL) {
- dvb_adapter_poweroff(tda);
- return;
- }
-
- /* Someone is actively using */
- if(service_compute_weight(&tda->tda_transports) > 0)
- return;
-
- if(tda->tda_mux_current != NULL &&
- LIST_FIRST(&tda->tda_mux_current->tdmi_subscriptions) != NULL)
- return; // Someone is doing full mux dump
-
- /* Check if we have muxes pending for quickscan, if so, choose them */
- if((tdmi = TAILQ_FIRST(&tda->tda_dn->dn_initial_scan_queue)) != NULL) {
- dvb_fe_tune(tdmi, "Initial autoscan");
- return;
- }
-
- /* Check EPG */
- if (tda->tda_dn->dn_mux_epg) {
- // timeout anything not complete
- epggrab_mux_stop(tda->tda_dn->dn_mux_epg, 1);
- tda->tda_dn->dn_mux_epg = NULL; // skip this time
- } else {
- tda->tda_dn->dn_mux_epg = epggrab_mux_next(tda);
- }
-
- /* EPG */
- if (tda->tda_dn->dn_mux_epg) {
- int period = epggrab_mux_period(tda->tda_dn->dn_mux_epg);
- if (period > 20)
- gtimer_arm(&tda->tda_mux_scanner_timer,
- dvb_adapter_mux_scanner, tda, period);
- dvb_fe_tune(tda->tda_dn->dn_mux_epg->dm_tdmi, "EPG scan");
- return;
-
- }
-
- /* Ensure we stop current mux and power off (if required) */
- if (tda->tda_mux_current)
- dvb_fe_stop(tda->tda_mux_current, 0);
-}
-#endif
-
-/**
- *
- */
-void
-dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src)
-{
-#if 0
- th_dvb_mux_instance_t *tdmi_src, *tdmi_dst;
-
- lock_assert(&global_lock);
-
- while((tdmi_dst = LIST_FIRST(&dst->tda_dn->dn_mux_instances)) != NULL)
- dvb_mux_destroy(tdmi_dst);
-
- tda_save(dst);
-#endif
- abort(); // XXX(dvbreorg)
-}
/**
#endif
-/**
- *
- */
-void
-dvb_adapter_clean(th_dvb_adapter_t *tda)
-{
- service_t *t;
-
- lock_assert(&global_lock);
-
- while((t = LIST_FIRST(&tda->tda_transports)) != NULL)
- /* Flush all subscribers */
- service_remove_subscriber(t, NULL, SM_CODE_SUBSCRIPTION_OVERRIDDEN);
-}
-
-
-
-
/**
*
*/
htsmsg_t *
dvb_adapter_build_msg(th_dvb_adapter_t *tda)
{
- char buf[100];
htsmsg_t *m = htsmsg_create_map();
int fdiv;
if(tda->tda_current_tdmi != NULL) {
th_dvb_mux_instance_t *tdmi = tda->tda_current_tdmi;
- dvb_mux_nicename(buf, sizeof(buf), tda->tda_current_tdmi->tdmi_mux);
- htsmsg_add_str(m, "currentMux", buf);
+ htsmsg_add_str(m, "currentMux",
+ dvb_mux_nicename(tda->tda_current_tdmi->tdmi_mux));
htsmsg_add_u32(m, "signal", MIN(tdmi->tdmi_signal * 100 / 65535, 100));
htsmsg_add_u32(m, "snr", tdmi->tdmi_snr);
}
-#if 0
-/**
- * Stop the given TDMI
- */
-void
-dvb_fe_stop(th_dvb_adapter_t *tda, int retune)
-{
- lock_assert(&global_lock);
-
- th_dvb_mux_instance_t *tdmi = tda->tda_current_tdmi;
- assert(tdmi != NULL);
- dvb_mux_t *dm = tdmi->tdmi_mux;
-
- dvb_table_flush_all(dm);
-
- epggrab_mux_stop(dm, 0);
-
-#if 0 /// XXX(dvbreorg)
- if(!retune) {
- gtimer_disarm(&tda->tda_fe_monitor_timer);
- dvb_adapter_stop(tda);
- }
-#endif
-}
-#endif
-
#if DVB_API_VERSION >= 5
+/**
+ *
+ */
int
-dvb_fe_tune_tdmi(th_dvb_mux_instance_t *tdmi)
+dvb_fe_tune_tdmi(th_dvb_mux_instance_t *tdmi, const char *reason)
{
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
- const dvb_mux_t *dm = tdmi->tdmi_mux;
+ dvb_mux_t *dm = tdmi->tdmi_mux;
// copy dmc, cause frequency may be change with FE_QPSK
dvb_mux_conf_t dmc = dm->dm_conf;
dvb_frontend_parameters_t* p = &dmc.dmc_fe_params;
int r;
char buf[256];
- dvb_adapter_start(tda);
+ if(tda->tda_current_tdmi != NULL) {
- assert(tda->tda_current_tdmi == NULL);
+ if(tda->tda_current_tdmi == tdmi)
+ return 0; // Already currently tuned
+ /*
+ * Adapter tuned to something else.
+ * But at this stage we're no longer caring about such things.
+ * That should have been sorted out by our callers.
+ * So let's just kick it out the current occupant
+ */
+ dvb_mux_stop(tda->tda_current_tdmi);
+ }
+ free(tda->tda_tune_reason);
+ tda->tda_tune_reason = strdup(reason);
+
+ dvb_adapter_start(tda);
+
+ // Make sure dvb_mux_stop() did the right thing
+ assert(tda->tda_current_tdmi == NULL);
if(tda->tda_fe_type == FE_QPSK) {
}
- if(!r)
+ if(!r) {
gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1);
+ tda->tda_current_tdmi = tdmi;
+ dm->dm_current_tdmi = tdmi;
+
+ dvb_table_add_default(dm);
+ epggrab_mux_start(dm);
+ dvb_adapter_notify(tda);
+
+ } else {
+
+ tvhlog(LOG_ERR, "dvb", "\"%s\" tuning to \"%s\""
+ " -- Front configuration failed -- %s",
+ tda->tda_rootpath, dvb_mux_nicename(dm), strerror(errno));
+ /* Mark as bad */
+ tdmi->tdmi_tune_failed = 1;
+ }
return r;
}
/**
* These are created on the fly
*/
-static void
+void
dvb_create_tdmis(dvb_mux_t *dm)
{
th_dvb_mux_instance_t *tdmi;
/**
*
*/
-static void
+void
dvb_mux_stop(th_dvb_mux_instance_t *tdmi)
{
dvb_mux_t *dm = tdmi->tdmi_mux;
th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
+ service_t *s;
+
assert(dm->dm_current_tdmi == tdmi);
assert(tda->tda_current_tdmi == tdmi);
+ lock_assert(&global_lock);
+
+ /* Flush all subscribers */
+ while((s = LIST_FIRST(&tda->tda_transports)) != NULL)
+ service_remove_subscriber(s, NULL, SM_CODE_SUBSCRIPTION_OVERRIDDEN);
+
dvb_table_flush_all(dm);
epggrab_mux_stop(dm, 0);
- assert(dm->dm_scan_status == DM_SCAN_DONE);
+ if(dm->dm_scan_status == DM_SCAN_CURRENT) {
+ /*
+ * If we were currently doing initial scan but lost the adapter
+ * before finishing, put us back on the pending queue
+ */
+ dvb_network_t *dn = dm->dm_dn;
+ TAILQ_REMOVE(&dn->dn_initial_scan_current_queue, dm, dm_scan_link);
+ dm->dm_scan_status = DM_SCAN_PENDING;
+ TAILQ_INSERT_TAIL(&dn->dn_initial_scan_pending_queue, dm, dm_scan_link);
+ dvb_network_schedule_initial_scan(dn);
+ }
dm->dm_current_tdmi = NULL;
tda->tda_current_tdmi = NULL;
-
- printf("NEED TO TAKE CARE OF SERVICES in dvb_mux_stop\n");
}
/**
*
*/
-static int
-tdmi_compute_weight(const th_dvb_mux_instance_t *tdmi)
+int
+tdmi_current_weight(const th_dvb_mux_instance_t *tdmi)
{
- const dvb_mux_t *dm = tdmi->tdmi_mux;
- if(dm->dm_scan_status == DM_SCAN_CURRENT)
- return 1;
- return 0;
+ int w = 0;
+ th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
+ const service_t *s;
+
+
+ // This max weight of all subscriptions could be kept in the adapter struct
+ pthread_mutex_lock(&tda->tda_delivery_mutex);
+ LIST_FOREACH(s, &tda->tda_transports, s_active_link) {
+ const th_subscription_t *ths;
+ LIST_FOREACH(ths, &s->s_subscriptions, ths_service_link)
+ w = MAX(w, ths->ths_weight);
+ }
+ pthread_mutex_unlock(&tda->tda_delivery_mutex);
+
+ w = MAX(w, tdmi->tdmi_mux->dm_scan_status == DM_SCAN_CURRENT);
+ return w;
}
th_dvb_mux_instance_t *tdmi;
int r;
- assert(dm->dm_current_tdmi == NULL);
-
lock_assert(&global_lock);
- dvb_create_tdmis(dm);
+ if(dm->dm_current_tdmi == NULL) {
- retry:
- // Figure which adapter to use
- LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link)
- if(!tdmi->tdmi_tune_failed && tdmi->tdmi_adapter->tda_current_tdmi == NULL)
- break;
+ dvb_create_tdmis(dm);
- if(tdmi == NULL) {
- // None available, need to strike one out
- LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link) {
- if(tdmi->tdmi_tune_failed)
- continue;
+ while(1) {
+ // Figure which adapter to use
+ LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link)
+ if(!tdmi->tdmi_tune_failed && tdmi->tdmi_adapter->tda_current_tdmi == NULL)
+ break;
- th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
- th_dvb_mux_instance_t *t2 = tda->tda_current_tdmi;
- assert(t2 != NULL);
- assert(t2 != tdmi);
+ if(tdmi == NULL) {
+ // None available, need to strike one out
+ LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link) {
+ if(tdmi->tdmi_tune_failed)
+ continue;
- if(tdmi_compute_weight(t2) < weight) {
- dvb_mux_stop(t2);
- break;
- }
- }
+ th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
+ th_dvb_mux_instance_t *t2 = tda->tda_current_tdmi;
+ assert(t2 != NULL);
+ assert(t2 != tdmi);
- if(tdmi == NULL)
- return SM_CODE_NO_FREE_ADAPTER;
+ if(tdmi_current_weight(t2) < weight) {
+ break;
+ }
+ }
- }
-
- tdmi->tdmi_weight = weight;
-
- th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
-
- free(tda->tda_tune_reason);
- tda->tda_tune_reason = strdup(reason);
-
- r = dvb_fe_tune_tdmi(tdmi);
-
- if(r != 0) {
- tvhlog(LOG_ERR, "dvb", "\"%s\" tuning to \"%s\""
- " -- Front configuration failed -- %s",
- tda->tda_rootpath, dvb_mux_nicename(dm), strerror(errno));
+ if(tdmi == NULL)
+ return SM_CODE_NO_FREE_ADAPTER;
+ }
- /* Mark as bad */
- tdmi->tdmi_tune_failed = 1;
- goto retry;
+ r = dvb_fe_tune_tdmi(tdmi, reason);
+ if(!r)
+ break;
+ }
}
- tda->tda_current_tdmi = tdmi;
- dm->dm_current_tdmi = tdmi;
if(dm->dm_scan_status == DM_SCAN_PENDING) {
TAILQ_REMOVE(&dn->dn_initial_scan_pending_queue, dm, dm_scan_link);
dm->dm_scan_status = DM_SCAN_CURRENT;
gtimer_arm(&dm->dm_initial_scan_timeout, dvb_mux_initial_scan_timeout, dm, 10);
}
- dvb_table_add_default(dm);
- epggrab_mux_start(dm);
-
- dvb_adapter_notify(tda);
return 0;
}
* transports that is subscribing to the adapter
*/
static int
-dvb_service_start(service_t *t, unsigned int weight, int force_start)
+dvb_service_start(service_t *s, int instance)
{
-#if 0
- int w, r;
- th_dvb_adapter_t *tda = t->s_dvb_mux_instance->tdmi_adapter;
- th_dvb_mux_instance_t *tdmi = tda->tda_current_tdmi;
-
- lock_assert(&global_lock);
-
- if(tda->tda_rootpath == NULL)
- return SM_CODE_NO_HW_ATTACHED;
+ int r;
+ dvb_mux_t *dm = s->s_dvb_mux;
+ th_dvb_mux_instance_t *tdmi;
- if(t->s_dvb_mux_instance && !t->s_dvb_mux_instance->tdmi_enabled)
- return SM_CODE_MUX_NOT_ENABLED; /* Mux is disabled */
+ assert(s->s_status == SERVICE_IDLE);
- /* Check if adapter is idle, or already tuned */
+ lock_assert(&global_lock);
- if(tdmi != NULL &&
- (tdmi != t->s_dvb_mux_instance ||
- tda->tda_hostconnection == HOSTCONNECTION_USB12)) {
+ LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link)
+ if(tdmi->tdmi_adapter->tda_instance == instance)
+ break;
- w = service_compute_weight(&tda->tda_transports);
- if(w && w >= weight && !force_start)
- /* We are outranked by weight, cant use it */
- return SM_CODE_NOT_FREE;
+ assert(tdmi != NULL); // We should always find this instance
- if(LIST_FIRST(&tdmi->tdmi_subscriptions) != NULL)
- return SM_CODE_NOT_FREE;
+ r = dvb_fe_tune_tdmi(tdmi, "service start");
- dvb_adapter_clean(tda);
+ if(!r) {
+ th_dvb_adapter_t *tda = dm->dm_current_tdmi->tdmi_adapter;
+ pthread_mutex_lock(&tda->tda_delivery_mutex);
+ LIST_INSERT_HEAD(&tda->tda_transports, s, s_active_link);
+ pthread_mutex_unlock(&tda->tda_delivery_mutex);
+ tda->tda_open_service(tda, s);
+ dvb_table_add_pmt(dm, s->s_pmt_pid);
}
- pthread_mutex_lock(&tda->tda_delivery_mutex);
-
- r = dvb_fe_tune(t->s_dvb_mux_instance->tdmi_mux, "Transport start");
- if(!r)
- LIST_INSERT_HEAD(&tda->tda_transports, t, s_active_link);
-
- pthread_mutex_unlock(&tda->tda_delivery_mutex);
-
- if(!r)
- tda->tda_open_service(tda, t);
+ return r;
+}
- dvb_table_add_pmt(t->s_dvb_mux_instance->tdmi_mux, t->s_pmt_pid);
- return r;
-#endif
- return SM_CODE_NO_FREE_ADAPTER;
+/**
+ *
+ */
+static th_dvb_adapter_t *
+dvb_service_get_tda(service_t *s)
+{
+ dvb_mux_t *dm = s->s_dvb_mux;
+ assert(dm->dm_current_tdmi != NULL);
+ th_dvb_adapter_t *tda = dm->dm_current_tdmi->tdmi_adapter;
+ assert(tda != NULL);
+ return tda;
}
*
*/
static void
-dvb_service_stop(service_t *t)
+dvb_service_stop(service_t *s)
{
-#if 0
- th_dvb_adapter_t *tda = t->s_dvb_mux_instance->tdmi_adapter;
-
+ th_dvb_adapter_t *tda = dvb_service_get_tda(s);
lock_assert(&global_lock);
pthread_mutex_lock(&tda->tda_delivery_mutex);
- LIST_REMOVE(t, s_active_link);
+ LIST_REMOVE(s, s_active_link);
pthread_mutex_unlock(&tda->tda_delivery_mutex);
- tda->tda_close_service(tda, t);
+ tda->tda_close_service(tda, s);
- t->s_status = SERVICE_IDLE;
-#endif
+ s->s_status = SERVICE_IDLE;
}
*
*/
static void
-dvb_service_refresh(service_t *t)
+dvb_service_refresh(service_t *s)
{
-#if 0
- th_dvb_adapter_t *tda = t->s_dvb_mux_instance->tdmi_adapter;
-
+ th_dvb_adapter_t *tda = dvb_service_get_tda(s);
lock_assert(&global_lock);
- tda->tda_open_service(tda, t);
-#endif
+ tda->tda_open_service(tda, s);
+}
+
+
+/**
+ *
+ */
+static void
+dvb_service_enlist(struct service *s, struct service_instance_list *sil)
+{
+ dvb_mux_t *dm = s->s_dvb_mux;
+ th_dvb_mux_instance_t *tdmi;
+
+ dvb_create_tdmis(dm);
+
+ LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link) {
+ if(tdmi->tdmi_tune_failed)
+ continue; // The hardware is not able to tune to this frequency, never consider it
+
+ service_instance_add(sil, s, tdmi->tdmi_adapter->tda_instance, 100,
+ tdmi_current_weight(tdmi));
+ }
}
t->s_setsourceinfo = dvb_service_setsourceinfo;
t->s_grace_period = dvb_grace_period;
t->s_serialize = dvb_service_serialize;
+ t->s_enlist = dvb_service_enlist;
t->s_dvb_mux = dm;
LIST_INSERT_HEAD(&dm->dm_services, t, s_group_link);
*
*/
static int
-iptv_service_start(service_t *t, unsigned int weight, int force_start)
+iptv_service_start(service_t *t, int instance)
{
pthread_t tid;
int fd;
*/
void
service_remove_subscriber(service_t *t, th_subscription_t *s,
- int reason)
+ int reason)
{
lock_assert(&global_lock);
*
*/
int
-service_start(service_t *t, unsigned int weight, int force_start)
+service_start(service_t *t, int instance)
{
elementary_stream_t *st;
int r, timeout = 2;
t->s_streaming_status = 0;
t->s_pcr_drift = 0;
- if((r = t->s_start_feed(t, weight, force_start)))
+ if((r = t->s_start_feed(t, instance)))
return r;
cwc_service_start(t);
return 0;
}
+
+/**
+ * Main entry point for starting a service based on a channel
+ */
+service_instance_t *
+service_find_instance(channel_t *ch, struct service_instance_list *sil,
+ int *error, int weight)
+{
+ service_t *s;
+ service_instance_t *si, *next;
+
+ lock_assert(&global_lock);
+
+ // First, update list of candidates
+
+ LIST_FOREACH(si, sil, si_link)
+ si->si_mark = 1;
+
+ LIST_FOREACH(s, &ch->ch_services, s_ch_link)
+ s->s_enlist(s, sil);
+
+ for(si = LIST_FIRST(sil); si != NULL; si = next) {
+ next = LIST_NEXT(si, si_link);
+ if(si->si_mark)
+ service_instance_destroy(si);
+ }
+
+ printf("Service start, enlisted candidates\n");
+ LIST_FOREACH(si, sil, si_link)
+ printf(" %s i:%d w:%d p:%d\n", si->si_s->s_nicename, si->si_instance, si->si_weight, si->si_prio);
+
+
+ // Check if any service is already running, if so, use that
+ LIST_FOREACH(si, sil, si_link)
+ if(si->si_s->s_status == SERVICE_RUNNING)
+ return si;
+
+ // Check if any is idle
+ LIST_FOREACH(si, sil, si_link)
+ if(si->si_weight == 0 && si->si_error == 0)
+ break;
+
+ // Check if to kick someone out
+ if(si == NULL) {
+ LIST_FOREACH(si, sil, si_link) {
+ if(si->si_weight < weight && si->si_error == 0)
+ break;
+ }
+ }
+
+ if(si == NULL) {
+ *error = SM_CODE_NO_FREE_ADAPTER;
+ return NULL;
+ }
+
+ service_start(si->si_s, si->si_instance);
+ return NULL;
+}
+
+
+
+#if 0
/**
*
*/
service_t *
-service_find(channel_t *ch, unsigned int weight, const char *loginfo,
- int *errorp, service_t *skip)
+service_enlist(channel_t *ch)
{
service_t *t, **vec;
int cnt = 0, i, r, off;
*errorp = SM_CODE_NO_SERVICE;
return NULL;
}
+#endif
/**
*
*/
static int
-ssc_cmp(const service_start_cand_t *a,
- const service_start_cand_t *b)
+si_cmp(const service_instance_t *a, const service_instance_t *b)
{
- return a->ssc_prio - b->ssc_prio;
+ return a->si_prio - b->si_prio;
}
/**
*
*/
-service_start_cand_t *
-service_find_cand(struct service_start_cand_list *sscl,
- struct service *s, int instance, int prio)
+service_instance_t *
+service_instance_add(struct service_instance_list *sil,
+ struct service *s, int instance, int prio,
+ int weight)
{
- service_start_cand_t *ssc;
- LIST_FOREACH(ssc, sscl, ssc_link) {
- if(ssc->ssc_s == s && ssc->ssc_instance == instance)
+ service_instance_t *si;
+ LIST_FOREACH(si, sil, si_link)
+ if(si->si_s == s && si->si_instance == instance)
break;
- }
- if(ssc != NULL) {
- ssc = calloc(1, sizeof(service_start_cand_t));
- ssc->ssc_s = s;
+ if(si == NULL) {
+ si = calloc(1, sizeof(service_instance_t));
+ si->si_s = s;
service_ref(s);
- ssc->ssc_instance = instance;
+ si->si_instance = instance;
+ si->si_weight = weight;
} else {
- if(ssc->ssc_prio == prio)
- return ssc;
- LIST_REMOVE(ssc, ssc_link);
+ si->si_mark = 0;
+ if(si->si_prio == prio && si->si_weight == weight)
+ return si;
+ LIST_REMOVE(si, si_link);
}
- ssc->ssc_prio = prio;
- LIST_INSERT_SORTED(sscl, ssc, ssc_link, ssc_cmp);
- return ssc;
+ si->si_weight = weight;
+ si->si_prio = prio;
+ LIST_INSERT_SORTED(sil, si, si_link, si_cmp);
+ return si;
+}
+
+
+/**
+ *
+ */
+void
+service_instance_destroy(service_instance_t *si)
+{
+ LIST_REMOVE(si, si_link);
+ service_unref(si->si_s);
+ free(si);
+}
+
+
+/**
+ *
+ */
+void
+service_instance_list_clear(struct service_instance_list *sil)
+{
+ lock_assert(&global_lock);
+
+ service_instance_t *si;
+ while((si = LIST_FIRST(sil)) != NULL)
+ service_instance_destroy(si);
}
} elementary_stream_t;
-LIST_HEAD(service_start_cand_list, service_start_cand);
+LIST_HEAD(service_instance_list, service_instance);
/**
*
*/
-typedef struct service_start_cand {
+typedef struct service_instance {
- LIST_ENTRY(service_start_cand) ssc_link;
+ LIST_ENTRY(service_instance) si_link;
- int ssc_prio;
+ int si_prio;
- struct service *ssc_s; // A reference is held
- int ssc_instance; // Discriminator when having multiple adapters, etc
+ struct service *si_s; // A reference is held
+ int si_instance; // Discriminator when having multiple adapters, etc
- int ssc_error_code; // Set if we deem this cand to be broken
- time_t ssc_err_time; // Time we detected it was broken
+ int si_error; /* Set if subscription layer deem this cand
+ to be broken. We typically set this if we
+ have not seen any demuxed packets after
+ the grace period has expired.
+ The actual value is current time
+ */
- int ssc_weight; // Highest weight that holds this cand
+ time_t si_error_time;
-} service_start_cand_t;
+
+ int si_weight; // Highest weight that holds this cand
+
+ int si_mark; // For mark & sweep
+
+} service_instance_t;
/**
*
*/
-service_start_cand_t *service_find_cand(struct service_start_cand_list *sscl,
- struct service *s,
- int instance,
- int prio);
+service_instance_t *service_instance_add(struct service_instance_list *sil,
+ struct service *s,
+ int instance,
+ int prio,
+ int weight);
+
+void service_instance_destroy(service_instance_t *si);
+
+void service_instance_list_clear(struct service_instance_list *sil);
/**
*
LIST_HEAD(, th_subscription) s_subscriptions;
- void (*s_enlist)(struct service *s,
- struct service_start_cand_list *sscl);
-
+ void (*s_enlist)(struct service *s, struct service_instance_list *sil);
- int (*s_start_feed)(struct service *t, unsigned int weight,
- int force_start);
+ int (*s_start_feed)(struct service *s, int instance);
void (*s_refresh_feed)(struct service *t);
unsigned int service_compute_weight(struct service_list *head);
-int service_start(service_t *t, unsigned int weight, int force_start);
+int service_start(service_t *t, int instance);
service_t *service_create(const char *uuid, int source_type);
void service_map_channel(service_t *t, struct channel *ch, int save);
-service_t *service_find(struct channel *ch, unsigned int weight,
- const char *loginfo, int *errorp,
- service_t *skip);
+service_instance_t *service_find_instance(struct channel *ch,
+ struct service_instance_list *sil,
+ int *error,
+ int weight);
elementary_stream_t *service_stream_find(service_t *t, int pid);
subscription_reschedule(void)
{
th_subscription_t *s;
- service_t *t, *skip;
+ service_instance_t *si;
streaming_message_t *sm;
- char buf[128];
int error;
lock_assert(&global_lock);
/* Already got a service */
if(s->ths_state != SUBSCRIPTION_BAD_SERVICE)
- continue; /* And it seems to work ok, so we're happy */
- skip = s->ths_service;
- error = s->ths_testing_error;
- service_remove_subscriber(s->ths_service, s, s->ths_testing_error);
- } else {
- error = 0;
- skip = NULL;
+ continue; /* And it not bad, so we're happy */
+
+ si = s->ths_current_instance;
+
+ assert(si != NULL);
+ si->si_error = s->ths_testing_error;
+ time(&si->si_error_time);
}
- snprintf(buf, sizeof(buf), "Subscription \"%s\"", s->ths_title);
- t = service_find(s->ths_channel, s->ths_weight, buf, &error, skip);
+ si = service_find_instance(s->ths_channel, &s->ths_instances, &error,
+ s->ths_weight);
+ s->ths_current_instance = si;
- if(t == NULL) {
+ if(si == NULL) {
/* No service available */
sm = streaming_msg_create_code(SMT_NOSTART, error);
continue;
}
- subscription_link_service(s, t);
+ subscription_link_service(s, si->si_s);
}
}
lock_assert(&global_lock);
+ service_instance_list_clear(&s->ths_instances);
+
LIST_REMOVE(s, ths_global_link);
if(s->ths_channel != NULL) {
subscription_create_from_service(service_t *t, const char *name,
streaming_target_t *st, int flags)
{
+#if 0
th_subscription_t *s;
source_info_t si;
int r;
subscription_link_service(s, t);
notify_reload("subscriptions");
return s;
+#endif
+ abort();
}
#ifndef SUBSCRIPTIONS_H
#define SUBSCRIPTIONS_H
+#include "service.h"
+
extern struct th_subscription_list subscriptions;
#define SUBSCRIPTION_RAW_MPEGTS 0x1
char *ths_username;
char *ths_client;
+ /**
+ * This is the list of service candidates we have
+ */
+ struct service_instance_list ths_instances;
+ struct service_instance *ths_current_instance;
+
// Ugly ugly ugly to refer DVB code here
LIST_ENTRY(th_subscription) ths_tdmi_link;
*
*/
static int
-v4l_service_start(service_t *t, unsigned int weight, int force_start)
+v4l_service_start(service_t *t, int instance)
{
v4l_adapter_t *va = t->s_v4l_adapter;
int frequency = t->s_v4l_frequency;
out = htsmsg_create_map();
htsmsg_add_u32(out, "success", 1);
-#if 0
+
} else if(!strcmp(op, "serviceprobe")) {
tvhlog(LOG_NOTICE, "web interface",
"Service probe started on \"%s\"", tda->tda_displayname);
- LIST_FOREACH(tdmi, &tda->tda_dn->dn_mux_instances, tdmi_adapter_link) {
- LIST_FOREACH(t, &tdmi->tdmi_mux->dm_services, s_group_link) {
- if(t->s_enabled)
- serviceprobe_enqueue(t);
+ dvb_mux_t *dm;
+ service_t *s;
+
+ LIST_FOREACH(dm, &tda->tda_dn->dn_muxes, dm_network_link) {
+ LIST_FOREACH(s, &dm->dm_services, s_group_link) {
+ if(s->s_enabled)
+ serviceprobe_enqueue(s);
}
}
out = htsmsg_create_map();
htsmsg_add_u32(out, "success", 1);
-#endif
} else {
pthread_mutex_unlock(&global_lock);
if (r.data.identifier != adapterId) return;
infoTemplate.overwrite(infoPanel.body, r.data);
+ serviceScanBtn.enable();
+
if (r.data.services > 0 && r.data.initialMuxes == 0) serviceScanBtn
.enable();
else serviceScanBtn.disable();
});
+ serviceScanBtn.enable();
return panel;
}
root : new Ext.tree.AsyncTreeNode({
id : 'root',
text: 'DVB Networks'
- })
+ }),
+ listeners: {
+ click: function(n) {
+ Ext.Msg.alert('Navigation Tree Click', 'You clicked: "' + n.attributes.text + '"');
+ }
+ }
});