]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
mpegts linuxdvb: starting to get working scanning on DVB-T
authorAdam Sutton <dev@adamsutton.me.uk>
Thu, 30 May 2013 15:09:47 +0000 (16:09 +0100)
committerAdam Sutton <dev@adamsutton.me.uk>
Thu, 30 May 2013 15:09:47 +0000 (16:09 +0100)
Moved DVB mux config into dvb_support
Updated table processing to include proper section tracking
Fixed some problem in the MPEG-TS core
Updates to get scanning working in LinuxDVB

13 files changed:
src/input/mpegts.h
src/input/mpegts/dvb.h
src/input/mpegts/dvb_psi.c
src/input/mpegts/dvb_support.c
src/input/mpegts/linuxdvb/linuxdvb_device.c
src/input/mpegts/linuxdvb/linuxdvb_frontend.c
src/input/mpegts/linuxdvb/linuxdvb_hardware.c
src/input/mpegts/linuxdvb/linuxdvb_mux.c
src/input/mpegts/linuxdvb/linuxdvb_network.c
src/input/mpegts/linuxdvb/linuxdvb_private.h
src/input/mpegts/mpegts_input.c
src/input/mpegts/mpegts_mux.c
src/input/mpegts/mpegts_table.c

index c6434cdec43d35aafe9480e1be156e7489c290d1..bb2e1a4767a8edf9e0670b72714aad3899f1341c 100644 (file)
@@ -93,9 +93,14 @@ struct mpegts_table
   void *mt_opaque;
   mpegts_table_callback_t mt_callback;
 
+  struct {
+    int section;
+    int version;
+    int complete;
+  } mt_state[256];
 
-  // TODO: remind myself of what each field is for
   int mt_count;
+
   int mt_pid;
 
   int mt_id;
@@ -169,7 +174,8 @@ struct mpegts_network
     (mpegts_mux_t*, uint16_t onid, uint16_t tsid, dvb_mux_conf_t *conf);
   mpegts_service_t* (*mn_create_service)
     (mpegts_mux_t*, uint16_t sid, uint16_t pmt_pid);
-  void              (*mn_config_save) (mpegts_network_t*);
+  void              (*mn_display_name) (mpegts_network_t*, char *buf, size_t len);
+  void              (*mn_config_save)  (mpegts_network_t*);
 
   // Note: the above are slightly odd in that they take mux instead of
   //       network as initial param. This is intentional as we need to
@@ -248,6 +254,7 @@ struct mpegts_mux
   void (*mm_open_table)       (mpegts_mux_t*,mpegts_table_t*);
   void (*mm_close_table)      (mpegts_mux_t*,mpegts_table_t*);
   void (*mm_create_instances) (mpegts_mux_t*);
+  void (*mm_display_name)     (mpegts_mux_t*, char *buf, size_t len);
 
   /*
    * Fields
@@ -364,6 +371,8 @@ struct mpegts_input
 {
   idnode_t mi_id;
 
+  int mi_enabled;
+
   int mi_instance;
 
   LIST_ENTRY(mpegts_input) mi_global_link;
@@ -403,6 +412,8 @@ struct mpegts_input
   void (*mi_close_service)  (mpegts_input_t*,mpegts_service_t*);
   int  (*mi_is_free)        (mpegts_input_t*);
   int  (*mi_current_weight) (mpegts_input_t*);
+  int  (*mi_is_enabled)     (mpegts_input_t*);
+  void (*mi_display_name)   (mpegts_input_t*, char *buf, size_t len);
 };
 
 #endif /* __TVH_MPEGTS_H__ */
index 2a058a8380de3583fb40d325fba8bc4304abaa80..64e7f10c9c81672ad5bb7794f7529070f8739fd9 100644 (file)
@@ -198,6 +198,11 @@ typedef struct dvb_mux_conf
 #endif
 } dvb_mux_conf_t;
 
+const char *dvb_mux_conf_load
+  ( fe_type_t type, dvb_mux_conf_t *dmc, htsmsg_t *m );
+int dvb_mux_conf_save
+  ( dvb_mux_conf_t *dmc, htsmsg_t *m );
+
 /* conversion routines */
 const char *dvb_rolloff2str ( int rolloff );
 const char *dvb_delsys2str  ( int delsys );
index d24d35ecf3a8c2262d59d02b9577c9dd29bf3392..b7469082dfeae14902b4a29f5311f85204dedbec 100644 (file)
@@ -370,25 +370,80 @@ dvb_desc_local_channel
  * *************************************************************************/
 
 /*
- * PAT processing
+ * Begin table
  */
