diff --git a/src/dvb/dvb.h b/src/dvb/dvb.h index 5f6cfbb7..1b61f576 100644 --- a/src/dvb/dvb.h +++ b/src/dvb/dvb.h @@ -229,6 +229,7 @@ typedef struct th_dvb_adapter { char *tda_demux_path; + char *tda_dvr_path; pthread_t tda_dvr_thread; th_pipe_t tda_dvr_pipe; @@ -344,7 +345,7 @@ void dvb_adapter_stop (th_dvb_adapter_t *tda); void dvb_adapter_set_displayname(th_dvb_adapter_t *tda, const char *s); -void dvb_adapter_set_enabled(th_dvb_adapter_t *tda, uint32_t enabled); +void dvb_adapter_set_enabled(th_dvb_adapter_t *tda, int on); void dvb_adapter_set_auto_discovery(th_dvb_adapter_t *tda, int on); diff --git a/src/dvb/dvb_adapter.c b/src/dvb/dvb_adapter.c index 3d727f12..6a1b1cc5 100644 --- a/src/dvb/dvb_adapter.c +++ b/src/dvb/dvb_adapter.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -49,6 +51,7 @@ struct th_dvb_adapter_queue dvb_adapters; struct th_dvb_mux_instance_tree dvb_muxes; static void *dvb_adapter_input_dvr(void *aux); +static void tda_init(th_dvb_adapter_t *tda); /** @@ -81,6 +84,12 @@ tda_save(th_dvb_adapter_t *tda) lock_assert(&global_lock); htsmsg_add_u32(m, "enabled", tda->tda_enabled); + if (tda->tda_fe_path) + htsmsg_add_str(m, "fe_path", tda->tda_fe_path); + if (tda->tda_demux_path) + htsmsg_add_str(m, "dmx_path", tda->tda_demux_path); + if (tda->tda_dvr_path) + htsmsg_add_str(m, "dvr_path", tda->tda_dvr_path); htsmsg_add_str(m, "type", dvb_adaptertype_to_str(tda->tda_type)); htsmsg_add_str(m, "displayname", tda->tda_displayname); htsmsg_add_u32(m, "autodiscovery", tda->tda_autodiscovery); @@ -101,6 +110,31 @@ tda_save(th_dvb_adapter_t *tda) htsmsg_destroy(m); } +/** + * + */ +void +dvb_adapter_set_enabled(th_dvb_adapter_t *tda, int on) +{ + if(tda->tda_enabled == on) + return; + + lock_assert(&global_lock); + + tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" %s", + tda->tda_displayname, on ? "Enabled" : "Disabled"); + + tda->tda_enabled = on; + tda_save(tda); + if (!on) { + gtimer_disarm(&tda->tda_mux_scanner_timer); + if (tda->tda_mux_current) + dvb_fe_stop(tda->tda_mux_current, 0); + dvb_adapter_stop(tda); + } else { + tda_init(tda); + } +} /** * @@ -124,26 +158,6 @@ dvb_adapter_set_displayname(th_dvb_adapter_t *tda, const char *s) dvb_adapter_notify(tda); } - -/** - * - */ -void -dvb_adapter_set_enabled(th_dvb_adapter_t *tda, uint32_t enabled) -{ - if(tda->tda_enabled == enabled) - return; - - lock_assert(&global_lock); - - tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" enabled set to \"%s\"", - tda->tda_displayname, enabled ? "Enabled" : "Disabled"); - - tda->tda_enabled = enabled; - tda_save(tda); -} - - /** * */ @@ -465,88 +479,113 @@ check_full_stream(th_dvb_adapter_t *tda) * */ static void -tda_add(int adapter_num, int frontend_num, int demux_num) +tda_add(int adapter_num) { - char path[200], fname[256]; - int fe, i, r; + char buf[1024], path[200], fepath[256], dmxpath[256], dvrpath[256]; + int i, j, fd; th_dvb_adapter_t *tda; - char buf[400]; + struct dvb_frontend_info fe_info; + DIR *dirp; + /* Check valid adapter */ snprintf(path, sizeof(path), "/dev/dvb/adapter%d", adapter_num); - snprintf(fname, sizeof(fname), "%s/frontend%d", path, frontend_num); - - fe = tvh_open(fname, O_RDWR | O_NONBLOCK, 0); - if(fe == -1) { - if(errno != ENOENT) + dirp = opendir(path); + if (!dirp) + return; + + /* Check each frontend */ + // Note: this algo will fail if there are really exotic variations + // of tuners and demuxers etc... but you can always manually + // override the config + for (i = 0; i < 32; i++) { + + /* Open/Query frontend */ + snprintf(fepath, sizeof(fepath), "%s/frontend%d", path, i); + fd = tvh_open(fepath, O_RDONLY, 0); + if (fd == -1) { + if (errno != ENOENT) + tvhlog(LOG_ALERT, "dvb", + "%s: unable to open (err=%s)", fepath, strerror(errno)); + continue; + } + if (ioctl(fd, FE_GET_INFO, &fe_info)) { tvhlog(LOG_ALERT, "dvb", - "Unable to open %s -- %s", fname, strerror(errno)); - return; + "%s: unable to query (err=%s)", fepath, strerror(errno)); + close(fd); + continue; + } + close(fd); + + /* Find Demux */ + snprintf(dmxpath, sizeof(dmxpath), "%s/demux%d", path, i); + fd = tvh_open(dmxpath, O_RDONLY, 0); + if (fd == -1) { + snprintf(dmxpath, sizeof(dmxpath), "%s/demux%d", path, 0); + fd = tvh_open(dmxpath, O_RDONLY, 0); + } + if (fd == -1) { + tvhlog(LOG_ALERT, "dvb", "%s: unable to find demux", fepath); + continue; + } + close(fd); + + /* Find DVR */ + snprintf(dvrpath, sizeof(dvrpath), "%s/dvr%d", path, i); + fd = tvh_open(dvrpath, O_RDONLY, 0); + if (fd == -1) { + snprintf(dvrpath, sizeof(dvrpath), "%s/dvr%d", path, 0); + fd = tvh_open(dvrpath, O_RDONLY, 0); + } + if (fd == -1) { + tvhlog(LOG_ALERT, "dvb", "%s: unable to find dvr", fepath); + continue; + } + close(fd); + + /* Create entry */ + tda = tda_alloc(); + tda->tda_adapter_num = adapter_num; + tda->tda_rootpath = strdup(path); + tda->tda_fe_path = strdup(fepath); + tda->tda_demux_path = strdup(dmxpath); + tda->tda_dvr_path = strdup(dvrpath); + tda->tda_fe_fd = -1; + tda->tda_dvr_pipe.rd = -1; + tda->tda_full_mux_rx = -1; + tda->tda_type = fe_info.type; + tda->tda_autodiscovery = tda->tda_type != FE_QPSK; + tda->tda_idlescan = 1; + tda->tda_sat = tda->tda_type == FE_QPSK; + tda->tda_displayname = strdup(fe_info.name); + tda->tda_fe_info = malloc(sizeof(struct dvb_frontend_info)); + memcpy(tda->tda_fe_info, &fe_info, sizeof(struct dvb_frontend_info)); + + /* ID the device (for configuration etc..) */ + // Note: would be better to include frontend dev in name, but that + // would require additional work to migrate config + snprintf(buf, sizeof(buf), "%s_%s", tda->tda_rootpath, + tda->tda_fe_info->name); + for(j = 0; j < strlen(buf); j++) + if(!isalnum((int)buf[j])) + buf[j] = '_'; + tda->tda_identifier = strdup(buf); + + /* Check device connection */ + dvb_adapter_checkspeed(tda); + + /* Adapters known to provide valid SNR */ + if(strcasestr(fe_info.name, "Sony CXD2820R")) + tda->tda_snr_valid = 1; + + /* Store */ + tvhlog(LOG_INFO, "dvb", + "Found adapter %s (%s) via %s%s", path, tda->tda_fe_info->name, + hostconnection2str(tda->tda_hostconnection), + tda->tda_snr_valid ? ", Reports valid SNR values" : ""); + TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link); } - - tda = tda_alloc(); - - tda->tda_adapter_num = adapter_num; - tda->tda_rootpath = strdup(path); - tda->tda_demux_path = malloc(256); - snprintf(tda->tda_demux_path, 256, "%s/demux%d", path, demux_num); - tda->tda_fe_path = strdup(fname); - tda->tda_fe_fd = -1; - tda->tda_dvr_pipe.rd = -1; - tda->tda_full_mux_rx = -1; - tda->tda_enabled = 0; - - tda->tda_fe_info = malloc(sizeof(struct dvb_frontend_info)); - - if(ioctl(fe, FE_GET_INFO, tda->tda_fe_info)) { - tvhlog(LOG_ALERT, "dvb", "%s: Unable to query adapter", fname); - close(fe); - free(tda); - return; - } - - close(fe); - fe = -1; - - tda->tda_type = tda->tda_fe_info->type; - - 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); - - tda->tda_autodiscovery = tda->tda_type != FE_QPSK; - tda->tda_idlescan = 1; - - tda->tda_sat = tda->tda_type == FE_QPSK; - - /* 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); - - dvb_adapter_checkspeed(tda); - - - if(strcasestr(tda->tda_fe_info->name, "Sony CXD2820R")) - tda->tda_snr_valid = 1; - - tvhlog(LOG_INFO, "dvb", - "Found adapter %s (%s) via %s%s", path, tda->tda_fe_info->name, - hostconnection2str(tda->tda_hostconnection), - tda->tda_snr_valid ? ", Reports valid SNR values" : ""); - - TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link); - - gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 1); } - - /** * */ @@ -592,21 +631,28 @@ tda_add_from_file(const char *filename) } /** - * Initiliase input + * Initiliase */ -static void tda_init_input (th_dvb_adapter_t *tda) +static void tda_init (th_dvb_adapter_t *tda) { - if(tda->tda_type == -1 || check_full_stream(tda)) { - tvhlog(LOG_INFO, "dvb", "Adapter %s will run in full mux mode", tda->tda_rootpath); - dvb_input_raw_setup(tda); - } else { - tvhlog(LOG_INFO, "dvb", "Adapter %s will run in filtered mode", tda->tda_rootpath); - dvb_input_filtered_setup(tda); + /* Disabled - ignore */ + if (!tda->tda_enabled || !tda->tda_rootpath) return; + + /* Initiliase input mode */ + if(!tda->tda_open_service) { + if(tda->tda_type == -1 || check_full_stream(tda)) { + tvhlog(LOG_INFO, "dvb", "Adapter %s will run in full mux mode", tda->tda_rootpath); + dvb_input_raw_setup(tda); + } else { + tvhlog(LOG_INFO, "dvb", "Adapter %s will run in filtered mode", tda->tda_rootpath); + dvb_input_filtered_setup(tda); + } } + + /* Enable mux scanner */ + gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 1); } - - /** * */ @@ -641,7 +687,7 @@ dvb_adapter_stop ( th_dvb_adapter_t *tda ) dvb_adapter_poweroff(tda); /* Don't stop/close */ - if (!tda->tda_idleclose) return; + if (!tda->tda_idleclose && tda->tda_enabled) return; /* Close front end */ if (tda->tda_fe_fd != -1) { @@ -661,6 +707,8 @@ dvb_adapter_stop ( th_dvb_adapter_t *tda ) tda->tda_dvr_pipe.rd = -1; tvhlog(LOG_DEBUG, "dvb", "%s stopped thread", tda->tda_rootpath); } + + dvb_adapter_notify(tda); } /** @@ -671,8 +719,8 @@ dvb_adapter_init(uint32_t adapter_mask, const char *rawfile) { htsmsg_t *l, *c; htsmsg_field_t *f; - const char *name, *s; - int i, j, type; + const char *s; + int i, type; uint32_t u32; th_dvb_adapter_t *tda; @@ -681,54 +729,52 @@ dvb_adapter_init(uint32_t adapter_mask, const char *rawfile) /* Initialise hardware */ for(i = 0; i < 32; i++) if ((1 << i) & adapter_mask) - for(j = 0; j < 32; j++) - tda_add(i, j, 0); + tda_add(i); /* Initialise rawts test file */ if(rawfile) tda_add_from_file(rawfile); /* Load configuration */ - l = hts_settings_load("dvbadapters"); - if(l != NULL) { + if ((l = hts_settings_load("dvbadapters")) != NULL) { HTSMSG_FOREACH(f, l) { if((c = htsmsg_get_map_by_field(f)) == NULL) continue; - name = htsmsg_get_str(c, "displayname"); - if((s = htsmsg_get_str(c, "type")) == NULL || (type = dvb_str_to_adaptertype(s)) < 0) continue; + // TODO: do we really want to do this? useful for debug? if((tda = dvb_adapter_find_by_identifier(f->hmf_name)) == NULL) { /* Not discovered by hardware, create it */ - tda = tda_alloc(); + tda = tda_alloc(); tda->tda_identifier = strdup(f->hmf_name); - tda->tda_type = type; - tda->tda_enabled = 0; + tda->tda_type = type; TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link); } else { if(type != tda->tda_type) continue; /* Something is wrong, ignore */ } - free(tda->tda_displayname); - tda->tda_displayname = strdup(name); + tvh_str_update(&tda->tda_displayname, htsmsg_get_str(c, "displayname")); + tvh_str_update(&tda->tda_dvr_path, htsmsg_get_str(c, "dvr_path")); + tvh_str_update(&tda->tda_demux_path, htsmsg_get_str(c, "dmx_path")); - htsmsg_get_u32(c, "enabled", &tda->tda_enabled); - htsmsg_get_u32(c, "autodiscovery", &tda->tda_autodiscovery); - htsmsg_get_u32(c, "idlescan", &tda->tda_idlescan); - htsmsg_get_u32(c, "idleclose", &tda->tda_idleclose); - htsmsg_get_u32(c, "skip_checksubscr", &tda->tda_skip_checksubscr); - htsmsg_get_u32(c, "sidtochan", &tda->tda_sidtochan); - htsmsg_get_u32(c, "qmon", &tda->tda_qmon); - htsmsg_get_u32(c, "poweroff", &tda->tda_poweroff); - htsmsg_get_u32(c, "nitoid", &tda->tda_nitoid); - htsmsg_get_u32(c, "diseqc_version", &tda->tda_diseqc_version); - htsmsg_get_u32(c, "diseqc_repeats", &tda->tda_diseqc_repeats); - htsmsg_get_u32(c, "extrapriority", &tda->tda_extrapriority); - htsmsg_get_u32(c, "skip_initialscan", &tda->tda_skip_initialscan); + if (htsmsg_get_u32(c, "enabled", &tda->tda_enabled)) + tda->tda_enabled = 1; + htsmsg_get_u32(c, "autodiscovery", &tda->tda_autodiscovery); + htsmsg_get_u32(c, "idlescan", &tda->tda_idlescan); + htsmsg_get_u32(c, "idleclose", &tda->tda_idleclose); + htsmsg_get_u32(c, "skip_checksubscr", &tda->tda_skip_checksubscr); + htsmsg_get_u32(c, "sidtochan", &tda->tda_sidtochan); + htsmsg_get_u32(c, "qmon", &tda->tda_qmon); + htsmsg_get_u32(c, "poweroff", &tda->tda_poweroff); + htsmsg_get_u32(c, "nitoid", &tda->tda_nitoid); + htsmsg_get_u32(c, "diseqc_version", &tda->tda_diseqc_version); + htsmsg_get_u32(c, "diseqc_repeats", &tda->tda_diseqc_repeats); + htsmsg_get_u32(c, "extrapriority", &tda->tda_extrapriority); + htsmsg_get_u32(c, "skip_initialscan", &tda->tda_skip_initialscan); htsmsg_get_u32(c, "disable_pmt_monitor", &tda->tda_disable_pmt_monitor); if (htsmsg_get_s32(c, "full_mux_rx", &tda->tda_full_mux_rx)) if (!htsmsg_get_u32(c, "disable_full_mux_rx", &u32) && u32) @@ -737,12 +783,9 @@ dvb_adapter_init(uint32_t adapter_mask, const char *rawfile) htsmsg_destroy(l); } + /* Initialise devices */ TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) { - tda_init_input(tda); - if (tda->tda_idlescan || !tda->tda_idleclose) { - close(tda->tda_fe_fd); - tda->tda_fe_fd = -1; - } + tda_init(tda); if(tda->tda_sat) dvb_satconf_init(tda); @@ -766,6 +809,9 @@ dvb_adapter_mux_scanner(void *aux) if(tda->tda_rootpath == NULL) return; // No hardware + if(!tda->tda_enabled) + return; // disabled + // default period gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 20); @@ -905,13 +951,10 @@ dvb_adapter_input_dvr(void *aux) uint8_t tsb[188 * 10]; service_t *t; struct epoll_event ev; - char path[256]; - snprintf(path, sizeof(path), "%s/dvr0", tda->tda_rootpath); - - fd = tvh_open(path, O_RDONLY | O_NONBLOCK, 0); + fd = tvh_open(tda->tda_dvr_path, O_RDONLY | O_NONBLOCK, 0); if(fd == -1) { - tvhlog(LOG_ALERT, "dvb", "Unable to open %s -- %s", path, strerror(errno)); + tvhlog(LOG_ALERT, "dvb", "Unable to open %s -- %s", tda->tda_dvr_path, strerror(errno)); return NULL; } @@ -1088,6 +1131,13 @@ dvb_adapter_build_msg(th_dvb_adapter_t *tda) htsmsg_add_u32(m, "ber", tdmi->tdmi_ber); htsmsg_add_u32(m, "unc", tdmi->tdmi_unc); htsmsg_add_u32(m, "uncavg", tdmi->tdmi_unc_avg); + } else { + htsmsg_add_str(m, "currentMux", ""); + htsmsg_add_u32(m, "signal", 0); + htsmsg_add_u32(m, "snr", 0); + htsmsg_add_u32(m, "ber", 0); + htsmsg_add_u32(m, "unc", 0); + htsmsg_add_u32(m, "uncavg", 0); } if(tda->tda_rootpath == NULL) diff --git a/src/dvb/dvb_multiplex.c b/src/dvb/dvb_multiplex.c index 1ac5caf1..e129ae63 100644 --- a/src/dvb/dvb_multiplex.c +++ b/src/dvb/dvb_multiplex.c @@ -288,7 +288,6 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc, tvhlog(LOG_NOTICE, "dvb", "New mux \"%s\" created by %s", buf, source); dvb_mux_save(tdmi); - dvb_adapter_notify(tda); } dvb_service_load(tdmi, identifier); @@ -303,6 +302,7 @@ dvb_mux_create(th_dvb_adapter_t *tda, const struct dvb_mux_conf *dmc, dvb_mux_add_to_scan_queue(tdmi); } } + dvb_adapter_notify(tda); return tdmi; }