diff --git a/Makefile b/Makefile
index 8df370f0..7558fefd 100644
--- a/Makefile
+++ b/Makefile
@@ -191,6 +191,7 @@ SRCS-${CONFIG_LINUXDVB} += \
src/input/mpegts/linuxdvb/linuxdvb_lnb.c \
src/input/mpegts/linuxdvb/linuxdvb_switch.c \
src/input/mpegts/linuxdvb/linuxdvb_rotor.c \
+ src/input/mpegts/linuxdvb/scanfile.c \
# IPTV
SRCS-${CONFIG_IPTV} += \
diff --git a/src/api/api_mpegts.c b/src/api/api_mpegts.c
index b75fe6e7..3bb8227c 100644
--- a/src/api/api_mpegts.c
+++ b/src/api/api_mpegts.c
@@ -25,6 +25,7 @@
#if ENABLE_LINUXDVB
#include "input/mpegts/linuxdvb.h"
#include "input/mpegts/linuxdvb/linuxdvb_private.h"
+#include "input/mpegts/linuxdvb/scanfile.h"
#endif
/*
@@ -271,6 +272,52 @@ api_linuxdvb_satconf_create
return err;
}
+
+static int
+api_linuxdvb_scanfile_list
+ ( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
+{
+ char buf[512];
+ const char *type = htsmsg_get_str(args, "type");
+ scanfile_region_list_t *list = NULL;
+ htsmsg_t *l, *e;
+ scanfile_region_t *r;
+ scanfile_network_t *n;
+
+ if (!type)
+ return -EINVAL;
+
+ if (!strcasecmp(type, "dvbt"))
+ list = &scanfile_regions_DVBT;
+ else if (!strcasecmp(type, "dvbc"))
+ list = &scanfile_regions_DVBC;
+ else if (!strcasecmp(type, "dvbs"))
+ list = &scanfile_regions_DVBS;
+ else if (!strcasecmp(type, "atsc"))
+ list = &scanfile_regions_ATSC;
+ else
+ return -EINVAL;
+
+ l = htsmsg_create_list();
+ LIST_FOREACH(r, list, sfr_link) {
+ LIST_FOREACH(n, &r->sfr_networks, sfn_link) {
+ e = htsmsg_create_map();
+ sprintf(buf, "%s/%s/%s", type, r->sfr_id, n->sfn_id);
+ htsmsg_add_str(e, "key", buf);
+ if (list != &scanfile_regions_DVBS) {
+ sprintf(buf, "%s: %s", r->sfr_name, n->sfn_name);
+ htsmsg_add_str(e, "val", buf);
+ } else {
+ htsmsg_add_str(e, "val", n->sfn_name);
+ }
+ htsmsg_add_msg(l, NULL, e);
+ }
+ }
+ *resp = htsmsg_create_map();
+ htsmsg_add_msg(*resp, "entries", l);
+
+ return 0;
+}
#endif
/*
@@ -316,6 +363,7 @@ api_mpegts_init ( void )
{ "linuxdvb/satconf/grid", ACCESS_ANONYMOUS, api_idnode_grid, api_linuxdvb_satconf_grid },
{ "linuxdvb/satconf/class", ACCESS_ANONYMOUS, api_idnode_class, (void*)&linuxdvb_satconf_class },
{ "linuxdvb/satconf/create", ACCESS_ANONYMOUS, api_linuxdvb_satconf_create, NULL },
+ { "linuxdvb/scanfile/list", ACCESS_ANONYMOUS, api_linuxdvb_scanfile_list, NULL },
#endif
{ NULL },
};
diff --git a/src/api/api_subscriptions.c b/src/api/api_subscriptions.c
new file mode 100644
index 00000000..1d0c4b1a
--- /dev/null
+++ b/src/api/api_subscriptions.c
@@ -0,0 +1,63 @@
+/*
+ * API - service related calls
+ *
+ * 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 .
+ */
+
+#ifndef __TVH_API_SERVICE_H__
+#define __TVH_API_SERVICE_H__
+
+#include "tvheadend.h"
+#include "subscriptions.h"
+#include "access.h"
+#include "api.h"
+
+static int
+api_subscription_list
+ ( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
+{
+ int c;
+ htsmsg_t *l, *e;
+ th_subscription_t *ths;
+
+ l = htsmsg_create_list();
+ c = 0;
+ LIST_FOREACH(ths, &subscriptions, ths_global_link) {
+ e = subscription_create_msg(ths);
+ htsmsg_add_msg(l, NULL, e);
+ c++;
+ }
+
+ *resp = htsmsg_create_map();
+ htsmsg_add_msg(*resp, "entries", l);
+ htsmsg_add_msg(*resp, "totalCount", c);
+
+ return 0;
+}
+
+void api_service_init ( void )
+{
+ extern const idclass_t service_class;
+ static api_hook_t ah[] = {
+ { "subscription/list", ACCESS_ANONYMOUS, api_subscribtion_list, NULL },
+ { NULL },
+ };
+
+ api_register_all(ah);
+}
+
+
+#endif /* __TVH_API_IDNODE_H__ */
diff --git a/src/input/mpegts/dvb.h b/src/input/mpegts/dvb.h
index 721f1b62..00d2cdf5 100644
--- a/src/input/mpegts/dvb.h
+++ b/src/input/mpegts/dvb.h
@@ -206,7 +206,7 @@ typedef enum polarisation {
typedef struct dvb_mux_conf
{
dvb_frontend_parameters_t dmc_fe_params;
-
+
// Additional DVB-S fields
polarisation_t dmc_fe_polarisation;
int dmc_fe_orbital_pos;
@@ -216,6 +216,10 @@ typedef struct dvb_mux_conf
fe_delivery_system_t dmc_fe_delsys;
fe_rolloff_t dmc_fe_rolloff;
#endif
+
+ // For scan file configurations
+ LIST_ENTRY(dvb_mux_conf) dmc_link;
+
} dvb_mux_conf_t;
const char *dvb_mux_conf_load
diff --git a/src/input/mpegts/dvb_support.c b/src/input/mpegts/dvb_support.c
index 203956f3..3e03b5c5 100644
--- a/src/input/mpegts/dvb_support.c
+++ b/src/input/mpegts/dvb_support.c
@@ -499,10 +499,10 @@ const static struct strtab hiertab[] = {
dvb_str2val(hier);
const static struct strtab poltab[] = {
- { "Vertical", POLARISATION_VERTICAL },
- { "Horizontal", POLARISATION_HORIZONTAL },
- { "Left", POLARISATION_CIRCULAR_LEFT },
- { "Right", POLARISATION_CIRCULAR_RIGHT },
+ { "V", POLARISATION_VERTICAL },
+ { "H", POLARISATION_HORIZONTAL },
+ { "L", POLARISATION_CIRCULAR_LEFT },
+ { "R", POLARISATION_CIRCULAR_RIGHT },
};
dvb_str2val(pol);
diff --git a/src/input/mpegts/linuxdvb/linuxdvb.c b/src/input/mpegts/linuxdvb/linuxdvb.c
index c283326a..fca78181 100644
--- a/src/input/mpegts/linuxdvb/linuxdvb.c
+++ b/src/input/mpegts/linuxdvb/linuxdvb.c
@@ -21,9 +21,13 @@
#include "input.h"
#include "settings.h"
#include "linuxdvb_private.h"
+#include "scanfile.h"
void linuxdvb_init ( int adapter_mask )
{
+ /* Load scan files */
+ scanfile_init();
+
/* Initialise networks */
linuxdvb_network_init();
diff --git a/src/input/mpegts/linuxdvb/linuxdvb_network.c b/src/input/mpegts/linuxdvb/linuxdvb_network.c
index d02cb8db..2c9d0757 100644
--- a/src/input/mpegts/linuxdvb/linuxdvb_network.c
+++ b/src/input/mpegts/linuxdvb/linuxdvb_network.c
@@ -22,6 +22,7 @@
#include "linuxdvb_private.h"
#include "queue.h"
#include "settings.h"
+#include "scanfile.h"
#include
#include
@@ -30,6 +31,10 @@
#include
#include
+static mpegts_mux_t *
+linuxdvb_network_find_mux
+ ( linuxdvb_network_t *ln, dvb_mux_conf_t *dmc );
+
/* ****************************************************************************
* Class definition
* ***************************************************************************/
@@ -49,6 +54,70 @@ linuxdvb_network_class_delete ( idnode_t *in )
mpegts_network_delete(mn);
}
+static const void *
+linuxdvb_network_class_scanfile_get ( void *o )
+{
+ static const char *s = NULL;
+ return &s;
+}
+static int
+linuxdvb_network_class_scanfile_set ( void *o, const void *s )
+{
+ dvb_mux_conf_t *dmc;
+ scanfile_network_t *sfn;
+ mpegts_mux_t *mm;
+
+ /* Find */
+ if (!s)
+ return 0;
+ if (!(sfn = scanfile_find(s)))
+ return 0;
+
+ /* Create */
+ LIST_FOREACH(dmc, &sfn->sfn_muxes, dmc_link) {
+ if (!(mm = linuxdvb_network_find_mux(o, dmc))) {
+ mm = (mpegts_mux_t*)linuxdvb_mux_create0(o,
+ MPEGTS_ONID_NONE,
+ MPEGTS_TSID_NONE,
+ dmc, NULL, NULL);
+ if (mm)
+ mm->mm_config_save(mm);
+ }
+ }
+ return 0;
+}
+static htsmsg_t *
+linuxdvb_network_class_scanfile_list ( const char *type )
+{
+ htsmsg_t *e, *m = htsmsg_create_map();
+ htsmsg_add_str(m, "type", "api");
+ htsmsg_add_str(m, "uri", "linuxdvb/scanfile/list");
+ e = htsmsg_create_map();
+ htsmsg_add_str(e, "type", type);
+ htsmsg_add_msg(m, "params", e);
+ return m;
+}
+static htsmsg_t *
+linuxdvb_network_dvbt_class_scanfile_list ( void *o )
+{
+ return linuxdvb_network_class_scanfile_list("dvbt");
+}
+static htsmsg_t *
+linuxdvb_network_dvbc_class_scanfile_list ( void *o )
+{
+ return linuxdvb_network_class_scanfile_list("dvbc");
+}
+static htsmsg_t *
+linuxdvb_network_dvbs_class_scanfile_list ( void *o )
+{
+ return linuxdvb_network_class_scanfile_list("dvbs");
+}
+static htsmsg_t *
+linuxdvb_network_atsc_class_scanfile_list ( void *o )
+{
+ return linuxdvb_network_class_scanfile_list("atsc");
+}
+
const idclass_t linuxdvb_network_class =
{
.ic_super = &mpegts_network_class,
@@ -66,6 +135,15 @@ const idclass_t linuxdvb_network_dvbt_class =
.ic_class = "linuxdvb_network_dvbt",
.ic_caption = "DVB-T Network",
.ic_properties = (const property_t[]) {
+ {
+ .type = PT_STR,
+ .id = "scanfile",
+ .name = "Pre-defined Muxes",
+ .set = linuxdvb_network_class_scanfile_set,
+ .get = linuxdvb_network_class_scanfile_get,
+ .list = linuxdvb_network_dvbt_class_scanfile_list,
+ .opts = PO_NOSAVE,
+ },
{}
}
};
@@ -76,6 +154,15 @@ const idclass_t linuxdvb_network_dvbc_class =
.ic_class = "linuxdvb_network_dvbc",
.ic_caption = "DVB-C Network",
.ic_properties = (const property_t[]) {
+ {
+ .type = PT_STR,
+ .id = "scanfile",
+ .name = "Pre-defined Muxes",
+ .set = linuxdvb_network_class_scanfile_set,
+ .get = linuxdvb_network_class_scanfile_get,
+ .list = linuxdvb_network_dvbc_class_scanfile_list,
+ .opts = PO_NOSAVE,
+ },
{}
}
};
@@ -86,6 +173,15 @@ const idclass_t linuxdvb_network_dvbs_class =
.ic_class = "linuxdvb_network_dvbs",
.ic_caption = "DVB-S Network",
.ic_properties = (const property_t[]) {
+ {
+ .type = PT_STR,
+ .id = "scanfile",
+ .name = "Pre-defined Muxes",
+ .set = linuxdvb_network_class_scanfile_set,
+ .get = linuxdvb_network_class_scanfile_get,
+ .list = linuxdvb_network_dvbs_class_scanfile_list,
+ .opts = PO_NOSAVE,
+ },
{}
}
};
@@ -96,6 +192,15 @@ const idclass_t linuxdvb_network_atsc_class =
.ic_class = "linuxdvb_network_atsc",
.ic_caption = "ATSC Network",
.ic_properties = (const property_t[]) {
+ {
+ .type = PT_STR,
+ .id = "scanfile",
+ .name = "Pre-defined Muxes",
+ .set = linuxdvb_network_class_scanfile_set,
+ .get = linuxdvb_network_class_scanfile_get,
+ .list = linuxdvb_network_atsc_class_scanfile_list,
+ .opts = PO_NOSAVE,
+ },
{}
}
};
@@ -194,11 +299,7 @@ linuxdvb_network_create0
htsmsg_t *c, *e;
htsmsg_field_t *f;
- /* Create */
- if (!(ln = (linuxdvb_network_t*)mpegts_network_create0(calloc(1, sizeof(linuxdvb_network_t)),
- idc, uuid, NULL, conf)))
- return NULL;
-
+ ln = calloc(1, sizeof(linuxdvb_network_t));
if (idc == &linuxdvb_network_dvbt_class)
ln->ln_type = FE_OFDM;
else if (idc == &linuxdvb_network_dvbc_class)
@@ -207,6 +308,11 @@ linuxdvb_network_create0
ln->ln_type = FE_QPSK;
else
ln->ln_type = FE_ATSC;
+
+ /* Create */
+ if (!(ln = (linuxdvb_network_t*)mpegts_network_create0((void*)ln,
+ idc, uuid, NULL, conf)))
+ return NULL;
/* Callbacks */
ln->mn_create_mux = linuxdvb_network_create_mux;
diff --git a/src/input/mpegts/linuxdvb/scanfile.c b/src/input/mpegts/linuxdvb/scanfile.c
new file mode 100644
index 00000000..b4984b8b
--- /dev/null
+++ b/src/input/mpegts/linuxdvb/scanfile.c
@@ -0,0 +1,464 @@
+/*
+ * tvheadend, intial mux list
+ * Copyright (C) 2012 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 "../dvb.h"
+#include "filebundle.h"
+#include "config2.h"
+#include "scanfile.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+scanfile_region_list_t scanfile_regions_DVBC;
+scanfile_region_list_t scanfile_regions_DVBT;
+scanfile_region_list_t scanfile_regions_DVBS;
+scanfile_region_list_t scanfile_regions_ATSC;
+
+/* **************************************************************************
+ * Country codes
+ * *************************************************************************/
+
+static const struct {
+ const char *code;
+ const char *name;
+} tldlist[] = {
+ {"auto", "--Generic--"},
+ {"ad", "Andorra"},
+ {"ar", "Argentina"},
+ {"at", "Austria"},
+ {"au", "Australia"},
+ {"ax", "Aland Islands"},
+ {"be", "Belgium"},
+ {"bg", "Bulgaria"},
+ {"br", "Brazil"},
+ {"ca", "Canada"},
+ {"ch", "Switzerland"},
+ {"cz", "Czech Republic"},
+ {"de", "Germany"},
+ {"dk", "Denmark"},
+ {"es", "Spain"},
+ {"fi", "Finland"},
+ {"fr", "France"},
+ {"gr", "Greece"},
+ {"hk", "Hong Kong"},
+ {"hr", "Croatia"},
+ {"hu", "Hungary"},
+ {"ie", "Ireland"},
+ {"il", "Israel"},
+ {"ir", "Iran"},
+ {"is", "Iceland"},
+ {"it", "Italy"},
+ {"lt", "Lithuania"},
+ {"lu", "Luxembourg"},
+ {"lv", "Latvia"},
+ {"nl", "Netherlands"},
+ {"no", "Norway"},
+ {"nz", "New Zealand"},
+ {"pl", "Poland"},
+ {"pt", "Portugal"},
+ {"ro", "Romania"},
+ {"ru", "Russia"},
+ {"se", "Sweden"},
+ {"si", "Slovenia"},
+ {"sk", "Slovakia"},
+ {"tw", "Taiwan"},
+ {"ua", "Ukraine"},
+ {"uk", "United Kingdom"},
+ {"us", "United States"},
+ {"vn", "Vietnam"},
+};
+
+static const char *
+tldcode2longname(const char *tld)
+{
+ int i;
+ for(i = 0; i < sizeof(tldlist) / sizeof(tldlist[0]); i++)
+ if(!strcmp(tld, tldlist[i].code))
+ return tldlist[i].name;
+ return tld;
+}
+
+/* **************************************************************************
+ * Type specific parsers
+ * *************************************************************************/
+
+static int
+scanfile_load_atsc ( dvb_mux_conf_t *mux, const char *line )
+{
+ char qam[20];
+ int r;
+ dvb_frontend_parameters_t *p = &mux->dmc_fe_params;
+
+ r = sscanf(line, "%u %s", &p->frequency, qam);
+ if (r != 2) return 1;
+ mux->dmc_fe_delsys = SYS_ATSC;
+ if ((p->u.vsb.modulation = dvb_str2qam(qam)) == -1) return 1;
+
+ return 0;
+}
+
+static int
+scanfile_load_dvbt ( dvb_mux_conf_t *mux, const char *line )
+{
+ char bw[20], fec[20], fec2[20], qam[20], mode[20], guard[20], hier[20];
+ int r;
+ uint32_t i;
+ dvb_frontend_parameters_t *p = &mux->dmc_fe_params;
+
+ if (*line == '2') {
+ r = sscanf(line+1, "%u %u %u %10s %10s %10s %10s %10s %10s %10s",
+ &i, &i, &p->frequency, bw, fec, fec2, qam, mode, guard, hier);
+ if(r != 10) return 1;
+ mux->dmc_fe_delsys = SYS_DVBT2;
+ } else {
+ r = sscanf(line, "%u %10s %10s %10s %10s %10s %10s %10s",
+ &p->frequency, bw, fec, fec2, qam, mode, guard, hier);
+ if(r != 8) return 1;
+ mux->dmc_fe_delsys = SYS_DVBT;
+ }
+
+ if ((p->u.ofdm.bandwidth = dvb_str2bw(bw)) == -1) return 1;
+ if ((p->u.ofdm.constellation = dvb_str2qam(qam)) == -1) return 1;
+ if ((p->u.ofdm.code_rate_HP = dvb_str2fec(fec)) == -1) return 1;
+ if ((p->u.ofdm.code_rate_LP = dvb_str2fec(fec2)) == -1) return 1;
+ if ((p->u.ofdm.transmission_mode = dvb_str2mode(mode)) == -1) return 1;
+ if ((p->u.ofdm.guard_interval = dvb_str2guard(guard)) == -1) return 1;
+ if ((p->u.ofdm.hierarchy_information = dvb_str2hier(hier)) == -1) return 1;
+
+ return 0;
+}
+
+static int
+scanfile_load_dvbs ( dvb_mux_conf_t *mux, const char *line )
+{
+ char pol[20], fec[20], qam[20], rolloff[20];
+ int r, v2 = 0;
+ dvb_frontend_parameters_t *p = &mux->dmc_fe_params;
+
+ if (*line == '2') {
+ v2 = 2;
+ line++;
+ }
+
+ r = sscanf(line, "%u %s %u %s %s %s",
+ &p->frequency, pol, &p->u.qpsk.symbol_rate,
+ fec, rolloff, qam);
+ if (r < (4+v2)) return 1;
+
+ if ((mux->dmc_fe_polarisation = dvb_str2pol(pol)) == -1) return 1;
+ if ((p->u.qpsk.fec_inner = dvb_str2fec(fec)) == -1) return 1;
+ if (v2) {
+ mux->dmc_fe_delsys = SYS_DVBS2;
+ if ((mux->dmc_fe_rolloff = dvb_str2rolloff(rolloff)) == -1) return 1;
+ if ((mux->dmc_fe_modulation = dvb_str2qam(qam)) == -1) return 1;
+ } else {
+ mux->dmc_fe_delsys = SYS_DVBS;
+ mux->dmc_fe_rolloff = ROLLOFF_35;
+ mux->dmc_fe_modulation = QPSK;
+ }
+
+ return 0;
+}
+
+static int
+scanfile_load_dvbc ( dvb_mux_conf_t *mux, const char *line )
+{
+ char fec[20], qam[20];
+ int r;
+ dvb_frontend_parameters_t *p = &mux->dmc_fe_params;
+
+ r = sscanf(line, "%u %u %s %s",
+ &p->frequency, &p->u.qam.symbol_rate, fec, qam);
+ if(r != 4) return 1;
+
+ mux->dmc_fe_delsys = SYS_DVBC_ANNEX_AC;
+ if ((p->u.qam.fec_inner = dvb_str2fec(fec)) == -1) return 1;
+ if ((p->u.qam.modulation = dvb_str2qam(qam)) == -1) return 1;
+
+ return 0;
+}
+
+
+/* **************************************************************************
+ * File processing
+ * *************************************************************************/
+
+/*
+ * Sorting
+ */
+static int
+scanfile_network_cmp
+ ( scanfile_network_t *a, scanfile_network_t *b )
+{
+ return strcmp(a->sfn_name, b->sfn_name);
+}
+static int
+scanfile_region_cmp
+ ( scanfile_region_t *a, scanfile_region_t *b )
+{
+ return strcmp(a->sfr_name, b->sfr_name);
+}
+
+/*
+ * Create/Find region entry
+ *
+ * TODO: not sure why I didn't use RB here!
+ */
+static scanfile_region_t *
+scanfile_region_create
+ ( const char *type, const char *id, const char *desc )
+{
+ scanfile_region_t *reg;
+ scanfile_region_list_t *list = NULL;
+ if (!strcmp(type, "dvb-s")) list = &scanfile_regions_DVBS;
+ else if (!strcmp(type, "dvb-t")) list = &scanfile_regions_DVBT;
+ else if (!strcmp(type, "dvb-c")) list = &scanfile_regions_DVBC;
+ else if (!strcmp(type, "atsc")) list = &scanfile_regions_ATSC;
+ if (!list) return NULL;
+
+ LIST_FOREACH(reg, list, sfr_link) {
+ if (!strcmp(reg->sfr_id, id)) break;
+ }
+
+ if (!reg) {
+ tvhtrace("scanfile", "%s region %s created", type, id);
+ reg = calloc(1, sizeof(scanfile_region_t));
+ reg->sfr_id = strdup(id);
+ reg->sfr_name = strdup(desc);
+ LIST_INSERT_SORTED(list, reg, sfr_link, scanfile_region_cmp);
+ }
+
+ return reg;
+}
+
+/*
+ * Process mux entry
+ */
+static void
+scanfile_load_one ( scanfile_network_t *net, const char *line )
+{
+ int r = 1;
+ dvb_mux_conf_t *mux = calloc(1, sizeof(dvb_mux_conf_t));
+
+ switch (line[0]) {
+ case 'A':
+ r = scanfile_load_atsc(mux, line+1);
+ break;
+ case 'T':
+ r = scanfile_load_dvbt(mux, line+1);
+ break;
+ case 'S':
+ r = scanfile_load_dvbs(mux, line+1);
+ break;
+ case 'C':
+ r = scanfile_load_dvbc(mux, line+1);
+ break;
+ }
+
+ tvhdebug("scanfile", "[%s] %s", line, r ? "FAIL" : "OK");
+ if (r) {
+ free(mux);
+ } else {
+ LIST_INSERT_HEAD(&net->sfn_muxes, mux, dmc_link);
+ }
+}
+
+/*
+ * Process a file
+ */
+static void
+scanfile_load_file
+ ( const char *type, fb_dir *dir, const char *name )
+{
+ int i;
+ fb_file *fp;
+ scanfile_region_t *reg = NULL;
+ scanfile_network_t *net;
+ char *str;
+ char buf[256], buf2[256];
+ tvhtrace("scanfile", "load file %s", name);
+
+ fp = fb_open2(dir, name, 1, 0);
+ if (!fp) return;
+
+ /* Region */
+ strncpy(buf, name, sizeof(buf));
+ if (!strcmp(type, "dvb-s")) {
+ reg = scanfile_region_create(type, "geo", "Geo-synchronous Orbit");
+ } else {
+ str = buf;
+ while (*str) {
+ if (*str == '-') {
+ *str = '\0';
+ reg = scanfile_region_create(type, buf, tldcode2longname(buf));
+ *str = '-';
+ break;
+ }
+ str++;
+ }
+ }
+ if (!reg) {
+ fb_close(fp);
+ return;
+ }
+
+ /* Network */
+ str = buf;
+ while (*str) {
+ if (!isalnum(*str)) *str = '_';
+ str++;
+ }
+ *str = '\0';
+ snprintf(buf2, sizeof(buf2), "%s_%s", type, buf);
+ net = calloc(1, sizeof(scanfile_network_t));
+ net->sfn_id = strdup(buf2);
+ net->sfn_name = strdup(buf);
+ LIST_INSERT_SORTED(®->sfr_networks, net, sfn_link, scanfile_network_cmp);
+
+ /* Process file */
+ while (!fb_eof(fp)) {
+
+ /* Get line */
+ memset(buf, 0, sizeof(buf));
+ if (!fb_gets(fp, buf, sizeof(buf) - 1)) break;
+ i = 0;
+ while (buf[i]) {
+ if (buf[i] == '#')
+ buf[i] = '\0';
+ else
+ i++;
+ }
+ while (i > 0 && buf[i-1] < 32) buf[--i] = 0;
+
+ /* Process mux */
+ switch (*buf) {
+ case 'A':
+ case 'C':
+ case 'T':
+ case 'S':
+ scanfile_load_one(net, buf);
+ default:
+ break;
+ }
+ }
+ fb_close(fp);
+}
+
+/*
+ * Process directory
+ *
+ * Note: should we follow symlinks?
+ */
+static void
+scanfile_load_dir
+ ( const char *path, const char *type, int lvl )
+{
+ char p[256];
+ fb_dir *dir;
+ fb_dirent *de;
+ tvhtrace("scanfile", "load dir %s", path);
+
+ if (lvl >= 3) return;
+ if (!(dir = fb_opendir(path))) return;
+ lvl++;
+
+ while ((de = fb_readdir(dir))) {
+ if (*de->name == '.') continue;
+ if (de->type == FB_DIR) {
+ snprintf(p, sizeof(p), "%s/%s", path, de->name);
+ scanfile_load_dir(p, de->name, lvl+1);
+ } else if (type) {
+ scanfile_load_file(type, dir, de->name);
+ }
+ }
+
+ fb_closedir(dir);
+}
+
+/*
+ * Initialise the mux list
+ */
+void
+scanfile_init ( void )
+{
+ const char *path = config_get_muxconfpath();
+ if (!path || !*path)
+#if ENABLE_DVBSCAN
+ path = "data/dvb-scan";
+#else
+ path = "/usr/share/dvb";
+#endif
+ scanfile_load_dir(path, NULL, 0);
+}
+
+/*
+ * Find scanfile
+ */
+scanfile_network_t *
+scanfile_find ( const char *id )
+{
+ char *tok, *s = NULL, *tmp;
+ scanfile_region_t *r = NULL;
+ scanfile_network_t *n = NULL;
+ scanfile_region_list_t *l;
+ tmp = strdup(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"))
+ l = &scanfile_regions_DVBC;
+ else if (!strcasecmp(tok, "dvbs"))
+ l = &scanfile_regions_DVBS;
+ else if (!strcasecmp(tok, "atsc"))
+ l = &scanfile_regions_ATSC;
+ else
+ return NULL;
+
+ /* 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;
+ if (!r) return NULL;
+
+ /* 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;
+
+ return n;
+}
diff --git a/src/input/mpegts/linuxdvb/scanfile.h b/src/input/mpegts/linuxdvb/scanfile.h
new file mode 100644
index 00000000..cda2da76
--- /dev/null
+++ b/src/input/mpegts/linuxdvb/scanfile.h
@@ -0,0 +1,46 @@
+/*
+ * tvheadend, intial mux list
+ * Copyright (C) 2012 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 .
+ */
+
+#ifndef __LINUXDVB_SCANFILES_H__
+#define __LINUXDVB_SCANFILES_H__
+
+typedef struct scanfile_network {
+ const char *sfn_id;
+ const char *sfn_name;
+ LIST_ENTRY(scanfile_network) sfn_link;
+ LIST_HEAD(,dvb_mux_conf) sfn_muxes;
+} scanfile_network_t;
+
+typedef struct scanfile_region {
+ const char *sfr_id;
+ const char *sfr_name;
+ LIST_ENTRY(scanfile_region) sfr_link;
+ LIST_HEAD(,scanfile_network) sfr_networks;
+} scanfile_region_t;
+
+typedef LIST_HEAD(,scanfile_region) scanfile_region_list_t;
+extern scanfile_region_list_t scanfile_regions_DVBC;
+extern scanfile_region_list_t scanfile_regions_DVBT;
+extern scanfile_region_list_t scanfile_regions_DVBS;
+extern scanfile_region_list_t scanfile_regions_ATSC;
+
+void scanfile_init ( void );
+
+scanfile_network_t *scanfile_find ( const char *id );
+
+#endif /* __LINUXDVB_SCANFILES_H__ */
diff --git a/src/input/mpegts/mpegts_mux.c b/src/input/mpegts/mpegts_mux.c
index 06c88f92..c994cfb1 100644
--- a/src/input/mpegts/mpegts_mux.c
+++ b/src/input/mpegts/mpegts_mux.c
@@ -319,11 +319,7 @@ mpegts_mux_start
mm->mm_create_instances(mm);
if (!LIST_FIRST(&mm->mm_instances)) {
tvhtrace("mpegts", "%s - has no instances", buf);
- return SM_CODE_TUNING_FAILED;
- // Note: we report a permanent inability to tune at this
- // time, rather than a lack of free tuners
- // this stops the init scan thinking we can't
- // proceed
+ return SM_CODE_NO_VALID_ADAPTER;
}
/* Find */
diff --git a/src/input/mpegts/mpegts_network.c b/src/input/mpegts/mpegts_network.c
index 9b1905a7..86f1ea52 100644
--- a/src/input/mpegts/mpegts_network.c
+++ b/src/input/mpegts/mpegts_network.c
@@ -300,8 +300,6 @@ mpegts_network_create0
/* Setup idnode */
idnode_insert(&mn->mn_id, uuid, idc);
- if (conf)
- idnode_load(&mn->mn_id, conf);
/* Default callbacks */
mn->mn_display_name = mpegts_network_display_name;
@@ -311,9 +309,6 @@ mpegts_network_create0
mn->mn_mux_class = mpegts_network_mux_class;
mn->mn_mux_create2 = mpegts_network_mux_create2;
- /* Network name */
- if (netname) mn->mn_network_name = strdup(netname);
-
/* Init Qs */
TAILQ_INIT(&mn->mn_initial_scan_pending_queue);
TAILQ_INIT(&mn->mn_initial_scan_current_queue);
@@ -321,6 +316,12 @@ mpegts_network_create0
/* Add to global list */
LIST_INSERT_HEAD(&mpegts_network_all, mn, mn_global_link);
+ /* Load config */
+ if (conf)
+ idnode_load(&mn->mn_id, conf);
+
+ /* Name */
+ if (netname) mn->mn_network_name = strdup(netname);
mn->mn_display_name(mn, buf, sizeof(buf));
tvhtrace("mpegts", "created network %s", buf);
diff --git a/src/main.c b/src/main.c
index 716f4086..3767ecc2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -54,7 +54,6 @@
#include "service.h"
#include "trap.h"
#include "settings.h"
-#include "muxes.h"
#include "config2.h"
#include "idnode.h"
#include "imagecache.h"
diff --git a/src/muxes.c b/src/muxes.c
deleted file mode 100644
index 6783fd85..00000000
--- a/src/muxes.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * tvheadend, intial mux list
- * Copyright (C) 2012 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
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "tvheadend.h"
-#include "dvb/dvb.h"
-#include "muxes.h"
-#include "filebundle.h"
-#include "config2.h"
-
-region_list_t regions_DVBC;
-region_list_t regions_DVBT;
-region_list_t regions_DVBS;
-region_list_t regions_ATSC;
-
-/* **************************************************************************
- * Country codes
- * *************************************************************************/
-
-static const struct {
- const char *code;
- const char *name;
-
-} tldlist[] = {
- {"auto", "--Generic--"},
- {"ad", "Andorra"},
- {"ar", "Argentina"},
- {"at", "Austria"},
- {"au", "Australia"},
- {"ax", "Aland Islands"},
- {"be", "Belgium"},
- {"br", "Brazil"},
- {"ca", "Canada"},
- {"ch", "Switzerland"},
- {"cz", "Czech Republic"},
- {"de", "Germany"},
- {"dk", "Denmark"},
- {"es", "Spain"},
- {"fi", "Finland"},
- {"fr", "France"},
- {"gr", "Greece"},
- {"hk", "Hong Kong"},
- {"hr", "Croatia"},
- {"hu", "Hungary"},
- {"ie", "Ireland"},
- {"il", "Israel"},
- {"ir", "Iran"},
- {"is", "Iceland"},
- {"it", "Italy"},
- {"lt", "Lithuania"},
- {"lu", "Luxembourg"},
- {"lv", "Latvia"},
- {"nl", "Netherlands"},
- {"no", "Norway"},
- {"nz", "New Zealand"},
- {"pl", "Poland"},
- {"ro", "Romania"},
- {"se", "Sweden"},
- {"si", "Slovenia"},
- {"sk", "Slovakia"},
- {"tw", "Taiwan"},
- {"uk", "United Kingdom"},
- {"us", "United States"},
- {"vn", "Vietnam"},
-};
-
-static const char *
-tldcode2longname(const char *tld)
-{
- int i;
- for(i = 0; i < sizeof(tldlist) / sizeof(tldlist[0]); i++)
- if(!strcmp(tld, tldlist[i].code))
- return tldlist[i].name;
- return tld;
-}
-
-/* **************************************************************************
- * Type specific parsers
- * *************************************************************************/
-
-static int _muxes_load_atsc ( mux_t *mux, const char *line )
-{
- char qam[20];
- int r;
-
- r = sscanf(line, "%u %s", &mux->freq, qam);
- if (r != 2) return 1;
- if ((mux->constellation = dvb_mux_str2qam(qam)) == -1) return 1;
-
- return 0;
-}
-
-static int _muxes_load_dvbt ( mux_t *mux, const char *line )
-{
- char bw[20], fec[20], fec2[20], qam[20], mode[20], guard[20], hier[20];
- int r;
- uint32_t i;
-
- if (*line == '2') {
- r = sscanf(line+1, "%u %u %u %10s %10s %10s %10s %10s %10s %10s",
- &i, &i, &mux->freq, bw, fec, fec2, qam, mode, guard, hier);
- if(r != 10) return 1;
- } else {
- r = sscanf(line, "%u %10s %10s %10s %10s %10s %10s %10s",
- &mux->freq, bw, fec, fec2, qam, mode, guard, hier);
- if(r != 8) return 1;
- }
-
- if ((mux->bw = dvb_mux_str2bw(bw)) == -1) return 1;
- if ((mux->constellation = dvb_mux_str2qam(qam)) == -1) return 1;
- if ((mux->fechp = dvb_mux_str2fec(fec)) == -1) return 1;
- if ((mux->feclp = dvb_mux_str2fec(fec2)) == -1) return 1;
- if ((mux->tmode = dvb_mux_str2mode(mode)) == -1) return 1;
- if ((mux->guard = dvb_mux_str2guard(guard)) == -1) return 1;
- if ((mux->hierarchy = dvb_mux_str2hier(hier)) == -1) return 1;
-
- return 0;
-}
-
-static int _muxes_load_dvbs ( mux_t *mux, const char *line )
-{
- char fec[20], qam[20], hier[20];
- int r, v2 = 0;
-
- if (*line == '2') {
- v2 = 2;
- line++;
- }
-
- r = sscanf(line, "%u %c %u %s %s %s",
- &mux->freq, &mux->polarisation, &mux->symrate,
- fec, hier, qam);
- if (r != (4+v2)) return 1;
-
- if ((mux->fec = dvb_mux_str2fec(fec)) == -1) return 1;
- if (v2) {
- if ((mux->hierarchy = dvb_mux_str2hier(hier)) == -1) return 1;
- if ((mux->constellation = dvb_mux_str2qam(qam)) == -1) return 1;
- }
-
- return 0;
-}
-
-static int _muxes_load_dvbc ( mux_t *mux, const char *line )
-{
- char fec[20], qam[20];
- int r;
-
- r = sscanf(line, "%u %u %s %s",
- &mux->freq, &mux->symrate, fec, qam);
- if(r != 4) return 1;
-
- if ((mux->fec = dvb_mux_str2fec(fec)) == -1) return 1;
- if ((mux->constellation = dvb_mux_str2qam(qam)) == -1) return 1;
-
- return 0;
-}
-
-
-/* **************************************************************************
- * File processing
- * *************************************************************************/
-
-/*
- * Sorting
- */
-static int _net_cmp ( void *a, void *b )
-{
- return strcmp(((network_t*)a)->name, ((network_t*)b)->name);
-}
-static int _reg_cmp ( void *a, void *b )
-{
- return strcmp(((region_t*)a)->name, ((region_t*)b)->name);
-}
-
-/*
- * Create/Find region entry
- */
-static region_t *_muxes_region_create
- ( const char *type, const char *id, const char *desc )
-{
- region_t *reg;
- region_list_t *list = NULL;
- if (!strcmp(type, "dvb-s")) list = ®ions_DVBS;
- else if (!strcmp(type, "dvb-t")) list = ®ions_DVBT;
- else if (!strcmp(type, "dvb-c")) list = ®ions_DVBC;
- else if (!strcmp(type, "atsc")) list = ®ions_ATSC;
- if (!list) return NULL;
-
- LIST_FOREACH(reg, list, link) {
- if (!strcmp(reg->id, id)) break;
- }
-
- if (!reg) {
- reg = calloc(1, sizeof(region_t));
- reg->id = strdup(id);
- reg->name = strdup(desc);
- LIST_INSERT_SORTED(list, reg, link, _reg_cmp);
- }
-
- return reg;
-}
-
-/*
- * Process mux entry
- */
-static void _muxes_load_one ( network_t *net, const char *line )
-{
- int r = 1;
- mux_t *mux = calloc(1, sizeof(mux_t));
-
- switch (line[0]) {
- case 'A':
- r = _muxes_load_atsc(mux, line+1);
- break;
- case 'T':
- r = _muxes_load_dvbt(mux, line+1);
- break;
- case 'S':
- r = _muxes_load_dvbs(mux, line+1);
- break;
- case 'C':
- r = _muxes_load_dvbc(mux, line+1);
- break;
- }
-
- if (r) {
- free(mux);
- } else {
- LIST_INSERT_HEAD(&net->muxes, mux, link);
- }
-}
-
-/*
- * Process a file
- */
-static void _muxes_load_file
- ( const char *type, fb_dir *dir, const char *name )
-{
- int i;
- fb_file *fp;
- region_t *reg = NULL;
- network_t *net;
- char *str;
- char buf[256], buf2[256];
-
- fp = fb_open2(dir, name, 1, 0);
- if (!fp) return;
-
- /* Region */
- strncpy(buf, name, sizeof(buf));
- if (!strcmp(type, "dvb-s")) {
- reg = _muxes_region_create(type, "geo", "Geo-synchronous Orbit");
- } else {
- str = buf;
- while (*str) {
- if (*str == '-') {
- *str = '\0';
- reg = _muxes_region_create(type, buf, tldcode2longname(buf));
- *str = '-';
- break;
- }
- str++;
- }
- }
- if (!reg) {
- fb_close(fp);
- return;
- }
-
- /* Network */
- str = buf;
- while (*str) {
- if (!isalnum(*str)) *str = '_';
- str++;
- }
- *str = '\0';
- snprintf(buf2, sizeof(buf2), "%s_%s", type, buf);
- net = calloc(1, sizeof(network_t));
- net->id = strdup(buf2);
- net->name = strdup(buf);
- LIST_INSERT_SORTED(®->networks, net, link, _net_cmp);
-
- /* Process file */
- while (!fb_eof(fp)) {
-
- /* Get line */
- memset(buf, 0, sizeof(buf));
- if (!fb_gets(fp, buf, sizeof(buf) - 1)) break;
- i = 0;
- while (buf[i]) {
- if (buf[i] == '#')
- buf[i] = '\0';
- else
- i++;
- }
- while (i > 0 && buf[i-1] < 32) buf[--i] = 0;
-
- /* Process mux */
- switch (*buf) {
- case 'A':
- case 'C':
- case 'T':
- case 'S':
- _muxes_load_one(net, buf);
- default:
- break;
- }
- }
- fb_close(fp);
-}
-
-/*
- * Process directory
- *
- * Note: should we follow symlinks?
- */
-static void _muxes_load_dir
- ( const char *path, const char *type, int lvl )
-{
- char p[256];
- fb_dir *dir;
- fb_dirent *de;
-
- if (lvl >= 3) return;
- if (!(dir = fb_opendir(path))) return;
- lvl++;
-
- while ((de = fb_readdir(dir))) {
- if (*de->name == '.') continue;
- if (de->type == FB_DIR) {
- snprintf(p, sizeof(p), "%s/%s", path, de->name);
- _muxes_load_dir(p, de->name, lvl+1);
- } else if (type) {
- _muxes_load_file(type, dir, de->name);
- }
- }
-
- fb_closedir(dir);
-}
-
-/*
- * Initialise the mux list
- */
-void muxes_init ( void )
-{
- const char *path = config_get_muxconfpath();
- if (!path || !*path)
-#if ENABLE_DVBSCAN
- path = "data/dvb-scan";
-#else
- path = "/usr/share/dvb";
-#endif
- _muxes_load_dir(path, NULL, 0);
-}
diff --git a/src/muxes.h b/src/muxes.h
deleted file mode 100644
index eda77e08..00000000
--- a/src/muxes.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * tvheadend, intial mux list
- * Copyright (C) 2012 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 .
- */
-
-#ifndef __TVH_MUXES_H__
-#define __TVH_MUXES_H__
-
-typedef struct mux {
- LIST_ENTRY(mux) link;
- unsigned int freq;
- unsigned int symrate;
- short fec;
- short constellation;
- short bw;
- short fechp;
- short feclp;
- short tmode;
- short guard;
- short hierarchy;
- char polarisation;
-} mux_t;
-
-typedef struct network {
-const char *id;
-const char *name;
-LIST_ENTRY(network) link;
-LIST_HEAD(,mux) muxes;
-} network_t;
-
-typedef struct region {
-const char *id;
-const char *name;
-LIST_ENTRY(region) link;
-LIST_HEAD(,network) networks;
-} region_t;
-
-typedef LIST_HEAD(,region) region_list_t;
-extern region_list_t regions_DVBC;
-extern region_list_t regions_DVBT;
-extern region_list_t regions_DVBS;
-extern region_list_t regions_ATSC;
-
-void muxes_init ( void );
-
-#endif /* __TVH_MUXES_H__ */