]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Add logical network support for CableCARD networks
authorRobert Cameron <rob@rpcameron.net>
Thu, 10 May 2018 17:41:31 +0000 (10:41 -0700)
committerperexg <perex@perex.cz>
Thu, 7 Jun 2018 16:17:44 +0000 (18:17 +0200)
src/input/mpegts/dvb.h
src/input/mpegts/dvb_support.c
src/input/mpegts/mpegts_dvb.h
src/input/mpegts/mpegts_mux_dvb.c
src/input/mpegts/mpegts_network_dvb.c

index 317dff8df3b89d558ea01da3c2c828507be63f12..db87594d4dbc1607469aca475f0b3b303ad0f99f 100644 (file)
@@ -421,6 +421,7 @@ typedef enum dvb_fe_type {
   DVB_TYPE_S,                  /* satellite */
   DVB_TYPE_ATSC_T,             /* terrestrial - north america */
   DVB_TYPE_ATSC_C,             /* cable - north america */
+  DVB_TYPE_CABLECARD, /* CableCARD - North America */
   DVB_TYPE_ISDB_T,              /* terrestrial - japan, brazil */
   DVB_TYPE_ISDB_C,              /* cable - japan, brazil */
   DVB_TYPE_ISDB_S,              /* satellite - japan, brazil */
@@ -615,6 +616,12 @@ typedef struct dvb_isdbt_config {
   } layers[3];
 } dvb_isdbt_config_t;
 
+typedef struct dvb_fe_vchan {
+  uint32_t  num;
+  uint16_t  minor;
+  char     *name;
+} dvb_fe_vchan_t;
+
 typedef struct dvb_mux_conf
 {
   dvb_fe_type_t               dmc_fe_type;
@@ -633,6 +640,7 @@ typedef struct dvb_mux_conf
     dvb_ofdm_config_t         dmc_fe_ofdm;
     dvb_isdbt_config_t        dmc_fe_isdbt;
   } u;
+  dvb_fe_vchan_t              dmc_fe_vchan;
 
   // For scan file configurations
   LIST_ENTRY(dvb_mux_conf)    dmc_link;
