linuxdvb: added pre-defined mux configuration file support

This had been left out for too long and makes it awkward for novices
to setup the networks. The config is possibly not as nice as before where
it was presented as a tree. But this can be improved later.
This commit is contained in:
Adam Sutton 2013-09-19 22:17:02 +01:00
parent 3fdac50ad4
commit 7da7006af6
14 changed files with 753 additions and 461 deletions

View file

@ -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} += \

View file

@ -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 },
};

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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__ */

View file

@ -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

View file

@ -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);

View file

@ -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();

View file

@ -22,6 +22,7 @@
#include "linuxdvb_private.h"
#include "queue.h"
#include "settings.h"
#include "scanfile.h"
#include <sys/types.h>
#include <sys/ioctl.h>
@ -30,6 +31,10 @@
#include <dirent.h>
#include <fcntl.h>
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;

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "tvheadend.h"
#include "../dvb.h"
#include "filebundle.h"
#include "config2.h"
#include "scanfile.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <libgen.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
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(&reg->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;
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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__ */

View file

@ -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 */

View file

@ -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);

View file

@ -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"

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <libgen.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#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 = &regions_DVBS;
else if (!strcmp(type, "dvb-t")) list = &regions_DVBT;
else if (!strcmp(type, "dvb-c")) list = &regions_DVBC;
else if (!strcmp(type, "atsc")) list = &regions_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(&reg->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);
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#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__ */