SAT>IP: Add possibility to define master/slave tuners

The signal from the standard universal LNB can be split using
a simple coaxial splitter (no multiswitch) to several outputs.
In this case, the position, the polarization and low-high band
settings must be equal.

This code adds the master/slave configuration option in the
tuner settings and does the tuner arbitration to preserve
above settings.

Ideally, this arbitration and configuration may be moved to
the generic dvbs input class in future, because all dvb-s
adapters can be wired in this way, but it's more complicated.
This commit is contained in:
Jaroslav Kysela 2014-04-19 22:52:50 +02:00
parent b8f2fa8461
commit cfe878319e
10 changed files with 188 additions and 18 deletions

View file

@ -505,7 +505,7 @@ struct mpegts_input
/*
* Functions
*/
int (*mi_is_enabled) (mpegts_input_t*);
int (*mi_is_enabled) (mpegts_input_t*, mpegts_mux_t *mm);
void (*mi_enabled_updated)(mpegts_input_t*);
void (*mi_display_name) (mpegts_input_t*, char *buf, size_t len);
int (*mi_is_free) (mpegts_input_t*);

View file

@ -119,7 +119,7 @@ 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))
if (lfe->mi_is_enabled((mpegts_input_t*)lfe, NULL))
return 1;
}
return 0;

View file