index ab646a375a2a6a104a53d5f9e064f28c8eb53c9d..7a90ae6778160556827ee98be64f0138f1c26b3d 100644 (file)
@@ -683,6 +683,7 @@ const static struct strtab delsystab[] = {
   { "DVBC/ANNEX_A", DVB_SYS_DVBC_ANNEX_A },
   { "DVBC_ANNEX_A", DVB_SYS_DVBC_ANNEX_A },
   { "ATSC-C",       DVB_SYS_DVBC_ANNEX_B },
+  { "CableCARD",    DVB_SYS_DVBC_ANNEX_B },
   { "DVBC/ANNEX_B", DVB_SYS_DVBC_ANNEX_B },
   { "DVBC_ANNEX_B", DVB_SYS_DVBC_ANNEX_B },
   { "DVB-C/ANNEX-C",DVB_SYS_DVBC_ANNEX_C },
@@ -738,6 +739,8 @@ dvb_delsys2type ( mpegts_network_t *ln, dvb_fe_delivery_system_t delsys )
     case DVB_SYS_DVBC_ANNEX_B:
       if (ln && idnode_is_instance(&ln->mn_id, &dvb_network_dvbc_class))
         return DVB_TYPE_C;
+      if (ln && idnode_is_instance(&ln->mn_id, &dvb_network_cablecard_class))
+        return DVB_TYPE_CABLECARD;
       else
         return DVB_TYPE_ATSC_C;
     case DVB_SYS_ISDBT:
@@ -946,24 +949,25 @@ const static struct strtab poltab[] = {
 dvb_str2val(pol);
 
 const static struct strtab typetab[] = {
-  {"DVB-T",  DVB_TYPE_T},
-  {"DVB-C",  DVB_TYPE_C},
-  {"DVB-S",  DVB_TYPE_S},
-  {"ATSC-T", DVB_TYPE_ATSC_T},
-  {"ATSC-C", DVB_TYPE_ATSC_C},
-  {"ISDB-T", DVB_TYPE_ISDB_T},
-  {"ISDB-C", DVB_TYPE_ISDB_C},
-  {"ISDB-S", DVB_TYPE_ISDB_S},
-  {"DAB",    DVB_TYPE_DAB},
-  {"DVBT",   DVB_TYPE_T},
-  {"DVBC",   DVB_TYPE_C},
-  {"DVBS",   DVB_TYPE_S},
-  {"ATSC",   DVB_TYPE_ATSC_T},
-  {"ATSCT",  DVB_TYPE_ATSC_T},
-  {"ATSCC",  DVB_TYPE_ATSC_C},
-  {"ISDBT",  DVB_TYPE_ISDB_T},
-  {"ISDBC",  DVB_TYPE_ISDB_C},
-  {"ISDBS",  DVB_TYPE_ISDB_S}
+  {"DVB-T",     DVB_TYPE_T},
+  {"DVB-C",     DVB_TYPE_C},
+  {"DVB-S",     DVB_TYPE_S},
+  {"ATSC-T",    DVB_TYPE_ATSC_T},
+  {"ATSC-C",    DVB_TYPE_ATSC_C},
+  {"CableCARD", DVB_TYPE_CABLECARD},
+  {"ISDB-T",    DVB_TYPE_ISDB_T},
+  {"ISDB-C",    DVB_TYPE_ISDB_C},
+  {"ISDB-S",    DVB_TYPE_ISDB_S},
+  {"DAB",       DVB_TYPE_DAB},
+  {"DVBT",      DVB_TYPE_T},
+  {"DVBC",      DVB_TYPE_C},
+  {"DVBS",      DVB_TYPE_S},
+  {"ATSC",      DVB_TYPE_ATSC_T},
+  {"ATSCT",     DVB_TYPE_ATSC_T},
+  {"ATSCC",     DVB_TYPE_ATSC_C},
+  {"ISDBT",     DVB_TYPE_ISDB_T},
+  {"ISDBC",     DVB_TYPE_ISDB_C},
+  {"ISDBS",     DVB_TYPE_ISDB_S}
 };
 dvb_str2val(type);
 
@@ -1081,6 +1085,20 @@ dvb_mux_conf_str_atsc_t ( dvb_mux_conf_t *dmc, char *buf, size_t bufsize )
            dvb_qam2str(dmc->dmc_fe_modulation));
 }
 
+static int
+dvb_mux_conf_str_cablecard(dvb_mux_conf_t *dmc, char *buf, size_t bufsize)
+{
+  if (!dmc->dmc_fe_vchan.minor)
+    return snprintf(buf, bufsize, "%s channel %u",
+      dvb_type2str(dmc->dmc_fe_type),
+      dmc->dmc_fe_vchan.num);
+  else
+    return snprintf(buf, bufsize, "%s channel %u.%u",
+      dvb_type2str(dmc->dmc_fe_type),
+      dmc->dmc_fe_vchan.num,
+      dmc->dmc_fe_vchan.minor);
+}
+
 static int
 dvb_mux_conf_str_isdb_t ( dvb_mux_conf_t *dmc, char *buf, size_t bufsize )
 {
@@ -1124,6 +1142,8 @@ dvb_mux_conf_str ( dvb_mux_conf_t *dmc, char *buf, size_t bufsize )
     return dvb_mux_conf_str_dvbs(dmc, buf, bufsize);
   case DVB_TYPE_ATSC_T:
     return dvb_mux_conf_str_atsc_t(dmc, buf, bufsize);
+  case DVB_TYPE_CABLECARD:
+    return dvb_mux_conf_str_cablecard(dmc, buf, bufsize);
   case DVB_TYPE_ISDB_T:
     return dvb_mux_conf_str_isdb_t(dmc, buf, bufsize);
   default:
index 43e163453a351a90cdcaf15e8ae50a5430160db8..87f5faf71527928558ebe5efdb8b00c66b4e18d6 100644 (file)
@@ -50,6 +50,7 @@ extern const idclass_t dvb_network_dvbc_class;
 extern const idclass_t dvb_network_dvbs_class;
 extern const idclass_t dvb_network_atsc_t_class;
 extern const idclass_t dvb_network_atsc_c_class;
+extern const idclass_t dvb_network_cablecard_class;
 extern const idclass_t dvb_network_isdb_t_class;
 extern const idclass_t dvb_network_isdb_c_class;
 extern const idclass_t dvb_network_isdb_s_class;
@@ -88,6 +89,7 @@ extern const idclass_t dvb_mux_dvbc_class;
 extern const idclass_t dvb_mux_dvbs_class;
 extern const idclass_t dvb_mux_atsc_t_class;
 extern const idclass_t dvb_mux_atsc_c_class;
+extern const idclass_t dvb_mux_cablecard_class;
 extern const idclass_t dvb_mux_isdb_t_class;
 extern const idclass_t dvb_mux_isdb_c_class;
 extern const idclass_t dvb_mux_isdb_s_class;
index 7228dcd1eb9a955b04f8aec3adb8806db6046233..a09725a68f23425ead4d2a1a25e329f060445407 100644 (file)
@@ -129,6 +129,39 @@ dvb_mux_class_delsys_set (void *o, const void *v)
   return 0;
 }
 
