293 lines
8.3 KiB
C
293 lines
8.3 KiB
C
/*
|
|
* Tvheadend - Linux DVB Network
|
|
*
|
|
* 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/>.
|
|
*/
|
|
|
|
#include "tvheadend.h"
|
|
#include "input.h"
|
|
#include "linuxdvb_private.h"
|
|
#include "queue.h"
|
|
#include "settings.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
|
|
/* ****************************************************************************
|
|
* Class definition
|
|
* ***************************************************************************/
|
|
|
|
extern const idclass_t mpegts_network_class;
|
|
|
|
static void
|
|
linuxdvb_network_class_delete ( idnode_t *in )
|
|
{
|
|
mpegts_network_t *mn = (mpegts_network_t*)in;
|
|
|
|
/* remove config */
|
|
hts_settings_remove("input/linuxdvb/networks/%s",
|
|
idnode_uuid_as_str(in));
|
|
|
|
/* Parent delete */
|
|
mpegts_network_delete(mn);
|
|
}
|
|
|
|
const idclass_t linuxdvb_network_class =
|
|
{
|
|
.ic_super = &mpegts_network_class,
|
|
.ic_class = "linuxdvb_network",
|
|
.ic_caption = "LinuxDVB Network",
|
|
.ic_delete = linuxdvb_network_class_delete,
|
|
.ic_properties = (const property_t[]){
|
|
{}
|
|
}
|
|
};
|
|
|
|
const idclass_t linuxdvb_network_dvbt_class =
|
|
{
|
|
.ic_super = &linuxdvb_network_class,
|
|
.ic_class = "linuxdvb_network_dvbt",
|
|
.ic_caption = "DVB-T Network",
|
|
.ic_properties = (const property_t[]) {
|
|
{}
|
|
}
|
|
};
|
|
|
|
const idclass_t linuxdvb_network_dvbc_class =
|
|
{
|
|
.ic_super = &linuxdvb_network_class,
|
|
.ic_class = "linuxdvb_network_dvbc",
|
|
.ic_caption = "DVB-C Network",
|
|
.ic_properties = (const property_t[]) {
|
|
{}
|
|
}
|
|
};
|
|
|
|
const idclass_t linuxdvb_network_dvbs_class =
|
|
{
|
|
.ic_super = &linuxdvb_network_class,
|
|
.ic_class = "linuxdvb_network_dvbs",
|
|
.ic_caption = "DVB-S Network",
|
|
.ic_properties = (const property_t[]) {
|
|
{}
|
|
}
|
|
};
|
|
|
|
const idclass_t linuxdvb_network_atsc_class =
|
|
{
|
|
.ic_super = &linuxdvb_network_class,
|
|
.ic_class = "linuxdvb_network_atsc",
|
|
.ic_caption = "ATSC Network",
|
|
.ic_properties = (const property_t[]) {
|
|
{}
|
|
}
|
|
};
|
|
|
|
/* ****************************************************************************
|
|
* Class methods
|
|
* ***************************************************************************/
|
|
|
|
static mpegts_mux_t *
|
|
linuxdvb_network_find_mux
|
|
( linuxdvb_network_t *ln, dvb_mux_conf_t *dmc )
|
|
{
|
|
#define LINUXDVB_FREQ_TOL 2000 // TODO: fix this!
|
|
mpegts_mux_t *mm;
|
|
LIST_FOREACH(mm, &ln->mn_muxes, mm_network_link) {
|
|
linuxdvb_mux_t *lm = (linuxdvb_mux_t*)mm;
|
|
if (abs(lm->lm_tuning.dmc_fe_params.frequency
|
|
- dmc->dmc_fe_params.frequency) > LINUXDVB_FREQ_TOL) continue;
|
|
if (lm->lm_tuning.dmc_fe_polarisation != dmc->dmc_fe_polarisation) continue;
|
|
break;
|
|
}
|
|
return mm;
|
|
}
|
|
|
|
static void
|
|
linuxdvb_network_config_save ( mpegts_network_t *mn )
|
|
{
|
|
htsmsg_t *c = htsmsg_create_map();
|
|
idnode_save(&mn->mn_id, c);
|
|
htsmsg_add_str(c, "class", mn->mn_id.in_class->ic_class);
|
|
hts_settings_save(c, "input/linuxdvb/networks/%s/config",
|
|
idnode_uuid_as_str(&mn->mn_id));
|
|
htsmsg_destroy(c);
|
|
}
|
|
|
|
static mpegts_mux_t *
|
|
linuxdvb_network_create_mux
|
|
( mpegts_mux_t *mm, uint16_t onid, uint16_t tsid, dvb_mux_conf_t *dmc )
|
|
{
|
|
// TODO: should we have a mux_find wrapper?
|
|
linuxdvb_network_t *ln = (linuxdvb_network_t*)mm->mm_network;
|
|
mm = linuxdvb_network_find_mux(ln, dmc);
|
|
if (!mm) {
|
|
mm = (mpegts_mux_t*)linuxdvb_mux_create0(ln, onid, tsid, dmc, NULL, NULL);
|
|
if (mm)
|
|
mm->mm_config_save(mm);
|
|
}
|
|
return mm;
|
|
}
|
|
|
|
static mpegts_service_t *
|
|
linuxdvb_network_create_service
|
|
( mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid )
|
|
{
|
|
return linuxdvb_service_create0((linuxdvb_mux_t*)mm, sid,
|
|
pmt_pid, NULL, NULL);
|
|
}
|
|
|
|
static const idclass_t *
|
|
linuxdvb_network_mux_class
|
|
( mpegts_network_t *mn )
|
|
{
|
|
extern const idclass_t linuxdvb_mux_dvbt_class;
|
|
extern const idclass_t linuxdvb_mux_dvbc_class;
|
|
extern const idclass_t linuxdvb_mux_dvbs_class;
|
|
extern const idclass_t linuxdvb_mux_atsc_class;
|
|
if (idnode_is_instance(&mn->mn_id, &linuxdvb_network_dvbt_class))
|
|
return &linuxdvb_mux_dvbt_class;
|
|
if (idnode_is_instance(&mn->mn_id, &linuxdvb_network_dvbc_class))
|
|
return &linuxdvb_mux_dvbc_class;
|
|
if (idnode_is_instance(&mn->mn_id, &linuxdvb_network_dvbs_class))
|
|
return &linuxdvb_mux_dvbs_class;
|
|
if (idnode_is_instance(&mn->mn_id, &linuxdvb_network_atsc_class))
|
|
return &linuxdvb_mux_atsc_class;
|
|
return NULL;
|
|
}
|
|
|
|
static mpegts_mux_t *
|
|
linuxdvb_network_mux_create2
|
|
( mpegts_network_t *mn, htsmsg_t *conf )
|
|
{
|
|
linuxdvb_network_t *ln = (linuxdvb_network_t*)mn;
|
|
return (mpegts_mux_t*)
|
|
linuxdvb_mux_create0(ln, MPEGTS_ONID_NONE, MPEGTS_TSID_NONE,
|
|
NULL, NULL, conf);
|
|
}
|
|
|
|
/* ****************************************************************************
|
|
* Creation/Config
|
|
* ***************************************************************************/
|
|
|
|
linuxdvb_network_t *
|
|
linuxdvb_network_create0
|
|
( const char *uuid, const idclass_t *idc, htsmsg_t *conf )
|
|
{
|
|
linuxdvb_network_t *ln;
|
|
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;
|
|
|
|
if (idc == &linuxdvb_network_dvbt_class)
|
|
ln->ln_type = FE_OFDM;
|
|
else if (idc == &linuxdvb_network_dvbc_class)
|
|
ln->ln_type = FE_QAM;
|
|
else if (idc == &linuxdvb_network_dvbs_class)
|
|
ln->ln_type = FE_QPSK;
|
|
else
|
|
ln->ln_type = FE_ATSC;
|
|
|
|
/* Callbacks */
|
|
ln->mn_create_mux = linuxdvb_network_create_mux;
|
|
ln->mn_create_service = linuxdvb_network_create_service;
|
|
ln->mn_config_save = linuxdvb_network_config_save;
|
|
ln->mn_mux_class = linuxdvb_network_mux_class;
|
|
ln->mn_mux_create2 = linuxdvb_network_mux_create2;
|
|
|
|
/* No config */
|
|
if (!conf)
|
|
return ln;
|
|
|
|
/* Load muxes */
|
|
if ((c = hts_settings_load_r(1, "input/linuxdvb/networks/%s/muxes", uuid))) {
|
|
HTSMSG_FOREACH(f, c) {
|
|
if (!(e = htsmsg_get_map_by_field(f))) continue;
|
|
if (!(e = htsmsg_get_map(e, "config"))) continue;
|
|
(void)linuxdvb_mux_create1(ln, f->hmf_name, e);
|
|
}
|
|
}
|
|
|
|
return ln;
|
|
}
|
|
|
|
static mpegts_network_t *
|
|
linuxdvb_network_builder
|
|
( const idclass_t *idc, htsmsg_t *conf )
|
|
{
|
|
return (mpegts_network_t*)linuxdvb_network_create0(NULL, idc, conf);
|
|
}
|
|
|
|
void linuxdvb_network_init ( void )
|
|
{
|
|
htsmsg_t *c, *e;
|
|
htsmsg_field_t *f;
|
|
const char *s;
|
|
int i;
|
|
|
|
const idclass_t* classes[] = {
|
|
&linuxdvb_network_dvbt_class,
|
|
&linuxdvb_network_dvbc_class,
|
|
&linuxdvb_network_dvbs_class,
|
|
&linuxdvb_network_atsc_class,
|
|
};
|
|
|
|
/* Register class builders */
|
|
for (i = 0; i < ARRAY_SIZE(classes); i++)
|
|
mpegts_network_register_builder(classes[i], linuxdvb_network_builder);
|
|
|
|
/* Load settings */
|
|
if (!(c = hts_settings_load_r(1, "input/linuxdvb/networks")))
|
|
return;
|
|
|
|
HTSMSG_FOREACH(f, c) {
|
|
if (!(e = htsmsg_get_map_by_field(f))) continue;
|
|
if (!(e = htsmsg_get_map(e, "config"))) continue;
|
|
if (!(s = htsmsg_get_str(e, "class"))) continue;
|
|
for (i = 0; i < ARRAY_SIZE(classes); i++) {
|
|
if(!strcmp(classes[i]->ic_class, s)) {
|
|
(void)linuxdvb_network_create0(f->hmf_name, classes[i], e);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
htsmsg_destroy(c);
|
|
}
|
|
|
|
/* ****************************************************************************
|
|
* Search
|
|
* ***************************************************************************/
|
|
|
|
linuxdvb_network_t*
|
|
linuxdvb_network_find_by_uuid(const char *uuid)
|
|
{
|
|
idnode_t *in = idnode_find(uuid, &linuxdvb_network_class);
|
|
return (linuxdvb_network_t*)in;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* Editor Configuration
|
|
*
|
|
* vim:sts=2:ts=2:sw=2:et
|
|
*****************************************************************************/
|