@ -252,7 +252,7 @@ linuxdvb_frontend_get_grace ( mpegts_input_t *mi, mpegts_mux_t *mm )
}
static int
linuxdvb_frontend_is_enabled ( mpegts_input_t *mi )
linuxdvb_frontend_is_enabled ( mpegts_input_t *mi, mpegts_mux_t *mm )
{
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
if (lfe->lfe_fe_path == NULL) return 0;

View file

@ -162,7 +162,7 @@ const idclass_t mpegts_input_class =
* *************************************************************************/
static int
mpegts_input_is_enabled ( mpegts_input_t *mi )
mpegts_input_is_enabled ( mpegts_input_t *mi, mpegts_mux_t *mm )
{
return mi->mi_enabled;
}

View file

@ -440,7 +440,7 @@ mpegts_mux_start
/* First pass - free only */
if (!pass) {
int e = mmi->mmi_input->mi_is_enabled(mmi->mmi_input);
int e = mmi->mmi_input->mi_is_enabled(mmi->mmi_input, mm);
int f = mmi->mmi_input->mi_is_free(mmi->mmi_input);
tvhtrace("mpegts", "%s - enabled %d free %d", buf, e, f);
if (e) enabled = 1;
@ -457,7 +457,7 @@ mpegts_mux_start
} else {
/* Enabled, valid and lower weight */
if (mmi->mmi_input->mi_is_enabled(mmi->mmi_input) &&
if (mmi->mmi_input->mi_is_enabled(mmi->mmi_input, mm) &&
!mmi->mmi_tune_failed &&
(weight > mmi->mmi_input->mi_get_weight(mmi->mmi_input))) {
tune = mmi;

View file

@ -592,7 +592,7 @@ dvb_mux_create_instances ( mpegts_mux_t *mm )
mpegts_network_link_t *mnl;
LIST_FOREACH(mnl, &mm->mm_network->mn_inputs, mnl_mn_link) {
mpegts_input_t *mi = mnl->mnl_input;
if (mi->mi_is_enabled(mi))
if (mi->mi_is_enabled(mi, mm))
mi->mi_create_mux_instance(mi, mm);
}
}

View file

@ -189,7 +189,7 @@ mpegts_service_enlist(service_t *t, struct service_instance_list *sil)
if (mmi->mmi_tune_failed)
continue;
if (!mmi->mmi_input->mi_is_enabled(mmi->mmi_input)) continue;
if (!mmi->mmi_input->mi_is_enabled(mmi->mmi_input, mmi->mmi_mux)) continue;
/* Set weight to -1 (forced) for already active mux */
if (mmi->mmi_mux->mm_active == mmi) {

View file

@ -28,6 +28,20 @@ static int
satip_frontend_tune1
( satip_frontend_t *lfe, mpegts_mux_instance_t *mmi );
/*
*
*/
static satip_frontend_t *
satip_frontend_find_by_number( satip_device_t *sd, int num )
{
satip_frontend_t *lfe;
TAILQ_FOREACH(lfe, &sd->sd_frontends, sf_link)
if (lfe->sf_number == num)
return lfe;
return NULL;
}
/* **************************************************************************
* Class definition
* *************************************************************************/
@ -147,6 +161,46 @@ satip_frontend_dvbs_class_positions_set ( void *self, const void *val )
return 0;
}
static int
satip_frontend_dvbs_class_master_set ( void *self, const void *val )
{
satip_frontend_t *lfe = self;
satip_frontend_t *lfe2 = NULL;
int num = *(int *)val, pos = 0;
if (num) {
TAILQ_FOREACH(lfe2, &lfe->sf_device->sd_frontends, sf_link)
if (lfe2 != lfe && lfe2->sf_type == lfe->sf_type)
if (++pos == num) {
num = lfe2->sf_number;
break;
}
}
if (lfe2 == NULL)
num = 0;
else if (lfe2->sf_master)
num = lfe2->sf_master;
if (lfe->sf_master != num) {
lfe->sf_master = num;
satip_device_destroy_later(lfe->sf_device, 100);
return 1;
}
return 0;
}
static htsmsg_t *
satip_frontend_dvbs_class_master_enum( void * self )
{
satip_frontend_t *lfe = self, *lfe2;
satip_device_t *sd = lfe->sf_device;
htsmsg_t *m = htsmsg_create_list();
htsmsg_add_str(m, NULL, "This Tuner");
TAILQ_FOREACH(lfe2, &sd->sd_frontends, sf_link)
if (lfe2 != lfe && lfe2->sf_type == lfe->sf_type)
htsmsg_add_str(m, NULL, lfe2->mi_name);
return m;
}
const idclass_t satip_frontend_dvbs_class =
{
.ic_super = &satip_frontend_class,
@ -163,6 +217,36 @@ const idclass_t satip_frontend_dvbs_class =
.off = offsetof(satip_frontend_t, sf_positions),
.def.i = 4
},
{
.type = PT_INT,
.id = "fe_master",
.name = "Master Tuner",
.set = satip_frontend_dvbs_class_master_set,
.list = satip_frontend_dvbs_class_master_enum,
.off = offsetof(satip_frontend_t, sf_master),
},
{
.id = "networks",
.type = PT_NONE,
},
{}
}
};
const idclass_t satip_frontend_dvbs_slave_class =
{
.ic_super = &satip_frontend_class,
.ic_class = "satip_frontend_dvbs",
.ic_caption = "SAT>IP DVB-S Slave Frontend",
.ic_properties = (const property_t[]){
{
.type = PT_INT,
.id = "fe_master",
.name = "Master Tuner",
.set = satip_frontend_dvbs_class_master_set,
.list = satip_frontend_dvbs_class_master_enum,
.off = offsetof(satip_frontend_t, sf_master),
},
{
.id = "networks",
.type = PT_NONE,
@ -227,10 +311,56 @@ satip_frontend_get_grace ( mpegts_input_t *mi, mpegts_mux_t *mm )
}
static int
satip_frontend_is_enabled ( mpegts_input_t *mi )
satip_frontend_match_satcfg ( satip_frontend_t *lfe2, mpegts_mux_t *mm2 )
{
mpegts_mux_t *mm1;
dvb_mux_conf_t *mc1, *mc2;
int position, high1, high2;
if (lfe2->sf_mmi == NULL)
return 0;
mm1 = lfe2->sf_mmi->mmi_mux;
position = satip_satconf_get_position(lfe2, mm2);
if (lfe2->sf_position != position)
return 0;
mc1 = &((dvb_mux_t *)mm1)->lm_tuning;
mc2 = &((dvb_mux_t *)mm2)->lm_tuning;
if (mc1->dmc_fe_type != DVB_TYPE_S || mc2->dmc_fe_type != DVB_TYPE_S)
return 0;
if (mc1->u.dmc_fe_qpsk.polarisation != mc2->u.dmc_fe_qpsk.polarisation)
return 0;
high1 = mc1->dmc_fe_freq > 11700000;
high2 = mc2->dmc_fe_freq > 11700000;
if (high1 != high2)
return 0;
return 1;
}
static int
satip_frontend_is_enabled ( mpegts_input_t *mi, mpegts_mux_t *mm )
{
satip_frontend_t *lfe = (satip_frontend_t*)mi;
satip_frontend_t *lfe2;
lock_assert(&global_lock);
if (!lfe->mi_enabled) return 0;
if (lfe->sf_type != DVB_TYPE_S) return 1;
/* check if any "blocking" tuner is running */
TAILQ_FOREACH(lfe2, &lfe->sf_device->sd_frontends, sf_link) {
if (lfe2 == lfe) continue;
if (lfe2->sf_type != DVB_TYPE_S) continue;
if (lfe->sf_master == lfe2->sf_number) {
if (!lfe2->sf_running)
return 0; /* master must be running */
return satip_frontend_match_satcfg(lfe2, mm);
}
if (lfe2->sf_master == lfe->sf_number && lfe2->sf_running) {
if (lfe2->sf_mmi == NULL)
return 0;
return satip_frontend_match_satcfg(lfe2, mm);
}
}
return 1;
}
@ -727,7 +857,7 @@ satip_frontend_input_thread ( void *aux )
#define RTP_PKTS 64
#define RTP_PKT_SIZE 1472 /* this is maximum UDP payload (standard ethernet) */
#define HTTP_CMD_NONE 9874
satip_frontend_t *lfe = aux;
satip_frontend_t *lfe = aux, *lfe2;
mpegts_mux_instance_t *mmi = lfe->sf_mmi;
http_client_t *rtsp;
dvb_mux_t *lm;
@ -775,8 +905,14 @@ satip_frontend_input_thread ( void *aux )
tvhpoll_add(efd, ev, 4);
rtsp->hc_efd = efd;
pos = lfe->sf_position;
if (lfe->sf_master) {
lfe2 = satip_frontend_find_by_number(lfe->sf_device, lfe->sf_master);
if (lfe2)
pos = lfe2->sf_position;
}
r = satip_rtsp_setup(rtsp,
lfe->sf_position, lfe->sf_number,
pos, lfe->sf_number,
lfe->sf_rtp_port, &lm->lm_tuning,
lfe->sf_device->sd_pids0);
if (r < 0) {
@ -1064,8 +1200,9 @@ satip_frontend_create
{
const idclass_t *idc;
const char *uuid = NULL, *override = NULL;
char id[12], lname[256];
char id[16], lname[256];
satip_frontend_t *lfe;
uint32_t master = 0;
int i;
/* Override type */
@ -1080,6 +1217,14 @@ satip_frontend_create
override = NULL;
}
}
/* Tuner slave */
snprintf(id, sizeof(id), "master for #%d", num);
if (conf && type == DVB_TYPE_S) {
if (htsmsg_get_u32(conf, id, &master))
master = 0;
if (master == num)
master = 0;
}
/* Internal config ID */
snprintf(id, sizeof(id), "%s #%d", dvb_type2str(type), num);
if (conf)
@ -1089,7 +1234,8 @@ satip_frontend_create
/* Class */
if (type == DVB_TYPE_S)
idc = &satip_frontend_dvbs_class;
idc = master ? &satip_frontend_dvbs_slave_class :
&satip_frontend_dvbs_class;
else if (type == DVB_TYPE_T)
idc = &satip_frontend_dvbt_class;
else if (type == DVB_TYPE_C)
@ -1107,6 +1253,7 @@ satip_frontend_create
lfe->sf_number = num;
lfe->sf_type = type;
lfe->sf_type_t2 = t2;
lfe->sf_master = master;
lfe->sf_type_override = override ? strdup(override) : NULL;
TAILQ_INIT(&lfe->sf_satconf);
pthread_mutex_init(&lfe->sf_dvr_lock, NULL);
@ -1146,16 +1293,28 @@ satip_frontend_create
TAILQ_INSERT_TAIL(&sd->sd_frontends, lfe, sf_link);
/* Create satconf */
if (lfe->sf_type == DVB_TYPE_S)
if (lfe->sf_type == DVB_TYPE_S && master == 0)
satip_satconf_create(lfe, conf);
/* Slave networks update */
if (master) {
satip_frontend_t *lfe2 = satip_frontend_find_by_number(sd, master);
if (lfe2) {
htsmsg_t *l = (htsmsg_t *)mpegts_input_class_network_get(lfe2);
if (l) {
mpegts_input_class_network_set(lfe, l);
htsmsg_destroy(l);
}
}
}
return lfe;
}
void
satip_frontend_save ( satip_frontend_t *lfe, htsmsg_t *fe )
{
char id[12];
char id[16];
htsmsg_t *m = htsmsg_create_map();
/* Save frontend */
@ -1166,6 +1325,7 @@ satip_frontend_save ( satip_frontend_t *lfe, htsmsg_t *fe )
htsmsg_delete_field(m, "networks");
}
htsmsg_delete_field(m, "fe_override");
htsmsg_delete_field(m, "fe_master");
/* Add to list */
snprintf(id, sizeof(id), "%s #%d", dvb_type2str(lfe->sf_type), lfe->sf_number);
@ -1174,6 +1334,10 @@ satip_frontend_save ( satip_frontend_t *lfe, htsmsg_t *fe )
snprintf(id, sizeof(id), "override #%d", lfe->sf_number);
htsmsg_add_str(fe, id, lfe->sf_type_override);
}
if (lfe->sf_master) {
snprintf(id, sizeof(id), "master for #%d", lfe->sf_number);
htsmsg_add_u32(fe, id, lfe->sf_master);
}
}
void