+static const void *
+dvb_mux_class_vchan_get(void *o)
+{
+  dvb_mux_t *lm = (dvb_mux_t *)o;
+
+  if (!lm->lm_tuning.dmc_fe_vchan.minor)
+    snprintf(prop_sbuf, PROP_SBUF_LEN, "%u",
+      lm->lm_tuning.dmc_fe_vchan.num);
+  else
+    snprintf(prop_sbuf, PROP_SBUF_LEN, "%u.%u",
+      lm->lm_tuning.dmc_fe_vchan.num,
+      lm->lm_tuning.dmc_fe_vchan.minor);
+       return &prop_sbuf_ptr;
+}
+
+static int
+dvb_mux_class_vchan_set(void *o, const void *v)
+{
+  dvb_mux_t *lm = (dvb_mux_t *)o;
+  int r;
+
+  r = sscanf(v, "%u%*[.-]%hu",
+    &lm->lm_tuning.dmc_fe_vchan.num,
+    &lm->lm_tuning.dmc_fe_vchan.minor);
+  switch (r) {
+  case 0:
+    return 1;
+  case 1:
+    lm->lm_tuning.dmc_fe_vchan.minor = 0;
+  }
+  return 0;
+}
+
 const idclass_t dvb_mux_class =
 {
   .ic_super      = &mpegts_mux_class,
@@ -614,6 +647,43 @@ const idclass_t dvb_mux_atsc_c_class =
   }
 };
 
+/*
+ * CableCARD
+ */
+const idclass_t dvb_mux_cablecard_class =
+{
+  .ic_super      = &dvb_mux_class,
+  .ic_class      = "dvb_mux_cablecard",
+  .ic_caption    = N_("CableCARD multiplex"),
+  .ic_properties = (const property_t[]){
+    {
+      .type = PT_STR,
+      .id   = "vchan",
+      .name = N_("Channel"),
+      .desc = N_("The channel on the cable provider's network."),
+      .get  = dvb_mux_class_vchan_get,
+      .set  = dvb_mux_class_vchan_set,
+    },
+    {
+      .type = PT_U32,
+      .id   = "frequency",
+      .name = N_("Frequency (Hz)"),
+      .desc = N_("The frequency of the mux (in Hertz)."),
+      .off  = offsetof(dvb_mux_t, lm_tuning.dmc_fe_freq),
+      .opts = PO_RDONLY | PO_NOSAVE,
+    },
+    {
+      .type = PT_STR,
+      .id   = "vchan_name",
+      .name = N_("Callsign"),
+      .desc = N_("The channel's name or callsign as set by the cable provider."),
+      .off  = offsetof(dvb_mux_t, lm_tuning.dmc_fe_vchan.name),
+      .opts = PO_RDONLY | PO_NOSAVE,
+    },
+    {}
+  }
+};
+
 /*
  * ISDB-T
  */
