From: Andreas Ă–man Date: Thu, 17 Jan 2013 15:21:55 +0000 (+0100) Subject: dvbreorg WIP X-Git-Tag: v3.9^2~229^2~13 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fef5755fe7b8e2fe327e45a34cce221e994eba87;p=thirdparty%2Ftvheadend.git dvbreorg WIP Initial scan now works again We have a new idnode system that can give an entity a UUID which then can be looked up externally (webui, etc). Good when browsing stuff The UUID is supposed to be persisted on on disk when saving enteties --- diff --git a/Makefile b/Makefile index a4e63011e..371457630 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,7 @@ endif # Core # SRCS = src/main.c \ + src/idnode.c \ src/utils.c \ src/wrappers.c \ src/version.c \ diff --git a/src/dvb/dvb.c b/src/dvb/dvb.c index 9e3775b31..44e905d51 100644 --- a/src/dvb/dvb.c +++ b/src/dvb/dvb.c @@ -26,5 +26,6 @@ void dvb_init(uint32_t adapter_mask, const char *rawfile) { dvb_charset_init(); + dvb_network_init(); dvb_adapter_init(adapter_mask, rawfile); } diff --git a/src/dvb/dvb.h b/src/dvb/dvb.h index 4c4594b2b..aa08aff03 100644 --- a/src/dvb/dvb.h +++ b/src/dvb/dvb.h @@ -24,6 +24,7 @@ #include #include "htsmsg.h" #include "psi.h" +#include "idnode.h" struct service; struct th_dvb_table; @@ -35,7 +36,7 @@ struct th_dvb_mux_instance; (DVB_VER_INT(DVB_API_VERSION, DVB_API_VERSION_MINOR) >= DVB_VER_INT(maj, min)) TAILQ_HEAD(th_dvb_adapter_queue, th_dvb_adapter); -RB_HEAD(th_dvb_mux_instance_tree, th_dvb_mux_instance); +LIST_HEAD(th_dvb_adapter_list, th_dvb_adapter); TAILQ_HEAD(th_dvb_mux_instance_queue, th_dvb_mux_instance); LIST_HEAD(th_dvb_mux_instance_list, th_dvb_mux_instance); TAILQ_HEAD(dvb_satconf_queue, dvb_satconf); @@ -89,11 +90,14 @@ typedef struct dvb_mux_conf { * */ typedef struct dvb_network { + idnode_t dn_id; LIST_ENTRY(dvb_network) dn_global_link; - struct dvb_mux_queue dn_initial_scan_queue; - int dn_initial_num_mux; + struct dvb_mux_queue dn_initial_scan_pending_queue; + struct dvb_mux_queue dn_initial_scan_current_queue; + int dn_initial_scan_num_mux; + gtimer_t dn_initial_scan_timer; struct dvb_mux *dn_mux_epg; @@ -101,13 +105,11 @@ typedef struct dvb_network { struct dvb_mux_list dn_muxes; - gtimer_t dn_mux_scanner_timer; - uint32_t dn_disable_pmt_monitor; uint32_t dn_autodiscovery; uint32_t dn_nitoid; - char *dn_uuid; + struct th_dvb_adapter_list dn_adapters; } dvb_network_t; @@ -117,7 +119,7 @@ typedef struct dvb_network { * */ typedef struct dvb_mux { - + idnode_t dm_id; LIST_ENTRY(dvb_mux) dm_network_link; dvb_network_t *dm_dn; @@ -132,14 +134,20 @@ typedef struct dvb_mux { TAILQ_HEAD(, epggrab_ota_mux) dm_epg_grab; + gtimer_t dm_initial_scan_timeout; + TAILQ_ENTRY(dvb_mux) dm_scan_link; - struct dvb_mux_queue *dm_scan_queue; + enum { + DM_SCAN_DONE, // All done + DM_SCAN_PENDING, // Waiting to be tuned for initial scan + DM_SCAN_CURRENT, // Currently tuned for initial scan + } dm_scan_status; LIST_HEAD(, th_dvb_table) dm_tables; int dm_num_tables; TAILQ_HEAD(, th_dvb_table) dm_table_queue; - int dm_table_initial; + // int dm_table_initial; struct th_dvb_mux_instance *dm_current_tdmi; @@ -148,8 +156,6 @@ typedef struct dvb_mux { // Derived from dm_conf (more or less) char *dm_local_identifier; - char *dm_uuid; - int dm_enabled; } dvb_mux_t; @@ -193,6 +199,8 @@ 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; @@ -226,6 +234,7 @@ typedef struct th_dvb_adapter { TAILQ_ENTRY(th_dvb_adapter) tda_global_link; dvb_network_t *tda_dn; + LIST_ENTRY(th_dvb_adapter) tda_network_link; struct th_dvb_mux_instance_list tda_tdmis; @@ -479,6 +488,8 @@ dvb_mux_t *dvb_mux_find(dvb_network_t *dn, const char *netname, uint16_t onid, uint16_t tsid, int enabled); +void dvb_mux_initial_scan_done(dvb_mux_t *dm); + /** * DVB Transport (aka DVB service) */ @@ -507,14 +518,12 @@ void dvb_service_notify(struct service *t); void dvb_service_notify_by_adapter(th_dvb_adapter_t *tda); -htsmsg_t *dvb_service_build_msg(struct service *t); - /** * DVB Frontend */ -int dvb_fe_tune(dvb_mux_t *dm, const char *reason); +int dvb_fe_tune(dvb_mux_t *dm, const char *reason, int weight); -void dvb_fe_stop(th_dvb_adapter_t *tda, int retune); +//void dvb_fe_stop(th_dvb_adapter_t *tda, int retune); /** @@ -551,9 +560,15 @@ void dvb_table_release(th_dvb_table_t *tdt); /** * */ -dvb_network_t *dvb_network_create(int fe_type); +dvb_network_t *dvb_network_create(int fe_type, const char *uuid); + +//void dvb_network_mux_scanner(void *aux); + +void dvb_network_init(void); + +idnode_t **dvb_network_root(void); -void dvb_network_mux_scanner(void *aux); +void dvb_network_schedule_initial_scan(dvb_network_t *dn); /** diff --git a/src/dvb/dvb_adapter.c b/src/dvb/dvb_adapter.c index b7029fb3a..d43938db1 100644 --- a/src/dvb/dvb_adapter.c +++ b/src/dvb/dvb_adapter.c @@ -46,7 +46,6 @@ #include "diseqc.h" struct th_dvb_adapter_queue dvb_adapters; -struct th_dvb_mux_instance_tree dvb_muxes; static void *dvb_adapter_input_dvr(void *aux); @@ -280,6 +279,20 @@ dvb_adapter_set_extrapriority(th_dvb_adapter_t *tda, int extrapriority) tda_save(tda); } + +/** + * + */ +static void +dvb_adapter_set_network(th_dvb_adapter_t *tda, const char *uuid) +{ + dvb_network_t *dn = LIST_FIRST(&dvb_networks); + tda->tda_dn = dn; + LIST_INSERT_HEAD(&dn->dn_adapters, tda, tda_network_link); +} + + + /** * */ @@ -402,7 +415,7 @@ tda_add(int adapter_num) close(fe); tda->tda_fe_type = tda->tda_fe_info->type; - tda->tda_dn = dvb_network_create(tda->tda_fe_type); + dvb_adapter_set_network(tda, NULL); snprintf(buf, sizeof(buf), "%s_%s", tda->tda_rootpath, tda->tda_fe_info->name); diff --git a/src/dvb/dvb_fe.c b/src/dvb/dvb_fe.c index dafca7147..ba05ed4f1 100644 --- a/src/dvb/dvb_fe.c +++ b/src/dvb/dvb_fe.c @@ -107,6 +107,7 @@ dvb_fe_monitor(void *aux) /** * Read out front end status */ + if(ioctl(tda->tda_fe_fd, FE_READ_STATUS, &fe_status)) fe_status = 0; @@ -254,6 +255,7 @@ dvb_fe_monitor(void *aux) } +#if 0 /** * Stop the given TDMI */ @@ -266,16 +268,8 @@ dvb_fe_stop(th_dvb_adapter_t *tda, int retune) assert(tdmi != NULL); dvb_mux_t *dm = tdmi->tdmi_mux; - if(dm->dm_table_initial) { - dm->dm_table_initial = 0; - dm->dm_dn->dn_initial_num_mux--; - dvb_mux_save(dm); - } - dvb_table_flush_all(dm); - assert(dm->dm_scan_queue == NULL); - epggrab_mux_stop(dm, 0); #if 0 /// XXX(dvbreorg) @@ -285,6 +279,9 @@ dvb_fe_stop(th_dvb_adapter_t *tda, int retune) } #endif } +#endif + + #if DVB_API_VERSION >= 5 @@ -342,9 +339,8 @@ static struct dtv_properties clear_cmdseq = { * */ static int -dvb_fe_tune_s2(th_dvb_mux_instance_t *tdmi, dvb_mux_conf_t *dmc) +dvb_fe_tune_s2(th_dvb_adapter_t *tda, dvb_mux_conf_t *dmc) { - th_dvb_adapter_t *tda = tdmi->tdmi_adapter; struct dvb_frontend_parameters *p = &dmc->dmc_fe_params; int r; @@ -388,47 +384,151 @@ dvb_fe_tune_s2(th_dvb_mux_instance_t *tdmi, dvb_mux_conf_t *dmc) #endif + /** - * + * These are created on the fly */ -int -dvb_fe_tune(dvb_mux_t *dm, const char *reason) +static void +dvb_create_tdmis(dvb_mux_t *dm) { + th_dvb_mux_instance_t *tdmi; dvb_network_t *dn = dm->dm_dn; + th_dvb_adapter_t *tda; + + LIST_FOREACH(tda, &dn->dn_adapters, tda_network_link) { + + LIST_FOREACH(tdmi, &dm->dm_tdmis, tdmi_mux_link) { + if(tdmi->tdmi_adapter != NULL) + break; + } - th_dvb_mux_instance_t *tdmi = NULL; // dm->dm_tdmi; + if(tdmi == NULL) { + tdmi = calloc(1, sizeof(th_dvb_mux_instance_t)); + tdmi->tdmi_adapter = tda; + tdmi->tdmi_mux = dm; + LIST_INSERT_HEAD(&tda->tda_tdmis, tdmi, tdmi_adapter_link); + LIST_INSERT_HEAD(&dm->dm_tdmis, tdmi, tdmi_mux_link); + } + } +} + + + +/** + * + */ +static 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; + assert(dm->dm_current_tdmi == tdmi); + assert(tda->tda_current_tdmi == tdmi); + + dvb_table_flush_all(dm); + epggrab_mux_stop(dm, 0); + + assert(dm->dm_scan_status == DM_SCAN_DONE); + + 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) +{ + const dvb_mux_t *dm = tdmi->tdmi_mux; + if(dm->dm_scan_status == DM_SCAN_CURRENT) + return 1; + return 0; +} + + +/** + * + */ +static void +dvb_mux_initial_scan_timeout(void *aux) +{ + dvb_mux_t *dm = aux; + char buf[100]; + + dvb_mux_nicename(buf, sizeof(buf), dm); + tvhlog(LOG_DEBUG, "dvb", "Initial scan timed out for \"%s\"", buf); + + dvb_mux_initial_scan_done(dm); +} + + +/** + * + */ +int +dvb_fe_tune(dvb_mux_t *dm, const char *reason, int weight) +{ + dvb_network_t *dn = dm->dm_dn; // 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; - + th_dvb_mux_instance_t *tdmi; + char buf[256]; int r; - + + assert(dm->dm_current_tdmi == NULL); lock_assert(&global_lock); - free(tda->tda_tune_reason); - tda->tda_tune_reason = strdup(reason); + dvb_create_tdmis(dm); - if(tda->tda_current_tdmi == tdmi) { - dvb_adapter_notify(tda); - return 0; - } + 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; + + 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; + + 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_compute_weight(t2) < weight) { + dvb_mux_stop(t2); + break; + } + } + + if(tdmi == NULL) + return SM_CODE_NO_FREE_ADAPTER; - if(dm->dm_scan_queue != NULL) { - TAILQ_REMOVE(dm->dm_scan_queue, dm, dm_scan_link); - dm->dm_scan_queue = NULL; } - if(tda->tda_current_tdmi != NULL) - dvb_fe_stop(tda, 1); - else - dvb_adapter_start(tda); - + th_dvb_adapter_t *tda = tdmi->tdmi_adapter; + + dvb_adapter_start(tda); + + assert(tda->tda_current_tdmi == NULL); + + free(tda->tda_tune_reason); + tda->tda_tune_reason = strdup(reason); + + tdmi->tdmi_weight = weight; + if(tda->tda_fe_type == FE_QPSK) { - + /* DVB-S */ int port, lowfreq, hifreq, switchfreq, hiband, pol, dbsbs; @@ -486,11 +586,11 @@ dvb_fe_tune(dvb_mux_t *dm, const char *reason) dvb_mux_fec2str(p->u.qpsk.fec_inner), dvb_mux_delsys2str(dmc.dmc_fe_delsys), dvb_mux_qam2str(dmc.dmc_fe_modulation), reason); - r = dvb_fe_tune_s2(tdmi, &dmc); + r = dvb_fe_tune_s2(tda, &dmc); } else #endif { - tvhlog(LOG_DEBUG, "dvb", "\"%s\" tuning to \"%s\" (%s)", tda->tda_rootpath, buf, reason); + tvhlog(LOG_DEBUG, "dvb", "\"%s\" tuning to \"%s\" (%s) fd:%d", tda->tda_rootpath, buf, reason, tda->tda_fe_fd); r = ioctl(tda->tda_fe_fd, FE_SET_FRONTEND, p); } @@ -499,24 +599,26 @@ dvb_fe_tune(dvb_mux_t *dm, const char *reason) " -- Front configuration failed -- %s, frequency: %u", tda->tda_rootpath, buf, strerror(errno), p->frequency); - /* Remove from initial scan set */ - if(dm->dm_table_initial) { - dm->dm_table_initial = 0; - dn->dn_initial_num_mux--; - } - /* Mark as bad */ tdmi->tdmi_tune_failed = 1; - return SM_CODE_TUNING_FAILED; + 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; + TAILQ_INSERT_TAIL(&dn->dn_initial_scan_current_queue, dm, dm_scan_link); - gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1); + gtimer_arm(&dm->dm_initial_scan_timeout, dvb_mux_initial_scan_timeout, dm, 10); + } - dvb_table_add_default(tdmi->tdmi_mux); - epggrab_mux_start(tdmi->tdmi_mux); + gtimer_arm(&tda->tda_fe_monitor_timer, dvb_fe_monitor, tda, 1); + + dvb_table_add_default(dm); + epggrab_mux_start(dm); dvb_adapter_notify(tda); return 0; diff --git a/src/dvb/dvb_input_filtered.c b/src/dvb/dvb_input_filtered.c index 68abf7bf5..9040dcd74 100644 --- a/src/dvb/dvb_input_filtered.c +++ b/src/dvb/dvb_input_filtered.c @@ -59,7 +59,7 @@ open_service(th_dvb_adapter_t *tda, service_t *s) st->es_demuxer_fd = -1; tvhlog(LOG_ERR, "dvb", "\"%s\" unable to open demuxer \"%s\" for pid %d -- %s", - s->s_uuid, tda->tda_demux_path, + s->s_nicename, tda->tda_demux_path, st->es_pid, strerror(errno)); continue; } @@ -74,7 +74,7 @@ open_service(th_dvb_adapter_t *tda, service_t *s) if(ioctl(fd, DMX_SET_PES_FILTER, &dmx_param)) { tvhlog(LOG_ERR, "dvb", "\"%s\" unable to configure demuxer \"%s\" for pid %d -- %s", - s->s_uuid, tda->tda_demux_path, + s->s_nicename, tda->tda_demux_path, st->es_pid, strerror(errno)); close(fd); fd = -1; diff --git a/src/dvb/dvb_multiplex.c b/src/dvb/dvb_multiplex.c index 694248371..49fe59f34 100644 --- a/src/dvb/dvb_multiplex.c +++ b/src/dvb/dvb_multiplex.c @@ -46,8 +46,6 @@ #include "subscriptions.h" #include "epggrab.h" -struct th_dvb_mux_instance_tree dvb_muxes; - static struct strtab muxfestatustab[] = { { "Unknown", TDMI_FE_UNKNOWN }, { "No signal", TDMI_FE_NO_SIGNAL }, @@ -58,18 +56,51 @@ static struct strtab muxfestatustab[] = { { "OK", TDMI_FE_OK }, }; + + +static htsmsg_t *dvb_mux_serialize(struct idnode *self, int full); +static idnode_t **dvb_mux_get_childs(struct idnode *self); + +static const idclass_t dvb_mux_class = { + .ic_class = "dvbmux", + .ic_serialize = dvb_mux_serialize, + .ic_get_childs = dvb_mux_get_childs, +}; + + + /** * */ static void mux_link_initial(dvb_network_t *dn, dvb_mux_t *dm) { - dm->dm_scan_queue = &dn->dn_initial_scan_queue; - TAILQ_INSERT_TAIL(dm->dm_scan_queue, dm, dm_scan_link); + assert(dm->dm_scan_status == DM_SCAN_DONE); - gtimer_arm(&dn->dn_mux_scanner_timer, dvb_network_mux_scanner, dn, 0); + dm->dm_scan_status = DM_SCAN_PENDING; + TAILQ_INSERT_TAIL(&dn->dn_initial_scan_pending_queue, dm, dm_scan_link); + dn->dn_initial_scan_num_mux++; + dvb_network_schedule_initial_scan(dn); } + +/** + * + */ +void +dvb_mux_initial_scan_done(dvb_mux_t *dm) +{ + dvb_network_t *dn = dm->dm_dn; + gtimer_disarm(&dm->dm_initial_scan_timeout); + assert(dm->dm_scan_status == DM_SCAN_CURRENT); + dn->dn_initial_scan_num_mux--; + dm->dm_scan_status = DM_SCAN_DONE; + TAILQ_REMOVE(&dn->dn_initial_scan_current_queue, dm, dm_scan_link); + dvb_network_schedule_initial_scan(dn); + dvb_mux_save(dm); // Save to dm_scan_status is persisted +} + + /** * Return a readable status text for the given mux */ @@ -136,7 +167,7 @@ dcm_compare_conf(int adapter_type, dvb_mux_t * dvb_mux_create(dvb_network_t *dn, const struct dvb_mux_conf *dmc, uint16_t onid, uint16_t tsid, const char *network, - const char *source, int enabled, int initialscan, + const char *source, int enabled, int needscan, const char *uuid) { dvb_mux_t *dm; @@ -186,16 +217,6 @@ dvb_mux_create(dvb_network_t *dn, const struct dvb_mux_conf *dmc, save = 1; } -#if 0 // XXX(dvbreorg) - /* HACK - load old transports and remove old mux config */ - if(identifier) { - save = 1; - dvb_service_load(tdmi, identifier); - hts_settings_remove("dvbmuxes/%s/%s", - tda->tda_identifier, identifier); - } -#endif - if(save) { char buf[128]; dvb_mux_save(dm); @@ -220,6 +241,8 @@ dvb_mux_create(dvb_network_t *dn, const struct dvb_mux_conf *dmc, dm->dm_dn = dn; LIST_INSERT_HEAD(&dn->dn_muxes, dm, dm_network_link); + idnode_insert(&dm->dm_id, uuid, &dvb_mux_class); + char identifier[128]; snprintf(identifier, sizeof(identifier), "%d%s", dmc->dmc_fe_params.frequency, @@ -231,8 +254,6 @@ dvb_mux_create(dvb_network_t *dn, const struct dvb_mux_conf *dmc, memcpy(&dm->dm_conf, dmc, sizeof(struct dvb_mux_conf)); - dm->dm_table_initial = initialscan; - if(source != NULL) { char buf[128]; dvb_mux_nicename(buf, sizeof(buf), dm); @@ -243,8 +264,8 @@ dvb_mux_create(dvb_network_t *dn, const struct dvb_mux_conf *dmc, dvb_service_load(dm); - if(enabled && dm->dm_table_initial) { - dn->dn_initial_num_mux++; + if(enabled && needscan) { + dn->dn_initial_scan_num_mux++; mux_link_initial(dn, dm); } @@ -271,6 +292,7 @@ void dvb_mux_destroy(dvb_mux_t *dm) { th_dvb_mux_instance_t *tdmi; + dvb_network_t *dn = dm->dm_dn; lock_assert(&global_lock); @@ -279,16 +301,25 @@ dvb_mux_destroy(dvb_mux_t *dm) while((tdmi = LIST_FIRST(&dm->dm_tdmis)) != NULL) dvb_tdmi_destroy(tdmi); - if(dm->dm_scan_queue != NULL) - TAILQ_REMOVE(dm->dm_scan_queue, dm, dm_scan_link); + switch(dm->dm_scan_status) { + case DM_SCAN_DONE: + break; + case DM_SCAN_CURRENT: + TAILQ_REMOVE(&dn->dn_initial_scan_current_queue, dm, dm_scan_link); + gtimer_disarm(&dm->dm_initial_scan_timeout); + if(0) // Sorry but i can't resist these whenever i get an oppertunity // andoma + case DM_SCAN_PENDING: + TAILQ_REMOVE(&dn->dn_initial_scan_pending_queue, dm, dm_scan_link); + dn->dn_initial_scan_num_mux--; + dvb_network_schedule_initial_scan(dn); + break; + } - if(dm->dm_table_initial) - dm->dm_dn->dn_initial_num_mux--; epggrab_mux_delete(dm); free(dm->dm_local_identifier); - free(dm->dm_uuid); + idnode_unlink(&dm->dm_id); free(dm); } @@ -492,7 +523,7 @@ dvb_mux_save(dvb_mux_t *dm) htsmsg_add_u32(m, "frequency", f->frequency); - htsmsg_add_u32(m, "initialscan", dm->dm_table_initial); + htsmsg_add_u32(m, "needscan", dm->dm_scan_status != DM_SCAN_DONE); if(dm->dm_default_authority) htsmsg_add_str(m, "default_authority", dm->dm_default_authority); @@ -559,7 +590,7 @@ dvb_mux_save(dvb_mux_t *dm) } hts_settings_save(m, "dvb/networks/%s/muxes/%s/config", - dm->dm_dn->dn_uuid, + idnode_uuid_as_str(&dm->dm_dn->dn_id), dm->dm_local_identifier); htsmsg_destroy(m); @@ -575,7 +606,7 @@ dvb_mux_create_by_msg(dvb_network_t *dn, htsmsg_t *m, const char *fname) struct dvb_mux_conf dmc; const char *s; int r; - unsigned int onid, tsid, enabled, initscan; + unsigned int onid, tsid, enabled; memset(&dmc, 0, sizeof(dmc)); dmc.dmc_fe_params.inversion = INVERSION_AUTO; @@ -694,10 +725,9 @@ dvb_mux_create_by_msg(dvb_network_t *dn, htsmsg_t *m, const char *fname) if(htsmsg_get_u32(m, "enabled", &enabled)) enabled = 1; - initscan = htsmsg_get_u32_or_default(m, "initialscan", 0); dm = dvb_mux_create(dn, &dmc, onid, tsid, htsmsg_get_str(m, "network"), NULL, enabled, - initscan, + htsmsg_get_u32_or_default(m, "needscan", 1), htsmsg_get_str(m, "uuid")); if(dm != NULL) { @@ -718,13 +748,16 @@ dvb_mux_load(dvb_network_t *dn) htsmsg_field_t *f; if((l = hts_settings_load_r(1, "dvb/networks/%s/muxes", - dn->dn_uuid)) == NULL) + idnode_uuid_as_str(&dn->dn_id))) == NULL) return; HTSMSG_FOREACH(f, l) { if((c = htsmsg_get_map_by_field(f)) == NULL) continue; + if((c = htsmsg_get_map(c, "config")) == NULL) + continue; + dvb_mux_create_by_msg(dn, c, f->hmf_name); } htsmsg_destroy(l); @@ -765,7 +798,7 @@ dvb_mux_set_tsid(dvb_mux_t *dm, uint16_t tsid) dvb_mux_save(dm); m = htsmsg_create_map(); - htsmsg_add_str(m, "uuid", dm->dm_uuid); + htsmsg_add_str(m, "uuid", idnode_uuid_as_str(&dm->dm_id)); htsmsg_add_u32(m, "muxid", dm->dm_transport_stream_id); notify_by_msg("dvbMux", m); } @@ -783,7 +816,7 @@ dvb_mux_set_onid(dvb_mux_t *dm, uint16_t onid) dvb_mux_save(dm); m = htsmsg_create_map(); - htsmsg_add_str(m, "uuid", dm->dm_uuid); + htsmsg_add_str(m, "uuid", idnode_uuid_as_str(&dm->dm_id)); htsmsg_add_u32(m, "onid", dm->dm_network_id); notify_by_msg("dvbMux", m); } @@ -917,7 +950,7 @@ dvb_mux_build_msg(dvb_mux_t *dm) htsmsg_t *m = htsmsg_create_map(); char buf[100]; - htsmsg_add_str(m, "uuid", dm->dm_uuid); + htsmsg_add_str(m, "uuid", idnode_uuid_as_str(&dm->dm_id)); htsmsg_add_u32(m, "enabled", dm->dm_enabled); htsmsg_add_str(m, "network", dm->dm_network_name ?: ""); @@ -1200,8 +1233,8 @@ dvb_subscription_create_from_tdmi(th_dvb_mux_instance_t *tdmi, s->ths_tdmi = tdmi; LIST_INSERT_HEAD(&tdmi->tdmi_subscriptions, s, ths_tdmi_link); - dvb_fe_tune(tdmi->tdmi_mux, "Full mux subscription"); - + dvb_fe_tune(tdmi->tdmi_mux, "Full mux subscription", 99999); + abort(); pthread_mutex_lock(&tda->tda_delivery_mutex); streaming_target_connect(&tda->tda_streaming_pad, &s->ths_input); pthread_mutex_unlock(&tda->tda_delivery_mutex); @@ -1209,3 +1242,56 @@ dvb_subscription_create_from_tdmi(th_dvb_mux_instance_t *tdmi, notify_reload("subscriptions"); return s; } + + + +/** + * + */ +static htsmsg_t * +dvb_mux_serialize(struct idnode *self, int full) +{ + dvb_mux_t *dm = (dvb_mux_t *)self; + htsmsg_t *m = htsmsg_create_map(); + htsmsg_add_str(m, "id", idnode_uuid_as_str(&dm->dm_id)); + + char buf[256]; + dvb_mux_nicename(buf, sizeof(buf), dm); + + htsmsg_add_str(m, "text", buf); + return m; +} + +/** + * + */ +static int +svcsortcmp(const void *A, const void *B) +{ + const service_t *a = *(service_t **)A; + const service_t *b = *(service_t **)B; + return (int)a->s_dvb_service_id - (int)b->s_dvb_service_id; +} + + +/** + * + */ +static idnode_t ** +dvb_mux_get_childs(struct idnode *self) +{ + dvb_mux_t *dm = (dvb_mux_t *)self; + service_t *s; + int cnt = 1; + + LIST_FOREACH(s, &dm->dm_services, s_group_link) + cnt++; + + idnode_t **v = malloc(sizeof(idnode_t *) * cnt); + cnt = 0; + LIST_FOREACH(s, &dm->dm_services, s_group_link) + v[cnt++] = (idnode_t *)s; + qsort(v, cnt, sizeof(idnode_t *), svcsortcmp); + v[cnt] = NULL; + return v; +} diff --git a/src/dvb/dvb_network.c b/src/dvb/dvb_network.c index ed140fdb3..4bc6d4add 100644 --- a/src/dvb/dvb_network.c +++ b/src/dvb/dvb_network.c @@ -16,36 +16,129 @@ * along with this program. If not, see . */ +#include + #include "tvheadend.h" #include "packet.h" #include "dvb.h" #include "epggrab.h" +#include "settings.h" +#include "dvb_support.h" struct dvb_network_list dvb_networks; +static htsmsg_t *dvb_network_serialize(struct idnode *self, int full); +static idnode_t **dvb_network_get_childs(struct idnode *self); + +static const idclass_t dvb_network_class = { + .ic_class = "dvbnetwork", + .ic_serialize = dvb_network_serialize, + .ic_get_childs = dvb_network_get_childs, +}; + /** * */ dvb_network_t * -dvb_network_create(int fe_type) +dvb_network_create(int fe_type, const char *uuid) { + printf("Creating network %s\n", uuid); dvb_network_t *dn = calloc(1, sizeof(dvb_network_t)); + if(idnode_insert(&dn->dn_id, uuid, &dvb_network_class)) { + free(dn); + return NULL; + } + + printf("Added network %s\n", idnode_uuid_as_str(&dn->dn_id)); + dn->dn_fe_type = fe_type; - TAILQ_INIT(&dn->dn_initial_scan_queue); - gtimer_arm(&dn->dn_mux_scanner_timer, dvb_network_mux_scanner, dn, 1); + TAILQ_INIT(&dn->dn_initial_scan_pending_queue); + TAILQ_INIT(&dn->dn_initial_scan_current_queue); dn->dn_autodiscovery = fe_type != FE_QPSK; LIST_INSERT_HEAD(&dvb_networks, dn, dn_global_link); return dn; } -#if 0 - htsmsg_get_u32(c, "autodiscovery", &tda->tda_autodiscovery); - htsmsg_get_u32(c, "nitoid", &tda->tda_nitoid); - htsmsg_get_u32(c, "disable_pmt_monitor", &tda->tda_disable_pmt_monitor); -#endif -#if 0 + +/** + * + */ +static htsmsg_t * +dvb_network_serialize(struct idnode *self, int full) +{ + dvb_network_t *dn = (dvb_network_t *)self; + htsmsg_t *m = htsmsg_create_map(); + htsmsg_add_str(m, "id", idnode_uuid_as_str(&dn->dn_id)); + htsmsg_add_str(m, "text", idnode_uuid_as_str(&dn->dn_id)); + return m; +} + + +/** + * + */ +static int +muxsortcmp(const void *A, const void *B) +{ + const dvb_mux_t *a = *(dvb_mux_t **)A; + const dvb_mux_t *b = *(dvb_mux_t **)B; + if(a->dm_conf.dmc_fe_params.frequency < b->dm_conf.dmc_fe_params.frequency) + return -1; + if(a->dm_conf.dmc_fe_params.frequency > b->dm_conf.dmc_fe_params.frequency) + return 1; + return a->dm_conf.dmc_polarisation - b->dm_conf.dmc_polarisation; +} + + +/** + * + */ +static idnode_t ** +dvb_network_get_childs(struct idnode *self) +{ + dvb_network_t *dn = (dvb_network_t *)self; + dvb_mux_t *dm; + int cnt = 1; + LIST_FOREACH(dm, &dn->dn_muxes, dm_network_link) + cnt++; + + idnode_t **v = malloc(sizeof(idnode_t *) * cnt); + cnt = 0; + LIST_FOREACH(dm, &dn->dn_muxes, dm_network_link) + v[cnt++] = (idnode_t *)dm; + qsort(v, cnt, sizeof(idnode_t *), muxsortcmp); + v[cnt] = NULL; + return v; +} + + +/** + * + */ +static void +dvb_network_load(htsmsg_t *m, const char *uuid) +{ + uint32_t fetype; + + if(htsmsg_get_u32(m, "fetype", &fetype)) + return; + + dvb_network_t *dn = dvb_network_create(fetype, uuid); + if(dn == NULL) + return; + + htsmsg_get_u32(m, "autodiscovery", &dn->dn_autodiscovery); + htsmsg_get_u32(m, "nitoid", &dn->dn_nitoid); + htsmsg_get_u32(m, "disable_pmt_monitor", &dn->dn_disable_pmt_monitor); + + dvb_mux_load(dn); + + dvb_network_schedule_initial_scan(dn); +} + +#if 1 /** * */ @@ -56,13 +149,18 @@ dvb_network_save(dvb_network_t *dn) lock_assert(&global_lock); + htsmsg_add_u32(m, "fetype", dn->dn_fe_type); htsmsg_add_u32(m, "autodiscovery", dn->dn_autodiscovery); htsmsg_add_u32(m, "nitoid", dn->dn_nitoid); htsmsg_add_u32(m, "disable_pmt_monitor", dn->dn_disable_pmt_monitor); - abort(); + + hts_settings_save(m, "dvb/networks/%s/config", + idnode_uuid_as_str(&dn->dn_id)); + htsmsg_destroy(m); } #endif + #if 0 /** * @@ -125,65 +223,82 @@ dvb_network_set_disable_pmt_monitor(th_dvb_network_t *dn, int on) #endif + /** * */ -void -dvb_network_mux_scanner(void *aux) +static void +dvb_network_initial_scan(void *aux) { dvb_network_t *dn = aux; dvb_mux_t *dm; - // default period - gtimer_arm(&dn->dn_mux_scanner_timer, dvb_network_mux_scanner, dn, 20); - -#if 0 - /* No muxes */ - if(LIST_FIRST(&dn->dn_mux_instances) == NULL) { - dvb_adapter_poweroff(tda); - return; + while((dm = TAILQ_FIRST(&dn->dn_initial_scan_pending_queue)) != NULL) { + assert(dm->dm_scan_status == DM_SCAN_PENDING); + if(dvb_fe_tune(dm, "initial scan", 1)) + break; + assert(dm->dm_scan_status == DM_SCAN_CURRENT); } -#endif -#if 0 - /* Someone is actively using */ - if(service_compute_weight(&tda->tda_transports) > 0) - return; -#endif -#if 0 - if(tda->tda_mux_current != NULL && - LIST_FIRST(&tda->tda_mux_current->tdmi_subscriptions) != NULL) - return; // Someone is doing full mux dump -#endif + gtimer_arm(&dn->dn_initial_scan_timer, dvb_network_initial_scan, dn, 10); +} - /* Check if we have muxes pending for quickscan, if so, choose them */ - if((dm = TAILQ_FIRST(&dn->dn_initial_scan_queue)) != NULL) { - dvb_fe_tune(dm, "Initial autoscan"); - return; - } +/** + * + */ +void +dvb_network_schedule_initial_scan(dvb_network_t *dn) +{ + gtimer_arm(&dn->dn_initial_scan_timer, dvb_network_initial_scan, dn, 0); +} - /* Check EPG */ - if (dn->dn_mux_epg) { - // timeout anything not complete - epggrab_mux_stop(dn->dn_mux_epg, 1); - dn->dn_mux_epg = NULL; // skip this time - } else { - dn->dn_mux_epg = epggrab_mux_next(dn); +/** + * + */ +void +dvb_network_init(void) +{ + htsmsg_t *l, *c; + htsmsg_field_t *f; + + if(0) { + dvb_network_save(dvb_network_create(FE_QAM, NULL)); + exit(0); } - /* EPG */ - if (dn->dn_mux_epg) { - int period = epggrab_mux_period(dn->dn_mux_epg); - if (period > 20) - gtimer_arm(&dn->dn_mux_scanner_timer, - dvb_network_mux_scanner, dn, period); - dvb_fe_tune(dn->dn_mux_epg, "EPG scan"); + if((l = hts_settings_load_r(1, "dvb/networks")) == NULL) return; + + htsmsg_print(l); + + HTSMSG_FOREACH(f, l) { + if((c = htsmsg_get_map_by_field(f)) == NULL) + continue; + + if((c = htsmsg_get_map(c, "config")) == NULL) + continue; + + dvb_network_load(c, f->hmf_name); } + htsmsg_destroy(l); +} -#if 0 - /* Ensure we stop current mux and power off (if required) */ - if (tda->tda_mux_current) - dvb_fe_stop(tda->tda_mux_current, 0); -#endif + +/** + * + */ +idnode_t ** +dvb_network_root(void) +{ + dvb_network_t *dn; + int cnt = 1; + LIST_FOREACH(dn, &dvb_networks, dn_global_link) + cnt++; + + idnode_t **v = malloc(sizeof(idnode_t *) * cnt); + cnt = 0; + LIST_FOREACH(dn, &dvb_networks, dn_global_link) + v[cnt++] = &dn->dn_id; + v[cnt] = NULL; + return v; } diff --git a/src/dvb/dvb_service.c b/src/dvb/dvb_service.c index e771d898f..109312e2c 100644 --- a/src/dvb/dvb_service.c +++ b/src/dvb/dvb_service.c @@ -44,15 +44,7 @@ #include "dvb_support.h" #include "notify.h" - - -/** - * - */ - - - - +static htsmsg_t *dvb_service_serialize(service_t *s, int full); /** @@ -110,7 +102,7 @@ dvb_service_start(service_t *t, unsigned int weight, int force_start) return r; #endif - return SM_CODE_NO_HW_ATTACHED; + return SM_CODE_NO_FREE_ADAPTER; } @@ -193,7 +185,7 @@ dvb_service_save(service_t *t) dvb_mux_t *dm = t->s_dvb_mux; hts_settings_save(m, "dvb/networks/%s/muxes/%s/services/%04x", - dm->dm_dn->dn_uuid, + idnode_uuid_as_str(&dm->dm_dn->dn_id), dm->dm_local_identifier, t->s_dvb_service_id); @@ -217,7 +209,8 @@ dvb_service_load(dvb_mux_t *dm) lock_assert(&global_lock); l = hts_settings_load("dvb/networks/%s/muxes/%s/services", - dm->dm_dn->dn_uuid, dm->dm_local_identifier); + idnode_uuid_as_str(&dm->dm_dn->dn_id), + dm->dm_local_identifier); if(l == NULL) return; @@ -398,6 +391,7 @@ dvb_service_find2(dvb_mux_t *dm, uint16_t sid, int pmt_pid, t->s_config_save = dvb_service_save; t->s_setsourceinfo = dvb_service_setsourceinfo; t->s_grace_period = dvb_grace_period; + t->s_serialize = dvb_service_serialize; t->s_dvb_mux = dm; LIST_INSERT_HEAD(&dm->dm_services, t, s_group_link); @@ -412,38 +406,44 @@ dvb_service_find2(dvb_mux_t *dm, uint16_t sid, int pmt_pid, /** * */ -htsmsg_t * -dvb_service_build_msg(service_t *t) +static htsmsg_t * +dvb_service_serialize(service_t *s, int full) { - dvb_mux_t *dm = t->s_dvb_mux; + dvb_mux_t *dm = s->s_dvb_mux; htsmsg_t *m = htsmsg_create_map(); char buf[100]; - - htsmsg_add_str(m, "uuid", t->s_uuid); - htsmsg_add_u32(m, "enabled", t->s_enabled); - htsmsg_add_u32(m, "channel", t->s_channel_number); - htsmsg_add_u32(m, "sid", t->s_dvb_service_id); - htsmsg_add_u32(m, "pmt", t->s_pmt_pid); - htsmsg_add_u32(m, "pcr", t->s_pcr_pid); - - htsmsg_add_str(m, "type", service_servicetype_txt(t)); + htsmsg_add_str(m, "id", idnode_uuid_as_str(&s->s_id)); + + snprintf(buf, sizeof(buf), "%s (0x%04x)", + s->s_svcname ?: "", s->s_dvb_service_id); + htsmsg_add_str(m, "text", buf); + + + htsmsg_add_u32(m, "enabled", s->s_enabled); + htsmsg_add_u32(m, "channel", s->s_channel_number); + + htsmsg_add_u32(m, "sid", s->s_dvb_service_id); + htsmsg_add_u32(m, "pmt", s->s_pmt_pid); + htsmsg_add_u32(m, "pcr", s->s_pcr_pid); - htsmsg_add_str(m, "svcname", t->s_svcname ?: ""); - htsmsg_add_str(m, "provider", t->s_provider ?: ""); + htsmsg_add_str(m, "type", service_servicetype_txt(s)); + + htsmsg_add_str(m, "svcname", s->s_svcname ?: ""); + htsmsg_add_str(m, "provider", s->s_provider ?: ""); htsmsg_add_str(m, "network", dm->dm_network_name ?: ""); dvb_mux_nicefreq(buf, sizeof(buf), dm); htsmsg_add_str(m, "mux", buf); - if(t->s_ch != NULL) - htsmsg_add_str(m, "channelname", t->s_ch->ch_name); + if(s->s_ch != NULL) + htsmsg_add_str(m, "channelname", s->s_ch->ch_name); - if(t->s_dvb_charset != NULL) - htsmsg_add_str(m, "dvb_charset", t->s_dvb_charset); + if(s->s_dvb_charset != NULL) + htsmsg_add_str(m, "dvb_charset", s->s_dvb_charset); - htsmsg_add_u32(m, "dvb_eit_enable", t->s_dvb_eit_enable); + htsmsg_add_u32(m, "dvb_eit_enable", s->s_dvb_eit_enable); return m; } diff --git a/src/dvb/dvb_tables.c b/src/dvb/dvb_tables.c index 6cd5e4515..3537cb514 100644 --- a/src/dvb/dvb_tables.c +++ b/src/dvb/dvb_tables.c @@ -52,25 +52,21 @@ dvb_table_fastswitch(th_dvb_mux_instance_t *tdmi) th_dvb_table_t *tdt; th_dvb_adapter_t *tda = tdmi->tdmi_adapter; dvb_mux_t *dm = tdmi->tdmi_mux; - dvb_network_t *dn = dm->dm_dn; char buf[100]; - if(!dm->dm_table_initial) + if(dm->dm_scan_status == DM_SCAN_DONE) return; LIST_FOREACH(tdt, &dm->dm_tables, tdt_link) if((tdt->tdt_flags & TDT_QUICKREQ) && tdt->tdt_count == 0) return; - dm->dm_table_initial = 0; - dn->dn_initial_num_mux--; dvb_mux_save(dm); - dvb_mux_nicename(buf, sizeof(buf), dm); tvhlog(LOG_DEBUG, "dvb", "\"%s\" initial scan completed for \"%s\"", tda->tda_rootpath, buf); - dvb_network_mux_scanner(dn); + dvb_mux_initial_scan_done(dm); } diff --git a/src/epggrab/otamux.c b/src/epggrab/otamux.c index b02e17fc0..85490585d 100644 --- a/src/epggrab/otamux.c +++ b/src/epggrab/otamux.c @@ -369,13 +369,14 @@ void epggrab_ota_complete ( epggrab_ota_mux_t *ota ) TAILQ_FOREACH(ota, &dm->dm_epg_grab, dm_link) { if (ota->is_reg && ota->state == EPGGRAB_OTA_MUX_RUNNING) break; } - +#if 0 // XXX(dvbreorg) /* All complete (bring timer forward) */ if (!ota) { dvb_network_t *dn = dm->dm_dn; gtimer_arm(&dn->dn_mux_scanner_timer, dvb_network_mux_scanner, dn, 20); } +#endif } } diff --git a/src/filebundle.c b/src/filebundle.c index 82450a377..d2b745152 100644 --- a/src/filebundle.c +++ b/src/filebundle.c @@ -305,7 +305,7 @@ int fb_scandir ( const char *path, fb_dirent ***list ) for (i = 0; i < ret; i++) { (*list)[i] = calloc(1, sizeof(fb_dirent)); strcpy((*list)[i]->name, de[i]->d_name); - (*list)[i]->type = FB_DIRECT; + (*list)[i]->type = de[i]->d_type == DT_DIR ? FB_DIR : FB_FILE; free(de[i]); } free(de); diff --git a/src/idnode.c b/src/idnode.c new file mode 100644 index 000000000..58b3bbd4b --- /dev/null +++ b/src/idnode.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include + +#include "idnode.h" + +static int randfd = 0; + +RB_HEAD(idnode_tree, idnode); + +static struct idnode_tree idnodes; + +/** + * + */ +static int +hexnibble(char c) +{ + switch(c) { + case '0' ... '9': return c - '0'; + case 'a' ... 'f': return c - 'a' + 10; + case 'A' ... 'F': return c - 'A' + 10; + default: + return -1; + } +} + + +/** + * + */ +static int +hex2bin(uint8_t *buf, size_t buflen, const char *str) +{ + int hi, lo; + + while(*str) { + if(buflen == 0) + return -1; + if((hi = hexnibble(*str++)) == -1) + return -1; + if((lo = hexnibble(*str++)) == -1) + return -1; + + *buf++ = hi << 4 | lo; + buflen--; + } + return 0; +} + + +/** + * + */ +static void +bin2hex(char *dst, size_t dstlen, const uint8_t *src, size_t srclen) +{ + while(dstlen > 2 && srclen > 0) { + *dst++ = "0123456789abcdef"[*src >> 4]; + *dst++ = "0123456789abcdef"[*src & 0xf]; + src++; + srclen--; + dstlen -= 2; + } + *dst = 0; +} + + +/** + * + */ +void +idnode_init(void) +{ + randfd = open("/dev/urandom", O_RDONLY); + if(randfd == -1) + exit(1); +} + + +/** + * + */ +static int +in_cmp(const idnode_t *a, const idnode_t *b) +{ + return memcmp(a->in_uuid, b->in_uuid, 16); +} + + +/** + * + */ +int +idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class) +{ + idnode_t *c; + if(uuid == NULL) { + if(read(randfd, in->in_uuid, 16) != 16) { + perror("read(random for uuid)"); + exit(1); + } + } else { + if(hex2bin(in->in_uuid, 16, uuid)) + return -1; + } + + in->in_class = class; + + c = RB_INSERT_SORTED(&idnodes, in, in_link, in_cmp); + if(c != NULL) { + fprintf(stderr, "Id node collision\n"); + abort(); + } + return 0; +} + + +/** + * + */ +const char * +idnode_uuid_as_str(const idnode_t *in) +{ + static char ret[16][33]; + static int p; + char *b = ret[p]; + bin2hex(b, 33, in->in_uuid, 16); + p = (p + 1) & 15; + return b; +} + + +/** + * + */ +idnode_t * +idnode_find(const char *uuid) +{ + idnode_t skel, *r; + + if(hex2bin(skel.in_uuid, 16, uuid)) + return NULL; + r = RB_FIND(&idnodes, &skel, in_link, in_cmp); + return r; +} + + +/** + * + */ +void +idnode_unlink(idnode_t *in) +{ + RB_REMOVE(&idnodes, in, in_link); +} diff --git a/src/idnode.h b/src/idnode.h new file mode 100644 index 000000000..a49b43821 --- /dev/null +++ b/src/idnode.h @@ -0,0 +1,29 @@ +#pragma once + +#include "tvheadend.h" + +struct htsmsg; +struct idnode; + +typedef struct idclass { + const char *ic_class; + struct htsmsg *(*ic_serialize)(struct idnode *self, int full); + struct idnode **(*ic_get_childs)(struct idnode *self); +} idclass_t; + + +typedef struct idnode { + uint8_t in_uuid[16]; + RB_ENTRY(idnode) in_link; + const idclass_t *in_class; +} idnode_t; + +void idnode_init(void); + +int idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class); + +const char *idnode_uuid_as_str(const idnode_t *in); + +idnode_t *idnode_find(const char *uuid); + +void idnode_unlink(idnode_t *in); diff --git a/src/iptv_input.c b/src/iptv_input.c index 8705e71da..5abc4ef38 100644 --- a/src/iptv_input.c +++ b/src/iptv_input.c @@ -227,7 +227,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start) fd = tvh_socket(AF_INET6, SOCK_DGRAM, 0); } if(fd == -1) { - tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot open socket", t->s_uuid); + tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot open socket", t->s_nicename); return -1; } @@ -237,7 +237,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start) ifr.ifr_name[IFNAMSIZ - 1] = 0; if(ioctl(fd, SIOCGIFINDEX, &ifr)) { tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot find interface %s", - t->s_uuid, t->s_iptv_iface); + t->s_nicename, t->s_iptv_iface); close(fd); return -1; } @@ -251,7 +251,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &m, sizeof(struct ip_mreqn)); if(bind(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot bind %s:%d -- %s", - t->s_uuid, inet_ntoa(sin.sin_addr), t->s_iptv_port, + t->s_nicename, inet_ntoa(sin.sin_addr), t->s_iptv_port, strerror(errno)); close(fd); return -1; @@ -265,7 +265,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start) if(setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, sizeof(struct ip_mreqn)) == -1) { tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s", - t->s_uuid, inet_ntoa(m.imr_multiaddr), strerror(errno)); + t->s_nicename, inet_ntoa(m.imr_multiaddr), strerror(errno)); close(fd); return -1; } @@ -279,7 +279,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start) if(bind(fd, (struct sockaddr *)&sin6, sizeof(sin6)) == -1) { inet_ntop(AF_INET6, &sin6.sin6_addr, straddr, sizeof(straddr)); tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot bind %s:%d -- %s", - t->s_uuid, straddr, t->s_iptv_port, + t->s_nicename, straddr, t->s_iptv_port, strerror(errno)); close(fd); return -1; @@ -294,7 +294,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start) inet_ntop(AF_INET6, m6.ipv6mr_multiaddr.s6_addr, straddr, sizeof(straddr)); tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot join %s -- %s", - t->s_uuid, straddr, strerror(errno)); + t->s_nicename, straddr, strerror(errno)); close(fd); return -1; } @@ -312,7 +312,7 @@ iptv_service_start(service_t *t, unsigned int weight, int force_start) ev.data.fd = fd; if(epoll_ctl(iptv_epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) { tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot add to epoll set -- %s", - t->s_uuid, strerror(errno)); + t->s_nicename, strerror(errno)); close(fd); return -1; } @@ -356,7 +356,7 @@ iptv_service_stop(service_t *t) ifr.ifr_name[IFNAMSIZ - 1] = 0; if(ioctl(t->s_iptv_fd, SIOCGIFINDEX, &ifr)) { tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot find interface %s", - t->s_uuid, t->s_iptv_iface); + t->s_nicename, t->s_iptv_iface); } if(t->s_iptv_group.s_addr != 0) { @@ -371,7 +371,7 @@ iptv_service_stop(service_t *t) if(setsockopt(t->s_iptv_fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, sizeof(struct ip_mreqn)) == -1) { tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s", - t->s_uuid, inet_ntoa(m.imr_multiaddr), strerror(errno)); + t->s_nicename, inet_ntoa(m.imr_multiaddr), strerror(errno)); } } else { char straddr[INET6_ADDRSTRLEN]; @@ -388,7 +388,7 @@ iptv_service_stop(service_t *t) straddr, sizeof(straddr)); tvhlog(LOG_ERR, "IPTV", "\"%s\" cannot leave %s -- %s", - t->s_uuid, straddr, strerror(errno)); + t->s_nicename, straddr, strerror(errno)); } @@ -440,8 +440,9 @@ iptv_service_save(service_t *t) psi_save_service_settings(m, t); pthread_mutex_unlock(&t->s_stream_mutex); - hts_settings_save(m, "iptvservices/%s", - t->s_uuid); + abort(); // XXX(dvbreorg); + + // hts_settings_save(m, "iptvservices/%s", t->s_uuid); htsmsg_destroy(m); } @@ -484,7 +485,8 @@ iptv_grace_period(service_t *t) static void iptv_service_dtor(service_t *t) { - hts_settings_remove("iptvservices/%s", t->s_uuid); + abort(); // XXX(dvbreorg); + // hts_settings_remove("iptvservices/%s", t->s_uuid); } @@ -504,7 +506,7 @@ iptv_service_find(const char *id, int create) return NULL; LIST_FOREACH(t, &iptv_all_services, s_group_link) - if(!strcmp(t->s_uuid, id)) + if(!strcmp(t->s_nicename, id)) // XXX(dvbreorg) return t; } diff --git a/src/main.c b/src/main.c index 580a151cf..5e93b94e9 100644 --- a/src/main.c +++ b/src/main.c @@ -60,6 +60,7 @@ #include "ffdecsa/FFdecsa.h" #include "muxes.h" #include "config2.h" +#include "idnode.h" int running; time_t dispatch_clock; @@ -444,6 +445,9 @@ main(int argc, char **argv) access_init(createdefault); tcp_server_init(); + + idnode_init(); + #if ENABLE_LINUXDVB dvb_init(adapter_mask, dvb_rawts_input); #endif diff --git a/src/service.c b/src/service.c index 90b8a4d72..c625148d9 100644 --- a/src/service.c +++ b/src/service.c @@ -49,11 +49,14 @@ #include "htsp_server.h" #include "lang_codes.h" -#define SERVICE_HASH_WIDTH 101 +static void service_data_timeout(void *aux); -static struct service_list servicehash[SERVICE_HASH_WIDTH]; +static htsmsg_t *service_serialize(struct idnode *self, int full); -static void service_data_timeout(void *aux); +static const idclass_t service_class = { + .ic_class = "service", + .ic_serialize = service_serialize, +}; /** * @@ -391,14 +394,14 @@ service_destroy(service_t *t) } LIST_REMOVE(t, s_group_link); - LIST_REMOVE(t, s_hash_link); - + + idnode_unlink(&t->s_id); + if(t->s_status != SERVICE_IDLE) service_stop(t); t->s_status = SERVICE_ZOMBIE; - free(t->s_uuid); free(t->s_svcname); free(t->s_provider); free(t->s_dvb_charset); @@ -429,14 +432,12 @@ service_destroy(service_t *t) service_t * service_create(const char *uuid, int source_type) { - unsigned int hash = tvh_strhash(uuid, SERVICE_HASH_WIDTH); service_t *t = calloc(1, sizeof(service_t)); lock_assert(&global_lock); pthread_mutex_init(&t->s_stream_mutex, NULL); pthread_cond_init(&t->s_tss_cond, NULL); - t->s_uuid = strdup(uuid); t->s_source_type = source_type; t->s_refcount = 1; t->s_enabled = 1; @@ -449,7 +450,8 @@ service_create(const char *uuid, int source_type) streaming_pad_init(&t->s_streaming_pad); - LIST_INSERT_HEAD(&servicehash[hash], t, s_hash_link); + idnode_insert(&t->s_id, uuid, &service_class); + return t; } @@ -459,15 +461,8 @@ service_create(const char *uuid, int source_type) service_t * service_find_by_identifier(const char *identifier) { - service_t *t; - unsigned int hash = tvh_strhash(identifier, SERVICE_HASH_WIDTH); - - lock_assert(&global_lock); - - LIST_FOREACH(t, &servicehash[hash], s_hash_link) - if(!strcmp(t->s_uuid, identifier)) - break; - return t; + idnode_t *id = idnode_find(identifier); + return id->in_class == &service_class ? (service_t *)id : NULL; } @@ -1128,3 +1123,14 @@ htsmsg_t *servicetype_list ( void ) } return ret; } + + +/** + * + */ +static htsmsg_t * +service_serialize(struct idnode *self, int full) +{ + service_t *s = (service_t *)self; + return s->s_serialize(s, full); +} diff --git a/src/service.h b/src/service.h index e63dfbfff..294ef695e 100644 --- a/src/service.h +++ b/src/service.h @@ -22,7 +22,7 @@ #define PID_TELETEXT_BASE 0x2000 #include "htsmsg.h" - +#include "idnode.h" /** @@ -201,8 +201,7 @@ service_start_cand_t *service_find_cand(struct service_start_cand_list *sscl, * */ typedef struct service { - - LIST_ENTRY(service) s_hash_link; + idnode_t s_id; enum { /** @@ -305,16 +304,13 @@ typedef struct service { void (*s_dtor)(struct service *t); + htsmsg_t *(*s_serialize)(struct service *s, int full); + /* * Per source type structs */ struct dvb_mux *s_dvb_mux; - /** - * Unique identifer - */ - char *s_uuid; - /** * Name usable for displaying to user */ diff --git a/src/streaming.c b/src/streaming.c index bf1614f88..7a490f536 100755 --- a/src/streaming.c +++ b/src/streaming.c @@ -401,8 +401,8 @@ streaming_code2txt(int code) case SM_CODE_SUBSCRIPTION_OVERRIDDEN: return "Subscription overridden"; - case SM_CODE_NO_HW_ATTACHED: - return "No hardware present"; + case SM_CODE_NO_FREE_ADAPTER: + return "No free adapter"; case SM_CODE_MUX_NOT_ENABLED: return "Mux not enabled"; case SM_CODE_NOT_FREE: diff --git a/src/tvheadend.h b/src/tvheadend.h index e401d5824..6fddae3bb 100644 --- a/src/tvheadend.h +++ b/src/tvheadend.h @@ -284,7 +284,7 @@ typedef enum { #define SM_CODE_SOURCE_DELETED 102 #define SM_CODE_SUBSCRIPTION_OVERRIDDEN 103 -#define SM_CODE_NO_HW_ATTACHED 200 +#define SM_CODE_NO_FREE_ADAPTER 200 #define SM_CODE_MUX_NOT_ENABLED 201 #define SM_CODE_NOT_FREE 202 #define SM_CODE_TUNING_FAILED 203 diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 98d124262..841840b84 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -1669,7 +1669,7 @@ build_record_iptv(service_t *t) htsmsg_t *r = htsmsg_create_map(); char abuf[INET_ADDRSTRLEN]; char abuf6[INET6_ADDRSTRLEN]; - htsmsg_add_str(r, "id", t->s_uuid); + // htsmsg_add_str(r, "id", t->s_uuid); // XXX(dvbreorg) htsmsg_add_str(r, "channelname", t->s_ch ? t->s_ch->ch_name : ""); htsmsg_add_str(r, "interface", t->s_iptv_iface ?: ""); @@ -1828,7 +1828,7 @@ extjs_tvadapter(http_connection_t *hc, const char *remain, void *opaque) array = htsmsg_create_list(); #if ENABLE_LINUXDVB - // extjs_list_dvb_adapters(array); + extjs_list_dvb_adapters(array); #endif #if ENABLE_V4L diff --git a/src/webui/extjs_dvb.c b/src/webui/extjs_dvb.c index c6aebc41d..f321200ae 100644 --- a/src/webui/extjs_dvb.c +++ b/src/webui/extjs_dvb.c @@ -43,7 +43,6 @@ #include "dvb/dvb_preconf.h" #include "dvr/dvr.h" -#if 0 @@ -61,7 +60,7 @@ extjs_dvblocations(http_connection_t *hc, const char *remain, void *opaque) if(s == NULL || a == NULL) return HTTP_STATUS_BAD_REQUEST; - + pthread_mutex_lock(&global_lock); if(http_access_verify(hc, ACCESS_ADMIN)) { @@ -85,6 +84,7 @@ extjs_dvblocations(http_connection_t *hc, const char *remain, void *opaque) return 0; } + /** * */ @@ -115,8 +115,6 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque) const char *op = http_arg_get(&hc->hc_req_args, "op"); const char *sibling = http_arg_get(&hc->hc_req_args, "sibling"); const char *s; - th_dvb_mux_instance_t *tdmi; - service_t *t; pthread_mutex_lock(&global_lock); @@ -151,15 +149,12 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque) htsmsg_add_str(r, "id", tda->tda_identifier); htsmsg_add_str(r, "device", tda->tda_rootpath ?: "No hardware attached"); htsmsg_add_str(r, "name", tda->tda_displayname); - htsmsg_add_u32(r, "automux", tda->tda_autodiscovery); htsmsg_add_u32(r, "skip_initialscan", tda->tda_skip_initialscan); htsmsg_add_u32(r, "idleclose", tda->tda_idleclose); htsmsg_add_u32(r, "skip_checksubscr", tda->tda_skip_checksubscr); htsmsg_add_u32(r, "qmon", tda->tda_qmon); htsmsg_add_u32(r, "poweroff", tda->tda_poweroff); htsmsg_add_u32(r, "sidtochan", tda->tda_sidtochan); - htsmsg_add_u32(r, "nitoid", tda->tda_nitoid); - htsmsg_add_u32(r, "disable_pmt_monitor", tda->tda_disable_pmt_monitor); htsmsg_add_u32(r, "full_mux_rx", tda->tda_full_mux_rx+1); htsmsg_add_str(r, "diseqcversion", ((const char *[]){"DiSEqC 1.0 / 2.0", @@ -176,9 +171,6 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque) if((s = http_arg_get(&hc->hc_req_args, "name")) != NULL) dvb_adapter_set_displayname(tda, s); - s = http_arg_get(&hc->hc_req_args, "automux"); - dvb_adapter_set_auto_discovery(tda, !!s); - s = http_arg_get(&hc->hc_req_args, "skip_initialscan"); dvb_adapter_set_skip_initialscan(tda, !!s); @@ -197,15 +189,9 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque) s = http_arg_get(&hc->hc_req_args, "sidtochan"); dvb_adapter_set_sidtochan(tda, !!s); - s = http_arg_get(&hc->hc_req_args, "disable_pmt_monitor"); - dvb_adapter_set_disable_pmt_monitor(tda, !!s); - s = http_arg_get(&hc->hc_req_args, "full_mux_rx"); dvb_adapter_set_full_mux_rx(tda, atoi(s)-1); - if((s = http_arg_get(&hc->hc_req_args, "nitoid")) != NULL) - dvb_adapter_set_nitoid(tda, atoi(s)); - if((s = http_arg_get(&hc->hc_req_args, "diseqcversion")) != NULL) { if(!strcmp(s, "DiSEqC 1.0 / 2.0")) dvb_adapter_set_diseqc_version(tda, 0); @@ -231,11 +217,11 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque) // sc = http_arg_get(&hc->hc_req_args, "satconf"); if((s = http_arg_get(&hc->hc_req_args, "network")) != NULL) - dvb_mux_preconf_add_network(tda, s); + dvb_mux_preconf_add_network(tda->tda_dn, s); out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); - +#if 0 } else if(!strcmp(op, "serviceprobe")) { tvhlog(LOG_NOTICE, "web interface", @@ -251,6 +237,7 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque) out = htsmsg_create_map(); htsmsg_add_u32(out, "success", 1); +#endif } else { pthread_mutex_unlock(&global_lock); @@ -265,6 +252,7 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque) return 0; } +#if 0 /** * @@ -678,6 +666,8 @@ extjs_dvb_copymux(http_connection_t *hc, const char *remain, void *opaque) } #endif +#endif + /** * */ @@ -689,7 +679,6 @@ extjs_list_dvb_adapters(htsmsg_t *array) htsmsg_add_msg(array, NULL, dvb_adapter_build_msg(tda)); } -#endif /** * @@ -711,27 +700,29 @@ extjs_dvbnetworks(http_connection_t *hc, const char *remain, void *opaque) return HTTP_STATUS_UNAUTHORIZED; } - printf("s=%s\n", s); - out = htsmsg_create_list(); + idnode_t **v; + if(!strcmp(s, "root")) { - htsmsg_t *n = htsmsg_create_map(); - htsmsg_add_str(n, "text", "Network1"); - htsmsg_add_str(n, "id", "net/1"); - htsmsg_add_str(n, "cls", "folder"); - htsmsg_add_str(n, "iconCls", "iptv"); - htsmsg_add_msg(out, NULL, n); - - n = htsmsg_create_map(); - htsmsg_add_str(n, "text", "Network2"); - htsmsg_add_str(n, "id", "net/2"); - htsmsg_add_str(n, "cls", "folder"); - htsmsg_add_msg(out, NULL, n); + v = dvb_network_root(); + } else { + idnode_t *n = idnode_find(s); + v = n != NULL && n->in_class->ic_get_childs != NULL ? + n->in_class->ic_get_childs(n) : NULL; } + int i; + for(i = 0; v[i] != NULL; i++) { + htsmsg_t *m = v[i]->in_class->ic_serialize(v[i], 0); + if(v[i]->in_class->ic_get_childs == NULL) + htsmsg_add_u32(m, "leaf", 1); + htsmsg_add_msg(out, NULL, m); + } pthread_mutex_unlock(&global_lock); + free(v); + htsmsg_json_serialize(out, hq, 0); htsmsg_destroy(out); http_output_content(hc, "text/x-json; charset=UTF-8"); @@ -748,14 +739,14 @@ extjs_start_dvb(void) { http_path_add("/dvb/networks", NULL, extjs_dvbnetworks, ACCESS_WEB_INTERFACE); -#if 0 http_path_add("/dvb/locations", NULL, extjs_dvblocations, ACCESS_WEB_INTERFACE); - http_path_add("/dvb/adapter", NULL, extjs_dvbadapter, ACCESS_ADMIN); +#if 0 + http_path_add("/dvb/muxes", NULL, extjs_dvbmuxes, ACCESS_ADMIN); diff --git a/src/webui/static/app/dvb_networks.js b/src/webui/static/app/dvb_networks.js new file mode 100644 index 000000000..44b686875 --- /dev/null +++ b/src/webui/static/app/dvb_networks.js @@ -0,0 +1,25 @@ +/** + * + */ +tvheadend.dvb_networks = function() { + + var loader = new Ext.tree.TreeLoader({ + dataUrl: 'dvb/networks' + }); + + var tree = new Ext.tree.TreePanel({ + title: 'DVB Networks', + loader: loader, + root : new Ext.tree.AsyncTreeNode({ + id : 'root', + text: 'DVB Networks' + }) + }); + + + tree.on('render', function() { + tree.getRootNode().expand(); + }); + + return tree; +} diff --git a/src/webui/webui.c b/src/webui/webui.c index f72a865dc..be97063f1 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -606,7 +606,7 @@ http_stream_tdmi(http_connection_t *hc, th_dvb_mux_instance_t *tdmi) streaming_queue_init(&sq, SMT_PACKET); s = dvb_subscription_create_from_tdmi(tdmi, "HTTP", &sq.sq_st); - name = strdupa(tdmi->tdmi_mux->dm_uuid); + name = "foo"; // strdupa(tdmi->tdmi_mux->dm_uuid); XXX(dvbreorg) pthread_mutex_unlock(&global_lock); http_stream_run(hc, &sq, name, MC_PASS); pthread_mutex_lock(&global_lock);