View file

@ -98,6 +98,7 @@ struct satip_frontend
dvb_fe_type_t sf_type;
int sf_type_t2;
char *sf_type_override;
int sf_master;
int sf_udp_rtp_port;
int sf_fullmux;

View file

@ -41,7 +41,7 @@ satip_satconf_get_priority
( satip_frontend_t *lfe, mpegts_mux_t *mm )
{
satip_satconf_t *sfc = satip_satconf_find_ele(lfe, mm);
return sfc->sfc_priority;
return sfc ? sfc->sfc_priority : 0;
}
int
@ -49,7 +49,7 @@ satip_satconf_get_position
( satip_frontend_t *lfe, mpegts_mux_t *mm )
{
satip_satconf_t *sfc = satip_satconf_find_ele(lfe, mm);
return sfc->sfc_position;
return sfc ? sfc->sfc_position : 0;
}
/* **************************************************************************
@ -94,7 +94,7 @@ satip_satconf_class_network_set( void *o, const void *p )
sfc->sfc_networks = n;
/* update the input (frontend) network list */
htsmsg_t *l = htsmsg_create_list();
satip_frontend_t *lfe = sfc->sfc_lfe;
satip_frontend_t *lfe = sfc->sfc_lfe, *lfe2;
satip_satconf_t *sfc2;
TAILQ_FOREACH(sfc2, &lfe->sf_satconf, sfc_link) {
for (i = 0; i < sfc2->sfc_networks->is_count; i++)
@ -102,6 +102,11 @@ satip_satconf_class_network_set( void *o, const void *p )
idnode_uuid_as_str(sfc2->sfc_networks->is_array[i]));
}
mpegts_input_class_network_set(lfe, l);
/* update the slave tuners, too */
TAILQ_FOREACH(lfe2, &lfe->sf_device->sd_frontends, sf_link)
if (lfe2->sf_number != lfe->sf_number &&
lfe2->sf_master == lfe->sf_number)
mpegts_input_class_network_set(lfe2, l);
htsmsg_destroy(l);
} else {
idnode_set_free(n);