@@ -1049,26 +1119,36 @@ dvb_mux_display_name ( mpegts_mux_t *mm, char *buf, size_t len )
   dvb_network_t *ln = (dvb_network_t*)mm->mm_network;
   uint32_t freq = lm->lm_tuning.dmc_fe_freq, freq2;
   char extra[8], buf2[5], *p;
-  if (ln->ln_type == DVB_TYPE_S) {
-    const char *s = dvb_pol2str(lm->lm_tuning.u.dmc_fe_qpsk.polarisation);
-    if (s) extra[0] = *s;
-    extra[1] = '\0';
+
+  if (lm->lm_tuning.dmc_fe_type == DVB_TYPE_CABLECARD) {
+    if (!lm->lm_tuning.dmc_fe_vchan.minor)
+      snprintf(buf, len, "%u", lm->lm_tuning.dmc_fe_vchan.num);
+    else
+      snprintf(buf, len, "%u.%u",
+        lm->lm_tuning.dmc_fe_vchan.num,
+        lm->lm_tuning.dmc_fe_vchan.minor);
   } else {
+    if (ln->ln_type == DVB_TYPE_S) {
+      const char *s = dvb_pol2str(lm->lm_tuning.u.dmc_fe_qpsk.polarisation);
+      if (s) extra[0] = *s;
+      extra[1] = '\0';
+    } else {
+      freq /= 1000;
+      strcpy(extra, "MHz");
+    }
+    freq2 = freq % 1000;
     freq /= 1000;
-    strcpy(extra, "MHz");
-  }
-  freq2 = freq % 1000;
-  freq /= 1000;
-  snprintf(buf2, sizeof(buf2), "%03d", freq2);
-  p = buf2 + 2;
-  while (freq2 && (freq2 % 10) == 0) {
-    freq2 /= 10;
-    *(p--) = '\0';
+    snprintf(buf2, sizeof(buf2), "%03d", freq2);
+    p = buf2 + 2;
+    while (freq2 && (freq2 % 10) == 0) {
+      freq2 /= 10;
+      *(p--) = '\0';
+    }
+    if (freq2)
+      snprintf(buf, len, "%d.%s%s", freq, buf2, extra);
+    else
+      snprintf(buf, len, "%d%s", freq, extra);
   }
-  if (freq2)
-    snprintf(buf, len, "%d.%s%s", freq, buf2, extra);
-  else
-    snprintf(buf, len, "%d%s", freq, extra);
 }
 
 static void
@@ -1122,6 +1202,9 @@ dvb_mux_create0
   } else if (ln->ln_type == DVB_TYPE_ATSC_C) {
     idc = &dvb_mux_atsc_c_class;
     delsys = DVB_SYS_DVBC_ANNEX_B;
+  } else if (ln->ln_type == DVB_TYPE_CABLECARD) {
+    idc = &dvb_mux_cablecard_class;
+    delsys = DVB_SYS_DVBC_ANNEX_B;
   } else if (ln->ln_type == DVB_TYPE_ISDB_T) {
     idc = &dvb_mux_isdb_t_class;
     delsys = DVB_SYS_ISDBT;
index a4904f20947fd171a17bbbf11f805d857f77b92e..e673d86b667fc087453577363b301362778dd992 100644 (file)
@@ -360,6 +360,16 @@ const idclass_t dvb_network_atsc_c_class =
   }
 };
 
