diff --git a/Makefile b/Makefile index a2f38434..479b8bb2 100644 --- a/Makefile +++ b/Makefile @@ -186,7 +186,6 @@ SRCS-$(CONFIG_MPEGTS) += \ # DVB SRCS-${CONFIG_LINUXDVB} += \ src/input/mpegts/linuxdvb/linuxdvb.c \ - src/input/mpegts/linuxdvb/linuxdvb_device.c \ src/input/mpegts/linuxdvb/linuxdvb_adapter.c \ src/input/mpegts/linuxdvb/linuxdvb_frontend.c \ src/input/mpegts/linuxdvb/linuxdvb_network.c \ diff --git a/src/idnode.c b/src/idnode.c index c260f505..f4bfdbdf 100644 --- a/src/idnode.c +++ b/src/idnode.c @@ -230,6 +230,12 @@ idnode_uuid_as_str(const idnode_t *in) p = (p + 1) % 16; return idnode_uuid_as_str0(in, b); } +const char * +idnode_uuid_as_str1 ( const uint8_t *bin, size_t len, char *b ) +{ + bin2hex(b, UUID_STR_LEN, bin, len); + return b; +} /** * diff --git a/src/idnode.h b/src/idnode.h index 85c247ae..af8f3d17 100644 --- a/src/idnode.h +++ b/src/idnode.h @@ -114,6 +114,7 @@ int idnode_insert(idnode_t *in, const char *uuid, const idclass_t *idc); void idnode_unlink(idnode_t *in); uint32_t idnode_get_short_uuid (const idnode_t *in); +const char *idnode_uuid_as_str1 (const uint8_t *bin, size_t len, char *b); const char *idnode_uuid_as_str0 (const idnode_t *in, char *b); const char *idnode_uuid_as_str (const idnode_t *in); idnode_set_t *idnode_get_childs (idnode_t *in); diff --git a/src/input.c b/src/input.c index e156f164..ecd8cdcd 100644 --- a/src/input.c +++ b/src/input.c @@ -17,10 +17,52 @@ */ #include "input.h" +#include "notify.h" tvh_input_list_t tvh_inputs; tvh_hardware_list_t tvh_hardware; +/* + * Create entry + */ +void * +tvh_hardware_create0 + ( void *o, const idclass_t *idc, const char *uuid, htsmsg_t *conf ) +{ + tvh_hardware_t *th = o; + + /* Create node */ + if (idnode_insert(&th->th_id, uuid, idc)) { + free(o); + return NULL; + } + + /* Update list */ + LIST_INSERT_HEAD(&tvh_hardware, th, th_link); + + /* Load config */ + if (conf) + idnode_load(&th->th_id, conf); + + /* Update */ + notify_reload("hardware"); + + return o; +} + +/* + * Delete hardware entry + */ + +void +tvh_hardware_delete ( tvh_hardware_t *th ) +{ + // TODO + LIST_REMOVE(th, th_link); + idnode_unlink(&th->th_id); + notify_reload("hardware"); +} + /* * Input status handling */ diff --git a/src/input.h b/src/input.h index ce98eca2..019397cd 100644 --- a/src/input.h +++ b/src/input.h @@ -78,6 +78,9 @@ struct tvh_hardware { LIST_ENTRY(tvh_hardware) th_link; }; +void *tvh_hardware_create0 + ( void *o, const idclass_t *idc, const char *uuid, htsmsg_t *conf ); +void tvh_hardware_delete ( tvh_hardware_t *th ); /* * Class and Global list defs diff --git a/src/input/mpegts/dvb.h b/src/input/mpegts/dvb.h index d2d61ed1..62d4ebb0 100644 --- a/src/input/mpegts/dvb.h +++ b/src/input/mpegts/dvb.h @@ -222,7 +222,7 @@ typedef struct dvb_mux_conf polarisation_t dmc_fe_polarisation; int dmc_fe_orbital_pos; char dmc_fe_orbital_dir; -#if DVB_API_VERSION >= 5 +#if DVB_VER_ATLEAST(5,0) fe_modulation_t dmc_fe_modulation; fe_delivery_system_t dmc_fe_delsys; fe_rolloff_t dmc_fe_rolloff; @@ -270,6 +270,10 @@ int dvb_str2pilot ( const char *str ); int dvb_bandwidth ( enum fe_bandwidth bw ); +#if DVB_VER_ATLEAST(5,10) +int dvb_delsys2type ( enum fe_delivery_system ds ); +#endif + #endif /* ENABLE_DVBAPI */ #endif /* DVB_SUPPORT_H */ diff --git a/src/input/mpegts/dvb_support.c b/src/input/mpegts/dvb_support.c index 5d74b8ff..8c9e8d2a 100644 --- a/src/input/mpegts/dvb_support.c +++ b/src/input/mpegts/dvb_support.c @@ -421,6 +421,33 @@ const static struct strtab delsystab[] = { }; dvb_str2val(delsys); +#if DVB_VER_ATLEAST(5,10) +int +dvb_delsys2type ( fe_delivery_system_t delsys ) +{ + switch (delsys) { + case SYS_DVBC_ANNEX_AC: + case SYS_DVBC_ANNEX_B: + case SYS_ISDBC: + return FE_QAM; + case SYS_DVBT: + case SYS_DVBT2: + case SYS_TURBO: + case SYS_ISDBT: + return FE_OFDM; + case SYS_DVBS: + case SYS_DVBS2: + case SYS_ISDBS: + return FE_QPSK; + case SYS_ATSC: + case SYS_ATSCMH: + return FE_ATSC; + default: + return -1; + } +} +#endif + const static struct strtab fectab[] = { { "NONE", FEC_NONE }, { "1/2", FEC_1_2 }, diff --git a/src/input/mpegts/linuxdvb/linuxdvb.c b/src/input/mpegts/linuxdvb/linuxdvb.c index 33287eb8..56457423 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb.c +++ b/src/input/mpegts/linuxdvb/linuxdvb.c @@ -36,5 +36,5 @@ void linuxdvb_init ( int adapter_mask ) linuxdvb_network_init(); /* Initialsie devices */ - linuxdvb_device_init(adapter_mask); + linuxdvb_adapter_init(); } diff --git a/src/input/mpegts/linuxdvb/linuxdvb_adapter.c b/src/input/mpegts/linuxdvb/linuxdvb_adapter.c index b75d0032..6f03ca44 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_adapter.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_adapter.c @@ -21,17 +21,21 @@ #include "input.h" #include "linuxdvb_private.h" #include "queue.h" +#include "fsmonitor.h" +#include "settings.h" #include #include +#include #include #include #include #include +#include -#define FE_PATH "/dev/dvb/adapter%d/frontend%d" -#define DVR_PATH "/dev/dvb/adapter%d/dvr%d" -#define DMX_PATH "/dev/dvb/adapter%d/demux%d" +#define FE_PATH "%s/frontend%d" +#define DVR_PATH "%s/dvr%d" +#define DMX_PATH "%s/demux%d" /* *************************************************************************** * DVB Adapter @@ -41,7 +45,7 @@ static void linuxdvb_adapter_class_save ( idnode_t *in ) { linuxdvb_adapter_t *la = (linuxdvb_adapter_t*)in; - linuxdvb_device_save(la->la_device); + linuxdvb_adapter_save(la); } static idnode_set_t * @@ -85,141 +89,114 @@ const idclass_t linuxdvb_adapter_class = * Save data */ void -linuxdvb_adapter_save ( linuxdvb_adapter_t *la, htsmsg_t *m ) +linuxdvb_adapter_save ( linuxdvb_adapter_t *la ) { - htsmsg_t *l; + htsmsg_t *m, *l; linuxdvb_frontend_t *lfe; - idnode_save(&la->la_id, m); - htsmsg_add_u32(m, "number", la->la_number); + m = htsmsg_create_map(); + idnode_save(&la->th_id, m); /* Frontends */ l = htsmsg_create_map(); - LIST_FOREACH(lfe, &la->la_frontends, lfe_link) { - htsmsg_t *e = htsmsg_create_map(); - linuxdvb_frontend_save(lfe, e); - htsmsg_add_msg(l, idnode_uuid_as_str(&lfe->ti_id), e); - } + LIST_FOREACH(lfe, &la->la_frontends, lfe_link) + linuxdvb_frontend_save(lfe, l); htsmsg_add_msg(m, "frontends", l); -} -/* - * Check if enabled - */ -static int -linuxdvb_adapter_is_enabled ( linuxdvb_adapter_t *la ) -{ - linuxdvb_frontend_t *lfe; - LIST_FOREACH(lfe, &la->la_frontends, lfe_link) { - if (lfe->mi_is_enabled((mpegts_input_t*)lfe)) - return 1; - } - return 0; + /* Save */ + hts_settings_save(m, "input/linuxdvb/adapters/%s", + idnode_uuid_as_str(&la->th_id)); + htsmsg_destroy(m); } /* * Create */ -linuxdvb_adapter_t * -linuxdvb_adapter_create0 - ( linuxdvb_device_t *ld, const char *uuid, htsmsg_t *conf ) +static linuxdvb_adapter_t * +linuxdvb_adapter_create + ( const char *uuid, htsmsg_t *conf, + const char *path, int number, struct dvb_frontend_info *dfi ) { - uint32_t u32; - htsmsg_t *e; - htsmsg_field_t *f; linuxdvb_adapter_t *la; + char buf[1024]; + /* Create */ la = calloc(1, sizeof(linuxdvb_adapter_t)); - if (idnode_insert(&la->la_id, uuid, &linuxdvb_adapter_class)) { + if (!tvh_hardware_create0((tvh_hardware_t*)la, &linuxdvb_adapter_class, + uuid, conf)) { free(la); return NULL; } - LIST_INSERT_HEAD(&ld->ld_adapters, la, la_link); - la->la_device = ld; - la->la_dvb_number = -1; - la->la_is_enabled = linuxdvb_adapter_is_enabled; - - /* No conf */ - if (!conf) - return la; - - idnode_load(&la->la_id, conf); - if (!htsmsg_get_u32(conf, "number", &u32)) - la->la_number = u32; - - /* Frontends */ - if ((conf = htsmsg_get_map(conf, "frontends"))) { - HTSMSG_FOREACH(f, conf) { - if (!(e = htsmsg_get_map_by_field(f))) continue; - (void)linuxdvb_frontend_create0(la, f->hmf_name, e, 0); - } - } + /* Setup */ + sprintf(buf, "%s [%s]", path, dfi->name); + la->la_rootpath = strdup(path); + la->la_name = strdup(buf); + la->la_dvb_number = number; return la; } /* - * Find existing adapter/device entry + * Add adapter by path */ -static linuxdvb_adapter_t * -linuxdvb_adapter_find_by_number ( int adapter ) +static void +linuxdvb_adapter_add ( const char *path ) { - int a; - char buf[1024]; - linuxdvb_device_t *ld; - linuxdvb_adapter_t *la; - - /* Find device */ - if (!(ld = linuxdvb_device_find_by_adapter(adapter))) - return NULL; - - /* Find existing adapter */ - a = adapter - ld->ld_devid.di_min_adapter; - LIST_FOREACH(la, &ld->ld_adapters, la_link) { - if (la->la_number == a) - break; - } - - /* Create */ - if (!la) { - if (!(la = linuxdvb_adapter_create0(ld, NULL, NULL))) - return NULL; - } - - /* Update */ - la->la_number = a; - snprintf(buf, sizeof(buf), "/dev/dvb/adapter%d", adapter); - tvh_str_update(&la->la_rootpath, buf); - - return la; -} - -/* - * Load an adapter - */ -void -linuxdvb_adapter_added ( int adapter ) -{ - int i, r, fd, save = 0; - char fe_path[512], dmx_path[512], dvr_path[512]; + int a, i, j, r, fd; + char fe_path[512], dmx_path[512], dvr_path[512], uuid[UUID_STR_LEN]; linuxdvb_adapter_t *la = NULL; struct dvb_frontend_info dfi; + SHA_CTX sha1; + uint8_t uuidbin[20]; + htsmsg_t *conf = NULL, *feconf = NULL; +#if DVB_VER_ATLEAST(5,10) + int fetypes[4] = { 0 }; + struct dtv_property cmd = { + .cmd = DTV_ENUM_DELSYS + }; + struct dtv_properties cmdseq = { + .num = 1, + .props = &cmd + }; +#endif + + /* Validate the path */ + if (sscanf(path, "/dev/dvb/adapter%d", &a) != 1) + return; + + /* Note: some of the below can take a while, so we relinquish the lock + * to stop us blocking everyhing else + */ + pthread_mutex_unlock(&global_lock); /* Process each frontend */ for (i = 0; i < 32; i++) { - snprintf(fe_path, sizeof(fe_path), FE_PATH, adapter, i); + snprintf(fe_path, sizeof(fe_path), FE_PATH, path, i); - /* No access */ + /* Wait for access (first FE can take a fe ms to be setup) */ + if (!i) { + for (j = 0; j < 10; j++) { + if (!access(fe_path, R_OK | W_OK)) break; + usleep(100000); + } + } if (access(fe_path, R_OK | W_OK)) continue; /* Get frontend info */ - fd = tvh_open(fe_path, O_RDONLY | O_NONBLOCK, 0); + for (j = 0; j < 10; j++) { + if ((fd = tvh_open(fe_path, O_RDONLY, 0)) > 0) break; + usleep(100000); + } if (fd == -1) { tvhlog(LOG_ERR, "linuxdvb", "unable to open %s", fe_path); continue; } r = ioctl(fd, FE_GET_INFO, &dfi); +#if DVB_VER_ATLEAST(5,10) + if (!r) + r = ioctl(fd, FE_GET_PROPERTY, &cmdseq); +#endif close(fd); if(r) { tvhlog(LOG_ERR, "linuxdvb", "unable to query %s", fe_path); @@ -227,38 +204,188 @@ linuxdvb_adapter_added ( int adapter ) } /* DVR/DMX (bit of a guess) */ - snprintf(dmx_path, sizeof(dmx_path), DMX_PATH, adapter, i); + snprintf(dmx_path, sizeof(dmx_path), DMX_PATH, path, i); if (access(dmx_path, R_OK | W_OK)) { - snprintf(dmx_path, sizeof(dmx_path), DMX_PATH, adapter, 0); + snprintf(dmx_path, sizeof(dmx_path), DMX_PATH, path, 0); if (access(dmx_path, R_OK | W_OK)) continue; } - snprintf(dvr_path, sizeof(dvr_path), DVR_PATH, adapter, i); + snprintf(dvr_path, sizeof(dvr_path), DVR_PATH, path, i); if (access(dvr_path, R_OK | W_OK)) { - snprintf(dvr_path, sizeof(dvr_path), DVR_PATH, adapter, 0); + snprintf(dvr_path, sizeof(dvr_path), DVR_PATH, path, 0); if (access(dvr_path, R_OK | W_OK)) continue; } /* Create/Find adapter */ + pthread_mutex_lock(&global_lock); if (!la) { - if (!(la = linuxdvb_adapter_find_by_number(adapter))) { - tvhlog(LOG_ERR, "linuxdvb", "failed to find/create adapter%d", adapter); - return; - } - la->la_dvb_number = adapter; - if (!la->la_name) { - char buf[512]; - snprintf(buf, sizeof(buf), "%s #%d", dfi.name, la->la_number); - la->la_name = strdup(buf); + + /* Create hash for adapter */ + SHA1_Init(&sha1); + SHA1_Update(&sha1, (void*)path, strlen(path)); + SHA1_Update(&sha1, (void*)dfi.name, strlen(dfi.name)); + // TODO: could include more form dfi, and maybe frontend enum + SHA1_Final(uuidbin, &sha1); + idnode_uuid_as_str1(uuidbin, sizeof(uuidbin), uuid); + + /* Load config */ + conf = hts_settings_load("input/linuxdvb/adapters/%s", uuid); + if (conf) + feconf = htsmsg_get_map(conf, "frontends"); + + /* Create */ + if (!(la = linuxdvb_adapter_create(uuid, conf, path, a, &dfi))) { + tvhlog(LOG_ERR, "linuxdvb", "failed to create %s", path); + return; // Note: save to return here as global_lock is held } } /* Create frontend */ - tvhlog(LOG_DEBUG, "linuxdvb", "fe_create(%p, %s, %s, %s)", - la, fe_path, dmx_path, dvr_path); - save |= linuxdvb_frontend_added(la, i, fe_path, dmx_path, dvr_path, &dfi); + linuxdvb_frontend_create(feconf, la, i, fe_path, dmx_path, dvr_path, &dfi); +#if DVB_VER_ATLEAST(5,10) + fetypes[dfi.type] = 1; + for (j = 0; j < cmd.u.buffer.len; j++) { + + /* Invalid */ + if ((dfi.type = dvb_delsys2type(cmd.u.buffer.data[j])) == -1) + continue; + + /* Couldn't find */ + if (fetypes[dfi.type]) + continue; + + /* Create */ + linuxdvb_frontend_create(feconf, la, i, fe_path, dmx_path, dvr_path, &dfi); + fetypes[dfi.type] = 1; + } +#endif + pthread_mutex_unlock(&global_lock); } - if (save) - linuxdvb_device_save(la->la_device); + /* Relock before exit */ + pthread_mutex_lock(&global_lock); + + /* Save configuration */ + if (!conf && la) + linuxdvb_adapter_save(la); +} + +static void +linuxdvb_adapter_del ( const char *path ) +{ + int a; + linuxdvb_frontend_t *lfe, *next; + linuxdvb_adapter_t *la; + tvh_hardware_t *th; + + if (sscanf(path, "/dev/dvb/adapter%d", &a) == 1) { + LIST_FOREACH(th, &tvh_hardware, th_link) + if (idnode_is_instance(&th->th_id, &linuxdvb_adapter_class)) { + la = (linuxdvb_adapter_t*)th; + if (!strcmp(path, la->la_rootpath)) + break; + } + if (!th) return; + + /* Delete the frontends */ + for (lfe = LIST_FIRST(&la->la_frontends); lfe != NULL; lfe = next) { + next = LIST_NEXT(lfe, lfe_link); + linuxdvb_frontend_delete(lfe); + } + + /* Free memory */ + free(la->la_rootpath); + free(la->la_name); + + /* Delete */ + tvh_hardware_delete((tvh_hardware_t*)la); + } +} + +/* ************************************************************************** + * Adapter Management + * *************************************************************************/ + +/* + * Scan for adapters + */ +static void +linuxdvb_adapter_scan ( void ) +{ + DIR *dir; + struct dirent buf, *de; + char path[1024]; + + if ((dir = opendir("/dev/dvb"))) { + while (!readdir_r(dir, &buf, &de) && de) { + if (de->d_name[0] == '.') continue; + snprintf(path, sizeof(path), "/dev/dvb/%s", de->d_name); + linuxdvb_adapter_add(path); + } + closedir(dir); + } +} + +/* + * /dev/dvb monitor + */ +static void +devdvb_create ( fsmonitor_t *fsm, const char *path ) +{ + linuxdvb_adapter_add(path); +} + +static void +devdvb_delete ( fsmonitor_t *fsm, const char *path ) +{ + linuxdvb_adapter_del(path); +} + +static fsmonitor_t devdvbmon = { + .fsm_create = devdvb_create, + .fsm_delete = devdvb_delete +}; + +/* + * /dev monitor + */ + +static void +dev_create ( fsmonitor_t *fsm, const char *path ) +{ + if (!strcmp(path, "/dev/dvb")) { + fsmonitor_add("/dev/dvb", &devdvbmon); + linuxdvb_adapter_scan(); + } +} + +static void +dev_delete ( fsmonitor_t *fsm, const char *path ) +{ + if (!strcmp(path, "/dev/dvb")) + fsmonitor_del("/dev/dvb", &devdvbmon); +} + +static fsmonitor_t devmon = { + .fsm_create = dev_create, + .fsm_delete = dev_delete +}; + +/* + * Initialise + */ + +void +linuxdvb_adapter_init ( void ) +{ + /* Install monitor on /dev */ + (void)fsmonitor_add("/dev", &devmon); + + /* Install monitor on /dev/dvb */ + if (!access("/dev/dvb", R_OK)) { + (void)fsmonitor_add("/dev/dvb", &devdvbmon); + + /* Scan for adapters */ + linuxdvb_adapter_scan(); + } } diff --git a/src/input/mpegts/linuxdvb/linuxdvb_device.c b/src/input/mpegts/linuxdvb/linuxdvb_device.c deleted file mode 100644 index 68a5396c..00000000 --- a/src/input/mpegts/linuxdvb/linuxdvb_device.c +++ /dev/null @@ -1,353 +0,0 @@ -/* - * Tvheadend - Linux DVB device management - * - * Copyright (C) 2013 Adam Sutton - * - * 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 "tvheadend.h" -#include "input.h" -#include "linuxdvb_private.h" -#include "queue.h" -#include "settings.h" - -#include -#include -#include -#include -#include -#include - -/* *************************************************************************** - * Device/BUS Info - * **************************************************************************/ - -/* - * BUS str table - */ -static struct strtab bustab[] = { - { "NONE", BUS_NONE }, - { "PCI", BUS_PCI }, - { "USB1", BUS_USB1 }, - { "USB2", BUS_USB2 }, - { "USB3", BUS_USB3 } -}; -#define devinfo_bus2str(p) val2str(p, bustab) -#define devinfo_str2bus(p) str2val(p, bustab) - -/* - * Get bus information - */ -static void -get_device_info ( device_info_t *di, int a ) -{ - FILE *fp; - DIR *dp; - struct dirent *de; - uint16_t u16; - int speed; - char path[512], buf[512]; - ssize_t c; - int mina = a; - - /* Clear */ - memset(di, 0, sizeof(device_info_t)); - - /* Check for subsystem */ -#define DVB_DEV_PATH "/sys/class/dvb/dvb%d.frontend0/device" - snprintf(path, sizeof(path), DVB_DEV_PATH "/subsystem", a); - if ((c = readlink(path, buf, sizeof(buf))) != -1) { - buf[c] = '\0'; - char *bus = basename(buf); - if (!strcmp(bus, "pci")) { - di->di_bus = BUS_PCI; - snprintf(path, sizeof(path), DVB_DEV_PATH "/subsystem_vendor", a); - if ((fp = fopen(path, "r"))) { - if (fscanf(fp, "0x%hx", &u16) == 1) - di->di_dev = u16; - fclose(fp); - } - di->di_dev <<= 16; - snprintf(path, sizeof(path), DVB_DEV_PATH "/subsystem_device", a); - if ((fp = fopen(path, "r"))) { - if (fscanf(fp, "0x%hx", &u16) == 1) - di->di_dev |= u16; - fclose(fp); - } - - } else if (!strcmp(bus, "usb")) { - di->di_bus = BUS_USB1; - snprintf(path, sizeof(path), DVB_DEV_PATH "/idVendor", a); - if ((fp = fopen(path, "r"))) { - if (fscanf(fp, "%hx", &u16) == 1) - di->di_dev = u16; - fclose(fp); - } - di->di_dev <<= 16; - snprintf(path, sizeof(path), DVB_DEV_PATH "/idProduct", a); - if ((fp = fopen(path, "r"))) { - if (fscanf(fp, "%hx", &u16) == 1) - di->di_dev |= u16; - fclose(fp); - } - snprintf(path, sizeof(path), DVB_DEV_PATH "/speed", a); - if ((fp = fopen(path, "r"))) { - if (fscanf(fp, "%d", &speed) == 1) { - if (speed > 480) { - di->di_bus = BUS_USB3; - } else if (speed == 480) { - di->di_bus = BUS_USB2; - } - } - fclose(fp); - } - } else { - tvhlog(LOG_WARNING, "linuxdvb", - "could not determine host connection for adapter%d", a); - } - } - - /* Get Path */ - snprintf(path, sizeof(path), DVB_DEV_PATH, a); - if ((c = readlink(path, buf, sizeof(buf))) != -1) { - buf[c] = '\0'; - strcpy(di->di_path, basename(buf)); - } - - /* Find minimum adapter number */ - snprintf(path, sizeof(path), DVB_DEV_PATH "/dvb", a); - if ((dp = opendir(path))) { - while ((de = readdir(dp))) { - int t; - if ((sscanf(de->d_name, "dvb%d.frontend0", &t))) - if (t < mina) mina = t; - } - closedir(dp); - } - di->di_min_adapter = mina; - - /* Create ID */ - if (*di->di_path && di->di_dev && di->di_bus) { - snprintf(buf, sizeof(buf), "%s/%s/%04x:%04x", - devinfo_bus2str(di->di_bus), di->di_path, - di->di_dev >> 16, di->di_dev & 0xFFFF); - } else { - snprintf(buf, sizeof(buf), "/dev/dvb/adapter%d", a); - } - di->di_id = strdup(buf); -} -static void -get_min_dvb_adapter ( device_info_t *di ) -{ - int mina = -1; - char path[512]; - DIR *dp; - struct dirent *de; - - snprintf(path, sizeof(path), "/sys/bus/%s/devices/%s/dvb", - di->di_bus == BUS_PCI ? "pci" : "usb", di->di_path); - - /* Find minimum adapter number */ - if ((dp = opendir(path))) { - while ((de = readdir(dp))) { - int t; - if ((sscanf(de->d_name, "dvb%d.frontend0", &t))) - if (mina == -1 || t < mina) mina = t; - } - closedir(dp); - } - di->di_min_adapter = mina; -} - -/* *************************************************************************** - * Class - * **************************************************************************/ - -static void -linuxdvb_device_class_save ( idnode_t *in ) -{ - linuxdvb_device_save((linuxdvb_device_t*)in); -} - -static const char * -linuxdvb_device_class_get_title ( idnode_t *in ) -{ - return ((linuxdvb_device_t*)in)->ld_devid.di_id; -} - -static idnode_set_t * -linuxdvb_device_class_get_childs ( idnode_t *in ) -{ - linuxdvb_adapter_t *la; - linuxdvb_device_t *ld = (linuxdvb_device_t*)in; - idnode_set_t *is = idnode_set_create(); - LIST_FOREACH(la, &ld->ld_adapters, la_link) - idnode_set_add(is, &la->la_id, NULL); - return is; -} - -const idclass_t linuxdvb_device_class = -{ - .ic_class = "linuxdvb_device", - .ic_caption = "LinuxDVB Device", - .ic_save = linuxdvb_device_class_save, - .ic_get_childs = linuxdvb_device_class_get_childs, - .ic_get_title = linuxdvb_device_class_get_title, - .ic_properties = (const property_t[]){ - { - .type = PT_STR, - .id = "devid", - .name = "Device ID", - .opts = PO_RDONLY, - .off = offsetof(linuxdvb_device_t, ld_devid.di_id) - }, - {} - } -}; - -void linuxdvb_device_save ( linuxdvb_device_t *ld ) -{ - htsmsg_t *m, *e, *l; - linuxdvb_adapter_t *la; - - m = htsmsg_create_map(); - - idnode_save(&ld->th_id, m); - - /* Adapters */ - l = htsmsg_create_map(); - LIST_FOREACH(la, &ld->ld_adapters, la_link) { - e = htsmsg_create_map(); - linuxdvb_adapter_save(la, e); - htsmsg_add_msg(l, idnode_uuid_as_str(&la->la_id), e); - } - htsmsg_add_msg(m, "adapters", l); - - /* Save */ - hts_settings_save(m, "input/linuxdvb/devices/%s", - idnode_uuid_as_str(&ld->th_id)); - htsmsg_destroy(m); -} - - -linuxdvb_device_t * -linuxdvb_device_create0 ( const char *uuid, htsmsg_t *conf ) -{ - linuxdvb_device_t *ld; - htsmsg_t *e; - htsmsg_field_t *f; - - /* Create */ - ld = calloc(1, sizeof(linuxdvb_device_t)); - if (idnode_insert(&ld->th_id, uuid, &linuxdvb_device_class)) { - free(ld); - return NULL; - } - LIST_INSERT_HEAD(&tvh_hardware, (tvh_hardware_t*)ld, th_link); - - /* No config */ - if (!conf) - return ld; - - /* Load config */ - idnode_load(&ld->th_id, conf); - get_min_dvb_adapter(&ld->ld_devid); - - /* Adapters */ - if ((conf = htsmsg_get_map(conf, "adapters"))) { - HTSMSG_FOREACH(f, conf) { - if (!(e = htsmsg_get_map_by_field(f))) continue; - (void)linuxdvb_adapter_create0(ld, f->hmf_name, e); - } - } - - return ld; -} - -static linuxdvb_device_t * -linuxdvb_device_find_by_hwid ( const char *hwid ) -{ - tvh_hardware_t *lh; - LIST_FOREACH(lh, &tvh_hardware, th_link) { - if (idnode_is_instance(&lh->th_id, &linuxdvb_device_class)) - if (!strcmp(hwid, ((linuxdvb_device_t*)lh)->ld_devid.di_id ?: "")) - return (linuxdvb_device_t*)lh; - } - return NULL; -} - -linuxdvb_device_t * -linuxdvb_device_find_by_adapter ( int a ) -{ - linuxdvb_device_t *ld; - device_info_t dev; - - /* Get device info */ - get_device_info(&dev, a); - - /* Find existing */ - if ((ld = linuxdvb_device_find_by_hwid(dev.di_id))) { - free(dev.di_id); - if (ld->ld_devid.di_bus == BUS_NONE) { - strcpy(ld->ld_devid.di_path, dev.di_path); - ld->ld_devid.di_bus = dev.di_bus; - ld->ld_devid.di_dev = dev.di_dev; - ld->ld_devid.di_min_adapter = dev.di_min_adapter; - } - return ld; - } - - /* Create new */ - if (!(ld = linuxdvb_device_create0(NULL, NULL))) { - free(dev.di_id); - tvhlog(LOG_ERR, "linuxdvb", "failed to create device for adapter%d", a); - return NULL; - } - - /* Copy device info */ - memcpy(&ld->ld_devid, &dev, sizeof(dev)); - ld->ld_devid.di_id = dev.di_id; - return ld; -} - -void linuxdvb_device_init ( int adapter_mask ) -{ - int a; - DIR *dp; - htsmsg_t *s, *e; - htsmsg_field_t *f; - - /* Load configuration */ - if ((s = hts_settings_load_r(1, "input/linuxdvb/devices"))) { - HTSMSG_FOREACH(f, s) { - if (!(e = htsmsg_get_map_by_field(f))) continue; - (void)linuxdvb_device_create0(f->hmf_name, e); - } - htsmsg_destroy(s); - } - - /* Scan for hardware */ - if ((dp = opendir("/dev/dvb"))) { - struct dirent *de; - while ((de = readdir(dp))) { - if (sscanf(de->d_name, "adapter%d", &a) != 1) continue; - if ((0x1 << a) & adapter_mask) - linuxdvb_adapter_added(a); - } - closedir(dp); - } - - // TODO: add udev support for hotplug -} diff --git a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c index e5a5d1e4..6a10a678 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c @@ -43,9 +43,8 @@ linuxdvb_frontend_input_thread ( void *aux ); static void linuxdvb_frontend_class_save ( idnode_t *in ) { - linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)in; - if (lfe->lfe_adapter && lfe->lfe_adapter->la_device) - linuxdvb_device_save(lfe->lfe_adapter->la_device); + linuxdvb_adapter_t *la = ((linuxdvb_frontend_t*)in)->lfe_adapter; + linuxdvb_adapter_save(la); } static const void* @@ -111,28 +110,28 @@ const idclass_t linuxdvb_frontend_class = .type = PT_STR, .id = "fe_path", .name = "Frontend Path", - .opts = PO_RDONLY, + .opts = PO_RDONLY | PO_NOSAVE, .off = offsetof(linuxdvb_frontend_t, lfe_fe_path), }, { .type = PT_STR, .id = "dvr_path", .name = "Input Path", - .opts = PO_RDONLY, + .opts = PO_RDONLY | PO_NOSAVE, .off = offsetof(linuxdvb_frontend_t, lfe_dvr_path), }, { .type = PT_STR, .id = "dmx_path", .name = "Demux Path", - .opts = PO_RDONLY, + .opts = PO_RDONLY | PO_NOSAVE, .off = offsetof(linuxdvb_frontend_t, lfe_dmx_path), }, { .type = PT_INT, .id = "fe_number", .name = "Frontend Number", - .opts = PO_RDONLY, + .opts = PO_RDONLY | PO_NOSAVE, .off = offsetof(linuxdvb_frontend_t, lfe_number), }, { @@ -184,7 +183,7 @@ linuxdvb_frontend_dvbs_class_satconf_set ( void *self, const void *str ) linuxdvb_frontend_t *lfe = self; if (lfe->lfe_satconf && !strcmp(str ?: "", lfe->lfe_satconf->ls_type)) return 0; - linuxdvb_satconf_destroy(lfe->lfe_satconf); + linuxdvb_satconf_delete(lfe->lfe_satconf); lfe->lfe_satconf = linuxdvb_satconf_create(lfe, str, NULL, NULL); return 1; } @@ -262,6 +261,28 @@ const idclass_t linuxdvb_frontend_atsc_class = * Class methods * *************************************************************************/ +static int +linuxdvb_frontend_is_free ( mpegts_input_t *mi ) +{ + linuxdvb_adapter_t *la = ((linuxdvb_frontend_t*)mi)->lfe_adapter; + linuxdvb_frontend_t *lfe; + LIST_FOREACH(lfe, &la->la_frontends, lfe_link) + if (!mpegts_input_is_free((mpegts_input_t*)lfe)) + return 0; + return 1; +} + +static int +linuxdvb_frontend_get_weight ( mpegts_input_t *mi ) +{ + int weight = 0; + linuxdvb_adapter_t *la = ((linuxdvb_frontend_t*)mi)->lfe_adapter; + linuxdvb_frontend_t *lfe; + LIST_FOREACH(lfe, &la->la_frontends, lfe_link) + weight = MAX(weight, mpegts_input_get_weight((mpegts_input_t*)lfe)); + return weight; +} + static int linuxdvb_frontend_is_enabled ( mpegts_input_t *mi ) { @@ -871,41 +892,65 @@ linuxdvb_frontend_tune1 /* ************************************************************************** * Creation/Config * *************************************************************************/ - -linuxdvb_frontend_t * -linuxdvb_frontend_create0 - ( linuxdvb_adapter_t *la, const char *uuid, htsmsg_t *conf, fe_type_t type ) -{ - const char *str; - const idclass_t *idc; - pthread_t tid; - const char *scuuid = NULL, *sctype = NULL; - htsmsg_t *scconf = NULL; - /* Get type */ - if (conf) { - if (!(str = htsmsg_get_str(conf, "type"))) - return NULL; - type = dvb_str2type(str); - } +linuxdvb_frontend_t * +linuxdvb_frontend_create + ( htsmsg_t *conf, linuxdvb_adapter_t *la, int number, + const char *fe_path, const char *dmx_path, const char *dvr_path, + struct dvb_frontend_info *dfi ) +{ + const idclass_t *idc; + const char *uuid = NULL, *scuuid = NULL, *sctype = NULL; + char id[12], name[256]; + linuxdvb_frontend_t *lfe; + htsmsg_t *scconf = NULL; + pthread_t tid; + + /* Internal config ID */ + snprintf(id, sizeof(id), "%s #%d", dvb_type2str(dfi->type), number); + if (conf) + conf = htsmsg_get_map(conf, id); + if (conf) + uuid = htsmsg_get_str(conf, "uuid"); /* Class */ - if (type == FE_QPSK) + if (dfi->type == FE_QPSK) idc = &linuxdvb_frontend_dvbs_class; - else if (type == FE_QAM) + else if (dfi->type == FE_QAM) idc = &linuxdvb_frontend_dvbc_class; - else if (type == FE_OFDM) + else if (dfi->type == FE_OFDM) idc = &linuxdvb_frontend_dvbt_class; - else if (type == FE_ATSC) + else if (dfi->type == FE_ATSC) idc = &linuxdvb_frontend_atsc_class; else { - tvherror("linuxdvb", "unknown FE type %d", type); + tvherror("linuxdvb", "unknown FE type %d", dfi->type); return NULL; } - linuxdvb_frontend_t *lfe = calloc(1, sizeof(linuxdvb_frontend_t)); - lfe->lfe_info.type = type; + /* Create */ + // Note: there is a bit of a chicken/egg issue below, without the + // correct "fe_type" we cannot set the network (which is done + // in mpegts_input_create()). So we must set early. + lfe = calloc(1, sizeof(linuxdvb_frontend_t)); + lfe->lfe_number = number; + memcpy(&lfe->lfe_info, dfi, sizeof(struct dvb_frontend_info)); lfe = (linuxdvb_frontend_t*)mpegts_input_create0((mpegts_input_t*)lfe, idc, uuid, conf); + if (!lfe) return NULL; + + /* Callbacks */ + lfe->mi_is_free = linuxdvb_frontend_is_free; + lfe->mi_get_weight = linuxdvb_frontend_get_weight; + + /* Default name */ + if (!lfe->mi_name) { + snprintf(name, sizeof(name), "%s : %s", dfi->name, id); + lfe->mi_name = strdup(name); + } + + /* Set paths */ + lfe->lfe_fe_path = strdup(fe_path); + lfe->lfe_dmx_path = strdup(dmx_path); + lfe->lfe_dvr_path = strdup(dvr_path); /* Input callbacks */ lfe->mi_is_enabled = linuxdvb_frontend_is_enabled; @@ -934,70 +979,19 @@ linuxdvb_frontend_create0 } /* Create satconf */ - if (type == FE_QPSK && !lfe->lfe_satconf) + if (dfi->type == FE_QPSK && !lfe->lfe_satconf) lfe->lfe_satconf = linuxdvb_satconf_create(lfe, sctype, scuuid, scconf); - /* No conf */ - if (!conf) - return lfe; - return lfe; } -int -linuxdvb_frontend_added - ( linuxdvb_adapter_t *la, int fe_num, - const char *fe_path, - const char *dmx_path, - const char *dvr_path, - const struct dvb_frontend_info *fe_info ) -{ - int save = 0; - linuxdvb_frontend_t *lfe = NULL; - - /* Find existing */ - LIST_FOREACH(lfe, &la->la_frontends, lfe_link) { - if (lfe->lfe_number == fe_num) { - if (lfe->lfe_info.type != fe_info->type) { - tvhlog(LOG_ERR, "linuxdvb", "detected incorrect fe_type %s != %s", - dvb_type2str(lfe->lfe_info.type), dvb_type2str(fe_info->type)); - return 0; - } - break; - } - } - - /* Create new */ - if (!lfe) { - if (!(lfe = linuxdvb_frontend_create0(la, NULL, NULL, fe_info->type))) { - tvhlog(LOG_ERR, "linuxdvb", "failed to create frontend"); - return 0; - } - save = 1; - } - - /* Defaults */ - if (!lfe->mi_name) - lfe->mi_name = strdup(fe_path); - - /* Copy info */ - lfe->lfe_number = fe_num; - memcpy(&lfe->lfe_info, fe_info, sizeof(struct dvb_frontend_info)); - - /* Set paths */ - free(lfe->lfe_fe_path); - free(lfe->lfe_dvr_path); - free(lfe->lfe_dmx_path); - lfe->lfe_fe_path = strdup(fe_path); - lfe->lfe_dmx_path = strdup(dmx_path); - lfe->lfe_dvr_path = strdup(dvr_path); - - return save; -} - void -linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *m ) +linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *fe ) { + char id[12]; + htsmsg_t *m = htsmsg_create_map(); + + /* Save frontend */ mpegts_input_save((mpegts_input_t*)lfe, m); htsmsg_add_str(m, "type", dvb_type2str(lfe->lfe_info.type)); if (lfe->lfe_satconf) { @@ -1006,6 +1000,44 @@ linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *m ) htsmsg_add_str(s, "uuid", idnode_uuid_as_str(&lfe->lfe_satconf->ls_id)); htsmsg_add_msg(m, "satconf", s); } + + /* Add to list */ + snprintf(id, sizeof(id), "%s #%d", dvb_type2str(lfe->lfe_info.type), lfe->lfe_number); + htsmsg_add_msg(fe, id, m); +} + +void +linuxdvb_frontend_delete ( linuxdvb_frontend_t *lfe ) +{ + mpegts_mux_instance_t *mmi; + + lock_assert(&global_lock); + + /* Ensure we're stopped */ + if ((mmi = LIST_FIRST(&lfe->mi_mux_active))) + mmi->mmi_mux->mm_stop(mmi->mmi_mux, 1); + + /* Stop monitor */ + gtimer_disarm(&lfe->lfe_monitor_timer); + + /* Close FDs */ + if (lfe->lfe_fe_fd > 0) + close(lfe->lfe_fe_fd); + + /* Remove from adapter */ + LIST_REMOVE(lfe, lfe_link); + + /* Free memory */ + free(lfe->lfe_fe_path); + free(lfe->lfe_dmx_path); + free(lfe->lfe_dvr_path); + + /* Delete satconf */ + if (lfe->lfe_satconf) + linuxdvb_satconf_delete(lfe->lfe_satconf); + + /* Finish */ + mpegts_input_delete((mpegts_input_t*)lfe); } /****************************************************************************** diff --git a/src/input/mpegts/linuxdvb/linuxdvb_private.h b/src/input/mpegts/linuxdvb/linuxdvb_private.h index 06a44fff..72845e32 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_private.h +++ b/src/input/mpegts/linuxdvb/linuxdvb_private.h @@ -26,7 +26,6 @@ #define LINUXDVB_FREQ_TOL 2000 typedef struct linuxdvb_hardware linuxdvb_hardware_t; -typedef struct linuxdvb_device linuxdvb_device_t; typedef struct linuxdvb_adapter linuxdvb_adapter_t; typedef struct linuxdvb_frontend linuxdvb_frontend_t; typedef struct linuxdvb_satconf linuxdvb_satconf_t; @@ -39,56 +38,15 @@ typedef struct linuxdvb_mux linuxdvb_mux_t; typedef LIST_HEAD(,linuxdvb_hardware) linuxdvb_hardware_list_t; typedef TAILQ_HEAD(linuxdvb_satconf_ele_list,linuxdvb_satconf_ele) linuxdvb_satconf_ele_list_t; -/* - * Hardware tree objects - */ - -typedef struct device_info -{ - char *di_id; - char di_path[128]; - enum { - BUS_NONE = 0, - BUS_PCI, - BUS_USB1, - BUS_USB2, - BUS_USB3 - } di_bus; - uint32_t di_dev; - int di_min_adapter; -} device_info_t; - -struct linuxdvb_device -{ - tvh_hardware_t; - - /* - * Device info - */ - device_info_t ld_devid; - - /* - * Adapters - */ - LIST_HEAD(,linuxdvb_adapter) ld_adapters; -}; - struct linuxdvb_adapter { - idnode_t la_id; - - /* - * Link to device - */ - linuxdvb_device_t *la_device; - LIST_ENTRY(linuxdvb_adapter) la_link; + tvh_hardware_t; /* * Adapter info */ char *la_name; char *la_rootpath; - uint32_t la_number; int la_dvb_number; /* @@ -223,40 +181,26 @@ struct linuxdvb_lnb * Methods */ -void linuxdvb_device_init ( int adapter_mask ); -void linuxdvb_device_save ( linuxdvb_device_t *ld ); - -linuxdvb_device_t *linuxdvb_device_create0 - (const char *uuid, htsmsg_t *conf); - -linuxdvb_device_t * linuxdvb_device_find_by_adapter ( int a ); - #define LINUXDVB_SUBSYS_FE 0x01 #define LINUXDVB_SUBSYS_DVR 0x02 -void linuxdvb_adapter_save ( linuxdvb_adapter_t *la, htsmsg_t *m ); +void linuxdvb_adapter_init ( void ); -linuxdvb_adapter_t *linuxdvb_adapter_create0 - ( linuxdvb_device_t *ld, const char *uuid, htsmsg_t *conf ); - -void linuxdvb_adapter_added (int a); +void linuxdvb_adapter_save ( linuxdvb_adapter_t *la ); int linuxdvb_adapter_is_free ( linuxdvb_adapter_t *la ); int linuxdvb_adapter_current_weight ( linuxdvb_adapter_t *la ); -linuxdvb_adapter_t *linuxdvb_adapter_find_by_hwid ( const char *hwid ); -linuxdvb_adapter_t *linuxdvb_adapter_find_by_path ( const char *path ); - linuxdvb_frontend_t * -linuxdvb_frontend_create0 - ( linuxdvb_adapter_t *la, const char *uuid, htsmsg_t *conf, fe_type_t type ); +linuxdvb_frontend_create + ( htsmsg_t *conf, linuxdvb_adapter_t *la, int number, + const char *fe_path, const char *dmx_path, const char *dvr_path, + struct dvb_frontend_info *dfi ); void linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *m ); -int linuxdvb_frontend_added - ( linuxdvb_adapter_t *la, int fe_num, - const char *fe_path, const char *dmx_path, const char *dvr_path, - const struct dvb_frontend_info *fe_info ); +void linuxdvb_frontend_delete ( linuxdvb_frontend_t *lfe ); + void linuxdvb_frontend_add_network ( linuxdvb_frontend_t *lfe, linuxdvb_network_t *net ); @@ -360,6 +304,5 @@ linuxdvb_satconf_t *linuxdvb_satconf_create const char *type, const char *uuid, htsmsg_t *conf ); void linuxdvb_satconf_delete ( linuxdvb_satconf_t *ls ); -void linuxdvb_satconf_destroy ( linuxdvb_satconf_t *ls ); #endif /* __TVH_LINUXDVB_PRIVATE_H__ */ diff --git a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c index 99fbaeed..72b34a8f 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_satconf.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_satconf.c @@ -115,9 +115,11 @@ linuxdvb_satconf_class_get_title ( idnode_t *p ) static void linuxdvb_satconf_class_save ( idnode_t *s ) { +#if 0 linuxdvb_satconf_t *ls = (linuxdvb_satconf_t*)s; linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)ls->ls_frontend; linuxdvb_device_save(lfe->lfe_adapter->la_device); +#endif } static const void * @@ -382,12 +384,6 @@ linuxdvb_satconf_type_list ( void *p ) * Create/Delete satconf * *************************************************************************/ -void -linuxdvb_satconf_destroy ( linuxdvb_satconf_t *ls ) -{ - // TODO -} - linuxdvb_satconf_t * linuxdvb_satconf_create ( linuxdvb_frontend_t *lfe, const char *type, const char *uuid, diff --git a/src/input/mpegts/linuxdvb/scanfile.c b/src/input/mpegts/linuxdvb/scanfile.c index 2bfc1feb..dcc34209 100644 --- a/src/input/mpegts/linuxdvb/scanfile.c +++ b/src/input/mpegts/linuxdvb/scanfile.c @@ -443,7 +443,6 @@ scanfile_find ( const char *id ) /* Type */ if (!(tok = strtok_r(tmp, "/", &s))) return NULL; - printf("tok = %s\n", tok); if (!strcasecmp(tok, "dvbt")) l = &scanfile_regions_DVBT; else if (!strcasecmp(tok, "dvbc")) @@ -458,7 +457,6 @@ scanfile_find ( const char *id ) /* Region */ if (!(tok = strtok_r(NULL, "/", &s))) return NULL; - printf("tok = %s\n", tok); LIST_FOREACH(r, l, sfr_link) if (!strcmp(r->sfr_id, tok)) break; @@ -467,7 +465,6 @@ scanfile_find ( const char *id ) /* Network */ if (!(tok = strtok_r(NULL, "/", &s))) return NULL; - printf("tok = %s\n", tok); LIST_FOREACH(n, &r->sfr_networks, sfn_link) if (!strcmp(n->sfn_id, tok)) break; diff --git a/src/main.c b/src/main.c index 967eddfb..a71d2b8f 100644 --- a/src/main.c +++ b/src/main.c @@ -59,6 +59,7 @@ #include "idnode.h" #include "imagecache.h" #include "timeshift.h" +#include "fsmonitor.h" #if ENABLE_LIBAV #include "libav.h" #include "plumbing/transcoding.h" @@ -420,6 +421,14 @@ main(int argc, char **argv) const char *log_debug = NULL, *log_trace = NULL; char buf[512]; + /* Setup global mutexes */ + pthread_mutex_init(&ffmpeg_lock, NULL); + pthread_mutex_init(&fork_lock, NULL); + pthread_mutex_init(&global_lock, NULL); + pthread_mutex_init(&atomic_lock, NULL); + pthread_mutex_lock(&global_lock); + pthread_cond_init(>imer_cond, NULL); + /* Defaults */ tvheadend_webui_port = 9981; tvheadend_webroot = NULL; @@ -702,14 +711,7 @@ main(int argc, char **argv) idnode_init(); hts_settings_init(opt_config); - /* Setup global mutexes */ - pthread_mutex_init(&ffmpeg_lock, NULL); - pthread_mutex_init(&fork_lock, NULL); - pthread_mutex_init(&global_lock, NULL); - pthread_mutex_init(&atomic_lock, NULL); - pthread_mutex_lock(&global_lock); - pthread_cond_init(>imer_cond, NULL); - + /* Initialise clock */ time(&dispatch_clock); /* Signal handling */ @@ -723,6 +725,8 @@ main(int argc, char **argv) api_init(); + fsmonitor_init(); + #if ENABLE_LIBAV libav_init(); transcoding_init(); diff --git a/src/webui/static/app/idnode.js b/src/webui/static/app/idnode.js index f3b1dc47..2a573286 100644 --- a/src/webui/static/app/idnode.js +++ b/src/webui/static/app/idnode.js @@ -611,12 +611,6 @@ tvheadend.idnode_grid = function(panel, conf) var delBtn = null; var editBtn = null; - /* Selection */ - var select = new Ext.grid.CheckboxSelectionModel({ - singleSelect : false - }); - columns.splice(0, 0, select); - /* Model */ var idnode = new tvheadend.IdNode(d); for (var i = 0; i < idnode.length(); i++) { @@ -658,6 +652,11 @@ tvheadend.idnode_grid = function(panel, conf) columns : columns }); + /* Selection */ + var select = new Ext.grid.RowSelectionModel({ + singleSelect : false + }); + /* Event handlers */ store.on('update', function(s, r, o){ var d = (s.getModifiedRecords().length == 0); @@ -995,6 +994,13 @@ tvheadend.idnode_tree = function (conf) } }); + if (conf.comet) { + tvheadend.comet.on(conf.comet, function(o) { + if (o.reload) + tree.getRootNode().reload(); + }); + } + // TODO: top-level reload tvheadend.comet.on('idnodeUpdated', function(o) { var n = tree.getNodeById(o.uuid); diff --git a/src/webui/static/app/tvadapters.js b/src/webui/static/app/tvadapters.js index 7e0ed001..a15bb21b 100644 --- a/src/webui/static/app/tvadapters.js +++ b/src/webui/static/app/tvadapters.js @@ -1,3 +1,3 @@ tvheadend.tvadapters = function() { - return tvheadend.idnode_tree({ url: 'api/hardware/tree', title: 'TV adapters'}); + return tvheadend.idnode_tree({ url: 'api/hardware/tree', title: 'TV adapters', comet: 'hardware'}); }