]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
various dvb related fixes
authorAndreas Öman <andreas@lonelycoder.com>
Mon, 27 Aug 2007 17:08:22 +0000 (17:08 +0000)
committerAndreas Öman <andreas@lonelycoder.com>
Mon, 27 Aug 2007 17:08:22 +0000 (17:08 +0000)
- use FE_GET_EVENT to get faster status updates from dvb adapter frontend
- avoid using dvb muxes that are not locked or if they have too many FEC errors

dvb.c
dvb.h
dvb_dvr.c
main.c
transports.c
transports.h

diff --git a/dvb.c b/dvb.c
index 5d8c5d37402cbbeb6f4a3b2e1404d99dcb21f9b4..449f97472cb86a59672ec88d0ce2364b70809202 100644 (file)
--- a/dvb.c
+++ b/dvb.c
@@ -54,11 +54,6 @@ static void dvb_tdt_add_demux(th_dvb_mux_instance_t *tdmi);
 static void dvb_eit_add_demux(th_dvb_mux_instance_t *tdmi);
 static void dvb_sdt_add_demux(th_dvb_mux_instance_t *tdmi);
 
-static int dvb_tune_tdmi(th_dvb_mux_instance_t *tdmi, int maylog, 
-                        tdmi_state_t state);
-
-static void *dvb_monitor_thread(void *aux);
-
 static void tdmi_check_scan_status(th_dvb_mux_instance_t *tdmi);
 
 static void dvb_start_initial_scan(th_dvb_mux_instance_t *tdmi);
@@ -67,13 +62,58 @@ static void tdmi_activate(th_dvb_mux_instance_t *tdmi);
 
 static void dvb_mux_scanner(void *aux);
 
+static void dvb_fec_monitor(void *aux);
+
+static void
+dvb_frontend_event(int events, void *opaque, int fd)
+{
+  th_dvb_adapter_t *tda = opaque;
+  struct dvb_frontend_event ev;
+  th_dvb_mux_instance_t *tdmi;
+  int r, v;
+
+  if(!(events & DISPATCH_PRI))
+    return;
+
+  r = ioctl(fd, FE_GET_EVENT, &ev);
+  if(r == 0) {
+
+    pthread_mutex_lock(&tda->tda_mux_lock);
+
+    tdmi = tda->tda_mux_current;
+    if(tdmi != NULL) {
+      tdmi->tdmi_fe_status = ev.status;
+    
+      if(tdmi->tdmi_fe_status & FE_HAS_LOCK) {
+       tdmi->tdmi_status = NULL;
+      } else if(tdmi->tdmi_fe_status & FE_HAS_SYNC)
+       tdmi->tdmi_status = "No lock, but sync ok";
+      else if(tdmi->tdmi_fe_status & FE_HAS_VITERBI)
+       tdmi->tdmi_status = "No lock, but FEC stable";
+      else if(tdmi->tdmi_fe_status & FE_HAS_CARRIER)
+       tdmi->tdmi_status = "No lock, but carrier present";
+      else if(tdmi->tdmi_fe_status & FE_HAS_SIGNAL)
+       tdmi->tdmi_status = "No lock, but faint signal present";
+      else
+       tdmi->tdmi_status = "No signal";
+
+      /* Reset FEC Error counter */
+
+      ioctl(tda->tda_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &v);
+    }
+
+    pthread_mutex_unlock(&tda->tda_mux_lock);
+  }
+}
+
+
+
 static void
 dvb_add_adapter(const char *path)
 {
   char fname[256];
   int fe;
   th_dvb_adapter_t *tda;
-  pthread_t ptid;
 
   snprintf(fname, sizeof(fname), "%s/frontend0", path);
   
@@ -110,9 +150,11 @@ dvb_add_adapter(const char *path)
   LIST_INSERT_HEAD(&dvb_adapters_probing, tda, tda_link);
 
   tda->tda_name = strdup(tda->tda_fe_info.name);
-  pthread_create(&ptid, NULL, dvb_monitor_thread, tda);
+
+  dispatch_addfd(tda->tda_fe_fd, dvb_frontend_event, tda, DISPATCH_PRI);
 
   syslog(LOG_INFO, "Adding adapter %s (%s)", tda->tda_fe_info.name, path);
+  stimer_add(dvb_fec_monitor, tda, 1);
 
 }
 