+const idclass_t dvb_network_cablecard_class =
+{
+  .ic_super      = &dvb_network_class,
+  .ic_class      = "dvb_network_cablecard",
+  .ic_caption    = N_("CableCARD Network"),
+  .ic_properties = (const property_t[]){
+    {}
+  }
+};
+
 const idclass_t dvb_network_isdb_t_class =
 {
   .ic_super      = &dvb_network_class,
@@ -632,6 +642,8 @@ dvb_network_mux_class
     return &dvb_mux_atsc_c_class;
   if (idnode_is_instance(&mn->mn_id, &dvb_network_isdb_t_class))
     return &dvb_mux_isdb_t_class;
+  if (idnode_is_instance(&mn->mn_id, &dvb_network_cablecard_class))
+    return &dvb_mux_cablecard_class;
   if (idnode_is_instance(&mn->mn_id, &dvb_network_isdb_c_class))
     return &dvb_mux_isdb_c_class;
   if (idnode_is_instance(&mn->mn_id, &dvb_network_isdb_s_class))
@@ -830,7 +842,25 @@ static mpegts_service_t *
 dvb_network_create_service
   ( mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid )
 {
-  return mpegts_service_create1(NULL, mm, sid, pmt_pid, NULL);
+  dvb_mux_t *lm = (dvb_mux_t *)mm;
+  mpegts_service_t *s;
+
+  s = mpegts_service_create1(NULL, mm, sid, pmt_pid, NULL);
+
+  /* Set service values from mux if CableCARD */
+  if (lm->lm_tuning.dmc_fe_type == DVB_TYPE_CABLECARD) {
+    mpegts_network_t *ln = mm->mm_network;
+    if (!s->s_dvb_provider && ln->mn_provider_network_name)
+      s->s_dvb_provider = strdup(ln->mn_provider_network_name);
+    if (!s->s_dvb_channel_num)
+      s->s_dvb_channel_num = lm->lm_tuning.dmc_fe_vchan.num;
+    if (!s->s_dvb_channel_minor && lm->lm_tuning.dmc_fe_vchan.minor)
+      s->s_dvb_channel_minor = lm->lm_tuning.dmc_fe_vchan.minor;
+    if (!s->s_dvb_svcname && lm->lm_tuning.dmc_fe_vchan.name)
+      s->s_dvb_svcname = strdup(lm->lm_tuning.dmc_fe_vchan.name);
+  }
+
+  return s;
 }
 
 static mpegts_mux_t *
@@ -910,6 +940,7 @@ static const idclass_t * dvb_network_classes[] = {
   &dvb_network_dvbs_class,
   &dvb_network_atsc_t_class,
   &dvb_network_atsc_c_class,
+  &dvb_network_cablecard_class,
   &dvb_network_isdb_t_class,
   &dvb_network_isdb_c_class,
   &dvb_network_isdb_s_class,
@@ -924,6 +955,7 @@ static const idclass_t * dvb_mux_classes[] = {
   &dvb_mux_dvbs_class,
   &dvb_mux_atsc_t_class,
   &dvb_mux_atsc_c_class,
+  &dvb_mux_cablecard_class,
   &dvb_mux_isdb_t_class,
   &dvb_mux_isdb_c_class,
   &dvb_mux_isdb_s_class,
@@ -1003,6 +1035,8 @@ const idclass_t *dvb_network_class_by_fe_type(dvb_fe_type_t type)
     return &dvb_network_atsc_t_class;
   else if (type == DVB_TYPE_ATSC_C)
     return &dvb_network_atsc_c_class;
+  else if (type == DVB_TYPE_CABLECARD)
+    return &dvb_network_cablecard_class;
   else if (type == DVB_TYPE_ISDB_T)
     return &dvb_network_isdb_t_class;
   else if (type == DVB_TYPE_ISDB_C)
@@ -1029,6 +1063,8 @@ dvb_fe_type_t dvb_fe_type_by_network_class(const idclass_t *idc)
     return DVB_TYPE_ATSC_T;
   else if (idc == &dvb_network_atsc_c_class)
     return DVB_TYPE_ATSC_C;
+  else if (idc == &dvb_network_cablecard_class)
+    return DVB_TYPE_CABLECARD;
   else if (idc == &dvb_network_isdb_t_class)
     return DVB_TYPE_ISDB_T;
   else if (idc == &dvb_network_isdb_c_class)