+static int
+dvb_table_begin
+  (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid,
+   int minlen, int *sect, int *last, int *ver)
+{
+  /* Not long enough */
+  if (len < minlen)
+    return -1;
+
+  /* Ignore next */
+  if((ptr[2] & 1) == 0)
+    return -1;
+
+  tvhtrace(mt->mt_name, "tableid %02X len %d", tableid, len);
+  tvhlog_hexdump(mt->mt_name, ptr, len);
+
+  /* Section info */
+  if (sect) {
+    *sect = ptr[3];
+    *last = ptr[4];
+    *ver  = (ptr[2] >> 1) & 0x1F;
+    tvhtrace(mt->mt_name, "  section %d last %d ver %d", *sect, *last, *ver);
+
+    /* New version */
+    if (mt->mt_state[tableid].complete && mt->mt_state[tableid].version != *ver) {
+      tvhtrace(mt->mt_name, "  new version");
+      mt->mt_state[tableid].complete = 0;
+      mt->mt_state[tableid].section  = 0;
+    }
+
+    /* Ignore */
+    if (mt->mt_state[tableid].complete) {
+      tvhtrace(mt->mt_name, "  already processed");
+      return -1;
+    }
 
+    /* Not the right section */
+    tvhtrace(mt->mt_name, "  waiting for section %d version %d", mt->mt_state[tableid].section, mt->mt_state[tableid].version);
+    if (mt->mt_state[tableid].section != *sect) {
+      tvhtrace(mt->mt_name, "  skip, wrong section");
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+static void
+dvb_table_end
+  (mpegts_table_t *mt, int tableid, int sect, int last, int ver)
+{
+  mt->mt_state[tableid].section = sect + 1;
+  mt->mt_state[tableid].version = ver;
+  if (sect == last)
+    mt->mt_state[tableid].complete = 1;
+}
+
+/*
+ * PAT processing
+ */
 int
 dvb_pat_callback
   (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
 {
+  int sect, last, ver;
   uint16_t sid, pid, tsid;
   uint16_t nit_pid = DVB_NIT_PID;
   mpegts_mux_t          *mm  = mt->mt_mux;
-  tvhtrace("pat", "tableid %02X len %d", tableid, len);
-  tvhlog_hexdump("pat", ptr, len);
 
-  /* Not enough data */
-  if(len < 5)
-    return -1;
-
-  /* Ignore next */
-  if((ptr[2] & 1) == 0)
+  /* Begin */
+  if (tableid != 0) return -1;
+  if (dvb_table_begin(mt, ptr, len, tableid, 5, &sect, &last, &ver) == -1)
     return -1;
 
   /* Multiplex */
@@ -431,7 +486,8 @@ dvb_pat_callback
   mpegts_table_add(mm, DVB_NIT_BASE, DVB_NIT_MASK, dvb_nit_callback,
                    NULL, "nit", MT_CRC | MT_QUICKREQ, nit_pid);
 
-  return 0;
+  dvb_table_end(mt, tableid, sect, last, ver);
+  return mt->mt_state[0].complete ? 0 : -1;
 }
 
 /*
@@ -442,10 +498,13 @@ int
 dvb_pmt_callback
   (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
 {
+  int sect, last, ver;
   mpegts_mux_t *mm = mt->mt_mux;
   mpegts_service_t *s;
-  tvhtrace("pmt", "tableid %02X len %d", tableid, len);
-  tvhlog_hexdump("pmt", ptr, len);
+
+  /* Start */
+  if (dvb_table_begin(mt, ptr, len, tableid, 5, &sect, &last, &ver))
+    return -1;
 
   LIST_FOREACH(s, &mm->mm_services, s_dvb_mux_link) {
     pthread_mutex_lock(&s->s_stream_mutex);
@@ -463,7 +522,9 @@ dvb_pmt_callback
                     dm->dm_current_tdmi, tdt);
 #endif
 
-  return 0;
+  /* Finish */
+  dvb_table_end(mt, tableid, sect, last, ver);
+  return (sect == last) ? 0 : -1;
 }
 
 /*
@@ -474,6 +535,7 @@ dvb_nit_callback
   (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
 {
   int save;
+  int sect, last, ver;
   uint8_t  dlen, dtag;
   uint16_t llen, dllen;
   const uint8_t *lptr, *dlptr, *dptr;
@@ -481,19 +543,10 @@ dvb_nit_callback
   mpegts_mux_t     *mm = mt->mt_mux, *mux;
   mpegts_network_t *mn = mm->mm_network;
   char name[256], dauth[256];
-  const char *dstr = (tableid == 0x4A) ? "bat" : "nit";
-
-  tvhtrace(dstr, "tableid %02X len %d", tableid, len);
-  tvhlog_hexdump(dstr, ptr, len);
-
-  /* Not long enough */
-  if (len < 7)
-    return -1;
-
-  tvhtrace(dstr, "  section %d last %d current %d", ptr[3], ptr[4], ptr[2]&1);
 
-  /* Ignore "next" */
-  if (!(ptr[2] & 0x01))
+  /* Begin */
+  if (tableid != 0x40 && tableid != 0x41 && tableid != 0x4A) return -1;
+  if (dvb_table_begin(mt, ptr, len, tableid, 7, &sect, &last, &ver))
     return -1;
 
   /* BAT */
@@ -518,7 +571,7 @@ dvb_nit_callback
   /* Network Descriptors */
   *name = 0;
   DVB_DESC_FOREACH(ptr, len, 5, lptr, llen, dtag, dlen, dptr) {
-    tvhtrace(dstr, "  dtag %02X dlen %d", dtag, dlen);
+    tvhtrace(mt->mt_name, "  dtag %02X dlen %d", dtag, dlen);
 
     switch (dtag) {
       case DVB_DESC_BOUQUET_NAME:
@@ -534,11 +587,11 @@ dvb_nit_callback
 
   /* BAT */
   if (tableid == 0x4A) {
-    tvhtrace("bat", "bouquet %04X (%d) [%s]", bid, bid, name);
+    tvhtrace(mt->mt_name, "bouquet %04X (%d) [%s]", bid, bid, name);
 
   /* NIT */
   } else {
-    tvhtrace("nit", "network %04X (%d) [%s]", nid, nid, name);
+    tvhtrace(mt->mt_name, "network %04X (%d) [%s]", nid, nid, name);
     save  = mpegts_network_set_nid(mn, nid);
     save |= mpegts_network_set_network_name(mn, name);
     if (save)
@@ -549,7 +602,7 @@ dvb_nit_callback
   DVB_LOOP_FOREACH(ptr, len, 0, lptr, llen, 6) {
     tsid  = (lptr[0] << 8) | lptr[1];
     onid  = (lptr[2] << 8) | lptr[3];
-    tvhtrace(dstr, "  onid %04X (%d) tsid %04X (%d)", onid, onid, tsid, tsid);
+    tvhtrace(mt->mt_name, "  onid %04X (%d) tsid %04X (%d)", onid, onid, tsid, tsid);
 
     /* Find existing mux */
     LIST_FOREACH(mux, &mn->mn_muxes, mm_network_link)
@@ -557,7 +610,7 @@ dvb_nit_callback
         break;
 
     DVB_DESC_FOREACH(lptr, llen, 4, dlptr, dllen, dtag, dlen, dptr) {
-      tvhtrace(dstr, "    dtag %02X dlen %d", dtag, dlen);
+      tvhtrace(mt->mt_name, "    dtag %02X dlen %d", dtag, dlen);
 
       switch (dtag) {
     
@@ -576,23 +629,25 @@ dvb_nit_callback
         case DVB_DESC_DEF_AUTHORITY:
           if (dvb_desc_def_authority(dptr, dlen, dauth, sizeof(dauth)))
             return -1;
-          tvhtrace(dstr, "    default auth [%s]", dauth);
+          tvhtrace(mt->mt_name, "    default auth [%s]", dauth);
           if (mux && *dauth)
             mpegts_mux_set_default_authority(mux, dauth);
           break;
         case DVB_DESC_LOCAL_CHAN:
-          if (dvb_desc_local_channel(dstr, dptr, dlen, mux))
+          if (dvb_desc_local_channel(mt->mt_name, dptr, dlen, mux))
             return -1;
           break;
         case DVB_DESC_SERVICE_LIST:
-          if (dvb_desc_service_list(dstr, dptr, dlen, mux))
+          if (dvb_desc_service_list(mt->mt_name, dptr, dlen, mux))
             return -1;
           break;
       }
     }
   }
 
-  return 0;
+  /* End */
+  dvb_table_end(mt, tableid, sect, last, ver);
+  return (sect == last) ? 0 : -1;
 }
 
 /**
@@ -602,28 +657,16 @@ int
 dvb_sdt_callback
   (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
 {
+  int sect, last, ver;
   uint16_t onid, tsid;
   uint16_t llen;
   uint8_t dtag, dlen;
   const uint8_t *lptr, *dptr;
   mpegts_mux_t     *mm = mt->mt_mux;
 
-  tvhtrace("sdt", "tableid %02X len %d", tableid, len);
-  tvhlog_hexdump("sdt", ptr, len);
-
-  /* Not enough data */
-  if(len < 8)
-    return -1;
-
-  tvhtrace("sdt", "  section %d last %d current %d", ptr[3], ptr[4], ptr[2]&1);
-
-  /* Ignore next */
-  if((ptr[2] & 1) == 0)
-    return -1;
-
-  /* Validate */
-  if (tableid != 0x42 && tableid != 0x46) 
-    return -1;
+  /* Begin */
+  if (tableid != 0x42 && tableid != 0x46) return -1;
+  dvb_table_begin(mt, ptr, len, tableid, 8, &sect, &last, &ver);
 
   /* ID */
   tsid = ptr[0] << 8 | ptr[1];
@@ -742,7 +785,10 @@ dvb_sdt_callback
       service_refresh_channel((service_t*)s);
     }
   }
-  return 0;
+
+  /* Done */
+  dvb_table_end(mt, tableid, sect, last, ver);
+  return (mt->mt_state[0x42].complete && mt->mt_state[0x46].complete) ? 0 : -1;
 }
 
 /*
index 828329e1740ad1c416c4b5206707e6435af11d3d..45a009cf9e0b4ef4d87a4224a03080b672a678e7 100644 (file)
@@ -406,7 +406,9 @@ const static struct strtab delsystab[] = {
   { "SYS_ATSCMH",           SYS_ATSCMH },
   { "SYS_DMBTH",            SYS_DMBTH },
   { "SYS_CMMB",             SYS_CMMB },
-  { "SYS_DAB",              SYS_DAB }
+  { "SYS_DAB",              SYS_DAB },
+  { "SYS_DVBT2",            SYS_DVBT2 },
+  { "SYS_TURBO",            SYS_TURBO }
 #endif
 };
 dvb_str2val(delsys);
@@ -511,8 +513,167 @@ const static struct strtab typetab[] = {
   {"ATSC",  FE_ATSC},
 };
 dvb_str2val(type);
+#undef dvb_str2val
 
+/*
+ * Process mux conf
+ */
+static const char *
+dvb_mux_conf_load_dvbt ( dvb_mux_conf_t *dmc, htsmsg_t *m )
+{
+  int r;
+  const char *s;
+
+  s = htsmsg_get_str(m, "bandwidth");
+  if(s == NULL || (r = dvb_str2bw(s)) < 0)
+    return "Invalid bandwidth";
+  dmc->dmc_fe_params.u.ofdm.bandwidth = r;
+
+  s = htsmsg_get_str(m, "constellation");
+  if(s == NULL || (r = dvb_str2qam(s)) < 0)
+    return "Invalid QAM constellation";
+  dmc->dmc_fe_params.u.ofdm.constellation = r;
+
+  s = htsmsg_get_str(m, "transmission_mode");
+  if(s == NULL || (r = dvb_str2mode(s)) < 0)
+    return "Invalid transmission mode";
+  dmc->dmc_fe_params.u.ofdm.transmission_mode = r;
+
+  s = htsmsg_get_str(m, "guard_interval");
+  if(s == NULL || (r = dvb_str2guard(s)) < 0)
+    return "Invalid guard interval";
+  dmc->dmc_fe_params.u.ofdm.guard_interval = r;
+
+  s = htsmsg_get_str(m, "hierarchy");
+  if(s == NULL || (r = dvb_str2hier(s)) < 0)
+    return "Invalid heirarchy information";
+  dmc->dmc_fe_params.u.ofdm.hierarchy_information = r;
+
+  s = htsmsg_get_str(m, "fec_hi");
+  if(s == NULL || (r = dvb_str2fec(s)) < 0)
+    return "Invalid hi-FEC";
+  dmc->dmc_fe_params.u.ofdm.code_rate_HP = r;
+
+  s = htsmsg_get_str(m, "fec_lo");
+  if(s == NULL || (r = dvb_str2fec(s)) < 0)
+    return "Invalid lo-FEC";
+  dmc->dmc_fe_params.u.ofdm.code_rate_LP = r;
+
+  return NULL;
+}
 
-#undef dvb_str2val
+static const char *
+dvb_mux_conf_load_dvbc ( dvb_mux_conf_t *dmc, htsmsg_t *m )
+{
+  int r;
+  const char *s;
+
+  htsmsg_get_u32(m, "symbol_rate", &dmc->dmc_fe_params.u.qam.symbol_rate);
+  if(dmc->dmc_fe_params.u.qam.symbol_rate == 0)
+    return "Invalid symbol rate";
+    
+  s = htsmsg_get_str(m, "constellation");
+  if(s == NULL || (r = dvb_str2qam(s)) < 0)
+    return "Invalid QAM constellation";
+  dmc->dmc_fe_params.u.qam.modulation = r;
+
+  s = htsmsg_get_str(m, "fec");
+  if(s == NULL || (r = dvb_str2fec(s)) < 0)
+    return "Invalid FEC";
+  dmc->dmc_fe_params.u.qam.fec_inner = r;
+
+  return NULL;
+}
+
+static const char *
+dvb_mux_conf_load_dvbs ( dvb_mux_conf_t *dmc, htsmsg_t *m )
+{
+  int r;
+  const char *s;
+
+  htsmsg_get_u32(m, "symbol_rate", &dmc->dmc_fe_params.u.qpsk.symbol_rate);
+  if(dmc->dmc_fe_params.u.qpsk.symbol_rate == 0)
+    return "Invalid symbol rate";
+    
+  s = htsmsg_get_str(m, "fec");
+  if(s == NULL || (r = dvb_str2fec(s)) < 0)
+    return "Invalid FEC";
+  dmc->dmc_fe_params.u.qpsk.fec_inner = r;
+
+  s = htsmsg_get_str(m, "polarisation");
+  if(s == NULL || (r = dvb_str2pol(s)) < 0)
+    return "Invalid polarisation";
+  dmc->dmc_fe_polarisation = r;
+
+#if DVB_API_VERSION >= 5
+  s = htsmsg_get_str(m, "modulation");
+  if(s == NULL || (r = dvb_str2qam(s)) < 0) {
+    r = QPSK;
+    tvhlog(LOG_INFO, "dvb", "no modulation, using default QPSK");
+  } 
+  dmc->dmc_fe_modulation = r;
+
+  s = htsmsg_get_str(m, "rolloff");
+  if(s == NULL || (r = dvb_str2rolloff(s)) < 0) {
+    r = ROLLOFF_35;
+    tvhlog(LOG_INFO, "dvb", "no rolloff, using default ROLLOFF_35");
+  }
+  dmc->dmc_fe_rolloff = r;
+
+  // TODO: pilot mode
+#endif
+  return NULL;
+}
+
+static const char *
+dvb_mux_conf_load_atsc ( dvb_mux_conf_t *dmc, htsmsg_t *m )
+{
+  int r;
+  const char *s;
+  s = htsmsg_get_str(m, "constellation");
+  if(s == NULL || (r = dvb_str2qam(s)) < 0)
+    return "Invalid VSB constellation";
+  dmc->dmc_fe_params.u.vsb.modulation = r;
+  return NULL;
+}
+
+const char *
+dvb_mux_conf_load ( fe_type_t type, dvb_mux_conf_t *dmc, htsmsg_t *m )
+{
+  int r;
+  uint32_t u32;
+  const char *str;
+
+  memset(dmc, 0, sizeof(dvb_mux_conf_t));
+  dmc->dmc_fe_params.inversion = INVERSION_AUTO;
+
+  /* Delivery system */
+#if DVB_API_VERSION >= 5
+  str = htsmsg_get_str(m, "delsys");
+  if (!str || (r = dvb_str2delsys(str)) < 0) {
+         if (type == FE_OFDM) r = SYS_DVBT;
+    else if (type == FE_QAM)  r = SYS_DVBC_ANNEX_B;
+    else if (type == FE_QPSK) r = SYS_DVBS;
+    else if (type == FE_ATSC) r = SYS_ATSC;
+    else
+      return "Invalid FE type";
+    tvhlog(LOG_INFO, "dvb", "no delsys, using default %s", dvb_delsys2str(r));
+  }
+#endif
+  dmc->dmc_fe_delsys           = r;
+
+  /* Frequency */
+  if (htsmsg_get_u32(m, "frequency", &u32))
+    return "Invalid frequency";
+  dmc->dmc_fe_params.frequency = u32;
+
+  /* Type specific */
+  if      (type == FE_OFDM) return dvb_mux_conf_load_dvbt(dmc, m);
+  else if (type == FE_QAM)  return dvb_mux_conf_load_dvbc(dmc, m);
+  else if (type == FE_QPSK) return dvb_mux_conf_load_dvbs(dmc, m);
+  else if (type == FE_ATSC) return dvb_mux_conf_load_atsc(dmc, m);
+  else
+    return "Invalid FE type";
+}
 
 #endif /* ENABLE_DVBAPI */
index e94c80eab051adc25ac70eb7830e87a13458e42b..7547883493a790032abf89a8d71ac6838871db66 100644 (file)
@@ -249,7 +249,7 @@ linuxdvb_device_create0 ( const char *uuid, htsmsg_t *conf )
   /* Load config */
   linuxdvb_hardware_load((linuxdvb_hardware_t*)ld, conf);
   if (!htsmsg_get_u32(conf, "enabled", &u32) && u32)
-    ld->lh_enabled     = 1;
+    ld->mi_enabled     = 1;
   if ((str = htsmsg_get_str(conf, "displayname")))
     ld->lh_displayname = strdup(str);
   if ((str = htsmsg_get_str(conf, "devid")))
index dee1a793623be1297031f251d064cb1aadbc6bd2..4181a1f311b5d075c385bd086bab439852fde1d8 100644 (file)
@@ -158,6 +158,15 @@ static void
 linuxdvb_frontend_stop_mux
   ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
 {
+  linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
+
+  /* Stop thread */
+  if (lfe->lfe_dvr_pipe.wr > 0) {
+    tvh_write(lfe->lfe_dvr_pipe.wr, "", 1);
+    pthread_join(lfe->lfe_dvr_thread, NULL);
+    tvh_pipe_close(&lfe->lfe_dvr_pipe);
+    tvhlog(LOG_DEBUG, "linuxdvb", "stopped dvr thread");
+  }
 }
 
 static void *
@@ -212,6 +221,9 @@ linuxdvb_frontend_input_thread ( void *aux )
   ev.events  = EPOLLIN;
   ev.data.fd = dvr;
   epoll_ctl(efd, EPOLL_CTL_ADD, ev.data.fd, &ev);
+  ev.events  = EPOLLIN;
+  ev.data.fd = lfe->lfe_dvr_pipe.rd;
+  epoll_ctl(efd, EPOLL_CTL_ADD, ev.data.fd, &ev);
 
   /* Read */
   while (1) {
@@ -250,7 +262,6 @@ linuxdvb_frontend_monitor ( void *aux )
   linuxdvb_frontend_t *lfe = aux;
   mpegts_mux_instance_t *mmi = LIST_FIRST(&lfe->mi_mux_active);
   mpegts_mux_t *mm;
-  pthread_t tid;
 
   if (!mmi) return;
   mm = mmi->mmi_mux;
@@ -265,7 +276,10 @@ linuxdvb_frontend_monitor ( void *aux )
   if (fe_status & FE_HAS_LOCK) {
     // Note: the lock
     // Open pending services
-    pthread_create(&tid, NULL, linuxdvb_frontend_input_thread, lfe);
+    tvh_pipe(O_NONBLOCK, &lfe->lfe_dvr_pipe);
+    pthread_create(&lfe->lfe_dvr_thread, NULL, linuxdvb_frontend_input_thread, lfe);
+
+    // TODO: these tables need to vary based on type
     mpegts_table_add(mm, DVB_PAT_BASE, DVB_PAT_MASK, dvb_pat_callback,
                      NULL, "pat", MT_QUICKREQ | MT_CRC, DVB_PAT_PID);
     mpegts_table_add(mm, DVB_SDT_BASE, DVB_SDT_MASK, dvb_sdt_callback,
@@ -460,6 +474,9 @@ linuxdvb_frontend_create0
   if (!conf)
     return lfe;
 
+  if (!htsmsg_get_u32(conf, "enabled", &u32) && u32)
+    lfe->mi_enabled = u32;
+  printf("LFE ENABLED = %d\n", lfe->mi_enabled);
   if (!htsmsg_get_u32(conf, "number", &u32))
     lfe->lfe_number = u32; 
   if ((str = htsmsg_get_str(conf, "network"))) {
index 0c62c5c1e74fbdccf393727160170074bdc5850a..053d95400f1accd652fb2bc5fa2ff4fb6d3e89cd 100644 (file)
@@ -47,7 +47,7 @@ linuxdvb_hardware_enumerate ( linuxdvb_hardware_list_t *list )
 
 void linuxdvb_hardware_save ( linuxdvb_hardware_t *lh, htsmsg_t *m )
 {
-  htsmsg_add_u32(m, "enabled", lh->lh_enabled);
+  htsmsg_add_u32(m, "enabled", lh->mi_enabled);
   if (lh->lh_displayname)
     htsmsg_add_str(m, "displayname", lh->lh_displayname);
 }
@@ -57,7 +57,7 @@ void linuxdvb_hardware_load ( linuxdvb_hardware_t *lh, htsmsg_t *conf )
   uint32_t u32;
   const char *str;
   if (!htsmsg_get_u32(conf, "enabled", &u32) && u32)
-    lh->lh_enabled     = 1;
+    lh->mi_enabled     = 1;
   if ((str = htsmsg_get_str(conf, "displayname")))
     lh->lh_displayname = strdup(str);
 }
@@ -82,7 +82,7 @@ const idclass_t linuxdvb_hardware_class =
   .ic_get_childs = linuxdvb_hardware_class_get_childs,
   .ic_properties = (const property_t[]){
     { PROPDEF1("enabled", "Enabled",
-               PT_BOOL, linuxdvb_hardware_t, lh_enabled) },
+               PT_BOOL, linuxdvb_hardware_t, mi_enabled) },
     { PROPDEF1("displayname", "Name",
                PT_STR, linuxdvb_hardware_t, lh_displayname) },
     {}
index 2bdbe9744909f67f0c2ad80dcb325c6db4fa78f8..3347f46093d4c931ba7c1fe729c65fe81764128a 100644 (file)
@@ -93,31 +93,32 @@ linuxdvb_mux_config_save ( mpegts_mux_t *mm )
 {
 }
 
-#if 0
-static int
-linuxdvb_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
-{
-  return SM_CODE_TUNING_FAILED;
-}
-
 static void
-linuxdvb_mux_stop ( mpegts_mux_t *mm )
+linuxdvb_mux_display_name ( mpegts_mux_t *mm, char *buf, size_t len )
 {
+  size_t c = 0;
+  const char *unit = "Hz";
+  linuxdvb_mux_t *lm = (linuxdvb_mux_t*)mm;
+  c = snprintf(buf+c, len-c, "%d %s [%04X:%04X]",
+               lm->lm_tuning.dmc_fe_params.frequency,
+               unit, mm->mm_onid, mm->mm_tsid);
 }
-#endif
-
-extern const idclass_t mpegts_mux_instance_class;
 
 static void
 linuxdvb_mux_create_instances ( mpegts_mux_t *mm )
 {
+  extern const idclass_t mpegts_mux_instance_class;
   mpegts_input_t *mi;
   mpegts_mux_instance_t *mmi;
+  tvhtrace("linuxdvb", "mm %p create instances", mm);
   LIST_FOREACH(mi, &mm->mm_network->mn_inputs, mi_network_link) {
+    tvhtrace("linuxdvb", "  checking mi %p", mi);
     LIST_FOREACH(mmi, &mi->mi_mux_instances, mmi_input_link)
       if (mmi->mmi_mux == mm) break;
-    if (!mmi)
+    if (!mmi) {
       mmi = mpegts_mux_instance_create(mpegts_mux_instance, NULL, mi, mm);
+      tvhtrace("linuxdvb", "    created mmi %p", mmi);
+    }
     // TODO: we might eventually want to keep history!
   }
 }
@@ -134,57 +135,6 @@ linuxdvb_mux_close_table ( mpegts_mux_t *mm, mpegts_table_t *mt )
 }
 #endif
 
-static const char *
-dvb_mux_conf_load ( fe_type_t type, dvb_mux_conf_t *dmc, htsmsg_t *m )
-{
-  int r;
-  const char *s;
-  dmc->dmc_fe_params.inversion = INVERSION_AUTO;
-  htsmsg_get_u32(m, "frequency", &dmc->dmc_fe_params.frequency);
-
-  switch(type) {
-  case FE_OFDM:
-    s = htsmsg_get_str(m, "bandwidth");
-    if(s == NULL || (r = dvb_str2bw(s)) < 0)
-      return "Invalid bandwidth";
-    dmc->dmc_fe_params.u.ofdm.bandwidth = r;
-
-    s = htsmsg_get_str(m, "constellation");
-    if(s == NULL || (r = dvb_str2qam(s)) < 0)
-      return "Invalid QAM constellation";
-    dmc->dmc_fe_params.u.ofdm.constellation = r;
-
-    s = htsmsg_get_str(m, "transmission_mode");
-    if(s == NULL || (r = dvb_str2mode(s)) < 0)
-      return "Invalid transmission mode";
-    dmc->dmc_fe_params.u.ofdm.transmission_mode = r;
-
-    s = htsmsg_get_str(m, "guard_interval");
-    if(s == NULL || (r = dvb_str2guard(s)) < 0)
-      return "Invalid guard interval";
-    dmc->dmc_fe_params.u.ofdm.guard_interval = r;
-
-    s = htsmsg_get_str(m, "hierarchy");
-    if(s == NULL || (r = dvb_str2hier(s)) < 0)
-      return "Invalid heirarchy information";
-    dmc->dmc_fe_params.u.ofdm.hierarchy_information = r;
-
-    s = htsmsg_get_str(m, "fec_hi");
-    if(s == NULL || (r = dvb_str2fec(s)) < 0)
-      return "Invalid hi-FEC";
-    dmc->dmc_fe_params.u.ofdm.code_rate_HP = r;
-
-    s = htsmsg_get_str(m, "fec_lo");
-    if(s == NULL || (r = dvb_str2fec(s)) < 0)
-      return "Invalid lo-FEC";
-    dmc->dmc_fe_params.u.ofdm.code_rate_LP = r;
-    break;
-  default:
-    return "Not yet supported";
-  }
-  return NULL;
-}
-
 linuxdvb_mux_t *
 linuxdvb_mux_create0
   ( linuxdvb_network_t *ln,
@@ -193,6 +143,7 @@ linuxdvb_mux_create0
 {
   const idclass_t *idc;
   mpegts_mux_t *mm;
+  linuxdvb_mux_t *lm;
 
   /* Search for existing */
 
@@ -214,7 +165,13 @@ linuxdvb_mux_create0
   if (!(mm = mpegts_mux_create0(calloc(1, sizeof(linuxdvb_mux_t)), idc, uuid,
                                 (mpegts_network_t*)ln, onid, tsid)))
     return NULL;
-  memcpy(&((linuxdvb_mux_t*)mm)->lm_tuning, dmc, sizeof(dvb_mux_conf_t));
+  lm = (linuxdvb_mux_t*)mm;
+  memcpy(&lm->lm_tuning, dmc, sizeof(dvb_mux_conf_t));
+
+  /* Callbacks */
+  lm->mm_display_name     = linuxdvb_mux_display_name;
+  lm->mm_config_save      = linuxdvb_mux_config_save;
+  lm->mm_create_instances = linuxdvb_mux_create_instances;
 
   return (linuxdvb_mux_t*)mm;
 }
@@ -244,14 +201,6 @@ linuxdvb_mux_create1
   if (!lm) printf("OH DEAR\n");
   if (!lm) return NULL;
   
-  /* Callbacks */
-  lm->mm_config_save      = linuxdvb_mux_config_save;
-#if 0
-  lm->mm_open_table       = linuxdvb_mux_open_table;
-  lm->mm_close_table      = linuxdvb_mux_close_table;
-#endif
-  lm->mm_create_instances = linuxdvb_mux_create_instances;
-
   /* No config */
   if (!conf)
     return lm;
index 1079193ef695f53617ba97b931b337d38e90c358..5ca94fdd375a1756f1b9cbb09dc30ceb614b2f03 100644 (file)
@@ -46,12 +46,29 @@ const idclass_t linuxdvb_network_class =
   }
 };
 
+static mpegts_mux_t *
+linuxdvb_network_find_mux
+  ( linuxdvb_network_t *ln, dvb_mux_conf_t *dmc )
+{
+  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) > 2000) continue;
+    if (lm->lm_tuning.dmc_fe_polarisation != dmc->dmc_fe_polarisation) continue;
+    break;
+  }
+  return mm;
+}
+
 static mpegts_mux_t *
 linuxdvb_network_create_mux
   ( mpegts_mux_t *mm, uint16_t onid, uint16_t tsid, dvb_mux_conf_t *conf )
 {
   linuxdvb_network_t *ln = (linuxdvb_network_t*)mm->mm_network;
-  return (mpegts_mux_t*)linuxdvb_mux_create0(ln, onid, tsid, conf, NULL);
+  mm = linuxdvb_network_find_mux(ln, conf);
+  if (!mm)
+    mm = (mpegts_mux_t*)linuxdvb_mux_create0(ln, onid, tsid, conf, NULL);
+  return mm;
 }
 
 static mpegts_service_t *
