]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
SAT>IP: Add possibility to define master/slave tuners
authorJaroslav Kysela <perex@perex.cz>
Sat, 19 Apr 2014 20:52:50 +0000 (22:52 +0200)
committerJaroslav Kysela <perex@perex.cz>
Mon, 5 May 2014 20:00:37 +0000 (22:00 +0200)
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
src/input/mpegts/linuxdvb/linuxdvb_adapter.c
src/input/mpegts/linuxdvb/linuxdvb_frontend.c
src/input/mpegts/mpegts_input.c
src/input/mpegts/mpegts_mux.c
src/input/mpegts/mpegts_mux_dvb.c
src/input/mpegts/mpegts_service.c
src/input/mpegts/satip/satip_frontend.c
src/input/mpegts/satip/satip_private.h
src/input/mpegts/satip/satip_satconf.c

index 24068b98600c491bea3e1075f9e85eb989109fe6..85493faaa4708c98e1c4275abb8d307f5295af42 100644 (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*);
index 74ba3c2685adac9595a2128154ca0889dde67bff..1ee9ba8e21b9cee36bafbe2bcaac47bd1b4c1bd0 100644 (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;
index 9cf81aa1964bb8b12280624d72be3943052e8dda..3d1d2f896c967015612cbd0cb8f7ca3be7a8e0ea 100644 (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;
index 2b3cd99074593e5d843ac7752b56e6cc67dc97ba..8a14cc846961d826af02f08ef4f83a368338d069 100644 (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;
 }
index a19ba78b68e8f841c0f57018f40c4985bc9f1833..a1c96d252c85fdf3625ca4c7358fcfd122022877 100644 (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;
index 094dd7e350de6ee459d7de5d5e80288356cbe1bd..29d799279b6f9923bd69ea5ae0ab917d2ea39b0b 100644 (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);
   }
 }
index 7a7dd8804412831bef973b146451db454ba3c347..15f4a9a2bbf9c4824eb53d7cb99ce0599a562757 100644 (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) {
index 430a0cfcbdbcbe67202a51f65c4875a0fb9c1bcf..fb894768b719e8bfe1311b6c211095ca92049e84 100644 (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
index a1051c2b51cbe944cfd10be164f05c43f0e72943..17be60fd845aa4bf6eea4916575f8763bbe35e5d 100644 (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;
 
index 20b47c68265766beb7474761ca775b4108469926..5e2a2b088fa218be8c80a7a0014a3c21e485b03b 100644 (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);