From 3ef0bc729ba3ca16a5b1b4d6bef64c3115218f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Mon, 25 Aug 2008 16:55:27 +0000 Subject: [PATCH] Clean up the dvb.c and move stuff into separate files. --- Makefile | 2 +- dvb/dvb.c | 779 +------------------------------------------- dvb/dvb.h | 85 +++-- dvb/dvb_adapter.c | 478 +++++++++++++++++++++++++++ dvb/dvb_multiplex.c | 510 +++++++++++++++++++++++++++++ dvb/dvb_muxconfig.c | 320 ------------------ dvb/dvb_muxconfig.h | 25 -- dvb/dvb_tables.c | 16 +- dvb/dvb_transport.c | 161 +++++++++ webui/extjs.c | 2 +- 10 files changed, 1217 insertions(+), 1161 deletions(-) create mode 100644 dvb/dvb_adapter.c create mode 100644 dvb/dvb_multiplex.c create mode 100644 dvb/dvb_transport.c diff --git a/Makefile b/Makefile index 60b52552..3fd1ac3c 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ SRCS += epg.c epg_xmltv.c VPATH += dvb SRCS += dvb.c dvb_support.c dvb_dvr.c dvb_muxconfig.c dvb_fe.c dvb_tables.c \ - diseqc.c + diseqc.c dvb_adapter.c dvb_multiplex.c dvb_transport.c SRCS += iptv_input.c iptv_output.c diff --git a/dvb/dvb.c b/dvb/dvb.c index c78b6518..4c4cdd7e 100644 --- a/dvb/dvb.c +++ b/dvb/dvb.c @@ -31,789 +31,12 @@ #include #include -#include -#include - -#include - #include "tvhead.h" -#include "dispatch.h" #include "dvb.h" -#include "channels.h" -#include "transports.h" -#include "subscriptions.h" -#include "teletext.h" -#include "epg.h" -#include "psi.h" -#include "dvb_support.h" -#include "dvb_dvr.h" -#include "dvb_muxconfig.h" -#include "notify.h" - -struct th_dvb_adapter_queue dvb_adapters; -struct th_dvb_mux_instance_tree dvb_muxes; -static void dvb_mux_scanner(void *aux, int64_t now); -static void dvb_fec_monitor(void *aux, int64_t now); - -static void dvb_transport_save(th_transport_t *t); -static const char *dvb_source_name(th_transport_t *t); -static int dvb_transport_quality(th_transport_t *t); - - -static th_dvb_adapter_t * -tda_alloc(void) -{ - th_dvb_adapter_t *tda = calloc(1, sizeof(th_dvb_adapter_t)); - pthread_mutex_init(&tda->tda_lock, NULL); - pthread_cond_init(&tda->tda_cond, NULL); - TAILQ_INIT(&tda->tda_fe_cmd_queue); - return tda; -} - - - -static void -dvb_add_adapter(const char *path) -{ - char fname[256]; - int fe, i, r; - th_dvb_adapter_t *tda; - char buf[400]; - - snprintf(fname, sizeof(fname), "%s/frontend0", path); - - fe = open(fname, O_RDWR | O_NONBLOCK); - if(fe == -1) { - if(errno != ENOENT) - tvhlog(LOG_ALERT, "dvb", - "Unable to open %s -- %s\n", fname, strerror(errno)); - return; - } - - tda = tda_alloc(); - - tda->tda_rootpath = strdup(path); - tda->tda_demux_path = malloc(256); - snprintf(tda->tda_demux_path, 256, "%s/demux0", path); - tda->tda_dvr_path = malloc(256); - snprintf(tda->tda_dvr_path, 256, "%s/dvr0", path); - - - tda->tda_fe_fd = fe; - - tda->tda_fe_info = malloc(sizeof(struct dvb_frontend_info)); - - if(ioctl(tda->tda_fe_fd, FE_GET_INFO, tda->tda_fe_info)) { - tvhlog(LOG_ALERT, "dvb", "%s: Unable to query adapter\n", fname); - close(fe); - free(tda); - return; - } - - tda->tda_type = tda->tda_fe_info->type; - - if(dvb_dvr_init(tda) < 0) { - close(fe); - free(tda); - return; - } - - snprintf(buf, sizeof(buf), "%s_%s", tda->tda_rootpath, - tda->tda_fe_info->name); - - r = strlen(buf); - for(i = 0; i < r; i++) - if(!isalnum((int)buf[i])) - buf[i] = '_'; - - tda->tda_identifier = strdup(buf); - - - /* Come up with an initial displayname, user can change it and it will - be overridden by any stored settings later on */ - - tda->tda_displayname = strdup(tda->tda_fe_info->name); - - tvhlog(LOG_INFO, "dvb", - "Found adapter %s (%s)", path, tda->tda_fe_info->name); - - TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link); - dtimer_arm(&tda->tda_fec_monitor_timer, dvb_fec_monitor, tda, 1); - dvb_fe_start(tda); -} - - void dvb_init(void) { - char path[200]; - htsmsg_t *l, *c; - htsmsg_field_t *f; - const char *name, *s; - int i, type; - th_dvb_adapter_t *tda; - - TAILQ_INIT(&dvb_adapters); - - for(i = 0; i < 32; i++) { - snprintf(path, sizeof(path), "/dev/dvb/adapter%d", i); - dvb_add_adapter(path); - } - - l = hts_settings_load("dvbadapters"); - if(l != NULL) { - HTSMSG_FOREACH(f, l) { - if((c = htsmsg_get_msg_by_field(f)) == NULL) - continue; - - if(dvb_adapter_find_by_identifier(f->hmf_name) != NULL) { - /* Already loaded */ - continue; - } - - if((name = htsmsg_get_str(c, "displayname")) == NULL) - continue; - - if((s = htsmsg_get_str(c, "type")) == NULL || - (type = dvb_str_to_adaptertype(s)) < 0) - continue; - - tda = tda_alloc(); - tda->tda_identifier = strdup(f->hmf_name); - tda->tda_displayname = strdup(name); - tda->tda_type = type; - - TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link); - - } - htsmsg_destroy(l); - } - - TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) - dvb_tdmi_load(tda); - + dvb_adapter_init(); } - - - -/** - * Find a transport based on 'serviceid' on the given mux - * - * If it cannot be found we create it if 'pmt_pid' is also set - */ -th_transport_t * -dvb_find_transport(th_dvb_mux_instance_t *tdmi, uint16_t sid, int pmt_pid, - int *created) -{ - th_transport_t *t; - char tmp[200]; - - if(created != NULL) - *created = 0; - - LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) { - if(t->tht_dvb_service_id == sid) - return t; - } - - if(pmt_pid == 0) - return NULL; - - if(created != NULL) - *created = 1; - - snprintf(tmp, sizeof(tmp), "%s_%04x", tdmi->tdmi_identifier, sid); - - t = transport_create(tmp, TRANSPORT_DVB, THT_MPEG_TS); - - t->tht_dvb_service_id = sid; - t->tht_pmt = pmt_pid; - - t->tht_start_feed = dvb_start_feed; - t->tht_stop_feed = dvb_stop_feed; - t->tht_config_change = dvb_transport_save; - t->tht_sourcename = dvb_source_name; - t->tht_dvb_mux_instance = tdmi; - t->tht_quality_index = dvb_transport_quality; - - LIST_INSERT_HEAD(&tdmi->tdmi_transports, t, tht_mux_link); - return t; -} - - -/** - * - */ -static void -dvb_notify_mux_quality(th_dvb_mux_instance_t *tdmi) -{ - htsmsg_t *m = htsmsg_create(); - htsmsg_add_str(m, "id", tdmi->tdmi_identifier); - - htsmsg_add_u32(m, "quality", 100 + tdmi->tdmi_quality * 2); - notify_by_msg("dvbmux", m); -} - - -/** - * - */ -static void -dvb_notify_mux_status(th_dvb_mux_instance_t *tdmi) -{ - htsmsg_t *m = htsmsg_create(); - htsmsg_add_str(m, "id", tdmi->tdmi_identifier); - - htsmsg_add_str(m, "status", tdmi->tdmi_last_status); - notify_by_msg("dvbmux", m); -} - - -/** - * - */ -static void -dvb_adapter_notify_reload(th_dvb_adapter_t *tda) -{ - htsmsg_t *m = htsmsg_create(); - htsmsg_add_str(m, "id", tda->tda_identifier); - - htsmsg_add_u32(m, "reload", 1); - notify_by_msg("dvbadapter", m); -} - - -/** - * - */ -static void -dvb_fec_monitor(void *aux, int64_t now) -{ - th_dvb_adapter_t *tda = aux; - th_dvb_mux_instance_t *tdmi; - int i, v, vv; - const char *s; - - dtimer_arm(&tda->tda_fec_monitor_timer, dvb_fec_monitor, tda, 1); - - tdmi = tda->tda_mux_current; - if(tdmi == NULL) - return; - if(tdmi->tdmi_status == NULL) { - - v = vv = 0; - for(i = 0; i < TDMI_FEC_ERR_HISTOGRAM_SIZE; i++) { - if(tdmi->tdmi_fec_err_histogram[i] > DVB_FEC_ERROR_LIMIT) - v++; - vv += tdmi->tdmi_fec_err_histogram[i]; - } - vv /= TDMI_FEC_ERR_HISTOGRAM_SIZE; - - if(v == TDMI_FEC_ERR_HISTOGRAM_SIZE) { - if(LIST_FIRST(&tda->tda_transports) != NULL) { - tvhlog(LOG_ERR, "dvb", - "\"%s\": Constant rate of FEC errors (average at %d / s), " - "last %d seconds, flushing subscribers\n", - tdmi->tdmi_identifier, vv, - TDMI_FEC_ERR_HISTOGRAM_SIZE); - - dvb_adapter_clean(tdmi->tdmi_adapter); - } - } - } - - - if(dvb_mux_status(tdmi, 1) != NULL) { - if(tdmi->tdmi_quality > -50) { - tdmi->tdmi_quality--; - dvb_notify_mux_quality(tdmi); - } - } else { - - if(tdmi->tdmi_quality < 0) { - tdmi->tdmi_quality++; - dvb_notify_mux_quality(tdmi); - } - } - - s = dvb_mux_status(tdmi, 0); - - if(s != tdmi->tdmi_last_status) { - tdmi->tdmi_last_status = s; - dvb_notify_mux_status(tdmi); - } -} - -/** - * If nobody is subscribing, cycle thru all muxes to get some stats - * and EIT updates - */ -static void -dvb_mux_scanner(void *aux, int64_t now) -{ - th_dvb_adapter_t *tda = aux; - th_dvb_mux_instance_t *tdmi; - - dtimer_arm(&tda->tda_mux_scanner_timer, dvb_mux_scanner, tda, 10); - - if(transport_compute_weight(&tda->tda_transports) > 0) - return; /* someone is here */ - - /* Check if we have muxes pending for quickscan, if so, choose them */ - - if((tdmi = RB_FIRST(&tda->tda_muxes_qscan_waiting)) != NULL) { - RB_REMOVE(&tda->tda_muxes_qscan_waiting, tdmi, tdmi_qscan_link); - tdmi->tdmi_quickscan = TDMI_QUICKSCAN_RUNNING; - dvb_tune_tdmi(tdmi, 0, TDMI_IDLESCAN); - return; - } - - /* otherwise, just rotate */ - - tdmi = tda->tda_mux_current; - if(tdmi != NULL) - tdmi->tdmi_quickscan = TDMI_QUICKSCAN_NONE; - - tdmi = tdmi != NULL ? RB_NEXT(tdmi, tdmi_adapter_link) : NULL; - tdmi = tdmi != NULL ? tdmi : RB_FIRST(&tda->tda_muxes); - - if(tdmi == NULL) - return; /* no instances */ - - dvb_tune_tdmi(tdmi, 0, TDMI_IDLESCAN); -} - -/** - * - */ -static int -tdmi_cmp(th_dvb_mux_instance_t *a, th_dvb_mux_instance_t *b) -{ - if(a->tdmi_switchport != b->tdmi_switchport) - return a->tdmi_switchport - b->tdmi_switchport; - - if(a->tdmi_fe_params.frequency != b->tdmi_fe_params.frequency) - return a->tdmi_fe_params.frequency - b->tdmi_fe_params.frequency; - - return a->tdmi_polarisation - b->tdmi_polarisation; -} - -/** - * - */ -static int -tdmi_global_cmp(th_dvb_mux_instance_t *a, th_dvb_mux_instance_t *b) -{ - return strcmp(a->tdmi_identifier, b->tdmi_identifier); -} - - -/** - * Create a new mux on the given adapter, return NULL if it already exists - */ -th_dvb_mux_instance_t * -dvb_mux_create(th_dvb_adapter_t *tda, struct dvb_frontend_parameters *fe_param, - int polarisation, int switchport, - uint16_t tsid, const char *network, const char *source) -{ - th_dvb_mux_instance_t *tdmi; - static th_dvb_mux_instance_t *skel; - char buf[200]; - char qpsktxt[20]; - int entries_before = tda->tda_muxes.entries; - - if(skel == NULL) - skel = calloc(1, sizeof(th_dvb_mux_instance_t)); - - skel->tdmi_polarisation = polarisation; - skel->tdmi_switchport = switchport; - skel->tdmi_fe_params.frequency = fe_param->frequency; - - tdmi = RB_INSERT_SORTED(&tda->tda_muxes, skel, tdmi_adapter_link, tdmi_cmp); - if(tdmi != NULL) - return NULL; - - tdmi = skel; - skel = NULL; - - tdmi->tdmi_refcnt = 1; - - RB_INSERT_SORTED(&tda->tda_muxes_qscan_waiting, tdmi, tdmi_qscan_link, - tdmi_cmp); - - tdmi->tdmi_quickscan = TDMI_QUICKSCAN_WAITING; - - pthread_mutex_init(&tdmi->tdmi_table_lock, NULL); - tdmi->tdmi_state = TDMI_IDLE; - tdmi->tdmi_transport_stream_id = tsid; - tdmi->tdmi_adapter = tda; - tdmi->tdmi_network = network ? strdup(network) : NULL; - - if(entries_before == 0 && tda->tda_rootpath != NULL) { - /* First mux on adapter with backing hardware, start scanner */ - dtimer_arm(&tda->tda_mux_scanner_timer, dvb_mux_scanner, tda, 1); - } - - memcpy(&tdmi->tdmi_fe_params, fe_param, - sizeof(struct dvb_frontend_parameters)); - - if(tda->tda_type == FE_QPSK) - snprintf(qpsktxt, sizeof(qpsktxt), "_%s_%d", - dvb_polarisation_to_str(polarisation), switchport); - else - qpsktxt[0] = 0; - - snprintf(buf, sizeof(buf), "%s%d%s", - tda->tda_identifier,fe_param->frequency, qpsktxt); - - tdmi->tdmi_identifier = strdup(buf); - - RB_INSERT_SORTED(&dvb_muxes, tdmi, tdmi_global_link, tdmi_global_cmp); - - if(source != NULL) { - dvb_mux_nicename(buf, sizeof(buf), tdmi); - tvhlog(LOG_NOTICE, "dvb", "New mux \"%s\" created by %s", buf, source); - - dvb_tdmi_save(tdmi); - dvb_adapter_notify_reload(tda); - } - - return tdmi; -} - -/** - * Unref a TDMI and optionally free it - */ -void -dvb_mux_unref(th_dvb_mux_instance_t *tdmi) -{ - if(tdmi->tdmi_refcnt > 1) { - tdmi->tdmi_refcnt--; - return; - } - - free(tdmi->tdmi_network); - free(tdmi->tdmi_identifier); - free(tdmi); -} - -/** - * Destroy a DVB mux (it might come back by itself very soon though :) - */ -void -dvb_mux_destroy(th_dvb_mux_instance_t *tdmi) -{ - th_dvb_adapter_t *tda = tdmi->tdmi_adapter; - th_transport_t *t; - char buf[400]; - - snprintf(buf, sizeof(buf), "%s/dvbmuxes/%s", - settings_dir, tdmi->tdmi_identifier); - unlink(buf); - - while((t = LIST_FIRST(&tdmi->tdmi_transports)) != NULL) - transport_destroy(t); - - if(tda->tda_mux_current == tdmi) - tdmi_stop(tda->tda_mux_current); - - dtimer_disarm(&tdmi->tdmi_initial_scan_timer); - RB_REMOVE(&dvb_muxes, tdmi, tdmi_global_link); - RB_REMOVE(&tda->tda_muxes, tdmi, tdmi_adapter_link); - - if(tdmi->tdmi_quickscan == TDMI_QUICKSCAN_WAITING) - RB_REMOVE(&tda->tda_muxes_qscan_waiting, tdmi, tdmi_qscan_link); - - hts_settings_remove("dvbmuxes/%s", tdmi->tdmi_identifier); - - pthread_mutex_lock(&tda->tda_lock); - dvb_fe_flush(tdmi); - dvb_mux_unref(tdmi); - pthread_mutex_unlock(&tda->tda_lock); -} - - - - -#if 0 - -/** - * Load config for the given adapter - */ -static int -dvb_tda_load(th_dvb_adapter_t *tda) -{ - struct config_head cl; - config_entry_t *ce; - char buf[400]; - const char *v; - - snprintf(buf, sizeof(buf), "%s/dvbadapters/%s", - settings_dir, tda->tda_identifier); - - TAILQ_INIT(&cl); - if(config_read_file0(buf, &cl)) - return 0; - - if((v = config_get_str_sub(&cl, "type", NULL)) == NULL) - goto err; - - if((tda->tda_type = dvb_str_to_adaptertype(v)) < 0) - goto err; - - if((v = config_get_str_sub(&cl, "displayname", NULL)) == NULL) - goto err; - - free(tda->tda_displayname); - tda->tda_displayname = strdup(v); - - TAILQ_FOREACH(ce, &cl, ce_link) { - if(ce->ce_type != CFG_SUB || strcasecmp("mux", ce->ce_key)) - continue; - - v = dvb_mux_create_str(tda, - config_get_str_sub(&ce->ce_sub, - "transportstreamid", NULL), - config_get_str_sub(&ce->ce_sub, - "network", NULL), - config_get_str_sub(&ce->ce_sub, - "frequency", NULL), - config_get_str_sub(&ce->ce_sub, - "symbol_rate", NULL), - config_get_str_sub(&ce->ce_sub, - "constellation", NULL), - config_get_str_sub(&ce->ce_sub, - "fec", NULL), - config_get_str_sub(&ce->ce_sub, - "fec_hi", NULL), - config_get_str_sub(&ce->ce_sub, - "fec_lo", NULL), - config_get_str_sub(&ce->ce_sub, - "bandwidth", NULL), - config_get_str_sub(&ce->ce_sub, - "transmission_mode", NULL), - config_get_str_sub(&ce->ce_sub, - "guard_interval", NULL), - config_get_str_sub(&ce->ce_sub, - "hierarchy", NULL), - config_get_str_sub(&ce->ce_sub, - "polarisation", NULL), - config_get_str_sub(&ce->ce_sub, - "switchport", NULL), - 0); - - if(v != NULL) - tvhlog(LOG_ALERT, "dvb", - "Unable to init saved mux on %s -- %s\n", - tda->tda_identifier, v); - } - config_free0(&cl); - return 0; - err: - config_free0(&cl); - return -1; -} -#endif - -static void -dvb_transport_save(th_transport_t *t) -{ - htsmsg_t *m = htsmsg_create(); - - - htsmsg_add_u32(m, "service_id", t->tht_dvb_service_id); - htsmsg_add_u32(m, "pmt", t->tht_pmt); - htsmsg_add_u32(m, "stype", t->tht_servicetype); - htsmsg_add_u32(m, "scrambled", t->tht_scrambled); - - if(t->tht_provider != NULL) - htsmsg_add_str(m, "provider", t->tht_provider); - - if(t->tht_svcname != NULL) - htsmsg_add_str(m, "servicename", t->tht_svcname); - - if(t->tht_chname != NULL) - htsmsg_add_str(m, "channelname", t->tht_chname); - - htsmsg_add_u32(m, "mapped", !!t->tht_ch); - - psi_get_transport_settings(m, t); - - hts_settings_save(m, "dvbtransports/%s", t->tht_identifier); - htsmsg_destroy(m); -} - - -/** - * Called to get quality for the given transport - * - * We keep track of this for the entire mux (if we see errors), soo.. - * return that value - */ -static int -dvb_transport_quality(th_transport_t *t) -{ - th_dvb_mux_instance_t *tdmi = t->tht_dvb_mux_instance; - return tdmi->tdmi_quality; -} - - -/** - * Generate a descriptive name for the source - */ -static const char * -dvb_source_name(th_transport_t *t) -{ - th_dvb_mux_instance_t *tdmi; - static char buf[200]; - - tdmi = t->tht_dvb_mux_instance; - - snprintf(buf, sizeof(buf), "\"%s\" on \"%s\"", - tdmi->tdmi_network ?: "Unknown network", - tdmi->tdmi_adapter->tda_rootpath); - - return buf; -} - -/** - * - */ -void -dvb_tda_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src) -{ - th_dvb_mux_instance_t *tdmi_src, *tdmi_dst; - th_transport_t *t_src, *t_dst; - th_stream_t *st_src, *st_dst; - - while((tdmi_dst = RB_FIRST(&dst->tda_muxes)) != NULL) - dvb_mux_destroy(tdmi_dst); - - RB_FOREACH(tdmi_src, &src->tda_muxes, tdmi_adapter_link) { - - tdmi_dst = dvb_mux_create(dst, - &tdmi_src->tdmi_fe_params, - tdmi_src->tdmi_polarisation, - tdmi_src->tdmi_switchport, - tdmi_src->tdmi_transport_stream_id, - tdmi_src->tdmi_network, - "copy operation"); - - - assert(tdmi_dst != NULL); - - LIST_FOREACH(t_src, &tdmi_src->tdmi_transports, tht_mux_link) { - t_dst = dvb_find_transport(tdmi_dst, - t_src->tht_dvb_service_id, - t_src->tht_pmt, - NULL); - - t_dst->tht_pcr_pid = t_src->tht_pcr_pid; - t_dst->tht_disabled = t_src->tht_disabled; - t_dst->tht_servicetype = t_src->tht_servicetype; - t_dst->tht_scrambled = t_src->tht_scrambled; - - if(t_src->tht_provider != NULL) - t_dst->tht_provider = strdup(t_src->tht_provider); - - if(t_src->tht_svcname != NULL) - t_dst->tht_svcname = strdup(t_src->tht_svcname); - - if(t_src->tht_chname != NULL) - t_dst->tht_chname = strdup(t_src->tht_chname); - - if(t_src->tht_ch != NULL) - transport_map_channel(t_dst, t_src->tht_ch); - - - - LIST_FOREACH(st_src, &t_src->tht_streams, st_link) { - - st_dst = transport_add_stream(t_dst, - st_src->st_pid, - st_src->st_type); - - st_dst->st_tb = (AVRational){1, 90000}; - - memcpy(st_dst->st_lang, st_src->st_lang, 4); - st_dst->st_frame_duration = st_src->st_frame_duration; - st_dst->st_caid = st_src->st_caid; - } - } - dvb_tdmi_save(tdmi_dst); - } - dvb_tda_save(dst); -} - -/** - * - */ -int -dvb_tda_destroy(th_dvb_adapter_t *tda) -{ - th_dvb_mux_instance_t *tdmi; - - char buf[400]; - - if(tda->tda_rootpath != NULL) - return -1; - - snprintf(buf, sizeof(buf), "%s/dvbadapters/%s", - settings_dir, tda->tda_identifier); - - unlink(buf); - - while((tdmi = RB_FIRST(&tda->tda_muxes)) != NULL) - dvb_mux_destroy(tdmi); - - TAILQ_REMOVE(&dvb_adapters, tda, tda_global_link); - - free(tda->tda_identifier); - free(tda->tda_displayname); - - free(tda); - - return 0; -} - -/** - * - */ -void -dvb_tdmi_fastswitch(th_dvb_mux_instance_t *tdmi) -{ - th_dvb_table_t *tdt; - - if(tdmi->tdmi_quickscan == TDMI_QUICKSCAN_NONE) - return; - - pthread_mutex_lock(&tdmi->tdmi_table_lock); - LIST_FOREACH(tdt, &tdmi->tdmi_tables, tdt_link) { - if(tdt->tdt_quickreq && tdt->tdt_count == 0) - break; - } - pthread_mutex_unlock(&tdmi->tdmi_table_lock); - - if(tdt != NULL) - return; /* Still tables we've not seen */ - - tdmi->tdmi_quickscan = TDMI_QUICKSCAN_NONE; - dvb_mux_scanner(tdmi->tdmi_adapter, 0); - -} - - -/** - * - */ -th_dvb_mux_instance_t * -dvb_mux_find_by_identifier(const char *identifier) -{ - th_dvb_mux_instance_t skel; - - skel.tdmi_identifier = (char *)identifier; - return RB_FIND(&dvb_muxes, &skel, tdmi_global_link, tdmi_global_cmp); -} - diff --git a/dvb/dvb.h b/dvb/dvb.h index ef294875..122ddd93 100644 --- a/dvb/dvb.h +++ b/dvb/dvb.h @@ -33,9 +33,66 @@ extern struct th_dvb_mux_instance_tree dvb_muxes; void dvb_init(void); +/** + * DVB Adapter + */ +void dvb_adapter_init(void); + +void dvb_adapter_mux_scanner(void *aux, int64_t now); + +void dvb_adapter_notify_reload(th_dvb_adapter_t *tda); + +void dvb_adapter_set_displayname(th_dvb_adapter_t *tda, const char *s); + +void dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src); + +int dvb_adapter_destroy(th_dvb_adapter_t *tda); + +/** + * DVB Multiplex + */ +void dvb_mux_save(th_dvb_mux_instance_t *tdmi); + +void dvb_mux_load(th_dvb_adapter_t *tda); + +void dvb_mux_unref(th_dvb_mux_instance_t *tdmi); + +void dvb_mux_destroy(th_dvb_mux_instance_t *tdmi); + +void dvb_mux_fastswitch(th_dvb_mux_instance_t *tdmi); + +th_dvb_mux_instance_t *dvb_mux_create(th_dvb_adapter_t *tda, + struct dvb_frontend_parameters *fe_param, + int polarisation, int switchport, + uint16_t tsid, const char *network, + const char *logprefix); + void dvb_tune_tdmi(th_dvb_mux_instance_t *tdmi, int maylog, tdmi_state_t state); +/** + * DVB Transport (aka DVB service) + */ +th_transport_t *dvb_transport_find(th_dvb_mux_instance_t *tdmi, + uint16_t sid, int pmt_pid, int *created); + +void tdmi_check_scan_status(th_dvb_mux_instance_t *tdmi); + +void tdmi_stop(th_dvb_mux_instance_t *tdmi); + + +/** + * DVB Frontend + */ +void dvb_fe_start(th_dvb_adapter_t *tda); + +void dvb_fe_flush(th_dvb_mux_instance_t *tdmi); + + +/** + * DVB Tables + */ + void dvb_table_add_default(th_dvb_mux_instance_t *tdmi); void dvb_table_add_transport(th_dvb_mux_instance_t *tdmi, th_transport_t *t, @@ -43,32 +100,4 @@ void dvb_table_add_transport(th_dvb_mux_instance_t *tdmi, th_transport_t *t, void dvb_tdt_destroy(th_dvb_table_t *tdt); -void dvb_fe_start(th_dvb_adapter_t *tda); - -void tdmi_check_scan_status(th_dvb_mux_instance_t *tdmi); - -th_transport_t *dvb_find_transport(th_dvb_mux_instance_t *tdmi, - uint16_t sid, int pmt_pid, int *created); - -th_dvb_mux_instance_t *dvb_mux_create(th_dvb_adapter_t *tda, - struct dvb_frontend_parameters *fe_param, - int polarisation, int switchport, - uint16_t tsid, const char *network, - const char *logprefix); - - -void dvb_mux_unref(th_dvb_mux_instance_t *tdmi); - -void dvb_fe_flush(th_dvb_mux_instance_t *tdmi); - -void dvb_mux_destroy(th_dvb_mux_instance_t *tdmi); - -void tdmi_stop(th_dvb_mux_instance_t *tdmi); - -void dvb_tda_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src); - -int dvb_tda_destroy(th_dvb_adapter_t *tda); - -void dvb_tdmi_fastswitch(th_dvb_mux_instance_t *tdmi); - #endif /* DVB_H_ */ diff --git a/dvb/dvb_adapter.c b/dvb/dvb_adapter.c new file mode 100644 index 00000000..d8bfef18 --- /dev/null +++ b/dvb/dvb_adapter.c @@ -0,0 +1,478 @@ +/* + * TV Input - Linux DVB interface + * Copyright (C) 2007 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "tvhead.h" +#include "dispatch.h" +#include "dvb.h" +#include "channels.h" +#include "transports.h" +#include "subscriptions.h" +#include "teletext.h" +#include "epg.h" +#include "psi.h" +#include "dvb_support.h" +#include "dvb_dvr.h" +#include "dvb_muxconfig.h" +#include "notify.h" + +struct th_dvb_adapter_queue dvb_adapters; +struct th_dvb_mux_instance_tree dvb_muxes; +static void dvb_fec_monitor(void *aux, int64_t now); + + +/** + * + */ +static th_dvb_adapter_t * +tda_alloc(void) +{ + th_dvb_adapter_t *tda = calloc(1, sizeof(th_dvb_adapter_t)); + pthread_mutex_init(&tda->tda_lock, NULL); + pthread_cond_init(&tda->tda_cond, NULL); + TAILQ_INIT(&tda->tda_fe_cmd_queue); + return tda; +} + + +/** + * Save config for the given adapter + */ +static void +tda_save(th_dvb_adapter_t *tda) +{ + htsmsg_t *m = htsmsg_create(); + + htsmsg_add_str(m, "type", dvb_adaptertype_to_str(tda->tda_type)); + htsmsg_add_str(m, "displayname", tda->tda_displayname); + hts_settings_save(m, "dvbadapters/%s", tda->tda_identifier); + htsmsg_destroy(m); +} + + +/** + * + */ +void +dvb_adapter_set_displayname(th_dvb_adapter_t *tda, const char *s) +{ + htsmsg_t *m = htsmsg_create(); + htsmsg_add_str(m, "id", tda->tda_identifier); + + free(tda->tda_displayname); + tda->tda_displayname = strdup(s); + + tda_save(tda); + + htsmsg_add_str(m, "name", tda->tda_displayname); + + notify_by_msg("dvbadapter", m); +} + + +/** + * + */ +static void +tda_add(const char *path) +{ + char fname[256]; + int fe, i, r; + th_dvb_adapter_t *tda; + char buf[400]; + + snprintf(fname, sizeof(fname), "%s/frontend0", path); + + fe = open(fname, O_RDWR | O_NONBLOCK); + if(fe == -1) { + if(errno != ENOENT) + tvhlog(LOG_ALERT, "dvb", + "Unable to open %s -- %s\n", fname, strerror(errno)); + return; + } + + tda = tda_alloc(); + + tda->tda_rootpath = strdup(path); + tda->tda_demux_path = malloc(256); + snprintf(tda->tda_demux_path, 256, "%s/demux0", path); + tda->tda_dvr_path = malloc(256); + snprintf(tda->tda_dvr_path, 256, "%s/dvr0", path); + + + tda->tda_fe_fd = fe; + + tda->tda_fe_info = malloc(sizeof(struct dvb_frontend_info)); + + if(ioctl(tda->tda_fe_fd, FE_GET_INFO, tda->tda_fe_info)) { + tvhlog(LOG_ALERT, "dvb", "%s: Unable to query adapter\n", fname); + close(fe); + free(tda); + return; + } + + tda->tda_type = tda->tda_fe_info->type; + + if(dvb_dvr_init(tda) < 0) { + close(fe); + free(tda); + return; + } + + snprintf(buf, sizeof(buf), "%s_%s", tda->tda_rootpath, + tda->tda_fe_info->name); + + r = strlen(buf); + for(i = 0; i < r; i++) + if(!isalnum((int)buf[i])) + buf[i] = '_'; + + tda->tda_identifier = strdup(buf); + + + /* Come up with an initial displayname, user can change it and it will + be overridden by any stored settings later on */ + + tda->tda_displayname = strdup(tda->tda_fe_info->name); + + tvhlog(LOG_INFO, "dvb", + "Found adapter %s (%s)", path, tda->tda_fe_info->name); + + TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link); + dtimer_arm(&tda->tda_fec_monitor_timer, dvb_fec_monitor, tda, 1); + dvb_fe_start(tda); +} + + +/** + * + */ +void +dvb_adapter_init(void) +{ + char path[200]; + htsmsg_t *l, *c; + htsmsg_field_t *f; + const char *name, *s; + int i, type; + th_dvb_adapter_t *tda; + + TAILQ_INIT(&dvb_adapters); + + for(i = 0; i < 32; i++) { + snprintf(path, sizeof(path), "/dev/dvb/adapter%d", i); + tda_add(path); + } + + l = hts_settings_load("dvbadapters"); + if(l != NULL) { + HTSMSG_FOREACH(f, l) { + if((c = htsmsg_get_msg_by_field(f)) == NULL) + continue; + + if(dvb_adapter_find_by_identifier(f->hmf_name) != NULL) { + /* Already loaded */ + continue; + } + + if((name = htsmsg_get_str(c, "displayname")) == NULL) + continue; + + if((s = htsmsg_get_str(c, "type")) == NULL || + (type = dvb_str_to_adaptertype(s)) < 0) + continue; + + tda = tda_alloc(); + tda->tda_identifier = strdup(f->hmf_name); + tda->tda_displayname = strdup(name); + tda->tda_type = type; + + TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link); + + } + htsmsg_destroy(l); + } + + TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) + dvb_mux_load(tda); + +} + + +/** + * + */ +static void +dvb_notify_mux_quality(th_dvb_mux_instance_t *tdmi) +{ + htsmsg_t *m = htsmsg_create(); + htsmsg_add_str(m, "id", tdmi->tdmi_identifier); + + htsmsg_add_u32(m, "quality", 100 + tdmi->tdmi_quality * 2); + notify_by_msg("dvbmux", m); +} + + +/** + * + */ +static void +dvb_notify_mux_status(th_dvb_mux_instance_t *tdmi) +{ + htsmsg_t *m = htsmsg_create(); + htsmsg_add_str(m, "id", tdmi->tdmi_identifier); + + htsmsg_add_str(m, "status", tdmi->tdmi_last_status); + notify_by_msg("dvbmux", m); +} + + +/** + * + */ +void +dvb_adapter_notify_reload(th_dvb_adapter_t *tda) +{ + htsmsg_t *m = htsmsg_create(); + htsmsg_add_str(m, "id", tda->tda_identifier); + + htsmsg_add_u32(m, "reload", 1); + notify_by_msg("dvbadapter", m); +} + + +/** + * + */ +static void +dvb_fec_monitor(void *aux, int64_t now) +{ + th_dvb_adapter_t *tda = aux; + th_dvb_mux_instance_t *tdmi; + int i, v, vv; + const char *s; + + dtimer_arm(&tda->tda_fec_monitor_timer, dvb_fec_monitor, tda, 1); + + tdmi = tda->tda_mux_current; + if(tdmi == NULL) + return; + if(tdmi->tdmi_status == NULL) { + + v = vv = 0; + for(i = 0; i < TDMI_FEC_ERR_HISTOGRAM_SIZE; i++) { + if(tdmi->tdmi_fec_err_histogram[i] > DVB_FEC_ERROR_LIMIT) + v++; + vv += tdmi->tdmi_fec_err_histogram[i]; + } + vv /= TDMI_FEC_ERR_HISTOGRAM_SIZE; + + if(v == TDMI_FEC_ERR_HISTOGRAM_SIZE) { + if(LIST_FIRST(&tda->tda_transports) != NULL) { + tvhlog(LOG_ERR, "dvb", + "\"%s\": Constant rate of FEC errors (average at %d / s), " + "last %d seconds, flushing subscribers\n", + tdmi->tdmi_identifier, vv, + TDMI_FEC_ERR_HISTOGRAM_SIZE); + + dvb_adapter_clean(tdmi->tdmi_adapter); + } + } + } + + + if(dvb_mux_status(tdmi, 1) != NULL) { + if(tdmi->tdmi_quality > -50) { + tdmi->tdmi_quality--; + dvb_notify_mux_quality(tdmi); + } + } else { + + if(tdmi->tdmi_quality < 0) { + tdmi->tdmi_quality++; + dvb_notify_mux_quality(tdmi); + } + } + + s = dvb_mux_status(tdmi, 0); + + if(s != tdmi->tdmi_last_status) { + tdmi->tdmi_last_status = s; + dvb_notify_mux_status(tdmi); + } +} + + +/** + * If nobody is subscribing, cycle thru all muxes to get some stats + * and EIT updates + */ +void +dvb_adapter_mux_scanner(void *aux, int64_t now) +{ + th_dvb_adapter_t *tda = aux; + th_dvb_mux_instance_t *tdmi; + + dtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 10); + + if(transport_compute_weight(&tda->tda_transports) > 0) + return; /* someone is here */ + + /* Check if we have muxes pending for quickscan, if so, choose them */ + + if((tdmi = RB_FIRST(&tda->tda_muxes_qscan_waiting)) != NULL) { + RB_REMOVE(&tda->tda_muxes_qscan_waiting, tdmi, tdmi_qscan_link); + tdmi->tdmi_quickscan = TDMI_QUICKSCAN_RUNNING; + dvb_tune_tdmi(tdmi, 0, TDMI_IDLESCAN); + return; + } + + /* otherwise, just rotate */ + + tdmi = tda->tda_mux_current; + if(tdmi != NULL) + tdmi->tdmi_quickscan = TDMI_QUICKSCAN_NONE; + + tdmi = tdmi != NULL ? RB_NEXT(tdmi, tdmi_adapter_link) : NULL; + tdmi = tdmi != NULL ? tdmi : RB_FIRST(&tda->tda_muxes); + + if(tdmi == NULL) + return; /* no instances */ + + dvb_tune_tdmi(tdmi, 0, TDMI_IDLESCAN); +} + +/** + * + */ +void +dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src) +{ + th_dvb_mux_instance_t *tdmi_src, *tdmi_dst; + th_transport_t *t_src, *t_dst; + th_stream_t *st_src, *st_dst; + + while((tdmi_dst = RB_FIRST(&dst->tda_muxes)) != NULL) + dvb_mux_destroy(tdmi_dst); + + RB_FOREACH(tdmi_src, &src->tda_muxes, tdmi_adapter_link) { + + tdmi_dst = dvb_mux_create(dst, + &tdmi_src->tdmi_fe_params, + tdmi_src->tdmi_polarisation, + tdmi_src->tdmi_switchport, + tdmi_src->tdmi_transport_stream_id, + tdmi_src->tdmi_network, + "copy operation"); + + + assert(tdmi_dst != NULL); + + LIST_FOREACH(t_src, &tdmi_src->tdmi_transports, tht_mux_link) { + t_dst = dvb_transport_find(tdmi_dst, + t_src->tht_dvb_service_id, + t_src->tht_pmt, + NULL); + + t_dst->tht_pcr_pid = t_src->tht_pcr_pid; + t_dst->tht_disabled = t_src->tht_disabled; + t_dst->tht_servicetype = t_src->tht_servicetype; + t_dst->tht_scrambled = t_src->tht_scrambled; + + if(t_src->tht_provider != NULL) + t_dst->tht_provider = strdup(t_src->tht_provider); + + if(t_src->tht_svcname != NULL) + t_dst->tht_svcname = strdup(t_src->tht_svcname); + + if(t_src->tht_chname != NULL) + t_dst->tht_chname = strdup(t_src->tht_chname); + + if(t_src->tht_ch != NULL) + transport_map_channel(t_dst, t_src->tht_ch); + + + + LIST_FOREACH(st_src, &t_src->tht_streams, st_link) { + + st_dst = transport_add_stream(t_dst, + st_src->st_pid, + st_src->st_type); + + st_dst->st_tb = (AVRational){1, 90000}; + + memcpy(st_dst->st_lang, st_src->st_lang, 4); + st_dst->st_frame_duration = st_src->st_frame_duration; + st_dst->st_caid = st_src->st_caid; + } + } + dvb_mux_save(tdmi_dst); + } + tda_save(dst); +} + +/** + * + */ +int +dvb_adapter_destroy(th_dvb_adapter_t *tda) +{ + th_dvb_mux_instance_t *tdmi; + + char buf[400]; + + if(tda->tda_rootpath != NULL) + return -1; + + snprintf(buf, sizeof(buf), "%s/dvbadapters/%s", + settings_dir, tda->tda_identifier); + + unlink(buf); + + while((tdmi = RB_FIRST(&tda->tda_muxes)) != NULL) + dvb_mux_destroy(tdmi); + + TAILQ_REMOVE(&dvb_adapters, tda, tda_global_link); + + free(tda->tda_identifier); + free(tda->tda_displayname); + + free(tda); + + return 0; +} + diff --git a/dvb/dvb_multiplex.c b/dvb/dvb_multiplex.c new file mode 100644 index 00000000..fcaa3edf --- /dev/null +++ b/dvb/dvb_multiplex.c @@ -0,0 +1,510 @@ +/* + * TV Input - Linux DVB interface + * Copyright (C) 2007 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "tvhead.h" +#include "dispatch.h" +#include "dvb.h" +#include "channels.h" +#include "transports.h" +#include "subscriptions.h" +#include "teletext.h" +#include "epg.h" +#include "psi.h" +#include "dvb_support.h" +#include "dvb_dvr.h" +#include "dvb_muxconfig.h" +#include "notify.h" + +struct th_dvb_mux_instance_tree dvb_muxes; + + + + +/** + * + */ +static int +tdmi_cmp(th_dvb_mux_instance_t *a, th_dvb_mux_instance_t *b) +{ + if(a->tdmi_switchport != b->tdmi_switchport) + return a->tdmi_switchport - b->tdmi_switchport; + + if(a->tdmi_fe_params.frequency != b->tdmi_fe_params.frequency) + return a->tdmi_fe_params.frequency - b->tdmi_fe_params.frequency; + + return a->tdmi_polarisation - b->tdmi_polarisation; +} + +/** + * + */ +static int +tdmi_global_cmp(th_dvb_mux_instance_t *a, th_dvb_mux_instance_t *b) +{ + return strcmp(a->tdmi_identifier, b->tdmi_identifier); +} + + +/** + * Create a new mux on the given adapter, return NULL if it already exists + */ +th_dvb_mux_instance_t * +dvb_mux_create(th_dvb_adapter_t *tda, struct dvb_frontend_parameters *fe_param, + int polarisation, int switchport, + uint16_t tsid, const char *network, const char *source) +{ + th_dvb_mux_instance_t *tdmi; + static th_dvb_mux_instance_t *skel; + char buf[200]; + char qpsktxt[20]; + int entries_before = tda->tda_muxes.entries; + + if(skel == NULL) + skel = calloc(1, sizeof(th_dvb_mux_instance_t)); + + skel->tdmi_polarisation = polarisation; + skel->tdmi_switchport = switchport; + skel->tdmi_fe_params.frequency = fe_param->frequency; + + tdmi = RB_INSERT_SORTED(&tda->tda_muxes, skel, tdmi_adapter_link, tdmi_cmp); + if(tdmi != NULL) + return NULL; + + tdmi = skel; + skel = NULL; + + tdmi->tdmi_refcnt = 1; + + RB_INSERT_SORTED(&tda->tda_muxes_qscan_waiting, tdmi, tdmi_qscan_link, + tdmi_cmp); + + tdmi->tdmi_quickscan = TDMI_QUICKSCAN_WAITING; + + pthread_mutex_init(&tdmi->tdmi_table_lock, NULL); + tdmi->tdmi_state = TDMI_IDLE; + tdmi->tdmi_transport_stream_id = tsid; + tdmi->tdmi_adapter = tda; + tdmi->tdmi_network = network ? strdup(network) : NULL; + + if(entries_before == 0 && tda->tda_rootpath != NULL) { + /* First mux on adapter with backing hardware, start scanner */ + dtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 1); + } + + memcpy(&tdmi->tdmi_fe_params, fe_param, + sizeof(struct dvb_frontend_parameters)); + + if(tda->tda_type == FE_QPSK) + snprintf(qpsktxt, sizeof(qpsktxt), "_%s_%d", + dvb_polarisation_to_str(polarisation), switchport); + else + qpsktxt[0] = 0; + + snprintf(buf, sizeof(buf), "%s%d%s", + tda->tda_identifier,fe_param->frequency, qpsktxt); + + tdmi->tdmi_identifier = strdup(buf); + + RB_INSERT_SORTED(&dvb_muxes, tdmi, tdmi_global_link, tdmi_global_cmp); + + if(source != NULL) { + dvb_mux_nicename(buf, sizeof(buf), tdmi); + tvhlog(LOG_NOTICE, "dvb", "New mux \"%s\" created by %s", buf, source); + + dvb_mux_save(tdmi); + dvb_adapter_notify_reload(tda); + } + + return tdmi; +} + +/** + * Unref a TDMI and optionally free it + */ +void +dvb_mux_unref(th_dvb_mux_instance_t *tdmi) +{ + if(tdmi->tdmi_refcnt > 1) { + tdmi->tdmi_refcnt--; + return; + } + + free(tdmi->tdmi_network); + free(tdmi->tdmi_identifier); + free(tdmi); +} + +/** + * Destroy a DVB mux (it might come back by itself very soon though :) + */ +void +dvb_mux_destroy(th_dvb_mux_instance_t *tdmi) +{ + th_dvb_adapter_t *tda = tdmi->tdmi_adapter; + th_transport_t *t; + char buf[400]; + + snprintf(buf, sizeof(buf), "%s/dvbmuxes/%s", + settings_dir, tdmi->tdmi_identifier); + unlink(buf); + + while((t = LIST_FIRST(&tdmi->tdmi_transports)) != NULL) + transport_destroy(t); + + if(tda->tda_mux_current == tdmi) + tdmi_stop(tda->tda_mux_current); + + dtimer_disarm(&tdmi->tdmi_initial_scan_timer); + RB_REMOVE(&dvb_muxes, tdmi, tdmi_global_link); + RB_REMOVE(&tda->tda_muxes, tdmi, tdmi_adapter_link); + + if(tdmi->tdmi_quickscan == TDMI_QUICKSCAN_WAITING) + RB_REMOVE(&tda->tda_muxes_qscan_waiting, tdmi, tdmi_qscan_link); + + hts_settings_remove("dvbmuxes/%s", tdmi->tdmi_identifier); + + pthread_mutex_lock(&tda->tda_lock); + dvb_fe_flush(tdmi); + dvb_mux_unref(tdmi); + pthread_mutex_unlock(&tda->tda_lock); +} + + + +/** + * + */ +void +dvb_mux_fastswitch(th_dvb_mux_instance_t *tdmi) +{ + th_dvb_table_t *tdt; + + if(tdmi->tdmi_quickscan == TDMI_QUICKSCAN_NONE) + return; + + pthread_mutex_lock(&tdmi->tdmi_table_lock); + LIST_FOREACH(tdt, &tdmi->tdmi_tables, tdt_link) { + if(tdt->tdt_quickreq && tdt->tdt_count == 0) + break; + } + pthread_mutex_unlock(&tdmi->tdmi_table_lock); + + if(tdt != NULL) + return; /* Still tables we've not seen */ + + tdmi->tdmi_quickscan = TDMI_QUICKSCAN_NONE; + dvb_adapter_mux_scanner(tdmi->tdmi_adapter, 0); + +} + + +/** + * + */ +th_dvb_mux_instance_t * +dvb_mux_find_by_identifier(const char *identifier) +{ + th_dvb_mux_instance_t skel; + + skel.tdmi_identifier = (char *)identifier; + return RB_FIND(&dvb_muxes, &skel, tdmi_global_link, tdmi_global_cmp); +} + + + + + + +static struct strtab fectab[] = { + { "NONE", FEC_NONE }, + { "1/2", FEC_1_2 }, + { "2/3", FEC_2_3 }, + { "3/4", FEC_3_4 }, + { "4/5", FEC_4_5 }, + { "5/6", FEC_5_6 }, + { "6/7", FEC_6_7 }, + { "7/8", FEC_7_8 }, + { "8/9", FEC_8_9 }, + { "AUTO", FEC_AUTO } +}; + +static struct strtab qamtab[] = { + { "QPSK", QPSK }, + { "QAM16", QAM_16 }, + { "QAM32", QAM_32 }, + { "QAM64", QAM_64 }, + { "QAM128", QAM_128 }, + { "QAM256", QAM_256 }, + { "AUTO", QAM_AUTO }, + { "8VSB", VSB_8 }, + { "16VSB", VSB_16 } +}; + +static struct strtab bwtab[] = { + { "8MHz", BANDWIDTH_8_MHZ }, + { "7MHz", BANDWIDTH_7_MHZ }, + { "6MHz", BANDWIDTH_6_MHZ }, + { "AUTO", BANDWIDTH_AUTO } +}; + +static struct strtab modetab[] = { + { "2k", TRANSMISSION_MODE_2K }, + { "8k", TRANSMISSION_MODE_8K }, + { "AUTO", TRANSMISSION_MODE_AUTO } +}; + +static struct strtab guardtab[] = { + { "1/32", GUARD_INTERVAL_1_32 }, + { "1/16", GUARD_INTERVAL_1_16 }, + { "1/8", GUARD_INTERVAL_1_8 }, + { "1/4", GUARD_INTERVAL_1_4 }, + { "AUTO", GUARD_INTERVAL_AUTO }, +}; + +static struct strtab hiertab[] = { + { "NONE", HIERARCHY_NONE }, + { "1", HIERARCHY_1 }, + { "2", HIERARCHY_2 }, + { "4", HIERARCHY_4 }, + { "AUTO", HIERARCHY_AUTO } +}; + +static struct strtab poltab[] = { + { "Vertical", POLARISATION_VERTICAL }, + { "Horizontal", POLARISATION_HORIZONTAL }, +}; + + +/** + * + */ +void +dvb_mux_save(th_dvb_mux_instance_t *tdmi) +{ + struct dvb_frontend_parameters *f = &tdmi->tdmi_fe_params; + + htsmsg_t *m = htsmsg_create(); + + htsmsg_add_u32(m, "transportstreamid", tdmi->tdmi_transport_stream_id); + if(tdmi->tdmi_network != NULL) + htsmsg_add_str(m, "network", tdmi->tdmi_network); + + htsmsg_add_u32(m, "frequency", f->frequency); + + switch(tdmi->tdmi_adapter->tda_type) { + case FE_OFDM: + htsmsg_add_str(m, "bandwidth", + val2str(f->u.ofdm.bandwidth, bwtab)); + + htsmsg_add_str(m, "constellation", + val2str(f->u.ofdm.constellation, qamtab)); + + htsmsg_add_str(m, "transmission_mode", + val2str(f->u.ofdm.transmission_mode, modetab)); + + htsmsg_add_str(m, "guard_interval", + val2str(f->u.ofdm.guard_interval, guardtab)); + + htsmsg_add_str(m, "hierarchy", + val2str(f->u.ofdm.hierarchy_information, hiertab)); + + htsmsg_add_str(m, "fec_hi", + val2str(f->u.ofdm.code_rate_HP, fectab)); + + htsmsg_add_str(m, "fec_lo", + val2str(f->u.ofdm.code_rate_LP, fectab)); + break; + + case FE_QPSK: + htsmsg_add_u32(m, "symbol_rate", f->u.qpsk.symbol_rate); + + htsmsg_add_str(m, "fec", + val2str(f->u.qpsk.fec_inner, fectab)); + + htsmsg_add_str(m, "polarisation", + val2str(tdmi->tdmi_polarisation, poltab)); + + htsmsg_add_u32(m, "switchport", tdmi->tdmi_switchport); + break; + + case FE_QAM: + htsmsg_add_u32(m, "symbol_rate", f->u.qam.symbol_rate); + + htsmsg_add_str(m, "fec", + val2str(f->u.qam.fec_inner, fectab)); + + htsmsg_add_str(m, "constellation", + val2str(f->u.qam.modulation, qamtab)); + break; + + case FE_ATSC: + break; + } + + hts_settings_save(m, "dvbmuxes/%s/%s", + tdmi->tdmi_adapter->tda_identifier, tdmi->tdmi_identifier); + htsmsg_destroy(m); +} + + +/** + * + */ +static const char * +tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m) +{ + struct dvb_frontend_parameters f; + const char *s; + int r; + int polarisation = 0; + unsigned int switchport = 0; + unsigned int tsid; + + memset(&f, 0, sizeof(f)); + + f.inversion = INVERSION_AUTO; + htsmsg_get_u32(m, "frequency", &f.frequency); + + + switch(tda->tda_type) { + case FE_OFDM: + s = htsmsg_get_str(m, "bandwidth"); + if(s == NULL || (r = str2val(s, bwtab)) < 0) + return "Invalid bandwidth"; + f.u.ofdm.bandwidth = r; + + s = htsmsg_get_str(m, "constellation"); + if(s == NULL || (r = str2val(s, qamtab)) < 0) + return "Invalid QAM constellation"; + f.u.ofdm.constellation = r; + + s = htsmsg_get_str(m, "transmission_mode"); + if(s == NULL || (r = str2val(s, modetab)) < 0) + return "Invalid transmission mode"; + f.u.ofdm.transmission_mode = r; + + s = htsmsg_get_str(m, "guard_interval"); + if(s == NULL || (r = str2val(s, guardtab)) < 0) + return "Invalid guard interval"; + f.u.ofdm.guard_interval = r; + + s = htsmsg_get_str(m, "hierarchy"); + if(s == NULL || (r = str2val(s, hiertab)) < 0) + return "Invalid heirarchy information"; + f.u.ofdm.hierarchy_information = r; + + s = htsmsg_get_str(m, "fec_hi"); + if(s == NULL || (r = str2val(s, fectab)) < 0) + return "Invalid hi-FEC"; + f.u.ofdm.code_rate_HP = r; + + s = htsmsg_get_str(m, "fec_lo"); + if(s == NULL || (r = str2val(s, fectab)) < 0) + return "Invalid lo-FEC"; + f.u.ofdm.code_rate_LP = r; + break; + + case FE_QPSK: + htsmsg_get_u32(m, "symbol_rate", &f.u.qpsk.symbol_rate); + if(f.u.qpsk.symbol_rate == 0) + return "Invalid symbol rate"; + + s = htsmsg_get_str(m, "fec"); + if(s == NULL || (r = str2val(s, fectab)) < 0) + return "Invalid FEC"; + f.u.qpsk.fec_inner = r; + + s = htsmsg_get_str(m, "polarisation"); + if(s == NULL || (r = str2val(s, poltab)) < 0) + return "Invalid polarisation"; + polarisation = r; + + htsmsg_get_u32(m, "switchport", &switchport); + break; + + case FE_QAM: + htsmsg_get_u32(m, "symbol_rate", &f.u.qam.symbol_rate); + if(f.u.qam.symbol_rate == 0) + return "Invalid symbol rate"; + + s = htsmsg_get_str(m, "constellation"); + if(s == NULL || (r = str2val(s, qamtab)) < 0) + return "Invalid QAM constellation"; + f.u.qam.modulation = r; + + s = htsmsg_get_str(m, "fec"); + if(s == NULL || (r = str2val(s, fectab)) < 0) + return "Invalid FEC"; + f.u.qam.fec_inner = r; + break; + + case FE_ATSC: + break; + } + + if(htsmsg_get_u32(m, "transportstreamid", &tsid)) + tsid = 0xffff; + + dvb_mux_create(tda, &f, polarisation, switchport, + tsid, htsmsg_get_str(m, "network"), NULL); + return NULL; +} + + + +/** + * + */ +void +dvb_mux_load(th_dvb_adapter_t *tda) +{ + htsmsg_t *l, *c; + htsmsg_field_t *f; + + if((l = hts_settings_load("dvbmuxes/%s", tda->tda_identifier)) == NULL) + return; + + HTSMSG_FOREACH(f, l) { + if((c = htsmsg_get_msg_by_field(f)) == NULL) + continue; + + tdmi_create_by_msg(tda, c); + } + htsmsg_destroy(l); +} + diff --git a/dvb/dvb_muxconfig.c b/dvb/dvb_muxconfig.c index 66fcf480..50f4bef0 100644 --- a/dvb/dvb_muxconfig.c +++ b/dvb/dvb_muxconfig.c @@ -21,332 +21,14 @@ #include #include #include -#include #include #include #include "tvhead.h" -#include "channels.h" #include "dvb.h" -#include "dvb_dvr.h" #include "dvb_muxconfig.h" -#include "dvb_support.h" -#include "transports.h" -#include "notify.h" - - - -/** - * Save config for the given adapter - */ -void -dvb_tda_save(th_dvb_adapter_t *tda) -{ - htsmsg_t *m = htsmsg_create(); - - htsmsg_add_str(m, "type", dvb_adaptertype_to_str(tda->tda_type)); - htsmsg_add_str(m, "displayname", tda->tda_displayname); - hts_settings_save(m, "dvbadapters/%s", tda->tda_identifier); - htsmsg_destroy(m); -} - - -/** - * - */ -static htsmsg_t * -dvb_tda_createmsg(th_dvb_adapter_t *tda) -{ - htsmsg_t *m = htsmsg_create(); - htsmsg_add_str(m, "id", tda->tda_identifier); - return m; -} - -/** - * - */ -void -dvb_tda_set_displayname(th_dvb_adapter_t *tda, const char *s) -{ - htsmsg_t *m = dvb_tda_createmsg(tda); - - free(tda->tda_displayname); - tda->tda_displayname = strdup(s); - - dvb_tda_save(tda); - - htsmsg_add_str(m, "name", tda->tda_displayname); - - notify_by_msg("dvbadapter", m); -} - - - - - - -static struct strtab fectab[] = { - { "NONE", FEC_NONE }, - { "1/2", FEC_1_2 }, - { "2/3", FEC_2_3 }, - { "3/4", FEC_3_4 }, - { "4/5", FEC_4_5 }, - { "5/6", FEC_5_6 }, - { "6/7", FEC_6_7 }, - { "7/8", FEC_7_8 }, - { "8/9", FEC_8_9 }, - { "AUTO", FEC_AUTO } -}; - -static struct strtab qamtab[] = { - { "QPSK", QPSK }, - { "QAM16", QAM_16 }, - { "QAM32", QAM_32 }, - { "QAM64", QAM_64 }, - { "QAM128", QAM_128 }, - { "QAM256", QAM_256 }, - { "AUTO", QAM_AUTO }, - { "8VSB", VSB_8 }, - { "16VSB", VSB_16 } -}; - -static struct strtab bwtab[] = { - { "8MHz", BANDWIDTH_8_MHZ }, - { "7MHz", BANDWIDTH_7_MHZ }, - { "6MHz", BANDWIDTH_6_MHZ }, - { "AUTO", BANDWIDTH_AUTO } -}; - -static struct strtab modetab[] = { - { "2k", TRANSMISSION_MODE_2K }, - { "8k", TRANSMISSION_MODE_8K }, - { "AUTO", TRANSMISSION_MODE_AUTO } -}; - -static struct strtab guardtab[] = { - { "1/32", GUARD_INTERVAL_1_32 }, - { "1/16", GUARD_INTERVAL_1_16 }, - { "1/8", GUARD_INTERVAL_1_8 }, - { "1/4", GUARD_INTERVAL_1_4 }, - { "AUTO", GUARD_INTERVAL_AUTO }, -}; - -static struct strtab hiertab[] = { - { "NONE", HIERARCHY_NONE }, - { "1", HIERARCHY_1 }, - { "2", HIERARCHY_2 }, - { "4", HIERARCHY_4 }, - { "AUTO", HIERARCHY_AUTO } -}; - -static struct strtab poltab[] = { - { "Vertical", POLARISATION_VERTICAL }, - { "Horizontal", POLARISATION_HORIZONTAL }, -}; - - -/** - * - */ -void -dvb_tdmi_save(th_dvb_mux_instance_t *tdmi) -{ - struct dvb_frontend_parameters *f = &tdmi->tdmi_fe_params; - - htsmsg_t *m = htsmsg_create(); - - htsmsg_add_u32(m, "transportstreamid", tdmi->tdmi_transport_stream_id); - if(tdmi->tdmi_network != NULL) - htsmsg_add_str(m, "network", tdmi->tdmi_network); - - htsmsg_add_u32(m, "frequency", f->frequency); - - switch(tdmi->tdmi_adapter->tda_type) { - case FE_OFDM: - htsmsg_add_str(m, "bandwidth", - val2str(f->u.ofdm.bandwidth, bwtab)); - - htsmsg_add_str(m, "constellation", - val2str(f->u.ofdm.constellation, qamtab)); - - htsmsg_add_str(m, "transmission_mode", - val2str(f->u.ofdm.transmission_mode, modetab)); - - htsmsg_add_str(m, "guard_interval", - val2str(f->u.ofdm.guard_interval, guardtab)); - - htsmsg_add_str(m, "hierarchy", - val2str(f->u.ofdm.hierarchy_information, hiertab)); - - htsmsg_add_str(m, "fec_hi", - val2str(f->u.ofdm.code_rate_HP, fectab)); - - htsmsg_add_str(m, "fec_lo", - val2str(f->u.ofdm.code_rate_LP, fectab)); - break; - - case FE_QPSK: - htsmsg_add_u32(m, "symbol_rate", f->u.qpsk.symbol_rate); - - htsmsg_add_str(m, "fec", - val2str(f->u.qpsk.fec_inner, fectab)); - - htsmsg_add_str(m, "polarisation", - val2str(tdmi->tdmi_polarisation, poltab)); - - htsmsg_add_u32(m, "switchport", tdmi->tdmi_switchport); - break; - - case FE_QAM: - htsmsg_add_u32(m, "symbol_rate", f->u.qam.symbol_rate); - - htsmsg_add_str(m, "fec", - val2str(f->u.qam.fec_inner, fectab)); - - htsmsg_add_str(m, "constellation", - val2str(f->u.qam.modulation, qamtab)); - break; - - case FE_ATSC: - break; - } - - hts_settings_save(m, "dvbmuxes/%s/%s", - tdmi->tdmi_adapter->tda_identifier, tdmi->tdmi_identifier); - htsmsg_destroy(m); -} - - -/** - * - */ -static const char * -dvb_tdmi_create_by_msg(th_dvb_adapter_t *tda, htsmsg_t *m) -{ - struct dvb_frontend_parameters f; - const char *s; - int r; - int polarisation = 0; - unsigned int switchport = 0; - unsigned int tsid; - - memset(&f, 0, sizeof(f)); - - f.inversion = INVERSION_AUTO; - htsmsg_get_u32(m, "frequency", &f.frequency); - - - switch(tda->tda_type) { - case FE_OFDM: - s = htsmsg_get_str(m, "bandwidth"); - if(s == NULL || (r = str2val(s, bwtab)) < 0) - return "Invalid bandwidth"; - f.u.ofdm.bandwidth = r; - - s = htsmsg_get_str(m, "constellation"); - if(s == NULL || (r = str2val(s, qamtab)) < 0) - return "Invalid QAM constellation"; - f.u.ofdm.constellation = r; - - s = htsmsg_get_str(m, "transmission_mode"); - if(s == NULL || (r = str2val(s, modetab)) < 0) - return "Invalid transmission mode"; - f.u.ofdm.transmission_mode = r; - - s = htsmsg_get_str(m, "guard_interval"); - if(s == NULL || (r = str2val(s, guardtab)) < 0) - return "Invalid guard interval"; - f.u.ofdm.guard_interval = r; - - s = htsmsg_get_str(m, "hierarchy"); - if(s == NULL || (r = str2val(s, hiertab)) < 0) - return "Invalid heirarchy information"; - f.u.ofdm.hierarchy_information = r; - - s = htsmsg_get_str(m, "fec_hi"); - if(s == NULL || (r = str2val(s, fectab)) < 0) - return "Invalid hi-FEC"; - f.u.ofdm.code_rate_HP = r; - - s = htsmsg_get_str(m, "fec_lo"); - if(s == NULL || (r = str2val(s, fectab)) < 0) - return "Invalid lo-FEC"; - f.u.ofdm.code_rate_LP = r; - break; - - case FE_QPSK: - htsmsg_get_u32(m, "symbol_rate", &f.u.qpsk.symbol_rate); - if(f.u.qpsk.symbol_rate == 0) - return "Invalid symbol rate"; - - s = htsmsg_get_str(m, "fec"); - if(s == NULL || (r = str2val(s, fectab)) < 0) - return "Invalid FEC"; - f.u.qpsk.fec_inner = r; - - s = htsmsg_get_str(m, "polarisation"); - if(s == NULL || (r = str2val(s, poltab)) < 0) - return "Invalid polarisation"; - polarisation = r; - - htsmsg_get_u32(m, "switchport", &switchport); - break; - - case FE_QAM: - htsmsg_get_u32(m, "symbol_rate", &f.u.qam.symbol_rate); - if(f.u.qam.symbol_rate == 0) - return "Invalid symbol rate"; - - s = htsmsg_get_str(m, "constellation"); - if(s == NULL || (r = str2val(s, qamtab)) < 0) - return "Invalid QAM constellation"; - f.u.qam.modulation = r; - - s = htsmsg_get_str(m, "fec"); - if(s == NULL || (r = str2val(s, fectab)) < 0) - return "Invalid FEC"; - f.u.qam.fec_inner = r; - break; - - case FE_ATSC: - break; - } - - if(htsmsg_get_u32(m, "transportstreamid", &tsid)) - tsid = 0xffff; - - dvb_mux_create(tda, &f, polarisation, switchport, - tsid, htsmsg_get_str(m, "network"), NULL); - return NULL; -} - - - -/** - * - */ -void -dvb_tdmi_load(th_dvb_adapter_t *tda) -{ - htsmsg_t *l, *c; - htsmsg_field_t *f; - - if((l = hts_settings_load("dvbmuxes/%s", tda->tda_identifier)) == NULL) - return; - - HTSMSG_FOREACH(f, l) { - if((c = htsmsg_get_msg_by_field(f)) == NULL) - continue; - - dvb_tdmi_create_by_msg(tda, c); - } - htsmsg_destroy(l); -} - - - /** * A big list of all known DVB networks (from linuxtv.org) @@ -365,8 +47,6 @@ dvb_mux_preconf_add(th_dvb_adapter_t *tda, const struct mux *m, int num, int polarisation; int switchport; - printf("m = %p, num = %d\n", m, num); - for(i = 0; i < num; i++) { polarisation = 0; diff --git a/dvb/dvb_muxconfig.h b/dvb/dvb_muxconfig.h index eb1ad6d5..251f5ae6 100644 --- a/dvb/dvb_muxconfig.h +++ b/dvb/dvb_muxconfig.h @@ -21,33 +21,8 @@ #include -void dvb_tda_save(th_dvb_adapter_t *tda); - -void dvb_tda_set_displayname(th_dvb_adapter_t *tda, const char *s); - -void dvb_tdmi_save(th_dvb_mux_instance_t *tdmi); - -const char *dvb_mux_create_str(th_dvb_adapter_t *tda, - const char *tsidstr, - const char *network, - const char *freqstr, - const char *symratestr, - const char *qamstr, - const char *fecstr, - const char *fechistr, - const char *feclostr, - const char *bwstr, - const char *tmodestr, - const char *guardstr, - const char *hierstr, - const char *polstr, - const char *switchportstr, - int save); - htsmsg_t *dvb_mux_preconf_get_node(int fetype, const char *node); int dvb_mux_preconf_add_network(th_dvb_adapter_t *tda, const char *id); -void dvb_tdmi_load(th_dvb_adapter_t *tda); - #endif /* DVB_MUXCONFIG_H */ diff --git a/dvb/dvb_tables.c b/dvb/dvb_tables.c index 527d7f31..5d182dd3 100644 --- a/dvb/dvb_tables.c +++ b/dvb/dvb_tables.c @@ -98,7 +98,7 @@ dvb_table_recv(int events, void *opaque, int fd) tdt->tdt_count++; tdt->tdt_callback(tdt->tdt_tdmi, ptr, len, tableid, tdt->tdt_opaque); - dvb_tdmi_fastswitch(tdt->tdt_tdmi); + dvb_mux_fastswitch(tdt->tdt_tdmi); } @@ -258,7 +258,7 @@ dvb_eit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, if(tdmi == NULL) return; - t = dvb_find_transport(tdmi, serviceid, 0, NULL); + t = dvb_transport_find(tdmi, serviceid, 0, NULL); if(t == NULL) return; @@ -409,7 +409,7 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, snprintf(chname0, sizeof(chname0), "noname-sid-0x%x", service_id); } - t = dvb_find_transport(tdmi, service_id, 0, NULL); + t = dvb_transport_find(tdmi, service_id, 0, NULL); if(t == NULL) break; @@ -438,7 +438,7 @@ dvb_sdt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, } } if(change) { - dvb_tdmi_save(tdmi); + dvb_mux_save(tdmi); // notify_tdmi_services_change(tdmi); } } @@ -461,7 +461,7 @@ dvb_pat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, if(tdmi->tdmi_transport_stream_id != tid) { tdmi->tdmi_transport_stream_id = tid; - dvb_tda_save(tdmi->tdmi_adapter); + dvb_mux_save(tdmi); } ptr += 5; @@ -472,7 +472,7 @@ dvb_pat_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, pmt = (ptr[2] & 0x1f) << 8 | ptr[3]; if(service != 0) { - t = dvb_find_transport(tdmi, service, pmt, &created); + t = dvb_transport_find(tdmi, service, pmt, &created); if(created) { /* Add PMT to our table scanner */ dvb_table_add_transport(tdmi, t, pmt); } @@ -647,7 +647,7 @@ dvb_nit_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, free((void *)tdmi->tdmi_network); tdmi->tdmi_network = strdup(networkname); //notify_tdmi_name_change(tdmi); - dvb_tda_save(tdmi->tdmi_adapter); + dvb_mux_save(tdmi); } break; } @@ -713,7 +713,7 @@ dvb_pmt_callback(th_dvb_mux_instance_t *tdmi, uint8_t *ptr, int len, psi_parse_pmt(t, ptr, len, 1); v ^= t->tht_pmt_seen; if(v) { - dvb_tdmi_save(tdmi); + dvb_mux_save(tdmi); //notify_tdmi_services_change(tdmi); } return; diff --git a/dvb/dvb_transport.c b/dvb/dvb_transport.c new file mode 100644 index 00000000..61cf9d75 --- /dev/null +++ b/dvb/dvb_transport.c @@ -0,0 +1,161 @@ +/* + * TV Input - Linux DVB interface + * Copyright (C) 2007 Andreas Öman + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "tvhead.h" +#include "dispatch.h" +#include "dvb.h" +#include "channels.h" +#include "transports.h" +#include "subscriptions.h" +#include "psi.h" +#include "dvb_support.h" +#include "dvb_dvr.h" +#include "dvb_muxconfig.h" +#include "notify.h" + + +/** + * + */ +static void +dvb_transport_save(th_transport_t *t) +{ + htsmsg_t *m = htsmsg_create(); + + + htsmsg_add_u32(m, "service_id", t->tht_dvb_service_id); + htsmsg_add_u32(m, "pmt", t->tht_pmt); + htsmsg_add_u32(m, "stype", t->tht_servicetype); + htsmsg_add_u32(m, "scrambled", t->tht_scrambled); + + if(t->tht_provider != NULL) + htsmsg_add_str(m, "provider", t->tht_provider); + + if(t->tht_svcname != NULL) + htsmsg_add_str(m, "servicename", t->tht_svcname); + + if(t->tht_chname != NULL) + htsmsg_add_str(m, "channelname", t->tht_chname); + + htsmsg_add_u32(m, "mapped", !!t->tht_ch); + + psi_get_transport_settings(m, t); + + hts_settings_save(m, "dvbtransports/%s", t->tht_identifier); + htsmsg_destroy(m); +} + + +/** + * Called to get quality for the given transport + * + * We keep track of this for the entire mux (if we see errors), soo.. + * return that value + */ +static int +dvb_transport_quality(th_transport_t *t) +{ + th_dvb_mux_instance_t *tdmi = t->tht_dvb_mux_instance; + return tdmi->tdmi_quality; +} + + +/** + * Generate a descriptive name for the source + */ +static const char * +dvb_transport_name(th_transport_t *t) +{ + th_dvb_mux_instance_t *tdmi; + static char buf[200]; + + tdmi = t->tht_dvb_mux_instance; + + snprintf(buf, sizeof(buf), "\"%s\" on \"%s\"", + tdmi->tdmi_network ?: "Unknown network", + tdmi->tdmi_adapter->tda_rootpath); + + return buf; +} + + + + +/** + * Find a transport based on 'serviceid' on the given mux + * + * If it cannot be found we create it if 'pmt_pid' is also set + */ +th_transport_t * +dvb_transport_find(th_dvb_mux_instance_t *tdmi, uint16_t sid, int pmt_pid, + int *created) +{ + th_transport_t *t; + char tmp[200]; + + if(created != NULL) + *created = 0; + + LIST_FOREACH(t, &tdmi->tdmi_transports, tht_mux_link) { + if(t->tht_dvb_service_id == sid) + return t; + } + + if(pmt_pid == 0) + return NULL; + + if(created != NULL) + *created = 1; + + snprintf(tmp, sizeof(tmp), "%s_%04x", tdmi->tdmi_identifier, sid); + + t = transport_create(tmp, TRANSPORT_DVB, THT_MPEG_TS); + + t->tht_dvb_service_id = sid; + t->tht_pmt = pmt_pid; + + t->tht_start_feed = dvb_start_feed; + t->tht_stop_feed = dvb_stop_feed; + t->tht_config_change = dvb_transport_save; + t->tht_sourcename = dvb_transport_name; + t->tht_dvb_mux_instance = tdmi; + t->tht_quality_index = dvb_transport_quality; + + LIST_INSERT_HEAD(&tdmi->tdmi_transports, t, tht_mux_link); + return t; +} diff --git a/webui/extjs.c b/webui/extjs.c index 8665723d..8d2c2752 100644 --- a/webui/extjs.c +++ b/webui/extjs.c @@ -368,7 +368,7 @@ extjs_dvbadapter(http_connection_t *hc, http_reply_t *hr, } else if(!strcmp(op, "save")) { if((s = http_arg_get(&hc->hc_req_args, "name")) != NULL) - dvb_tda_set_displayname(tda, s); + dvb_adapter_set_displayname(tda, s); out = htsmsg_create(); htsmsg_add_u32(out, "success", 1);