From cfe878319e7e348de11642d673e94b513303b3e1 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sat, 19 Apr 2014 22:52:50 +0200 Subject: [PATCH] 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. --- src/input/mpegts.h | 2 +- src/input/mpegts/linuxdvb/linuxdvb_adapter.c | 2 +- src/input/mpegts/linuxdvb/linuxdvb_frontend.c | 2 +- src/input/mpegts/mpegts_input.c | 2 +- src/input/mpegts/mpegts_mux.c | 4 +- src/input/mpegts/mpegts_mux_dvb.c | 2 +- src/input/mpegts/mpegts_service.c | 2 +- src/input/mpegts/satip/satip_frontend.c | 178 +++++++++++++++++- src/input/mpegts/satip/satip_private.h | 1 + src/input/mpegts/satip/satip_satconf.c | 11 +- 10 files changed, 188 insertions(+), 18 deletions(-) diff --git a/src/input/mpegts.h b/src/input/mpegts.h index 24068b98..85493faa 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -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*); diff --git a/src/input/mpegts/linuxdvb/linuxdvb_adapter.c b/src/input/mpegts/linuxdvb/linuxdvb_adapter.c index 74ba3c26..1ee9ba8e 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_adapter.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_adapter.c @@ -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; diff --git a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c index 9cf81aa1..3d1d2f89 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c @@ -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; diff --git a/src/input/mpegts/mpegts_input.c b/src/input/mpegts/mpegts_input.c index 2b3cd990..8a14cc84 100644 --- a/src/input/mpegts/mpegts_input.c +++ b/src/input/mpegts/mpegts_input.c @@ -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; } diff --git a/src/input/mpegts/mpegts_mux.c b/src/input/mpegts/mpegts_mux.c index a19ba78b..a1c96d25 100644 --- a/src/input/mpegts/mpegts_mux.c +++ b/src/input/mpegts/mpegts_mux.c @@ -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; diff --git a/src/input/mpegts/mpegts_mux_dvb.c b/src/input/mpegts/mpegts_mux_dvb.c index 094dd7e3..29d79927 100644 --- a/src/input/mpegts/mpegts_mux_dvb.c +++ b/src/input/mpegts/mpegts_mux_dvb.c @@ -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); } } diff --git a/src/input/mpegts/mpegts_service.c b/src/input/mpegts/mpegts_service.c index 7a7dd880..15f4a9a2 100644 --- a/src/input/mpegts/mpegts_service.c +++ b/src/input/mpegts/mpegts_service.c @@ -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) { diff --git a/src/input/mpegts/satip/satip_frontend.c b/src/input/mpegts/satip/satip_frontend.c index 430a0cfc..fb894768 100644 --- a/src/input/mpegts/satip/satip_frontend.c +++ b/src/input/mpegts/satip/satip_frontend.c @@ -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 diff --git a/src/input/mpegts/satip/satip_private.h b/src/input/mpegts/satip/satip_private.h index a1051c2b..17be60fd 100644 --- a/src/input/mpegts/satip/satip_private.h +++ b/src/input/mpegts/satip/satip_private.h @@ -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; diff --git a/src/input/mpegts/satip/satip_satconf.c b/src/input/mpegts/satip/satip_satconf.c index 20b47c68..5e2a2b08 100644 --- a/src/input/mpegts/satip/satip_satconf.c +++ b/src/input/mpegts/satip/satip_satconf.c @@ -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);