@@ -227,7 +269,7 @@ tdt_add(th_dvb_mux_instance_t *tdmi, int fd,
 
 
 
-static int
+int
 dvb_tune_tdmi(th_dvb_mux_instance_t *tdmi, int maylog, tdmi_state_t state)
 {
   th_dvb_adapter_t *tda = tdmi->tdmi_adapter;
@@ -259,19 +301,16 @@ dvb_tune_tdmi(th_dvb_mux_instance_t *tdmi, int maylog, tdmi_state_t state)
     return -1;
   }
 
-
   dvb_tdt_add_demux(tdmi);
   dvb_eit_add_demux(tdmi);
   dvb_sdt_add_demux(tdmi);
 
   time(&tdmi->tdmi_got_adapter);
 
-
   /* Reset FEC counter */
   ioctl(tda->tda_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &v);
 
   pthread_mutex_unlock(&tda->tda_mux_lock);
-
   return 0;
 }
 
@@ -279,90 +318,6 @@ dvb_tune_tdmi(th_dvb_mux_instance_t *tdmi, int maylog, tdmi_state_t state)
 
 
 
-
-
-int
-dvb_tune(th_dvb_adapter_t *tda, th_dvb_mux_t *tdm, int maylog)
-{
-  th_dvb_mux_instance_t *tdmi;
-  
-  LIST_FOREACH(tdmi, &tda->tda_muxes_active, tdmi_adapter_link)
-    if(tdmi->tdmi_mux == tdm)
-      break;
-  if(tdmi == NULL)
-    return -1;
-
-  return dvb_tune_tdmi(tdmi, maylog, TDMI_RUNNING);
-}
-
-static void
-dvb_monitor_current_mux(th_dvb_adapter_t *tda)
-{
-  th_dvb_mux_instance_t *tdmi;
-  time_t now;
-  int v;
-  time(&now);
-
-  pthread_mutex_lock(&tda->tda_mux_lock);
-
-  tdmi = tda->tda_mux_current;
-
-  if(tdmi != NULL && now > tdmi->tdmi_got_adapter + 1) {
-
-    if(ioctl(tda->tda_fe_fd, FE_READ_STATUS, &tdmi->tdmi_fe_status) < 0)
-      tdmi->tdmi_fe_status = 0;
-
-    if(tdmi->tdmi_fe_status & FE_HAS_LOCK) {
-      tdmi->tdmi_status = NULL;
-    } else if(tdmi->tdmi_fe_status & FE_HAS_SYNC)
-      tdmi->tdmi_status = "No lock, but sync ok";
-    else if(tdmi->tdmi_fe_status & FE_HAS_VITERBI)
-      tdmi->tdmi_status = "No lock, but FEC stable";
-    else if(tdmi->tdmi_fe_status & FE_HAS_CARRIER)
-      tdmi->tdmi_status = "No lock, but carrier present";
-    else if(tdmi->tdmi_fe_status & FE_HAS_SIGNAL)
-      tdmi->tdmi_status = "No lock, but faint signal present";
-    else
-      tdmi->tdmi_status = "No signal";
-
-#if 0
-    if(ioctl(tda->tda_fe_fd, FE_READ_SIGNAL_STRENGTH, &tdmi->tdmi_signal) < 0)
-      tdmi->tdmi_signal = 0;
-
-    if(ioctl(tda->tda_fe_fd, FE_READ_SNR, &tdmi->tdmi_snr) < 0)
-      tdmi->tdmi_snr = 0;
-
-    if(ioctl(tda->tda_fe_fd, FE_READ_BER, &tdmi->tdmi_ber) < 0)
-      tdmi->tdmi_ber = 0;
-#endif
-
-    if(tdmi->tdmi_status == NULL) {
-      v = 0;
-      ioctl(tda->tda_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &v);
-      tdmi->tdmi_fec_err_per_sec = (tdmi->tdmi_fec_err_per_sec + v) / 2;
-    }
-  }
-  pthread_mutex_unlock(&tda->tda_mux_lock);
-}
-    
-    
-
-
-static void *
-dvb_monitor_thread(void *aux)
-{
-  th_dvb_adapter_t *tda = aux;
-
-  while(1) {
-    sleep(1);
-    dvb_monitor_current_mux(tda);
-  }
-}
-
-
-
-
-
 /*
  *
  */
@@ -950,6 +905,44 @@ dvb_start_initial_scan(th_dvb_mux_instance_t *tdmi)
 
 }
 
+/**
+ *
+ *
+ */
+
+static int
+mux_sort_quality(th_dvb_mux_instance_t *a, th_dvb_mux_instance_t *b)
+{
+  return a->tdmi_fec_err_per_sec - b->tdmi_fec_err_per_sec;
+}
+
+
+static void
+dvb_fec_monitor(void *aux)
+{
+  th_dvb_adapter_t *tda = aux;
+  th_dvb_mux_instance_t *tdmi;
+  th_dvb_mux_t *tdm;
+  int v;
+
+  stimer_add(dvb_fec_monitor, tda, 1);
+  tdmi = tda->tda_mux_current;
+
+  if(tdmi != NULL && tdmi->tdmi_status == NULL) {
+    if(ioctl(tda->tda_fe_fd, FE_READ_UNCORRECTED_BLOCKS, &v) < 0)
+      v = 0;
+    tdmi->tdmi_fec_err_per_sec = (tdmi->tdmi_fec_err_per_sec + v) / 2;
+
+    subscription_lock();
+
+    tdm = tdmi->tdmi_mux;
+    LIST_REMOVE(tdmi, tdmi_mux_link);
+    LIST_INSERT_SORTED(&tdm->tdm_instances, tdmi, tdmi_mux_link,
+                      mux_sort_quality);
+    subscription_unlock();
+  }
+}
+
 /**
  * If nobody is subscribing, cycle thru all muxes to get some stats
  * and EIT updates
diff --git a/dvb.h b/dvb.h
index 616e2b9b9a9dfde6a96675717e60d587fcc1fbb9..67c9aa2f0d3ff25621ff63de71e5b1bdb9006245 100644 (file)
--- a/dvb.h
+++ b/dvb.h
@@ -27,6 +27,6 @@ void dvb_init(void);
 
 int dvb_configure_transport(th_transport_t *t, const char *muxname);
 
-int dvb_tune(th_dvb_adapter_t *tda, th_dvb_mux_t *tdm, int maylog);
+int dvb_tune_tdmi(th_dvb_mux_instance_t *tdmi, int maylog, tdmi_state_t state);
 
 #endif /* DVB_H_ */
index e4e34bcdcebcd9dd039f6676b430dfe0771496e5..a9b421e19ede047ece675a43af76e39220057f68 100644 (file)
--- a/dvb_dvr.c
+++ b/dvb_dvr.c
@@ -139,29 +139,40 @@ dvb_stop_feed(th_transport_t *t)
 int
 dvb_start_feed(th_transport_t *t, unsigned int weight)
 {
-  th_dvb_adapter_t *tda, *cand = NULL;
+  th_dvb_adapter_t *tda;
   struct dmx_pes_filter_params dmx_param;
   th_pid_t *tp;
   int w, fd, pid;
 
-  LIST_FOREACH(tda, &dvb_adapters_running, tda_link) {
-    w = transport_compute_weight(&tda->tda_transports);
-    if(w < weight)
-      cand = tda;
+  th_dvb_mux_instance_t *tdmi, *cand = NULL;
+  th_dvb_mux_t *mux = t->tht_dvb_mux;
 
-    if(tda->tda_mux_current != NULL &&
-       tda->tda_mux_current->tdmi_mux == t->tht_dvb_mux)
-      break;
-  }
+  LIST_FOREACH(tdmi, &mux->tdm_instances, tdmi_mux_link) {
+
+    if(tdmi->tdmi_status != NULL)
+      continue; /* no lock */
 
-  if(tda == NULL) {
-    if(cand == NULL)
-      return 1;
+    if(tdmi->tdmi_fec_err_per_sec > 100)
+      continue; /* too much errors to even consider */
 
-    dvb_adapter_clean(cand);
-    tda = cand;
+    if(tdmi->tdmi_state == TDMI_RUNNING)
+      goto gotmux;
+
+    w = transport_compute_weight(&tdmi->tdmi_adapter->tda_transports);
+    if(w < weight && cand == NULL)
+      cand = tdmi;
   }
 
+  if(cand == NULL)
+    return 1;
+
+  tdmi = cand;
+
+  dvb_adapter_clean(tdmi->tdmi_adapter);
+  
+ gotmux:
+  tda = tdmi->tdmi_adapter;
+
   LIST_FOREACH(tp, &t->tht_pids, tp_link) {
     
     fd = open(tda->tda_demux_path, O_RDWR);
@@ -198,8 +209,8 @@ dvb_start_feed(th_transport_t *t, unsigned int weight)
   LIST_INSERT_HEAD(&tda->tda_transports, t, tht_adapter_link);
   t->tht_dvb_adapter = tda;
   t->tht_status = TRANSPORT_RUNNING;
-
-  dvb_tune(tda, t->tht_dvb_mux, 1);
+  
+  dvb_tune_tdmi(tdmi, 1, TDMI_RUNNING);
   return 0;
 }
 
diff --git a/main.c b/main.c
index 46777283239772d81b23f45460b7ecdc7bdd0e92..5851b5d12d841bbbe0a3e7621b46347540e3f24e 100644 (file)
--- a/main.c
+++ b/main.c
@@ -45,6 +45,7 @@
 #include "epg_xmltv.h"
 #include "pvr.h"
 #include "dispatch.h"
+#include "transports.h"
 #include "iptv_output.h"
 
 int running;
@@ -175,6 +176,7 @@ main(int argc, char **argv)
   pvr_init();
   output_multicast_setup();
 
+  transport_scheduler_init();
   
   running = 1;
 
index c62bdca151e6eb9660cb4f62e0ca914d232fcb2c..5d522a11732855a1bce8836a757ed978974149fa 100644 (file)
@@ -195,6 +195,17 @@ subscription_reschedule(void)
 
 
 
+static void
+auto_reschedule(void *aux)
+{
+  stimer_add(auto_reschedule, NULL, 10);
+
+  pthread_mutex_lock(&subscription_mutex);
+  subscription_reschedule();
+  pthread_mutex_unlock(&subscription_mutex);
+}
+
+
 
 
 
@@ -382,6 +393,7 @@ transport_recv_tsb(th_transport_t *t, int pid, uint8_t *tsb)
 }
 
 
+
 static void
 transport_monitor(void *aux)
 {
@@ -423,6 +435,13 @@ transport_monitor_init(th_transport_t *t)
 }
 
 
+void
+transport_scheduler_init(void)
+{
+  stimer_add(auto_reschedule, NULL, 60);
+}
+
+
 void
 transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type)
 {
index 4918fb2db776ccf6d575caec4a4e750057c56a12..b6d032b45c6999dfc23d2b5fb0dd45bd5617358f 100644 (file)
@@ -38,6 +38,8 @@ void transport_add_pid(th_transport_t *t, uint16_t pid, tv_streamtype_t type);
 
 int transport_set_channel(th_transport_t *th, const char *name);
 
+void transport_scheduler_init(void);
+
 th_subscription_t *channel_subscribe(th_channel_t *ch, void *opaque,
                                     void (*ths_callback)
                                     (struct th_subscription *s, 
@@ -45,4 +47,5 @@ th_subscription_t *channel_subscribe(th_channel_t *ch, void *opaque,
                                     unsigned int weight,
                                     const char *name);
 
+
 #endif /* TRANSPORTS_H */