index 5e2a80d0a84c59556620c3a11eee9414e26f68d4..540ed4fd84cb8ed75fa01947740cdb0e567b3cda 100644 (file)
@@ -62,7 +62,6 @@ struct linuxdvb_hardware
   /*
    * Device info
    */
-  int                           lh_enabled;
   char                         *lh_displayname;
 };
 
@@ -132,8 +131,13 @@ struct linuxdvb_frontend
   char                     *lfe_dmx_path;
   char                     *lfe_dvr_path;
 
+  /*
+   * Reception
+   */
   int                       lfe_fe_fd;
   int                       lfe_dvr_fd;
+  pthread_t                 lfe_dvr_thread;
+  th_pipe_t                 lfe_dvr_pipe;
  
   /*
    * Tuning
index ae0d587ea362deb41e032ab513959c64a9f66140..fb6a1a5d37ace9e2eb63b100260ff88cacd91faa 100644 (file)
@@ -185,6 +185,7 @@ int
 mpegts_input_is_free ( mpegts_input_t *mi )
 {
   mpegts_mux_instance_t *mmi = LIST_FIRST(&mi->mi_mux_active);
+  tvhtrace("mpegts", "input_is_free(%p) mmi = %p", mi, mmi);
   return mmi ? 0 : 1;
 }
 
@@ -204,6 +205,12 @@ mpegts_input_current_weight ( mpegts_input_t *mi )
   return w;
 }
 
+static int
+mpegts_input_is_enabled ( mpegts_input_t *mi )
+{
+  return mi->mi_enabled;
+}
+
 mpegts_input_t*
 mpegts_input_create0  
   ( mpegts_input_t *mi, const idclass_t *class, const char *uuid )
@@ -215,6 +222,7 @@ mpegts_input_create0
   mi->mi_stop_mux       = NULL;
   mi->mi_open_service   = mpegts_input_open_service;
   mi->mi_close_service  = mpegts_input_close_service;
+  mi->mi_is_enabled     = mpegts_input_is_enabled;
   mi->mi_is_free        = mpegts_input_is_free;
   mi->mi_current_weight = mpegts_input_current_weight;
 
index 0647311476f253e6da44fa6f43e5915753f32d2d..9040b3f57f1c100753442b651a819589204f76b5 100644 (file)
@@ -116,6 +116,19 @@ mpegts_mux_initial_scan_timeout ( void *aux )
   mpegts_mux_initial_scan_done(mm);
 }
 
+static int
+mpegts_mux_has_subscribers ( mpegts_mux_t *mm )
+{
+  service_t *t;
+  mpegts_mux_instance_t *mmi = mm->mm_active;
+  if (mmi) {
+    LIST_FOREACH(t, &mmi->mmi_input->mi_transports, s_active_link)
+      if (((mpegts_service_t*)t)->s_dvb_mux == mm)
+        return 1;
+  }
+  return 0;
+}
+
 void
 mpegts_mux_initial_scan_done ( mpegts_mux_t *mm )
 {
@@ -127,12 +140,18 @@ mpegts_mux_initial_scan_done ( mpegts_mux_t *mm )
   mm->mm_initial_scan_status = MM_SCAN_DONE;
   TAILQ_REMOVE(&mn->mn_initial_scan_current_queue, mm, mm_initial_scan_link);
   mpegts_network_schedule_initial_scan(mn);
+
+  /* Stop */
+  if (!mpegts_mux_has_subscribers(mm))
+    mm->mm_stop(mm);
+
   // TODO: save
 }
 
 static int
 mpegts_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
 {
+  char buf[128];
   mpegts_network_t      *mn = mm->mm_network;
   mpegts_mux_instance_t *mmi;
 
@@ -147,6 +166,8 @@ mpegts_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
   
   /* Create mux instances (where needed) */
   mm->mm_create_instances(mm);
+  if (!LIST_FIRST(&mm->mm_instances))
+    tvhtrace("mpegts", "mm %p has no instances", mm);
 
   /* Find */
   // TODO: don't like this is unbounded, if for some reason mi_start_mux()
@@ -154,10 +175,12 @@ mpegts_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
   while (1) {
 
     /* Find free input */
-    LIST_FOREACH(mmi, &mm->mm_instances, mmi_mux_link)
+    LIST_FOREACH(mmi, &mm->mm_instances, mmi_mux_link) {
       if (!mmi->mmi_tune_failed &&
+          mmi->mmi_input->mi_is_enabled(mmi->mmi_input) &&
           mmi->mmi_input->mi_is_free(mmi->mmi_input))
         break;
+    }
     if (mmi)
       tvhtrace("mpegts", "found free mmi %p", mmi);
     else
@@ -189,6 +212,8 @@ mpegts_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
     }
     
     /* Tune */
+    mm->mm_display_name(mm, buf, sizeof(buf));
+    tvhlog(LOG_INFO, "mpegts", "tuning %s", buf);
     if (!mmi->mmi_input->mi_start_mux(mmi->mmi_input, mmi)) {
       LIST_INSERT_HEAD(&mmi->mmi_input->mi_mux_active, mmi, mmi_active_link);
       mm->mm_active = mmi;
@@ -203,7 +228,7 @@ mpegts_mux_start ( mpegts_mux_t *mm, const char *reason, int weight )
     TAILQ_REMOVE(&mn->mn_initial_scan_pending_queue, mm, mm_initial_scan_link);
     mm->mm_initial_scan_status = MM_SCAN_CURRENT;
     TAILQ_INSERT_TAIL(&mn->mn_initial_scan_current_queue, mm, mm_initial_scan_link);
-    gtimer_arm(&mm->mm_initial_scan_timeout, mpegts_mux_initial_scan_timeout, mm, 10);
+    gtimer_arm(&mm->mm_initial_scan_timeout, mpegts_mux_initial_scan_timeout, mm, 30);
   }
 
   return 0;
@@ -217,11 +242,15 @@ mpegts_mux_stop ( mpegts_mux_t *mm )
   mpegts_input_t *mi;
 
   tvhtrace("mpegts", "stopping mux %p", mm);
-  assert(0);
 
-  /* Flush all subscribers */
   if (mmi) {
     mi = mmi->mmi_input;
+    mi->mi_stop_mux(mi, mmi);
+    mm->mm_active = NULL;
+    LIST_REMOVE(mmi, mmi_active_link);
+    tvhtrace("mpegts", "active first = %p", LIST_FIRST(&mi->mi_mux_active));
+
+    /* Flush all subscribers */
     s = LIST_FIRST(&mi->mi_transports);
     while (s) {
       t = s;
index 7efc79fd34ede900694110dab3c4a7714218d036..05f3ff28385efafb9518ea10397e994e278b488d 100644 (file)
@@ -29,9 +29,10 @@ mpegts_table_fastswitch ( mpegts_mux_t *mm )
   if(mm->mm_initial_scan_status == MM_SCAN_DONE)
     return;
 
-  LIST_FOREACH(mt, &mm->mm_tables, mt_link)
+  LIST_FOREACH(mt, &mm->mm_tables, mt_link) {
     if((mt->mt_flags & MT_QUICKREQ) && mt->mt_count == 0)
       return;
+  }
 
   // TODO:
   //dvb_mux_save(dm);
@@ -121,11 +122,12 @@ mpegts_table_add
   mpegts_table_t *mt;
 
   /* Check for existing */
-  LIST_FOREACH(mt, &mm->mm_tables, mt_link)
+  LIST_FOREACH(mt, &mm->mm_tables, mt_link) {
     if ( mt->mt_pid      == pid      &&
          mt->mt_callback == callback &&
          mt->mt_opaque   == opaque )
       return;
+  }
 
   tvhtrace("mpegts", "add %s table %02X/%02X (%d) pid %04X (%d)",
            name, tableid, mask, tableid, pid, pid);