dvbreorg: Service subscription now possible
This commit is contained in:
parent
2cd41e90e5
commit
6f6f422bdf
14 changed files with 377 additions and 321 deletions
|
@ -199,8 +199,6 @@ typedef struct th_dvb_mux_instance {
|
|||
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;
|
||||
|
@ -231,6 +229,9 @@ typedef struct dvb_table_feed {
|
|||
|
||||
typedef struct th_dvb_adapter {
|
||||
|
||||
int tda_instance;
|
||||
|
||||
|
||||
TAILQ_ENTRY(th_dvb_adapter) tda_global_link;
|
||||
|
||||
dvb_network_t *tda_dn;
|
||||
|
@ -403,8 +404,6 @@ void dvb_adapter_set_full_mux_rx(th_dvb_adapter_t *tda, int r);
|
|||
|
||||
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);
|
||||
|
@ -490,9 +489,15 @@ dvb_mux_t *dvb_mux_find(dvb_network_t *dn, const char *netname, uint16_t onid,
|
|||
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);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
struct th_dvb_adapter_queue dvb_adapters;
|
||||
static void *dvb_adapter_input_dvr(void *aux);
|
||||
|
||||
static int dvb_adapter_instance_generator;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -59,6 +59,7 @@ tda_alloc(void)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -631,87 +632,6 @@ dvb_adapter_init(uint32_t adapter_mask, const char *rawfile)
|
|||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -746,24 +666,6 @@ dvb_adapter_destroy(th_dvb_adapter_t *tda)
|
|||
#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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -921,7 +823,6 @@ dvb_adapter_input_dvr(void *aux)
|
|||
htsmsg_t *
|
||||
dvb_adapter_build_msg(th_dvb_adapter_t *tda)
|
||||
{
|
||||
char buf[100];
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
int fdiv;
|
||||
|
||||
|
@ -933,8 +834,8 @@ dvb_adapter_build_msg(th_dvb_adapter_t *tda)
|
|||
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);
|
||||
|
|
|
@ -254,32 +254,6 @@ dvb_fe_monitor(void *aux)
|
|||
}
|
||||
|
||||
|
||||
#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
|
||||
|
@ -385,23 +359,42 @@ dvb_fe_tune_s2(th_dvb_adapter_t *tda, dvb_mux_conf_t *dmc)
|
|||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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];
|
||||
|
||||
if(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) {
|
||||
|
||||
/* DVB-S */
|
||||
|
@ -467,8 +460,23 @@ dvb_fe_tune_tdmi(th_dvb_mux_instance_t *tdmi)
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -1293,7 +1293,7 @@ dvb_mux_get_childs(struct idnode *self)
|
|||
/**
|
||||
* These are created on the fly
|
||||
*/
|
||||
static void
|
||||
void
|
||||
dvb_create_tdmis(dvb_mux_t *dm)
|
||||
{
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
|
@ -1322,36 +1322,64 @@ dvb_create_tdmis(dvb_mux_t *dm)
|
|||
/**
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1379,61 +1407,44 @@ dvb_mux_tune(dvb_mux_t *dm, const char *reason, int weight)
|
|||
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_current_weight(t2) < weight) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(tdmi == NULL)
|
||||
return SM_CODE_NO_FREE_ADAPTER;
|
||||
}
|
||||
|
||||
r = dvb_fe_tune_tdmi(tdmi, reason);
|
||||
if(!r)
|
||||
break;
|
||||
}
|
||||
|
||||
if(tdmi == NULL)
|
||||
return SM_CODE_NO_FREE_ADAPTER;
|
||||
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
/* Mark as bad */
|
||||
tdmi->tdmi_tune_failed = 1;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -1442,9 +1453,5 @@ dvb_mux_tune(dvb_mux_t *dm, const char *reason, int weight)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -55,54 +55,48 @@ static htsmsg_t *dvb_service_serialize(service_t *s, int full);
|
|||
* 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;
|
||||
int r;
|
||||
dvb_mux_t *dm = s->s_dvb_mux;
|
||||
th_dvb_mux_instance_t *tdmi;
|
||||
|
||||
assert(s->s_status == SERVICE_IDLE);
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if(tda->tda_rootpath == NULL)
|
||||
return SM_CODE_NO_HW_ATTACHED;
|
||||
LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link)
|
||||
if(tdmi->tdmi_adapter->tda_instance == instance)
|
||||
break;
|
||||
|
||||
if(t->s_dvb_mux_instance && !t->s_dvb_mux_instance->tdmi_enabled)
|
||||
return SM_CODE_MUX_NOT_ENABLED; /* Mux is disabled */
|
||||
assert(tdmi != NULL); // We should always find this instance
|
||||
|
||||
/* Check if adapter is idle, or already tuned */
|
||||
r = dvb_fe_tune_tdmi(tdmi, "service start");
|
||||
|
||||
if(tdmi != NULL &&
|
||||
(tdmi != t->s_dvb_mux_instance ||
|
||||
tda->tda_hostconnection == HOSTCONNECTION_USB12)) {
|
||||
|
||||
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;
|
||||
|
||||
if(LIST_FIRST(&tdmi->tdmi_subscriptions) != NULL)
|
||||
return SM_CODE_NOT_FREE;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -110,21 +104,18 @@ dvb_service_start(service_t *t, unsigned int weight, int force_start)
|
|||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -132,14 +123,32 @@ dvb_service_stop(service_t *t)
|
|||
*
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -389,6 +398,7 @@ dvb_service_find2(dvb_mux_t *dm, uint16_t sid, int pmt_pid,
|
|||
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);
|
||||
|
|
|
@ -198,7 +198,7 @@ iptv_thread(void *aux)
|
|||
*
|
||||
*/
|
||||
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;
|
||||
|
|
140
src/service.c
140
src/service.c
|
@ -176,7 +176,7 @@ service_stop(service_t *t)
|
|||
*/
|
||||
void
|
||||
service_remove_subscriber(service_t *t, th_subscription_t *s,
|
||||
int reason)
|
||||
int reason)
|
||||
{
|
||||
lock_assert(&global_lock);
|
||||
|
||||
|
@ -197,7 +197,7 @@ service_remove_subscriber(service_t *t, th_subscription_t *s,
|
|||
*
|
||||
*/
|
||||
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;
|
||||
|
@ -208,7 +208,7 @@ service_start(service_t *t, unsigned int weight, int force_start)
|
|||
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);
|
||||
|
@ -234,12 +234,73 @@ service_start(service_t *t, unsigned int weight, int force_start)
|
|||
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;
|
||||
|
@ -321,6 +382,7 @@ service_find(channel_t *ch, unsigned int weight, const char *loginfo,
|
|||
*errorp = SM_CODE_NO_SERVICE;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
|
@ -1031,38 +1093,66 @@ service_refresh_channel(service_t *t)
|
|||
*
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -167,35 +167,49 @@ typedef struct elementary_stream {
|
|||
} 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);
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -285,12 +299,9 @@ typedef struct service {
|
|||
|
||||
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);
|
||||
|
||||
|
@ -540,7 +551,7 @@ void service_init(void);
|
|||
|
||||
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);
|
||||
|
||||
|
@ -552,9 +563,10 @@ service_t *service_find_by_identifier(const char *identifier);
|
|||
|
||||
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);
|
||||
|
||||
|
|
|
@ -155,9 +155,8 @@ void
|
|||
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);
|
||||
|
@ -173,19 +172,20 @@ subscription_reschedule(void)
|
|||
/* 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);
|
||||
|
@ -193,7 +193,7 @@ subscription_reschedule(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
subscription_link_service(s, t);
|
||||
subscription_link_service(s, si->si_s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,6 +207,8 @@ subscription_unsubscribe(th_subscription_t *s)
|
|||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
service_instance_list_clear(&s->ths_instances);
|
||||
|
||||
LIST_REMOVE(s, ths_global_link);
|
||||
|
||||
if(s->ths_channel != NULL) {
|
||||
|
@ -407,6 +409,7 @@ th_subscription_t *
|
|||
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;
|
||||
|
@ -443,6 +446,8 @@ subscription_create_from_service(service_t *t, const char *name,
|
|||
subscription_link_service(s, t);
|
||||
notify_reload("subscriptions");
|
||||
return s;
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#ifndef SUBSCRIPTIONS_H
|
||||
#define SUBSCRIPTIONS_H
|
||||
|
||||
#include "service.h"
|
||||
|
||||
extern struct th_subscription_list subscriptions;
|
||||
|
||||
#define SUBSCRIPTION_RAW_MPEGTS 0x1
|
||||
|
@ -65,6 +67,12 @@ typedef struct th_subscription {
|
|||
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;
|
||||
|
|
|
@ -170,7 +170,7 @@ v4l_thread(void *aux)
|
|||
*
|
||||
*/
|
||||
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;
|
||||
|
|
|
@ -221,23 +221,25 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
|
|||
|
||||
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);
|
||||
|
|
|
@ -1266,10 +1266,13 @@ tvheadend.dvb_adapter_general = function(adapterData, satConfStore) {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,12 @@ tvheadend.dvb_networks = function() {
|
|||
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 + '"');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue