]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Make V4L and DVB conditionally compiled
authorAndreas Öman <andreas@lonelycoder.com>
Tue, 16 Feb 2010 19:49:54 +0000 (19:49 +0000)
committerAndreas Öman <andreas@lonelycoder.com>
Tue, 16 Feb 2010 19:49:54 +0000 (19:49 +0000)
Makefile
configure
src/main.c
src/webui/extjs.c
src/webui/extjs_dvb.c [new file with mode: 0644]
src/webui/extjs_v4l.c [new file with mode: 0644]
src/webui/statedump.c
src/webui/webui.h
support/configure.inc

index 549b02356a4229e2eeab0f828ca8df42fe9e575b..465cbb9347774a2789cd659f95a3c005c646d23e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -69,14 +69,13 @@ SRCS =  src/main.c \
        src/htsstr.c \
        src/rawtsinput.c \
        src/iptv_input.c \
-       src/v4l.c
-
 
 SRCS += src/dvr/dvr_db.c \
        src/dvr/dvr_rec.c \
        src/dvr/dvr_autorec.c
 
-SRCS += src/dvb/dvb.c \
+SRCS-${CONFIG_LINUXDVB} += \
+       src/dvb/dvb.c \
        src/dvb/dvb_support.c \
        src/dvb/dvb_fe.c \
        src/dvb/dvb_tables.c \
@@ -86,6 +85,12 @@ SRCS += src/dvb/dvb.c \
        src/dvb/dvb_transport.c \
        src/dvb/dvb_preconf.c \
        src/dvb/dvb_satconf.c \
+       src/webui/extjs_dvb.c \
+
+SRCS-${CONFIG_V4L} += \
+       src/v4l.c \
+       src/webui/extjs_v4l.c \
+
 
 #
 # cwc
index aecfc7a13aa095ac03178cb90a66a5fa454c0c23..e9ae17ce69dc04778e7555d89486867a1b91bb99 100755 (executable)
--- a/configure
+++ b/configure
@@ -36,6 +36,8 @@ show_help(){
 
 enable cwc
 enable avahi
+enable linuxdvb
+enable v4l
 
 for opt do
   optval="${opt#*=}"
index 79a2b373ba2eddf69233094c5c41b294169e0f4e..d0e4dc3cc010b63f207e19d72d13133b7af717d4 100644 (file)
@@ -371,13 +371,13 @@ main(int argc, char **argv)
   access_init(createdefault);
 
   tcp_server_init();
-
+#if ENABLE_LINUXDVB
   dvb_init(adapter_mask);
-
+#endif
   iptv_input_init();
-
+#if ENABLE_V4L
   v4l_init();
-
+#endif
   http_server_init();
 
   webui_init(TVHEADEND_CONTENT_PATH);
index 7e13d244192df6db2a7fd51b5e56c9d864af9962..244664d35846532899da76dbe502d171a9033fb4 100644 (file)
 #include "channels.h"
 #include "psi.h"
 
-#include "dvb/dvb.h"
-#include "dvb/dvb_support.h"
-#include "dvb/dvb_preconf.h"
 #include "dvr/dvr.h"
-#include "v4l.h"
 #include "transports.h"
 #include "serviceprobe.h"
 #include "xmltv.h"
@@ -129,9 +125,13 @@ extjs_root(http_connection_t *hc, const char *remain, void *opaque)
   extjs_load(hq, "static/app/cwceditor.js");
   extjs_load(hq, "static/app/capmteditor.js");
   extjs_load(hq, "static/app/tvadapters.js");
+#if ENABLE_LINUXDVB
   extjs_load(hq, "static/app/dvb.js");
+#endif
   extjs_load(hq, "static/app/iptv.js");
+#if ENABLE_V4L
   extjs_load(hq, "static/app/v4l.js");
+#endif
   extjs_load(hq, "static/app/chconf.js");
   extjs_load(hq, "static/app/epg.js");
   extjs_load(hq, "static/app/dvr.js");
@@ -444,45 +444,6 @@ extjs_ecglist(http_connection_t *hc, const char *remain, void *opaque)
   return 0;
 }
 
-
-/**
- *
- */
-static int
-extjs_dvbnetworks(http_connection_t *hc, const char *remain, void *opaque)
-{
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  const char *s = http_arg_get(&hc->hc_req_args, "node");
-  const char *a = http_arg_get(&hc->hc_req_args, "adapter");
-  th_dvb_adapter_t *tda;
-  htsmsg_t *out = NULL;
-
-  if(s == NULL || a == NULL)
-    return HTTP_STATUS_BAD_REQUEST;
-  
-  pthread_mutex_lock(&global_lock);
-
-  if(http_access_verify(hc, ACCESS_ADMIN)) {
-    pthread_mutex_unlock(&global_lock);
-    return HTTP_STATUS_UNAUTHORIZED;
-  }
-
-  if((tda = dvb_adapter_find_by_identifier(a)) == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return HTTP_STATUS_BAD_REQUEST;
-  }
-
-  pthread_mutex_unlock(&global_lock);
-
-  if((out = dvb_mux_preconf_get_node(tda->tda_type, s)) == NULL)
-    return 404;
-
-  htsmsg_json_serialize(out, hq, 0);
-  htsmsg_destroy(out);
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  return 0;
-}
-
 /**
  *
  */
@@ -1013,127 +974,22 @@ extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque)
 }
 
 
+
 /**
  *
  */
-static int
-extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
+void
+extjs_transport_delete(htsmsg_t *in)
 {
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  th_dvb_adapter_t *tda, *ref;
-  htsmsg_t *out, *array, *r;
-  const char *op = http_arg_get(&hc->hc_req_args, "op");
-  const char *sibling = http_arg_get(&hc->hc_req_args, "sibling");
-  const char *s, *sc;
-  th_dvb_mux_instance_t *tdmi;
+  htsmsg_field_t *f;
   th_transport_t *t;
+  const char *id;
 
-  pthread_mutex_lock(&global_lock);
-
-  if(remain == NULL) {
-    /* Just list all adapters */
-
-    ref = sibling != NULL ? dvb_adapter_find_by_identifier(sibling) : NULL;
-
-    array = htsmsg_create_list();
-
-    TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) {
-      if(ref == NULL || (ref != tda && ref->tda_type == tda->tda_type))
-       htsmsg_add_msg(array, NULL, dvb_adapter_build_msg(tda));
-    }
-    pthread_mutex_unlock(&global_lock);
-    out = htsmsg_create_map();
-    htsmsg_add_msg(out, "entries", array);
-
-    htsmsg_json_serialize(out, hq, 0);
-    htsmsg_destroy(out);
-    http_output_content(hc, "text/x-json; charset=UTF-8");
-    return 0;
-  }
-
-  if((tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  }
-
-  if(!strcmp(op, "load")) {
-    r = htsmsg_create_map();
-    htsmsg_add_str(r, "id", tda->tda_identifier);
-    htsmsg_add_str(r, "device", tda->tda_rootpath ?: "No hardware attached");
-    htsmsg_add_str(r, "name", tda->tda_displayname);
-    htsmsg_add_u32(r, "automux", tda->tda_autodiscovery);
-    htsmsg_add_u32(r, "idlescan", tda->tda_idlescan);
-    htsmsg_add_u32(r, "qmon", tda->tda_qmon);
-    htsmsg_add_u32(r, "nitoid", tda->tda_nitoid);
-    htsmsg_add_str(r, "diseqcversion", 
-                  ((const char *[]){"DiSEqC 1.0 / 2.0",
-                                      "DiSEqC 1.1 / 2.1"})
-                  [tda->tda_diseqc_version % 2]);
-    out = json_single_record(r, "dvbadapters");
-  } else if(!strcmp(op, "save")) {
-
-    if((s = http_arg_get(&hc->hc_req_args, "name")) != NULL)
-      dvb_adapter_set_displayname(tda, s);
-
-    s = http_arg_get(&hc->hc_req_args, "automux");
-    dvb_adapter_set_auto_discovery(tda, !!s);
-
-    s = http_arg_get(&hc->hc_req_args, "idlescan");
-    dvb_adapter_set_idlescan(tda, !!s);
-
-    s = http_arg_get(&hc->hc_req_args, "qmon");
-    dvb_adapter_set_qmon(tda, !!s);
-
-    if((s = http_arg_get(&hc->hc_req_args, "nitoid")) != NULL)
-      dvb_adapter_set_nitoid(tda, atoi(s));
-
-    if((s = http_arg_get(&hc->hc_req_args, "diseqcversion")) != NULL) {
-      if(!strcmp(s, "DiSEqC 1.0 / 2.0"))
-       dvb_adapter_set_diseqc_version(tda, 0);
-      else if(!strcmp(s, "DiSEqC 1.1 / 2.1"))
-       dvb_adapter_set_diseqc_version(tda, 1);
-    }
-
-    out = htsmsg_create_map();
-    htsmsg_add_u32(out, "success", 1);
-  } else if(!strcmp(op, "addnetwork")) {
-
-    sc = http_arg_get(&hc->hc_req_args, "satconf");
-
-    if((s = http_arg_get(&hc->hc_req_args, "network")) != NULL)
-      dvb_mux_preconf_add_network(tda, s, sc);
-
-    out = htsmsg_create_map();
-    htsmsg_add_u32(out, "success", 1);
-
-  } else if(!strcmp(op, "serviceprobe")) {
-
-    tvhlog(LOG_NOTICE, "web interface",
-          "Service probe started on \"%s\"", tda->tda_displayname);
-
-    LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
-      LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
-       if(t->tht_enabled)
-         serviceprobe_enqueue(t);
-      }
-    }
-
-
-    out = htsmsg_create_map();
-    htsmsg_add_u32(out, "success", 1);
-
-  } else {
-    pthread_mutex_unlock(&global_lock);
-    return HTTP_STATUS_BAD_REQUEST;
+  TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
+    if((id = htsmsg_field_get_string(f)) != NULL &&
+       (t = transport_find_by_identifier(id)) != NULL)
+      transport_destroy(t);
   }
-  pthread_mutex_unlock(&global_lock);
-
-  htsmsg_json_serialize(out, hq, 0);
-  htsmsg_destroy(out);
-
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  return 0;  
 }
 
 
@@ -1141,42 +997,28 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
  *
  */
 static void
-mux_update(htsmsg_t *in)
+transport_update(htsmsg_t *in)
 {
   htsmsg_field_t *f;
   htsmsg_t *c;
-  th_dvb_mux_instance_t *tdmi;
+  th_transport_t *t;
   uint32_t u32;
   const char *id;
+  const char *chname;
 
   TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
     if((c = htsmsg_get_map_by_field(f)) == NULL ||
        (id = htsmsg_get_str(c, "id")) == NULL)
       continue;
     
-    if((tdmi = dvb_mux_find_by_identifier(id)) == NULL)
+    if((t = transport_find_by_identifier(id)) == NULL)
       continue;
 
     if(!htsmsg_get_u32(c, "enabled", &u32))
-      dvb_mux_set_enable(tdmi, u32);
-  }
-}
-
-
-/**
- *
- */
-static void
-mux_delete(htsmsg_t *in)
-{
-  htsmsg_field_t *f;
-  th_dvb_mux_instance_t *tdmi;
-  const char *id;
+      transport_set_enable(t, u32);
 
-  TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
-    if((id = htsmsg_field_get_string(f)) != NULL &&
-       (tdmi = dvb_mux_find_by_identifier(id)) != NULL)
-      dvb_mux_destroy(tdmi);
+    if((chname = htsmsg_get_str(c, "channelname")) != NULL) 
+      transport_map_channel(t, channel_find_by_name(chname, 1), 1);
   }
 }
 
@@ -1185,97 +1027,139 @@ mux_delete(htsmsg_t *in)
  *
  */
 static int
-extjs_dvbmuxes(http_connection_t *hc, const char *remain, void *opaque)
+extjs_servicedetails(http_connection_t *hc, 
+                    const char *remain, void *opaque)
 {
   htsbuf_queue_t *hq = &hc->hc_reply;
-  th_dvb_adapter_t *tda;
-  htsmsg_t *out, *array, *in;
-  const char *op        = http_arg_get(&hc->hc_req_args, "op");
-  const char *entries   = http_arg_get(&hc->hc_req_args, "entries");
-  th_dvb_mux_instance_t *tdmi;
+  htsmsg_t *out, *streams, *c;
+  th_transport_t *t;
+  th_stream_t *st;
+  char buf[40];
 
   pthread_mutex_lock(&global_lock);
 
-  if(remain == NULL ||
-     (tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
+  if(remain == NULL || (t = transport_find_by_identifier(remain)) == NULL) {
     pthread_mutex_unlock(&global_lock);
     return 404;
   }
 
-  in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
+  streams = htsmsg_create_list();
 
-  out = htsmsg_create_map();
+  LIST_FOREACH(st, &t->tht_components, st_link) {
+    c = htsmsg_create_map();
 
-  if(!strcmp(op, "get")) {
-    array = htsmsg_create_list();
+    htsmsg_add_u32(c, "pid", st->st_pid);
 
-    LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link)
-      htsmsg_add_msg(array, NULL, dvb_mux_build_msg(tdmi));
+    htsmsg_add_str(c, "type", streaming_component_type2txt(st->st_type));
 
-    htsmsg_add_msg(out, "entries", array);
-  } else if(!strcmp(op, "update")) {
-    if(in != NULL)
-      mux_update(in);
+    switch(st->st_type) {
+    default:
+      htsmsg_add_str(c, "details", "");
+      break;
 
-    out = htsmsg_create_map();
+    case SCT_CA:
+      snprintf(buf, sizeof(buf), "%s (0x%04x)",
+              psi_caid2name(st->st_caid), st->st_caid);
+      htsmsg_add_str(c, "details", buf);
+      break;
 
-  } else if(!strcmp(op, "delete")) {
-    if(in != NULL)
-      mux_delete(in);
-    
-    out = htsmsg_create_map();
+    case SCT_AC3:
+    case SCT_AAC:
+    case SCT_MPEG2AUDIO:
+      htsmsg_add_str(c, "details", st->st_lang);
+      break;
 
-  } else {
-    pthread_mutex_unlock(&global_lock);
-    if(in != NULL)
-      htsmsg_destroy(in);
-    htsmsg_destroy(out);
-    return HTTP_STATUS_BAD_REQUEST;
+    case SCT_DVBSUB:
+      snprintf(buf, sizeof(buf), "%s (%04x %04x)",
+              st->st_lang, st->st_composition_id, st->st_ancillary_id);
+      htsmsg_add_str(c, "details", buf);
+      break;
+
+    case SCT_MPEG2VIDEO:
+    case SCT_H264:
+      buf[0] = 0;
+      if(st->st_frame_duration)
+       snprintf(buf, sizeof(buf), "%2.2f Hz",
+                90000.0 / st->st_frame_duration);
+      htsmsg_add_str(c, "details", buf);
+      break;
+    }
+
+    htsmsg_add_msg(streams, NULL, c);
   }
 
+  out = htsmsg_create_map();
+  htsmsg_add_str(out, "title", t->tht_svcname ?: "unnamed transport");
+
+  htsmsg_add_msg(out, "streams", streams);
+
   pthread_mutex_unlock(&global_lock);
+
   htsmsg_json_serialize(out, hq, 0);
   htsmsg_destroy(out);
   http_output_content(hc, "text/x-json; charset=UTF-8");
-
-  if(in != NULL)
-    htsmsg_destroy(in);
-
   return 0;
 }
 
 
+
 /**
  *
  */
-static void
-transport_delete(htsmsg_t *in)
+static int
+extjs_mergechannel(http_connection_t *hc, const char *remain, void *opaque)
 {
-  htsmsg_field_t *f;
-  th_transport_t *t;
-  const char *id;
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  const char *target = http_arg_get(&hc->hc_req_args, "targetID");
+  htsmsg_t *out;
+  channel_t *src, *dst;
 
-  TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
-    if((id = htsmsg_field_get_string(f)) != NULL &&
-       (t = transport_find_by_identifier(id)) != NULL)
-      transport_destroy(t);
+  if(remain == NULL || target == NULL)
+    return 400;
+
+  pthread_mutex_lock(&global_lock);
+
+  src = channel_find_by_identifier(atoi(remain));
+  dst = channel_find_by_identifier(atoi(target));
+
+  if(src == NULL || dst == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return 404;
+  }
+
+  out = htsmsg_create_map();
+
+  if(src != dst) {
+    channel_merge(dst, src);
+    htsmsg_add_u32(out, "success", 1);
+  } else {
+
+    htsmsg_add_u32(out, "success", 0);
+    htsmsg_add_str(out, "msg", "Target same as source");
   }
+
+  pthread_mutex_unlock(&global_lock);
+
+  htsmsg_json_serialize(out, hq, 0);
+  htsmsg_destroy(out);
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+  return 0;
 }
 
 
+
 /**
  *
  */
 static void
-transport_update(htsmsg_t *in)
+transport_update_iptv(htsmsg_t *in)
 {
   htsmsg_field_t *f;
   htsmsg_t *c;
   th_transport_t *t;
   uint32_t u32;
-  const char *id;
-  const char *chname;
+  const char *id, *s;
+  int save;
 
   TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
     if((c = htsmsg_get_map_by_field(f)) == NULL ||
@@ -1285,470 +1169,27 @@ transport_update(htsmsg_t *in)
     if((t = transport_find_by_identifier(id)) == NULL)
       continue;
 
-    if(!htsmsg_get_u32(c, "enabled", &u32))
-      transport_set_enable(t, u32);
+    save = 0;
 
-    if((chname = htsmsg_get_str(c, "channelname")) != NULL) 
-      transport_map_channel(t, channel_find_by_name(chname, 1), 1);
+    if(!htsmsg_get_u32(c, "port", &u32)) {
+      t->tht_iptv_port = u32;
+      save = 1;
+    }
+
+    if((s = htsmsg_get_str(c, "group")) != NULL) {
+      inet_pton(AF_INET, s, &t->tht_iptv_group.s_addr);
+      save = 1;
+    }
+    
+
+    save |= tvh_str_update(&t->tht_iptv_iface, htsmsg_get_str(c, "interface"));
+    if(save)
+      t->tht_config_save(t); // Save config
   }
 }
 
 
-/**
- *
- */
-static int
-transportcmp(const void *A, const void *B)
-{
-  th_transport_t *a = *(th_transport_t **)A;
-  th_transport_t *b = *(th_transport_t **)B;
-
-  return strcasecmp(a->tht_svcname ?: "\0377", b->tht_svcname ?: "\0377");
-}
-
-/**
- *
- */
-static int
-extjs_dvbservices(http_connection_t *hc, const char *remain, void *opaque)
-{
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  th_dvb_adapter_t *tda;
-  htsmsg_t *out, *array, *in;
-  const char *op        = http_arg_get(&hc->hc_req_args, "op");
-  const char *entries   = http_arg_get(&hc->hc_req_args, "entries");
-  th_dvb_mux_instance_t *tdmi;
-  th_transport_t *t, **tvec;
-  int count = 0, i = 0;
-
-  pthread_mutex_lock(&global_lock);
-
-  if(remain == NULL ||
-     (tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  }
-
-  in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
-
-  if(!strcmp(op, "get")) {
-
-    out = htsmsg_create_map();
-    array = htsmsg_create_list();
-
-    LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
-      LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
-       count++;
-      }
-    }
-
-    tvec = alloca(sizeof(th_transport_t *) * count);
-
-    LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
-      LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
-       tvec[i++] = t;
-      }
-    }
-
-    qsort(tvec, count, sizeof(th_transport_t *), transportcmp);
-
-    for(i = 0; i < count; i++)
-      htsmsg_add_msg(array, NULL, dvb_transport_build_msg(tvec[i]));
-
-    htsmsg_add_msg(out, "entries", array);
-
-  } else if(!strcmp(op, "update")) {
-    if(in != NULL)
-      transport_update(in);
-
-    out = htsmsg_create_map();
-
-  } else {
-    pthread_mutex_unlock(&global_lock);
-    htsmsg_destroy(in);
-    return HTTP_STATUS_BAD_REQUEST;
-  }
-
-  htsmsg_destroy(in);
-
-  pthread_mutex_unlock(&global_lock);
-
-  htsmsg_json_serialize(out, hq, 0);
-  htsmsg_destroy(out);
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  return 0;
-}
-
-/**
- *
- */
-static int
-extjs_lnbtypes(http_connection_t *hc, const char *remain, void *opaque)
-{
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  htsmsg_t *out;
-
-  out = htsmsg_create_map();
-
-  htsmsg_add_msg(out, "entries", dvb_lnblist_get());
-
-  htsmsg_json_serialize(out, hq, 0);
-  htsmsg_destroy(out);
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  return 0;
-}  
-
-
-
-
-/**
- *
- */
-static int
-extjs_dvbsatconf(http_connection_t *hc, const char *remain, void *opaque)
-{
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  th_dvb_adapter_t *tda;
-  htsmsg_t *out;
-
-  pthread_mutex_lock(&global_lock);
-
-  if(remain == NULL ||
-     (tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  }
-
-  out = htsmsg_create_map();
-  htsmsg_add_msg(out, "entries", dvb_satconf_list(tda));
-
-  pthread_mutex_unlock(&global_lock);
-
-  htsmsg_json_serialize(out, hq, 0);
-  htsmsg_destroy(out);
-
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  return 0;  
-}
-
-
-/**
- *
- */
-static int
-extjs_servicedetails(http_connection_t *hc, 
-                    const char *remain, void *opaque)
-{
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  htsmsg_t *out, *streams, *c;
-  th_transport_t *t;
-  th_stream_t *st;
-  char buf[40];
-
-  pthread_mutex_lock(&global_lock);
-
-  if(remain == NULL || (t = transport_find_by_identifier(remain)) == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  }
-
-  streams = htsmsg_create_list();
-
-  LIST_FOREACH(st, &t->tht_components, st_link) {
-    c = htsmsg_create_map();
-
-    htsmsg_add_u32(c, "pid", st->st_pid);
-
-    htsmsg_add_str(c, "type", streaming_component_type2txt(st->st_type));
-
-    switch(st->st_type) {
-    default:
-      htsmsg_add_str(c, "details", "");
-      break;
-
-    case SCT_CA:
-      snprintf(buf, sizeof(buf), "%s (0x%04x)",
-              psi_caid2name(st->st_caid), st->st_caid);
-      htsmsg_add_str(c, "details", buf);
-      break;
-
-    case SCT_AC3:
-    case SCT_AAC:
-    case SCT_MPEG2AUDIO:
-      htsmsg_add_str(c, "details", st->st_lang);
-      break;
-
-    case SCT_DVBSUB:
-      snprintf(buf, sizeof(buf), "%s (%04x %04x)",
-              st->st_lang, st->st_composition_id, st->st_ancillary_id);
-      htsmsg_add_str(c, "details", buf);
-      break;
-
-    case SCT_MPEG2VIDEO:
-    case SCT_H264:
-      buf[0] = 0;
-      if(st->st_frame_duration)
-       snprintf(buf, sizeof(buf), "%2.2f Hz",
-                90000.0 / st->st_frame_duration);
-      htsmsg_add_str(c, "details", buf);
-      break;
-    }
-
-    htsmsg_add_msg(streams, NULL, c);
-  }
-
-  out = htsmsg_create_map();
-  htsmsg_add_str(out, "title", t->tht_svcname ?: "unnamed transport");
-
-  htsmsg_add_msg(out, "streams", streams);
-
-  pthread_mutex_unlock(&global_lock);
-
-  htsmsg_json_serialize(out, hq, 0);
-  htsmsg_destroy(out);
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  return 0;
-}
-
-
-/**
- *
- */
-static int
-extjs_dvb_feopts(http_connection_t *hc, const char *remain, void *opaque)
-{
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  char *a, *r;
-  th_dvb_adapter_t *tda;
-  htsmsg_t *e, *out;
-
-  if(remain == NULL)
-    return 400;
-
-  r = tvh_strdupa(remain);
-  if((a = strchr(r, '/')) == NULL)
-    return 400;
-  *a++ = 0;
-
-  pthread_mutex_lock(&global_lock);
-
-  if((tda = dvb_adapter_find_by_identifier(a)) == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  }
-
-  e = dvb_fe_opts(tda, r);
-
-  if(e == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 400;
-  }
-
-  out = htsmsg_create_map();
-  htsmsg_add_msg(out, "entries", e);
-
-  pthread_mutex_unlock(&global_lock);
-
-  htsmsg_json_serialize(out, hq, 0);
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  htsmsg_destroy(out);
-  return 0;
-}
-
-/**
- *
- */
-static int
-extjs_dvb_addmux(http_connection_t *hc, const char *remain, void *opaque)
-{
-  htsmsg_t *out;
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  struct http_arg_list *args = &hc->hc_req_args;
-  th_dvb_adapter_t *tda;
-  const char *err;
-  pthread_mutex_lock(&global_lock);
-  if(remain == NULL ||
-     (tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  }
-
-  err =
-    dvb_mux_add_by_params(tda,
-                         atoi(http_arg_get(args, "frequency")?:"-1"),
-                         atoi(http_arg_get(args, "symbolrate")?: "-1"),
-                         atoi(http_arg_get(args, "bandwidthID")?: "-1"),
-                         atoi(http_arg_get(args, "constellationID")?: "-1"),
-                         atoi(http_arg_get(args, "delsysID")?: "-1"),
-                         atoi(http_arg_get(args, "tmodeID")?: "-1"),
-                         atoi(http_arg_get(args, "guardintervalID")?: "-1"),
-                         atoi(http_arg_get(args, "hierarchyID")?: "-1"),
-                         atoi(http_arg_get(args, "fechiID")?: "-1"),
-                         atoi(http_arg_get(args, "fecloID")?: "-1"),
-                         atoi(http_arg_get(args, "fecID")?: "-1"),
-                         atoi(http_arg_get(args, "polarisationID")?: "-1"),
-                         http_arg_get(args, "satconfID") ?: NULL);
-                       
-  if(err != NULL)
-    tvhlog(LOG_ERR, "web interface",
-          "Unable to create mux on %s: %s",
-          tda->tda_displayname, err);
-
-  pthread_mutex_unlock(&global_lock);
-
-  out = htsmsg_create_map();
-  htsmsg_json_serialize(out, hq, 0);
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  htsmsg_destroy(out);
-
-  return 0;
-}
-
-
-/**
- *
- */
-static int
-extjs_dvb_copymux(http_connection_t *hc, const char *remain, void *opaque)
-{
-  htsmsg_t *out;
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  th_dvb_adapter_t *tda;
-  htsmsg_t *in;
-  const char *entries   = http_arg_get(&hc->hc_req_args, "entries");
-  const char *id;
-  htsmsg_field_t *f;
-  th_dvb_mux_instance_t *tdmi;
-
-  in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
-
-  if(in == NULL)
-    return 400;
-
-  pthread_mutex_lock(&global_lock);
-  if(remain == NULL ||
-     (tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  }
-
-
-  TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
-    if((id = htsmsg_field_get_string(f)) != NULL &&
-       (tdmi = dvb_mux_find_by_identifier(id)) != NULL &&
-       tda != tdmi->tdmi_adapter) {
-
-      if(dvb_mux_copy(tda, tdmi)) {
-       char buf[100];
-       dvb_mux_nicename(buf, sizeof(buf), tdmi);
-
-       tvhlog(LOG_NOTICE, "DVB", 
-              "Skipped copy of mux %s to adapter %s, mux already exist",
-              buf, tda->tda_displayname);
-      }
-    }
-  }
-
-  pthread_mutex_unlock(&global_lock);
-
-  out = htsmsg_create_map();
-  htsmsg_json_serialize(out, hq, 0);
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  htsmsg_destroy(out);
-
-  return 0;
-}
-
-
-/**
- *
- */
-static int
-extjs_mergechannel(http_connection_t *hc, const char *remain, void *opaque)
-{
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  const char *target = http_arg_get(&hc->hc_req_args, "targetID");
-  htsmsg_t *out;
-  channel_t *src, *dst;
-
-  if(remain == NULL || target == NULL)
-    return 400;
-
-  pthread_mutex_lock(&global_lock);
-
-  src = channel_find_by_identifier(atoi(remain));
-  dst = channel_find_by_identifier(atoi(target));
-
-  if(src == NULL || dst == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  }
-
-  out = htsmsg_create_map();
-
-  if(src != dst) {
-    channel_merge(dst, src);
-    htsmsg_add_u32(out, "success", 1);
-  } else {
-
-    htsmsg_add_u32(out, "success", 0);
-    htsmsg_add_str(out, "msg", "Target same as source");
-  }
-
-  pthread_mutex_unlock(&global_lock);
-
-  htsmsg_json_serialize(out, hq, 0);
-  htsmsg_destroy(out);
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  return 0;
-}
-
-
-
-/**
- *
- */
-static void
-transport_update_iptv(htsmsg_t *in)
-{
-  htsmsg_field_t *f;
-  htsmsg_t *c;
-  th_transport_t *t;
-  uint32_t u32;
-  const char *id, *s;
-  int save;
-
-  TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
-    if((c = htsmsg_get_map_by_field(f)) == NULL ||
-       (id = htsmsg_get_str(c, "id")) == NULL)
-      continue;
-    
-    if((t = transport_find_by_identifier(id)) == NULL)
-      continue;
-
-    save = 0;
-
-    if(!htsmsg_get_u32(c, "port", &u32)) {
-      t->tht_iptv_port = u32;
-      save = 1;
-    }
-
-    if((s = htsmsg_get_str(c, "group")) != NULL) {
-      inet_pton(AF_INET, s, &t->tht_iptv_group.s_addr);
-      save = 1;
-    }
-    
-
-    save |= tvh_str_update(&t->tht_iptv_iface, htsmsg_get_str(c, "interface"));
-    if(save)
-      t->tht_config_save(t); // Save config
-  }
-}
-
-
-
+
 /**
  *
  */
@@ -1832,7 +1273,7 @@ extjs_iptvservices(http_connection_t *hc, const char *remain, void *opaque)
 
   } else if(!strcmp(op, "delete")) {
     if(in != NULL)
-      transport_delete(in);
+      extjs_transport_delete(in);
 
     out = htsmsg_create_map();
 
@@ -1852,87 +1293,20 @@ extjs_iptvservices(http_connection_t *hc, const char *remain, void *opaque)
   return 0;
 }
 
-/**
- *
- */
-static int
-extjs_v4ladapter(http_connection_t *hc, const char *remain, void *opaque)
-{
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  v4l_adapter_t *va;
-  htsmsg_t *out, *array, *r;
-  const char *op = http_arg_get(&hc->hc_req_args, "op");
-  const char *s;
-
-  pthread_mutex_lock(&global_lock);
-
-  if(remain == NULL) {
-    /* Just list all adapters */
-
-    array = htsmsg_create_list();
-
-    TAILQ_FOREACH(va, &v4l_adapters, va_global_link) 
-      htsmsg_add_msg(array, NULL, v4l_adapter_build_msg(va));
-
-    pthread_mutex_unlock(&global_lock);
-    out = htsmsg_create_map();
-    htsmsg_add_msg(out, "entries", array);
-
-    htsmsg_json_serialize(out, hq, 0);
-    htsmsg_destroy(out);
-    http_output_content(hc, "text/x-json; charset=UTF-8");
-    return 0;
-  }
-
-  if((va = v4l_adapter_find_by_identifier(remain)) == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  }
-
-  if(!strcmp(op, "load")) {
-    r = htsmsg_create_map();
-    htsmsg_add_str(r, "id", va->va_identifier);
-    htsmsg_add_str(r, "device", va->va_path ?: "No hardware attached");
-    htsmsg_add_str(r, "name", va->va_displayname);
-    htsmsg_add_u32(r, "logging", va->va_logging);
-    out = json_single_record(r, "v4ladapters");
-  } else if(!strcmp(op, "save")) {
-
-    if((s = http_arg_get(&hc->hc_req_args, "name")) != NULL)
-      v4l_adapter_set_displayname(va, s);
-
-    s = http_arg_get(&hc->hc_req_args, "logging");
-    v4l_adapter_set_logging(va, !!s);
-
-    out = htsmsg_create_map();
-    htsmsg_add_u32(out, "success", 1);
-
-  } else {
-    pthread_mutex_unlock(&global_lock);
-    return HTTP_STATUS_BAD_REQUEST;
-  }
-  pthread_mutex_unlock(&global_lock);
-
-  htsmsg_json_serialize(out, hq, 0);
-  htsmsg_destroy(out);
 
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  return 0;  
-}
 
 /**
  *
  */
-static void
-transport_update_v4l(htsmsg_t *in)
+void
+extjs_transport_update(htsmsg_t *in)
 {
   htsmsg_field_t *f;
   htsmsg_t *c;
   th_transport_t *t;
   uint32_t u32;
   const char *id;
-  int save;
+  const char *chname;
 
   TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
     if((c = htsmsg_get_map_by_field(f)) == NULL ||
@@ -1942,120 +1316,12 @@ transport_update_v4l(htsmsg_t *in)
     if((t = transport_find_by_identifier(id)) == NULL)
       continue;
 
-    save = 0;
-
-    if(!htsmsg_get_u32(c, "frequency", &u32)) {
-      t->tht_v4l_frequency = u32;
-      save = 1;
-    }
-    if(save)
-      t->tht_config_save(t); // Save config
-  }
-}
-
-
-
-/**
- *
- */
-static htsmsg_t *
-build_record_v4l(th_transport_t *t)
-{
-  htsmsg_t *r = htsmsg_create_map();
-
-  htsmsg_add_str(r, "id", t->tht_identifier);
-
-  htsmsg_add_str(r, "channelname", t->tht_ch ? t->tht_ch->ch_name : "");
-  htsmsg_add_u32(r, "frequency", t->tht_v4l_frequency);
-  htsmsg_add_u32(r, "enabled", t->tht_enabled);
-  return r;
-}
-
-/**
- *
- */
-static int
-v4l_transportcmp(const void *A, const void *B)
-{
-  th_transport_t *a = *(th_transport_t **)A;
-  th_transport_t *b = *(th_transport_t **)B;
-
-  return (int)a->tht_v4l_frequency - (int)b->tht_v4l_frequency;
-}
-
-/**
- *
- */
-static int
-extjs_v4lservices(http_connection_t *hc, const char *remain, void *opaque)
-{
-  v4l_adapter_t *va;
-  htsbuf_queue_t *hq = &hc->hc_reply;
-  htsmsg_t *out, *in, *array;
-  const char *op        = http_arg_get(&hc->hc_req_args, "op");
-  const char *entries   = http_arg_get(&hc->hc_req_args, "entries");
-  th_transport_t *t, **tvec;
-  int count = 0, i = 0;
-
-  pthread_mutex_lock(&global_lock);
-
-  if((va = v4l_adapter_find_by_identifier(remain)) == NULL) {
-    pthread_mutex_unlock(&global_lock);
-    return 404;
-  }
-
-  in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
-
-  if(!strcmp(op, "get")) {
-
-    LIST_FOREACH(t, &va->va_transports, tht_group_link)
-      count++;
-    tvec = alloca(sizeof(th_transport_t *) * count);
-    LIST_FOREACH(t, &va->va_transports, tht_group_link)
-      tvec[i++] = t;
-
-    out = htsmsg_create_map();
-    array = htsmsg_create_list();
-
-    qsort(tvec, count, sizeof(th_transport_t *), v4l_transportcmp);
-
-    for(i = 0; i < count; i++)
-      htsmsg_add_msg(array, NULL, build_record_v4l(tvec[i]));
-
-    htsmsg_add_msg(out, "entries", array);
-
-  } else if(!strcmp(op, "update")) {
-    if(in != NULL) {
-      transport_update(in);      // Generic transport parameters
-      transport_update_v4l(in);  // V4L speicifc
-    }
-
-    out = htsmsg_create_map();
-
-  } else if(!strcmp(op, "create")) {
-
-    out = build_record_v4l(v4l_transport_find(va, NULL, 1));
-
-  } else if(!strcmp(op, "delete")) {
-    if(in != NULL)
-      transport_delete(in);
-
-    out = htsmsg_create_map();
+    if(!htsmsg_get_u32(c, "enabled", &u32))
+      transport_set_enable(t, u32);
 
-  } else {
-    pthread_mutex_unlock(&global_lock);
-    htsmsg_destroy(in);
-    return HTTP_STATUS_BAD_REQUEST;
+    if((chname = htsmsg_get_str(c, "channelname")) != NULL) 
+      transport_map_channel(t, channel_find_by_name(chname, 1), 1);
   }
-
-  htsmsg_destroy(in);
-
-  pthread_mutex_unlock(&global_lock);
-
-  htsmsg_json_serialize(out, hq, 0);
-  htsmsg_destroy(out);
-  http_output_content(hc, "text/x-json; charset=UTF-8");
-  return 0;
 }
 
 
@@ -2067,19 +1333,19 @@ extjs_tvadapter(http_connection_t *hc, const char *remain, void *opaque)
 {
   htsbuf_queue_t *hq = &hc->hc_reply;
   htsmsg_t *out, *array;
-  th_dvb_adapter_t *tda;
-  v4l_adapter_t *va;
 
   pthread_mutex_lock(&global_lock);
 
   /* Just list all adapters */
   array = htsmsg_create_list();
 
-  TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link)
-    htsmsg_add_msg(array, NULL, dvb_adapter_build_msg(tda));
+#if ENABLE_LINUXDVB
+  extjs_list_dvb_adapters(array);
+#endif
 
-  TAILQ_FOREACH(va, &v4l_adapters, va_global_link) 
-    htsmsg_add_msg(array, NULL, v4l_adapter_build_msg(va));
+#if ENABLE_V4L
+  extjs_list_v4l_adapters(array);
+#endif
 
   pthread_mutex_unlock(&global_lock);
   out = htsmsg_create_map();
@@ -2101,7 +1367,6 @@ extjs_start(void)
   http_path_add("/about.html",  NULL, page_about,        ACCESS_WEB_INTERFACE);
   http_path_add("/extjs.html",  NULL, extjs_root,        ACCESS_WEB_INTERFACE);
   http_path_add("/tablemgr",    NULL, extjs_tablemgr,    ACCESS_WEB_INTERFACE);
-  http_path_add("/dvbnetworks", NULL, extjs_dvbnetworks, ACCESS_WEB_INTERFACE);
   http_path_add("/channels",    NULL, extjs_channels,    ACCESS_WEB_INTERFACE);
   http_path_add("/xmltv",       NULL, extjs_xmltv,       ACCESS_WEB_INTERFACE);
   http_path_add("/channeltags", NULL, extjs_channeltags, ACCESS_WEB_INTERFACE);
@@ -2113,44 +1378,20 @@ extjs_start(void)
   http_path_add("/mergechannel",
                NULL, extjs_mergechannel, ACCESS_ADMIN);
 
-  http_path_add("/dvb/adapter", 
-               NULL, extjs_dvbadapter, ACCESS_ADMIN);
-
-  http_path_add("/dvb/muxes", 
-               NULL, extjs_dvbmuxes, ACCESS_ADMIN);
-
-  http_path_add("/dvb/services", 
-               NULL, extjs_dvbservices, ACCESS_ADMIN);
-
-  http_path_add("/dvb/lnbtypes", 
-               NULL, extjs_lnbtypes, ACCESS_ADMIN);
-
-  http_path_add("/dvb/satconf", 
-               NULL, extjs_dvbsatconf, ACCESS_ADMIN);
-
-  http_path_add("/dvb/feopts", 
-               NULL, extjs_dvb_feopts, ACCESS_ADMIN);
-
-  http_path_add("/dvb/addmux", 
-               NULL, extjs_dvb_addmux, ACCESS_ADMIN);
-
-  http_path_add("/dvb/copymux", 
-               NULL, extjs_dvb_copymux, ACCESS_ADMIN);
-
   http_path_add("/iptv/services", 
                NULL, extjs_iptvservices, ACCESS_ADMIN);
 
   http_path_add("/servicedetails", 
                NULL, extjs_servicedetails, ACCESS_ADMIN);
 
-
-  http_path_add("/v4l/adapter", 
-               NULL, extjs_v4ladapter, ACCESS_ADMIN);
-
-  http_path_add("/v4l/services", 
-               NULL, extjs_v4lservices, ACCESS_ADMIN);
-
   http_path_add("/tv/adapter", 
                NULL, extjs_tvadapter, ACCESS_ADMIN);
 
+#if ENABLE_LINUXDVB
+  extjs_start_dvb();
+#endif
+
+#if ENABLE_V4L
+  extjs_start_v4l();
+#endif
 }
diff --git a/src/webui/extjs_dvb.c b/src/webui/extjs_dvb.c
new file mode 100644 (file)
index 0000000..83623c7
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ *  tvheadend, EXTJS based interface
+ *  Copyright (C) 2008 Andreas Öman
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <arpa/inet.h>
+#include <libavutil/avstring.h>
+
+#include "htsmsg.h"
+#include "htsmsg_json.h"
+
+#include "tvhead.h"
+#include "http.h"
+#include "webui.h"
+#include "access.h"
+#include "dtable.h"
+#include "channels.h"
+#include "psi.h"
+#include "transports.h"
+#include "serviceprobe.h"
+
+#include "dvb/dvb.h"
+#include "dvb/dvb_support.h"
+#include "dvb/dvb_preconf.h"
+#include "dvr/dvr.h"
+
+/**
+ *
+ */
+static int
+extjs_dvbnetworks(http_connection_t *hc, const char *remain, void *opaque)
+{
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  const char *s = http_arg_get(&hc->hc_req_args, "node");
+  const char *a = http_arg_get(&hc->hc_req_args, "adapter");
+  th_dvb_adapter_t *tda;
+  htsmsg_t *out = NULL;
+
+  if(s == NULL || a == NULL)
+    return HTTP_STATUS_BAD_REQUEST;
+  
+  pthread_mutex_lock(&global_lock);
+
+  if(http_access_verify(hc, ACCESS_ADMIN)) {
+    pthread_mutex_unlock(&global_lock);
+    return HTTP_STATUS_UNAUTHORIZED;
+  }
+
+  if((tda = dvb_adapter_find_by_identifier(a)) == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return HTTP_STATUS_BAD_REQUEST;
+  }
+
+  pthread_mutex_unlock(&global_lock);
+
+  if((out = dvb_mux_preconf_get_node(tda->tda_type, s)) == NULL)
+    return 404;
+
+  htsmsg_json_serialize(out, hq, 0);
+  htsmsg_destroy(out);
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+  return 0;
+}
+
+/**
+ *
+ */
+static htsmsg_t *
+json_single_record(htsmsg_t *rec, const char *root)
+{
+  htsmsg_t *out, *array;
+  
+  out = htsmsg_create_map();
+  array = htsmsg_create_list();
+
+  htsmsg_add_msg(array, NULL, rec);
+  htsmsg_add_msg(out, root, array);
+  return out;
+}
+
+
+
+/**
+ *
+ */
+static int
+extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
+{
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  th_dvb_adapter_t *tda, *ref;
+  htsmsg_t *out, *array, *r;
+  const char *op = http_arg_get(&hc->hc_req_args, "op");
+  const char *sibling = http_arg_get(&hc->hc_req_args, "sibling");
+  const char *s, *sc;
+  th_dvb_mux_instance_t *tdmi;
+  th_transport_t *t;
+
+  pthread_mutex_lock(&global_lock);
+
+  if(remain == NULL) {
+    /* Just list all adapters */
+
+    ref = sibling != NULL ? dvb_adapter_find_by_identifier(sibling) : NULL;
+
+    array = htsmsg_create_list();
+
+    TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) {
+      if(ref == NULL || (ref != tda && ref->tda_type == tda->tda_type))
+       htsmsg_add_msg(array, NULL, dvb_adapter_build_msg(tda));
+    }
+    pthread_mutex_unlock(&global_lock);
+    out = htsmsg_create_map();
+    htsmsg_add_msg(out, "entries", array);
+
+    htsmsg_json_serialize(out, hq, 0);
+    htsmsg_destroy(out);
+    http_output_content(hc, "text/x-json; charset=UTF-8");
+    return 0;
+  }
+
+  if((tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return 404;
+  }
+
+  if(!strcmp(op, "load")) {
+    r = htsmsg_create_map();
+    htsmsg_add_str(r, "id", tda->tda_identifier);
+    htsmsg_add_str(r, "device", tda->tda_rootpath ?: "No hardware attached");
+    htsmsg_add_str(r, "name", tda->tda_displayname);
+    htsmsg_add_u32(r, "automux", tda->tda_autodiscovery);
+    htsmsg_add_u32(r, "idlescan", tda->tda_idlescan);
+    htsmsg_add_u32(r, "qmon", tda->tda_qmon);
+    htsmsg_add_u32(r, "nitoid", tda->tda_nitoid);
+    htsmsg_add_str(r, "diseqcversion", 
+                  ((const char *[]){"DiSEqC 1.0 / 2.0",
+                                      "DiSEqC 1.1 / 2.1"})
+                  [tda->tda_diseqc_version % 2]);
+    out = json_single_record(r, "dvbadapters");
+  } else if(!strcmp(op, "save")) {
+
+    if((s = http_arg_get(&hc->hc_req_args, "name")) != NULL)
+      dvb_adapter_set_displayname(tda, s);
+
+    s = http_arg_get(&hc->hc_req_args, "automux");
+    dvb_adapter_set_auto_discovery(tda, !!s);
+
+    s = http_arg_get(&hc->hc_req_args, "idlescan");
+    dvb_adapter_set_idlescan(tda, !!s);
+
+    s = http_arg_get(&hc->hc_req_args, "qmon");
+    dvb_adapter_set_qmon(tda, !!s);
+
+    if((s = http_arg_get(&hc->hc_req_args, "nitoid")) != NULL)
+      dvb_adapter_set_nitoid(tda, atoi(s));
+
+    if((s = http_arg_get(&hc->hc_req_args, "diseqcversion")) != NULL) {
+      if(!strcmp(s, "DiSEqC 1.0 / 2.0"))
+       dvb_adapter_set_diseqc_version(tda, 0);
+      else if(!strcmp(s, "DiSEqC 1.1 / 2.1"))
+       dvb_adapter_set_diseqc_version(tda, 1);
+    }
+
+    out = htsmsg_create_map();
+    htsmsg_add_u32(out, "success", 1);
+  } else if(!strcmp(op, "addnetwork")) {
+
+    sc = http_arg_get(&hc->hc_req_args, "satconf");
+
+    if((s = http_arg_get(&hc->hc_req_args, "network")) != NULL)
+      dvb_mux_preconf_add_network(tda, s, sc);
+
+    out = htsmsg_create_map();
+    htsmsg_add_u32(out, "success", 1);
+
+  } else if(!strcmp(op, "serviceprobe")) {
+
+    tvhlog(LOG_NOTICE, "web interface",
+          "Service probe started on \"%s\"", tda->tda_displayname);
+
+    LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
+      LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
+       if(t->tht_enabled)
+         serviceprobe_enqueue(t);
+      }
+    }
+
+
+    out = htsmsg_create_map();
+    htsmsg_add_u32(out, "success", 1);
+
+  } else {
+    pthread_mutex_unlock(&global_lock);
+    return HTTP_STATUS_BAD_REQUEST;
+  }
+  pthread_mutex_unlock(&global_lock);
+
+  htsmsg_json_serialize(out, hq, 0);
+  htsmsg_destroy(out);
+
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+  return 0;  
+}
+
+
+/**
+ *
+ */
+static void
+mux_update(htsmsg_t *in)
+{
+  htsmsg_field_t *f;
+  htsmsg_t *c;
+  th_dvb_mux_instance_t *tdmi;
+  uint32_t u32;
+  const char *id;
+
+  TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
+    if((c = htsmsg_get_map_by_field(f)) == NULL ||
+       (id = htsmsg_get_str(c, "id")) == NULL)
+      continue;
+    
+    if((tdmi = dvb_mux_find_by_identifier(id)) == NULL)
+      continue;
+
+    if(!htsmsg_get_u32(c, "enabled", &u32))
+      dvb_mux_set_enable(tdmi, u32);
+  }
+}
+
+
+/**
+ *
+ */
+static void
+mux_delete(htsmsg_t *in)
+{
+  htsmsg_field_t *f;
+  th_dvb_mux_instance_t *tdmi;
+  const char *id;
+
+  TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
+    if((id = htsmsg_field_get_string(f)) != NULL &&
+       (tdmi = dvb_mux_find_by_identifier(id)) != NULL)
+      dvb_mux_destroy(tdmi);
+  }
+}
+
+
+/**
+ *
+ */
+static int
+extjs_dvbmuxes(http_connection_t *hc, const char *remain, void *opaque)
+{
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  th_dvb_adapter_t *tda;
+  htsmsg_t *out, *array, *in;
+  const char *op        = http_arg_get(&hc->hc_req_args, "op");
+  const char *entries   = http_arg_get(&hc->hc_req_args, "entries");
+  th_dvb_mux_instance_t *tdmi;
+
+  pthread_mutex_lock(&global_lock);
+
+  if(remain == NULL ||
+     (tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return 404;
+  }
+
+  in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
+
+  out = htsmsg_create_map();
+
+  if(!strcmp(op, "get")) {
+    array = htsmsg_create_list();
+
+    LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link)
+      htsmsg_add_msg(array, NULL, dvb_mux_build_msg(tdmi));
+
+    htsmsg_add_msg(out, "entries", array);
+  } else if(!strcmp(op, "update")) {
+    if(in != NULL)
+      mux_update(in);
+
+    out = htsmsg_create_map();
+
+  } else if(!strcmp(op, "delete")) {
+    if(in != NULL)
+      mux_delete(in);
+    
+    out = htsmsg_create_map();
+
+  } else {
+    pthread_mutex_unlock(&global_lock);
+    if(in != NULL)
+      htsmsg_destroy(in);
+    htsmsg_destroy(out);
+    return HTTP_STATUS_BAD_REQUEST;
+  }
+
+  pthread_mutex_unlock(&global_lock);
+  htsmsg_json_serialize(out, hq, 0);
+  htsmsg_destroy(out);
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+
+  if(in != NULL)
+    htsmsg_destroy(in);
+
+  return 0;
+}
+
+
+
+
+/**
+ *
+ */
+static int
+transportcmp(const void *A, const void *B)
+{
+  th_transport_t *a = *(th_transport_t **)A;
+  th_transport_t *b = *(th_transport_t **)B;
+
+  return strcasecmp(a->tht_svcname ?: "\0377", b->tht_svcname ?: "\0377");
+}
+
+/**
+ *
+ */
+static int
+extjs_dvbservices(http_connection_t *hc, const char *remain, void *opaque)
+{
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  th_dvb_adapter_t *tda;
+  htsmsg_t *out, *array, *in;
+  const char *op        = http_arg_get(&hc->hc_req_args, "op");
+  const char *entries   = http_arg_get(&hc->hc_req_args, "entries");
+  th_dvb_mux_instance_t *tdmi;
+  th_transport_t *t, **tvec;
+  int count = 0, i = 0;
+
+  pthread_mutex_lock(&global_lock);
+
+  if(remain == NULL ||
+     (tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return 404;
+  }
+
+  in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
+
+  if(!strcmp(op, "get")) {
+
+    out = htsmsg_create_map();
+    array = htsmsg_create_list();
+
+    LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
+      LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
+       count++;
+      }
+    }
+
+    tvec = alloca(sizeof(th_transport_t *) * count);
+
+    LIST_FOREACH(tdmi, &tda->tda_muxes, tdmi_adapter_link) {
+      LIST_FOREACH(t, &tdmi->tdmi_transports, tht_group_link) {
+       tvec[i++] = t;
+      }
+    }
+
+    qsort(tvec, count, sizeof(th_transport_t *), transportcmp);
+
+    for(i = 0; i < count; i++)
+      htsmsg_add_msg(array, NULL, dvb_transport_build_msg(tvec[i]));
+
+    htsmsg_add_msg(out, "entries", array);
+
+  } else if(!strcmp(op, "update")) {
+    if(in != NULL)
+      extjs_transport_update(in);
+
+    out = htsmsg_create_map();
+
+  } else {
+    pthread_mutex_unlock(&global_lock);
+    htsmsg_destroy(in);
+    return HTTP_STATUS_BAD_REQUEST;
+  }
+
+  htsmsg_destroy(in);
+
+  pthread_mutex_unlock(&global_lock);
+
+  htsmsg_json_serialize(out, hq, 0);
+  htsmsg_destroy(out);
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+  return 0;
+}
+
+/**
+ *
+ */
+static int
+extjs_lnbtypes(http_connection_t *hc, const char *remain, void *opaque)
+{
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  htsmsg_t *out;
+
+  out = htsmsg_create_map();
+
+  htsmsg_add_msg(out, "entries", dvb_lnblist_get());
+
+  htsmsg_json_serialize(out, hq, 0);
+  htsmsg_destroy(out);
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+  return 0;
+}  
+
+
+
+
+/**
+ *
+ */
+static int
+extjs_dvbsatconf(http_connection_t *hc, const char *remain, void *opaque)
+{
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  th_dvb_adapter_t *tda;
+  htsmsg_t *out;
+
+  pthread_mutex_lock(&global_lock);
+
+  if(remain == NULL ||
+     (tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return 404;
+  }
+
+  out = htsmsg_create_map();
+  htsmsg_add_msg(out, "entries", dvb_satconf_list(tda));
+
+  pthread_mutex_unlock(&global_lock);
+
+  htsmsg_json_serialize(out, hq, 0);
+  htsmsg_destroy(out);
+
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+  return 0;  
+}
+
+
+/**
+ *
+ */
+static int
+extjs_dvb_feopts(http_connection_t *hc, const char *remain, void *opaque)
+{
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  char *a, *r;
+  th_dvb_adapter_t *tda;
+  htsmsg_t *e, *out;
+
+  if(remain == NULL)
+    return 400;
+
+  r = tvh_strdupa(remain);
+  if((a = strchr(r, '/')) == NULL)
+    return 400;
+  *a++ = 0;
+
+  pthread_mutex_lock(&global_lock);
+
+  if((tda = dvb_adapter_find_by_identifier(a)) == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return 404;
+  }
+
+  e = dvb_fe_opts(tda, r);
+
+  if(e == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return 400;
+  }
+
+  out = htsmsg_create_map();
+  htsmsg_add_msg(out, "entries", e);
+
+  pthread_mutex_unlock(&global_lock);
+
+  htsmsg_json_serialize(out, hq, 0);
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+  htsmsg_destroy(out);
+  return 0;
+}
+
+/**
+ *
+ */
+static int
+extjs_dvb_addmux(http_connection_t *hc, const char *remain, void *opaque)
+{
+  htsmsg_t *out;
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  struct http_arg_list *args = &hc->hc_req_args;
+  th_dvb_adapter_t *tda;
+  const char *err;
+  pthread_mutex_lock(&global_lock);
+  if(remain == NULL ||
+     (tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return 404;
+  }
+
+  err =
+    dvb_mux_add_by_params(tda,
+                         atoi(http_arg_get(args, "frequency")?:"-1"),
+                         atoi(http_arg_get(args, "symbolrate")?: "-1"),
+                         atoi(http_arg_get(args, "bandwidthID")?: "-1"),
+                         atoi(http_arg_get(args, "constellationID")?: "-1"),
+                         atoi(http_arg_get(args, "delsysID")?: "-1"),
+                         atoi(http_arg_get(args, "tmodeID")?: "-1"),
+                         atoi(http_arg_get(args, "guardintervalID")?: "-1"),
+                         atoi(http_arg_get(args, "hierarchyID")?: "-1"),
+                         atoi(http_arg_get(args, "fechiID")?: "-1"),
+                         atoi(http_arg_get(args, "fecloID")?: "-1"),
+                         atoi(http_arg_get(args, "fecID")?: "-1"),
+                         atoi(http_arg_get(args, "polarisationID")?: "-1"),
+                         http_arg_get(args, "satconfID") ?: NULL);
+                       
+  if(err != NULL)
+    tvhlog(LOG_ERR, "web interface",
+          "Unable to create mux on %s: %s",
+          tda->tda_displayname, err);
+
+  pthread_mutex_unlock(&global_lock);
+
+  out = htsmsg_create_map();
+  htsmsg_json_serialize(out, hq, 0);
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+  htsmsg_destroy(out);
+
+  return 0;
+}
+
+
+/**
+ *
+ */
+static int
+extjs_dvb_copymux(http_connection_t *hc, const char *remain, void *opaque)
+{
+  htsmsg_t *out;
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  th_dvb_adapter_t *tda;
+  htsmsg_t *in;
+  const char *entries   = http_arg_get(&hc->hc_req_args, "entries");
+  const char *id;
+  htsmsg_field_t *f;
+  th_dvb_mux_instance_t *tdmi;
+
+  in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
+
+  if(in == NULL)
+    return 400;
+
+  pthread_mutex_lock(&global_lock);
+  if(remain == NULL ||
+     (tda = dvb_adapter_find_by_identifier(remain)) == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return 404;
+  }
+
+
+  TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
+    if((id = htsmsg_field_get_string(f)) != NULL &&
+       (tdmi = dvb_mux_find_by_identifier(id)) != NULL &&
+       tda != tdmi->tdmi_adapter) {
+
+      if(dvb_mux_copy(tda, tdmi)) {
+       char buf[100];
+       dvb_mux_nicename(buf, sizeof(buf), tdmi);
+
+       tvhlog(LOG_NOTICE, "DVB", 
+              "Skipped copy of mux %s to adapter %s, mux already exist",
+              buf, tda->tda_displayname);
+      }
+    }
+  }
+
+  pthread_mutex_unlock(&global_lock);
+
+  out = htsmsg_create_map();
+  htsmsg_json_serialize(out, hq, 0);
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+  htsmsg_destroy(out);
+
+  return 0;
+}
+
+/**
+ *
+ */
+void
+extjs_list_dvb_adapters(htsmsg_t *array)
+{
+  th_dvb_adapter_t *tda;
+  TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link)
+    htsmsg_add_msg(array, NULL, dvb_adapter_build_msg(tda));
+}
+
+
+/**
+ * DVB WEB user interface
+ */
+void
+extjs_start_dvb(void)
+{
+  http_path_add("/dvbnetworks", 
+               NULL, extjs_dvbnetworks, ACCESS_WEB_INTERFACE);
+
+  http_path_add("/dvb/adapter", 
+               NULL, extjs_dvbadapter, ACCESS_ADMIN);
+
+  http_path_add("/dvb/muxes", 
+               NULL, extjs_dvbmuxes, ACCESS_ADMIN);
+
+  http_path_add("/dvb/services", 
+               NULL, extjs_dvbservices, ACCESS_ADMIN);
+
+  http_path_add("/dvb/lnbtypes", 
+               NULL, extjs_lnbtypes, ACCESS_ADMIN);
+
+  http_path_add("/dvb/satconf", 
+               NULL, extjs_dvbsatconf, ACCESS_ADMIN);
+
+  http_path_add("/dvb/feopts", 
+               NULL, extjs_dvb_feopts, ACCESS_ADMIN);
+
+  http_path_add("/dvb/addmux", 
+               NULL, extjs_dvb_addmux, ACCESS_ADMIN);
+
+  http_path_add("/dvb/copymux", 
+               NULL, extjs_dvb_copymux, ACCESS_ADMIN);
+
+}
diff --git a/src/webui/extjs_v4l.c b/src/webui/extjs_v4l.c
new file mode 100644 (file)
index 0000000..ab81725
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ *  tvheadend, EXTJS based interface
+ *  Copyright (C) 2008 Andreas Öman
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <arpa/inet.h>
+#include <libavutil/avstring.h>
+
+#include "htsmsg.h"
+#include "htsmsg_json.h"
+
+#include "tvhead.h"
+#include "http.h"
+#include "webui.h"
+#include "access.h"
+#include "channels.h"
+#include "psi.h"
+
+#include "v4l.h"
+#include "transports.h"
+#include "serviceprobe.h"
+
+
+
+/**
+ *
+ */
+static htsmsg_t *
+json_single_record(htsmsg_t *rec, const char *root)
+{
+  htsmsg_t *out, *array;
+  
+  out = htsmsg_create_map();
+  array = htsmsg_create_list();
+
+  htsmsg_add_msg(array, NULL, rec);
+  htsmsg_add_msg(out, root, array);
+  return out;
+}
+
+
+
+/**
+ *
+ */
+static int
+extjs_v4ladapter(http_connection_t *hc, const char *remain, void *opaque)
+{
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  v4l_adapter_t *va;
+  htsmsg_t *out, *array, *r;
+  const char *op = http_arg_get(&hc->hc_req_args, "op");
+  const char *s;
+
+  pthread_mutex_lock(&global_lock);
+
+  if(remain == NULL) {
+    /* Just list all adapters */
+
+    array = htsmsg_create_list();
+
+    TAILQ_FOREACH(va, &v4l_adapters, va_global_link) 
+      htsmsg_add_msg(array, NULL, v4l_adapter_build_msg(va));
+
+    pthread_mutex_unlock(&global_lock);
+    out = htsmsg_create_map();
+    htsmsg_add_msg(out, "entries", array);
+
+    htsmsg_json_serialize(out, hq, 0);
+    htsmsg_destroy(out);
+    http_output_content(hc, "text/x-json; charset=UTF-8");
+    return 0;
+  }
+
+  if((va = v4l_adapter_find_by_identifier(remain)) == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return 404;
+  }
+
+  if(!strcmp(op, "load")) {
+    r = htsmsg_create_map();
+    htsmsg_add_str(r, "id", va->va_identifier);
+    htsmsg_add_str(r, "device", va->va_path ?: "No hardware attached");
+    htsmsg_add_str(r, "name", va->va_displayname);
+    htsmsg_add_u32(r, "logging", va->va_logging);
+    out = json_single_record(r, "v4ladapters");
+  } else if(!strcmp(op, "save")) {
+
+    if((s = http_arg_get(&hc->hc_req_args, "name")) != NULL)
+      v4l_adapter_set_displayname(va, s);
+
+    s = http_arg_get(&hc->hc_req_args, "logging");
+    v4l_adapter_set_logging(va, !!s);
+
+    out = htsmsg_create_map();
+    htsmsg_add_u32(out, "success", 1);
+
+  } else {
+    pthread_mutex_unlock(&global_lock);
+    return HTTP_STATUS_BAD_REQUEST;
+  }
+  pthread_mutex_unlock(&global_lock);
+
+  htsmsg_json_serialize(out, hq, 0);
+  htsmsg_destroy(out);
+
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+  return 0;  
+}
+
+/**
+ *
+ */
+static void
+transport_update_v4l(htsmsg_t *in)
+{
+  htsmsg_field_t *f;
+  htsmsg_t *c;
+  th_transport_t *t;
+  uint32_t u32;
+  const char *id;
+  int save;
+
+  TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
+    if((c = htsmsg_get_map_by_field(f)) == NULL ||
+       (id = htsmsg_get_str(c, "id")) == NULL)
+      continue;
+    
+    if((t = transport_find_by_identifier(id)) == NULL)
+      continue;
+
+    save = 0;
+
+    if(!htsmsg_get_u32(c, "frequency", &u32)) {
+      t->tht_v4l_frequency = u32;
+      save = 1;
+    }
+    if(save)
+      t->tht_config_save(t); // Save config
+  }
+}
+
+
+
+/**
+ *
+ */
+static htsmsg_t *
+build_record_v4l(th_transport_t *t)
+{
+  htsmsg_t *r = htsmsg_create_map();
+
+  htsmsg_add_str(r, "id", t->tht_identifier);
+
+  htsmsg_add_str(r, "channelname", t->tht_ch ? t->tht_ch->ch_name : "");
+  htsmsg_add_u32(r, "frequency", t->tht_v4l_frequency);
+  htsmsg_add_u32(r, "enabled", t->tht_enabled);
+  return r;
+}
+
+/**
+ *
+ */
+static int
+v4l_transportcmp(const void *A, const void *B)
+{
+  th_transport_t *a = *(th_transport_t **)A;
+  th_transport_t *b = *(th_transport_t **)B;
+
+  return (int)a->tht_v4l_frequency - (int)b->tht_v4l_frequency;
+}
+
+/**
+ *
+ */
+static int
+extjs_v4lservices(http_connection_t *hc, const char *remain, void *opaque)
+{
+  v4l_adapter_t *va;
+  htsbuf_queue_t *hq = &hc->hc_reply;
+  htsmsg_t *out, *in, *array;
+  const char *op        = http_arg_get(&hc->hc_req_args, "op");
+  const char *entries   = http_arg_get(&hc->hc_req_args, "entries");
+  th_transport_t *t, **tvec;
+  int count = 0, i = 0;
+
+  pthread_mutex_lock(&global_lock);
+
+  if((va = v4l_adapter_find_by_identifier(remain)) == NULL) {
+    pthread_mutex_unlock(&global_lock);
+    return 404;
+  }
+
+  in = entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
+
+  if(!strcmp(op, "get")) {
+
+    LIST_FOREACH(t, &va->va_transports, tht_group_link)
+      count++;
+    tvec = alloca(sizeof(th_transport_t *) * count);
+    LIST_FOREACH(t, &va->va_transports, tht_group_link)
+      tvec[i++] = t;
+
+    out = htsmsg_create_map();
+    array = htsmsg_create_list();
+
+    qsort(tvec, count, sizeof(th_transport_t *), v4l_transportcmp);
+
+    for(i = 0; i < count; i++)
+      htsmsg_add_msg(array, NULL, build_record_v4l(tvec[i]));
+
+    htsmsg_add_msg(out, "entries", array);
+
+  } else if(!strcmp(op, "update")) {
+    if(in != NULL) {
+      extjs_transport_update(in);      // Generic transport parameters
+      transport_update_v4l(in);  // V4L speicifc
+    }
+
+    out = htsmsg_create_map();
+
+  } else if(!strcmp(op, "create")) {
+
+    out = build_record_v4l(v4l_transport_find(va, NULL, 1));
+
+  } else if(!strcmp(op, "delete")) {
+    if(in != NULL)
+      extjs_transport_delete(in);
+
+    out = htsmsg_create_map();
+
+  } else {
+    pthread_mutex_unlock(&global_lock);
+    htsmsg_destroy(in);
+    return HTTP_STATUS_BAD_REQUEST;
+  }
+
+  htsmsg_destroy(in);
+
+  pthread_mutex_unlock(&global_lock);
+
+  htsmsg_json_serialize(out, hq, 0);
+  htsmsg_destroy(out);
+  http_output_content(hc, "text/x-json; charset=UTF-8");
+  return 0;
+}
+
+
+/**
+ *
+ */
+void
+extjs_list_v4l_adapters(htsmsg_t *array)
+{
+  v4l_adapter_t *va;
+
+  TAILQ_FOREACH(va, &v4l_adapters, va_global_link) 
+    htsmsg_add_msg(array, NULL, v4l_adapter_build_msg(va));
+}
+
+
+/**
+ * WEB user interface
+ */
+void
+extjs_start_v4l(void)
+{
+  http_path_add("/v4l/adapter", 
+               NULL, extjs_v4ladapter, ACCESS_ADMIN);
+
+  http_path_add("/v4l/services", 
+               NULL, extjs_v4lservices, ACCESS_ADMIN);
+}
index 947a278f0b3cd005bfa4c2d3bf3e0fe067cc454b..6bfa937d2ec420530e9deb2bae5508b3008e8f96 100644 (file)
 #include "webui.h"
 #include "access.h"
 #include "epg.h"
-#include "dvr/dvr.h"
 #include "xmltv.h"
+#if ENABLE_LINUXDVB
+#include "dvr/dvr.h"
 #include "dvb/dvb.h"
 #include "dvb/dvb_support.h"
+#endif
+
 #include "transports.h"
 
 extern char tvh_binshasum[20];
@@ -77,6 +80,7 @@ dumpchannels(htsbuf_queue_t *hq)
   }
 }
 
+#if ENABLE_LINUXDVB
 static void
 dumptransports(htsbuf_queue_t *hq, struct th_transport_list *l, int indent)
 {
@@ -141,7 +145,7 @@ dumpdvbadapters(htsbuf_queue_t *hq)
     }
   }
 }
-
+#endif
 
 int
 page_statedump(http_connection_t *hc, const char *remain, void *opaque)
@@ -178,8 +182,9 @@ page_statedump(http_connection_t *hc, const char *remain, void *opaque)
 
   dumpchannels(hq);
   
+#if ENABLE_LINUXDVB
   dumpdvbadapters(hq);
+#endif 
 
   http_output_content(hc, "text/plain; charset=UTF-8");
   return 0;
index 48020bb739a24720b317526d0cb46ea4c590e027..498ef6e25e8bdeb972b86a6201041095153f2e97 100644 (file)
@@ -27,6 +27,20 @@ void simpleui_start(void);
 
 void extjs_start(void);
 
+#if ENABLE_LINUXDVB
+void extjs_list_dvb_adapters(htsmsg_t *array);
+void extjs_start_dvb(void);
+#endif
+
+#if ENABLE_V4L
+void extjs_list_v4l_adapters(htsmsg_t *array);
+void extjs_start_v4l(void);
+#endif
+
+void extjs_transport_update(htsmsg_t *in);
+
+void extjs_transport_delete(htsmsg_t *in);
+
 
 /**
  *
index 72df3c18c860d54a46d69097a971d9b1c713a7a1..93b22074d995815e0d30c1089a660fc7f52521c2 100644 (file)
@@ -24,6 +24,8 @@ CONFIG_LIST="
  avahi
  mmx
  sse2
+ linuxdvb
+ v4l
 "
 
 die() {