]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
capmt/cwc/mpegts: descrambler changes - register CA PIDs on demand
authorJaroslav Kysela <perex@perex.cz>
Fri, 6 Jun 2014 09:39:30 +0000 (11:39 +0200)
committerJaroslav Kysela <perex@perex.cz>
Tue, 10 Jun 2014 12:02:36 +0000 (14:02 +0200)
- capmt code was a bit restructured again

src/descrambler.h
src/descrambler/capmt.c
src/descrambler/cwc.c
src/descrambler/descrambler.c
src/input/mpegts.h
src/input/mpegts/dvb_psi.c
src/input/mpegts/mpegts_input.c
src/input/mpegts/mpegts_mux.c
src/input/mpegts/mpegts_table.c
src/input/mpegts/tsdemux.c

index 921f7e1eb35b175c7985b946cfd94c33fd8b311f..758c1dc19f68c9400d27ba13a6876431d3e30a4b 100755 (executable)
@@ -26,6 +26,8 @@
 struct service;
 struct elementary_stream;
 struct tvhcsa;
+struct mpegts_table;
+struct mpegts_mux;
 
 /**
  * Descrambler superclass
@@ -45,13 +47,28 @@ typedef struct th_descrambler {
   struct service *td_service;
   struct tvhcsa  *td_csa;
 
-  void (*td_table)(struct th_descrambler *d, struct elementary_stream *st,
-                  const uint8_t *section, int section_len);
-
-  void (*td_stop)(struct th_descrambler *d);
+  void (*td_stop)       (struct th_descrambler *d);
+  void (*td_caid_change)(struct th_descrambler *d);
 
 } th_descrambler_t;
 
+typedef void (*descrambler_section_callback_t)
+  (void *opaque, int pid, const uint8_t *section, int section_len);
+
+/**
+ * Track required PIDs
+ */
+typedef struct descrambler_section {
+  TAILQ_ENTRY(descrambler_section) link;
+  descrambler_section_callback_t callback;
+  void *opaque;
+} descrambler_section_t;
+
+typedef struct descrambler_table {
+  TAILQ_ENTRY(descrambler_table) link;
+  struct mpegts_table *table;
+  TAILQ_HEAD(,descrambler_section) sections;
+} descrambler_table_t;
 
 /**
  * List of CA ids
@@ -87,11 +104,14 @@ void descrambler_init          ( void );
 void descrambler_done          ( void );
 void descrambler_service_start ( struct service *t );
 void descrambler_service_stop  ( struct service *t );
+void descrambler_caid_changed  ( struct service *t );
 int  descrambler_descramble    ( struct service *t,
                                  struct elementary_stream *st,
                                  const uint8_t *tsb );
-void descrambler_ca_section    ( struct elementary_stream *st,
-                                 const uint8_t *data, size_t len );
+int  descrambler_open_pid      ( struct mpegts_mux *mux, void *opaque, int pid,
+                                 descrambler_section_callback_t callback );
+int  descrambler_close_pid     ( struct mpegts_mux *mux, void *opaque, int pid );
+void descrambler_flush_tables  ( struct mpegts_mux *mux );
 const char *descrambler_caid2name( uint16_t caid );
 uint16_t descrambler_name2caid ( const char *str );
 card_type_t detect_card_type   ( const uint16_t caid );
index e0ce57edefa07b6cbb2c8eb403823b76048264e1..8b05132ff1bd0e2e0ca49b7ffb4255fa75f4a248 100644 (file)
@@ -116,6 +116,7 @@ typedef struct dmx_sct_filter_params {
 #define MAX_INDEX   64
 #define MAX_FILTER  64
 #define MAX_SOCKETS 16   // max sockets (simultaneous channels) per demux
+#define MAX_PIDS    64   // max opened pids
 
 /**
  *
@@ -215,6 +216,23 @@ typedef struct capmt_message {
   sbuf_t cm_sb;
 } capmt_message_t;
 
+/**
+ *
+ */
+struct capmt;
+typedef struct capmt_opaque {
+  struct capmt    *capmt;
+  uint16_t         adapter;
+  uint16_t         pid;
+} capmt_opaque_t;
+
+typedef struct capmt_adapter {
+  ca_info_t       ca_info[MAX_INDEX];
+  int             ca_sock;
+  mpegts_input_t *ca_tuner;
+  capmt_opaque_t  ca_pids[MAX_PIDS];
+} capmt_adapter_t;
+
 /**
  *
  */
@@ -244,7 +262,6 @@ typedef struct capmt {
   int   sids[MAX_SOCKETS];
   int   capmt_sock[MAX_SOCKETS];
   int   capmt_sock_reconnect[MAX_SOCKETS];
-  int   capmt_sock_ca0[MAX_CA];
 
   /* thread flags */
   int   capmt_connected;
@@ -258,15 +275,16 @@ typedef struct capmt {
   /* runtime status */
   tvhpoll_t      *capmt_poll;
   th_pipe_t       capmt_pipe;
-  mpegts_input_t *capmt_tuners[MAX_CA];
   capmt_demuxes_t capmt_demuxes;
-  ca_info_t       capmt_ca_info[MAX_CA][MAX_INDEX];
+  capmt_adapter_t capmt_adapters[MAX_CA];
   TAILQ_HEAD(, capmt_message) capmt_writeq;
   pthread_mutex_t capmt_mutex;
 } capmt_t;
 
 static void capmt_enumerate_services(capmt_t *capmt, int force);
 static void capmt_send_request(capmt_service_t *ct, int lm);
+static void capmt_table_input(void *opaque, int pid,
+                              const uint8_t *data, int len);
 
 /**
  *
@@ -325,6 +343,73 @@ capmt_poll_rem(capmt_t *capmt, int fd)
   tvhpoll_rem(capmt->capmt_poll, &ev, 1);
 }
 
+static void
+capmt_pid_add(capmt_t *capmt, int adapter, int pid)
+{
+  capmt_adapter_t *ca = &capmt->capmt_adapters[adapter];
+  capmt_opaque_t *o = NULL, *t;
+  mpegts_mux_instance_t *mmi;
+  int i = 0;
+
+  for (i = 0; i < MAX_PIDS; i++) {
+    t = &ca->ca_pids[i];
+    if (t->pid == pid)
+      return;
+    if (t->pid == 0)
+      o = t;
+  }
+  if (o) {
+    o->capmt   = capmt;
+    o->adapter = adapter;
+    o->pid     = pid;
+    mmi        = LIST_FIRST(&capmt->capmt_adapters[adapter].ca_tuner->mi_mux_active);
+    descrambler_open_pid(mmi->mmi_mux, o, pid, capmt_table_input);
+  }
+}
+
+static void
+capmt_pid_remove(capmt_t *capmt, int adapter, int pid)
+{
+  capmt_adapter_t *ca = &capmt->capmt_adapters[adapter];
+  mpegts_mux_instance_t *mmi;
+  int i = 0;
+
+  for (i = 0; i < MAX_PIDS; i++)
+    if (ca->ca_pids[i].pid == pid)
+      break;
+  if (i >= MAX_PIDS);
+    return;
+  mmi = LIST_FIRST(&capmt->capmt_adapters[adapter].ca_tuner->mi_mux_active);
+  descrambler_close_pid(mmi->mmi_mux, &ca->ca_pids[i], pid);
+  ca->ca_pids[i].pid = 0;
+}
+
+static void
+capmt_pid_flush(capmt_t *capmt)
+{
+  capmt_adapter_t *ca;
+  mpegts_mux_instance_t *mmi;
+  mpegts_input_t *tuner;
+  capmt_opaque_t *o;
+  int adapter, i;
+
+  for (adapter = 0; adapter < MAX_CA; adapter++) {
+    tuner = capmt->capmt_adapters[adapter].ca_tuner;
+    if (tuner == NULL)
+      continue;
+    ca = &capmt->capmt_adapters[adapter];
+    mmi = LIST_FIRST(&tuner->mi_mux_active);
+    for (i = 0; i < MAX_PIDS; i++) {
+      o = &ca->ca_pids[i];
+      if (o->pid) {
+        if (mmi)
+          descrambler_close_pid(mmi->mmi_mux, &ca->ca_pids[i], o->pid);
+        o->pid = 0;
+      }
+    }
+  }
+}
+
 /**
  *
  */
@@ -399,14 +484,16 @@ capmt_connect(capmt_t *capmt, int i)
  *
  */
 static void
-capmt_socket_close(capmt_t *capmt, int i)
+capmt_socket_close(capmt_t *capmt, int sock_idx)
 {
-  int fd = capmt->capmt_sock[i];
+  int fd = capmt->capmt_sock[sock_idx];
   if (fd < 0)
     return;
   capmt_poll_rem(capmt, fd);
   close(fd);
-  capmt->capmt_sock[i] = -1;
+  capmt->capmt_sock[sock_idx] = -1;
+  if (capmt_oscam_new(capmt))
+    capmt_pid_flush(capmt);
 }
 
 /**
@@ -505,7 +592,7 @@ capmt_queue_msg(capmt_t *capmt, int sid, const uint8_t *buf, size_t len)
 
   sbuf_init_fixed(&msg->cm_sb, len);
   sbuf_append(&msg->cm_sb, buf, len);
-  msg->cm_sid = sid;
+  msg->cm_sid     = sid;
   pthread_mutex_lock(&capmt->capmt_mutex);
   TAILQ_INSERT_TAIL(&capmt->capmt_writeq, msg, cm_link);
   pthread_mutex_unlock(&capmt->capmt_mutex);
@@ -630,7 +717,7 @@ capmt_service_destroy(th_descrambler_t *td)
     capmt_enumerate_services(ct->ct_capmt, 1);
 
   if (LIST_EMPTY(&ct->ct_capmt->capmt_services)) {
-    ct->ct_capmt->capmt_tuners[ct->ct_adapter] = NULL;
+    ct->ct_capmt->capmt_adapters[ct->ct_adapter].ca_tuner = NULL;
     memset(&ct->ct_capmt->capmt_demuxes, 0, sizeof(ct->ct_capmt->capmt_demuxes));
   }
 
@@ -639,7 +726,7 @@ capmt_service_destroy(th_descrambler_t *td)
 }
 
 static void
-capmt_filter_data(capmt_t *capmt, int sid, uint8_t adapter, uint8_t demux_index,
+capmt_filter_data(capmt_t *capmt, uint8_t adapter, uint8_t demux_index,
                   uint8_t filter_index, const uint8_t *data, int len)
 {
   uint8_t *buf = alloca(len + 6);
@@ -649,7 +736,7 @@ capmt_filter_data(capmt_t *capmt, int sid, uint8_t adapter, uint8_t demux_index,
   buf[5] = filter_index;
   memcpy(buf + 6, data, len);
   if (len - 3 == ((((uint16_t)buf[7] << 8) | buf[8]) & 0xfff))
-    capmt_queue_msg(capmt, sid, buf, len + 6);
+    capmt_queue_msg(capmt, 0, buf, len + 6);
 }
 
 static void
@@ -657,7 +744,7 @@ capmt_set_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
 {
   uint8_t demux_index  = sbuf_peek_u8 (sb, offset + 4);
   uint8_t filter_index = sbuf_peek_u8 (sb, offset + 5);
-  int     pid          = sbuf_peek_s32(sb, offset + 6);
+  uint16_t pid         = sbuf_peek_u16(sb, offset + 6);
   dmx_filter_params_t *filter;
   dmx_filter_params_t *params = (dmx_filter_params_t *)sbuf_peek(sb, offset + 6);
   capmt_filters_t *cf;
@@ -666,7 +753,8 @@ capmt_set_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
            adapter, demux_index, filter_index, pid);
   if (adapter >= MAX_CA ||
       demux_index >= MAX_INDEX ||
-      filter_index >= MAX_FILTER)
+      filter_index >= MAX_FILTER ||
+      (pid < 0 || pid > 8191))
     return;
   cf = &capmt->capmt_demuxes.filters[demux_index];
   if (cf->max && cf->adapter != adapter)
@@ -674,6 +762,7 @@ capmt_set_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
   cf->adapter = adapter;
   filter = &cf->dmx[filter_index];
   filter->pid = pid;
+  capmt_pid_add(capmt, adapter, pid);
   memcpy(&filter->filter, &params->filter, sizeof(params->filter));
   filter->timeout = filter->flags = 0;
   if (capmt->capmt_demuxes.max <= demux_index)
@@ -707,6 +796,7 @@ capmt_stop_filter(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
   if (filter->pid != pid)
     return;
   memset(filter, 0, sizeof(*filter));
+  capmt_pid_remove(capmt, adapter, pid);
   /* short the max values */
   filter_index = cf->max - 1;
   while (filter_index != 255 && cf->dmx[filter_index].pid == 0)
@@ -733,6 +823,28 @@ capmt_notify_server(capmt_t *capmt, capmt_service_t *ct)
   }
 }
 
+static void
+capmt_abort(capmt_t *capmt, int keystate)
+{
+  mpegts_service_t *t;
+  capmt_service_t *ct;
+
+  pthread_mutex_lock(&global_lock);
+  LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
+    t = (mpegts_service_t *)ct->td_service;
+
+    if (ct->td_keystate != keystate) {
+      tvhlog(LOG_ERR, "capmt",
+             "Can not descramble service \"%s\", %s",
+             t->s_dvb_svcname,
+             keystate == DS_FORBIDDEN ?
+               "access denied" : "connection close");
+      ct->td_keystate = keystate;
+    }
+  }
+  pthread_mutex_unlock(&global_lock);
+}
+
 static void
 capmt_process_key(capmt_t *capmt, uint8_t adapter, uint16_t seq,
                   const uint8_t *even, const uint8_t *odd,
@@ -785,6 +897,7 @@ static int
 capmt_msg_size(capmt_t *capmt, sbuf_t *sb, int offset)
 {
   uint32_t cmd;
+  int oscam_new = capmt_oscam_new(capmt);
 
   if (sb->sb_ptr - offset < 4)
     return 0;
@@ -803,9 +916,9 @@ capmt_msg_size(capmt_t *capmt, sbuf_t *sb, int offset)
     return 4 + 8;
   else if (cmd == CA_SET_DESCR)
     return 4 + 16;
-  else if (cmd == DMX_SET_FILTER)
+  else if (oscam_new && cmd == DMX_SET_FILTER)
     return 4 + 2 + sizeof(dmx_filter_params_t);
-  else if (cmd == DMX_STOP)
+  else if (oscam_new && cmd == DMX_STOP)
     return 4 + 4;
   else {
     sb->sb_err = 0;
@@ -826,9 +939,10 @@ capmt_analyze_cmd(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
     int32_t  index = sbuf_peek_s32(sb, offset + 8);
     tvhlog(LOG_DEBUG, "capmt", "CA_SET_PID adapter %d index %d pid 0x%04x", adapter, index, pid);
     if (adapter < MAX_CA && index >= 0 && index < MAX_INDEX) {
-      capmt->capmt_ca_info[adapter][index].pid = pid;
+      capmt->capmt_adapters[adapter].ca_info[index].pid = pid;
     } else if (index < 0) {
-      memset(&capmt->capmt_ca_info[adapter], 0, sizeof(capmt->capmt_ca_info[adapter]));
+      memset(&capmt->capmt_adapters[adapter].ca_info, 0,
+             sizeof(capmt->capmt_adapters[adapter].ca_info));
     } else
       tvhlog(LOG_ERR, "capmt", "Invalid index %d in CA_SET_PID (%d) for adapter %d", index, MAX_INDEX, adapter);
 
@@ -844,7 +958,7 @@ capmt_analyze_cmd(capmt_t *capmt, int adapter, sbuf_t *sb, int offset)
       return;
     if (adapter >= MAX_CA || index >= MAX_INDEX)
       return;
-    cai = &capmt->capmt_ca_info[adapter][index];
+    cai = &capmt->capmt_adapters[adapter].ca_info[index];
     if (parity == 0) {
       memcpy(cai->even, cw, 8); // even key
       capmt_process_key(capmt, adapter, cai->pid, cai->even, cai->odd, 1);
@@ -909,8 +1023,8 @@ handle_ca0(capmt_t *capmt) {
   capmt->capmt_poll = tvhpoll_create(MAX_CA + 1);
   capmt_poll_add(capmt, capmt->capmt_pipe.rd, 0);
   for (i = 0; i < MAX_CA; i++)
-    if (capmt->capmt_sock_ca0[i])
-      capmt_poll_add(capmt, capmt->capmt_sock_ca0[i], i + 1);
+    if (capmt->capmt_adapters[i].ca_sock)
+      capmt_poll_add(capmt, capmt->capmt_adapters[i].ca_sock, i + 1);
 
   i = 0;
   adapter = -1;
@@ -941,7 +1055,7 @@ handle_ca0(capmt_t *capmt) {
       if (adapter >= MAX_CA)
         continue;
 
-      recvsock = capmt->capmt_sock_ca0[adapter];
+      recvsock = capmt->capmt_adapters[adapter].ca_sock;
 
       if (recvsock <= 0)
         continue;
@@ -953,7 +1067,7 @@ handle_ca0(capmt_t *capmt) {
 
         close(recvsock);
         capmt_poll_rem(capmt, recvsock);
-        capmt->capmt_sock_ca0[adapter] = -1;
+        capmt->capmt_adapters[adapter].ca_sock = -1;
         continue;
       }
       
@@ -1013,14 +1127,11 @@ handle_single(capmt_t *capmt)
 
   while (capmt->capmt_running) {
 
-    tvhtrace("capmt", "poll");
     nfds = tvhpoll_wait(capmt->capmt_poll, &ev, 1, 500);
 
     if (nfds <= 0)
       continue;
 
-    tvhtrace("capmt", "poll ok for %i", ev.data.u32);
-
     if (ev.data.u32 == 0) {
       ret = read(capmt->capmt_pipe.rd, buf, 1);
       if (ret == 1 && buf[0] == 'c') {
@@ -1082,7 +1193,6 @@ handle_single(capmt_t *capmt)
   tvhpoll_destroy(capmt->capmt_poll);
   capmt->capmt_poll = NULL;
 }
-
 #if CONFIG_LINUXDVB
 static void 
 handle_ca0_wrapper(capmt_t *capmt)
@@ -1098,8 +1208,11 @@ handle_ca0_wrapper(capmt_t *capmt)
 
   while (capmt->capmt_running) {
 
+    if (capmt->capmt_sock[0] < 0)
+      break;
+
     /* receiving data from UDP socket */
-    ret = recv(capmt->capmt_sock_ca0[0], buffer, 18, MSG_WAITALL);
+    ret = recv(capmt->capmt_adapters[0].ca_sock, buffer, 18, MSG_WAITALL);
 
     if (ret < 0) {
       tvhlog(LOG_ERR, "capmt", "error receiving over socket");
@@ -1110,7 +1223,7 @@ handle_ca0_wrapper(capmt_t *capmt)
       break;
     } else {
 
-      tvhtrace("capmt", "Received message from socket %i", capmt->capmt_sock_ca0[0]);
+      tvhtrace("capmt", "Received message from socket %i", capmt->capmt_adapters[0].ca_sock);
       tvhlog_hexdump("capmt", buffer, ret);
 
       capmt_process_key(capmt, 0,
@@ -1120,6 +1233,7 @@ handle_ca0_wrapper(capmt_t *capmt)
     }
   }
 
+  capmt_abort(capmt, DS_UNKNOWN);
   tvhlog(LOG_INFO, "capmt", "connection from client closed ...");
 }
 #endif
@@ -1158,7 +1272,7 @@ capmt_thread(void *aux)
   while (capmt->capmt_running) {
     fatal = 0;
     for (i = 0; i < MAX_CA; i++)
-      capmt->capmt_sock_ca0[i] = -1;
+      capmt->capmt_adapters[i].ca_sock = -1;
     for (i = 0; i < MAX_SOCKETS; i++) {
       capmt->sids[i] = 0;
       capmt->capmt_sock[i] = -1;
@@ -1191,7 +1305,8 @@ capmt_thread(void *aux)
         int bind_ok = 0;
         /* open connection to emulated ca0 device */
         if (capmt->capmt_oscam == CAPMT_OSCAM_SO_WRAPPER) {
-          bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[0], capmt->capmt_port);
+          bind_ok = capmt_create_udp_socket(&capmt->capmt_adapters[0].ca_sock,
+                                            capmt->capmt_port);
           if (bind_ok)
             handle_ca0_wrapper(capmt);
         } else {
@@ -1208,7 +1323,8 @@ capmt_thread(void *aux)
               continue;
             }
             tvhlog(LOG_INFO, "capmt", "created UDP socket %d", n);
-            bind_ok = capmt_create_udp_socket(&capmt->capmt_sock_ca0[n], capmt->capmt_port + n);
+            bind_ok = capmt_create_udp_socket(&capmt->capmt_adapters[n].ca_sock,
+                                              capmt->capmt_port + n);
           }
           if (bind_ok)
             handle_ca0(capmt);
@@ -1231,11 +1347,10 @@ capmt_thread(void *aux)
 
     /* close opened sockets */
     for (i = 0; i < MAX_SOCKETS; i++)
-      if (capmt->capmt_sock[i] >= 0)
-        close(capmt->capmt_sock[i]);
+        capmt_socket_close(capmt, i);
     for (i = 0; i < MAX_CA; i++)
-      if (capmt->capmt_sock_ca0[i] >= 0)
-        close(capmt->capmt_sock_ca0[i]);
+      if (capmt->capmt_adapters[i].ca_sock >= 0)
+        close(capmt->capmt_adapters[i].ca_sock);
 
     if (!capmt->capmt_running)
       break;
@@ -1268,30 +1383,23 @@ capmt_thread(void *aux)
  *
  */
 static void
-capmt_table_input(struct th_descrambler *td,
-    struct elementary_stream *st, const uint8_t *data, int len)
+capmt_table_input(void *opaque, int pid, const uint8_t *data, int len)
 {
-  capmt_service_t *ct = (capmt_service_t *)td;
-  capmt_t *capmt = ct->ct_capmt;
-  mpegts_service_t *t = (mpegts_service_t*)td->td_service;
-  capmt_caid_ecm_t *cce;
-  int i, change, demux_index, filter_index;
+  capmt_opaque_t *o = opaque;
+  capmt_t *capmt = o->capmt;
+  int i, demux_index, filter_index;
   capmt_filters_t *cf;
   dmx_filter_t *f;
-  caid_t *c;
 
   /* Validate */
-  if (!idnode_is_instance(&td->td_service->s_id, &mpegts_service_class))
-    return;
-  if (!t->s_dvb_active_input) return;
   if (len > 4096) return;
 
   for (demux_index = 0; demux_index < capmt->capmt_demuxes.max; demux_index++) {
     cf = &capmt->capmt_demuxes.filters[demux_index];
-    if (cf->adapter != ct->ct_adapter)
+    if (cf->adapter != o->adapter)
       continue;
     for (filter_index = 0; filter_index < cf->max; filter_index++)
-      if (cf->dmx[filter_index].pid == st->es_pid) {
+      if (cf->dmx[filter_index].pid == pid) {
         f = &cf->dmx[filter_index].filter;
         for (i = 0; i < DMX_FILTER_SIZE && i < len; i++) {
           if (f->mode[i] != 0)
@@ -1300,40 +1408,46 @@ capmt_table_input(struct th_descrambler *td,
             break;
         }
         if (i >= DMX_FILTER_SIZE && i <= len) {
-          capmt_filter_data(capmt, t->s_dvb_service_id,
-                            ct->ct_adapter, demux_index,
+          capmt_filter_data(capmt,
+                            o->adapter, demux_index,
                             filter_index, data, len);
         }
       }
   }
 
-  /* Add new caids, no ecm management */
-  if (data[0] != 0x80 && data[0] != 0x81) return; /* ignore EMM */
-  change = 0;
-  LIST_FOREACH(c, &st->es_caids, link) {
-    /* search ecmpid in list */
-    LIST_FOREACH(cce, &ct->ct_caid_ecm, cce_link)
-      if (cce->cce_caid == c->caid)
-        break;
-    if (cce)
-      continue;
+}
 
-    tvhlog(LOG_DEBUG, "capmt",
-           "New caid 0x%04X for service \"%s\"", c->caid, t->s_dvb_svcname);
-
-    /* ecmpid not already seen, add it to list */
-    cce             = calloc(1, sizeof(capmt_caid_ecm_t));
-    cce->cce_caid   = c->caid;
-    cce->cce_ecmpid = st->es_pid;
-    cce->cce_providerid = c->providerid;
-    LIST_INSERT_HEAD(&ct->ct_caid_ecm, cce, cce_link);
-    change = 1;
-  }
+static void
+capmt_caid_change(th_descrambler_t *td)
+{
+  capmt_service_t *ct = (capmt_service_t *)td;
+  capmt_t *capmt = ct->ct_capmt;
+  mpegts_service_t *t = (mpegts_service_t*)td->td_service;
+  elementary_stream_t *st;
+  capmt_caid_ecm_t *cce;
+  caid_t *c;
+  int change = 0;
 
-  if (capmt->capmt_oscam == CAPMT_OSCAM_SO_WRAPPER && capmt->capmt_sock[0] == 0) {
-    /* New key, but we are not connected (anymore), can not descramble */
-    ct->td_keystate = DS_UNKNOWN;
-    return;
+  TAILQ_FOREACH(st, &t->s_components, es_link) {
+    LIST_FOREACH(c, &st->es_caids, link) {
+      /* search ecmpid in list */
+      LIST_FOREACH(cce, &ct->ct_caid_ecm, cce_link)
+        if (cce->cce_caid == c->caid && cce->cce_providerid == c->providerid)
+          break;
+      if (cce)
+        continue;
+      tvhlog(LOG_DEBUG, "capmt",
+             "New caid 0x%04X:0x%06X for service \"%s\"",
+              c->caid, c->providerid, t->s_dvb_svcname);
+
+      /* ecmpid not already seen, add it to list */
+      cce             = calloc(1, sizeof(capmt_caid_ecm_t));
+      cce->cce_caid   = c->caid;
+      cce->cce_ecmpid = st->es_pid;
+      cce->cce_providerid = c->providerid;
+      LIST_INSERT_HEAD(&ct->ct_caid_ecm, cce, cce_link);
+      change = 1;
+    }
   }
 
   if (change)
@@ -1553,9 +1667,9 @@ capmt_service_start(service_t *s)
 
     if (tuner < 0) {
       for (i = 0; i < MAX_CA; i++) {
-        if (capmt->capmt_tuners[i] == NULL && tuner < 0)
+        if (capmt->capmt_adapters[i].ca_tuner == NULL && tuner < 0)
           tuner = i;
-        if (capmt->capmt_tuners[i] == t->s_dvb_active_input) {
+        if (capmt->capmt_adapters[i].ca_tuner == t->s_dvb_active_input) {
           tuner = i;
           break;
         }
@@ -1572,7 +1686,7 @@ capmt_service_start(service_t *s)
            "Starting CAPMT server for service \"%s\" on adapter %d",
            t->s_dvb_svcname, tuner);
 
-    capmt->capmt_tuners[tuner] = t->s_dvb_active_input;
+    capmt->capmt_adapters[tuner].ca_tuner = t->s_dvb_active_input;
 
     /* create new capmt service */
     ct              = calloc(1, sizeof(capmt_service_t));
@@ -1590,8 +1704,6 @@ capmt_service_start(service_t *s)
         tvhlog(LOG_DEBUG, "capmt",
           "New caid 0x%04X for service \"%s\"", c->caid, t->s_dvb_svcname);
 
-        mpegts_table_register_caid(((mpegts_service_t *)s)->s_dvb_mux, c->caid);
-
         /* add it to list */
         cce             = calloc(1, sizeof(capmt_caid_ecm_t));
         cce->cce_caid   = c->caid;
@@ -1604,9 +1716,9 @@ capmt_service_start(service_t *s)
 
     td = (th_descrambler_t *)ct;
     tvhcsa_init(td->td_csa = &ct->ct_csa);
-    td->td_service    = s;
-    td->td_stop       = capmt_service_destroy;
-    td->td_table      = capmt_table_input;
+    td->td_service     = s;
+    td->td_stop        = capmt_service_destroy;
+    td->td_caid_change = capmt_caid_change;
     LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
 
     LIST_INSERT_HEAD(&capmt->capmt_services, ct, ct_link);
index 2545cad4f3b80d412c8b97e38e86a288b6cd3433..3a1534fb9ae591265a4e1edba60fcf9b4043ecbe 100755 (executable)
@@ -120,6 +120,17 @@ typedef struct ecm_pid {
 } ecm_pid_t;
 
 
+/**
+ *
+ */
+struct cwc_service;
+typedef struct cwc_opaque {
+  struct cwc_service  *service;
+  elementary_stream_t *estream;
+  mpegts_mux_t        *mux;
+} cwc_opaque_t;
+
+
 /**
  *
  */
@@ -131,6 +142,8 @@ typedef struct cwc_service {
   LIST_ENTRY(cwc_service) cs_link;
 
   int cs_channel;
+  int cs_pid;
+  cwc_opaque_t cs_opaque;
 
   /**
    * ECM Status
@@ -1594,11 +1607,12 @@ cwc_emm_viaccess(cwc_t *cwc, struct cs_card_data *pcard, uint8_t *data, int mlen
  * t->s_streaming_mutex is held
  */
 static void
-cwc_table_input(struct th_descrambler *td,
-               struct elementary_stream *st, const uint8_t *data, int len)
+cwc_table_input(void *opaque, int pid, const uint8_t *data, int len)
 {
-  cwc_service_t *ct = (cwc_service_t *)td;
-  mpegts_service_t *t = (mpegts_service_t*)td->td_service;
+  cwc_opaque_t *o = opaque;
+  elementary_stream_t *st = o->estream;
+  cwc_service_t *ct = o->service;
+  mpegts_service_t *t = (mpegts_service_t*)ct->td_service;
   uint16_t sid = t->s_dvb_service_id;
   cwc_t *cwc = ct->cs_cwc;
   int channel;
@@ -1618,10 +1632,11 @@ cwc_table_input(struct th_descrambler *td,
     return;
 
   LIST_FOREACH(ep, &ct->cs_pids, ep_link) {
-    if(ep->ep_pid == st->es_pid)
+    if(ep->ep_pid == pid)
       break;
   }
 
+  pthread_mutex_lock(&t->s_stream_mutex);
   if(ep == NULL) {
     if (ct->ecm_state == ECM_RESET) {
       ct->ecm_state = ECM_INIT;
@@ -1641,7 +1656,7 @@ cwc_table_input(struct th_descrambler *td,
         }
       }
 
-      if(t->s_dvb_prefcapid == st->es_pid) {
+      if(t->s_dvb_prefcapid == pid) {
         ep = calloc(1, sizeof(ecm_pid_t));
         ep->ep_pid = t->s_dvb_prefcapid;
         LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link);
@@ -1649,12 +1664,13 @@ cwc_table_input(struct th_descrambler *td,
       }
       else if(t->s_dvb_prefcapid == 0) {
           ep = calloc(1, sizeof(ecm_pid_t));
-          ep->ep_pid = st->es_pid;
+          ep->ep_pid = pid;
           LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link);
-          tvhlog(LOG_DEBUG, "cwc", "Insert new ECM (PID %d) for service \"%s\"", st->es_pid, t->s_dvb_svcname);
+          tvhlog(LOG_DEBUG, "cwc", "Insert new ECM (PID %d) for service \"%s\"", pid, t->s_dvb_svcname);
       }
     }
   }
+  pthread_mutex_unlock(&t->s_stream_mutex);
 
   if(ep == NULL)
     return;
@@ -1688,7 +1704,7 @@ cwc_table_input(struct th_descrambler *td,
         section = 0;
       }
       
-      channel = st->es_pid;
+      channel = pid;
       snprintf(chaninfo, sizeof(chaninfo), " (PID %d)", channel);
       
       if(ep->ep_sections[section] == NULL)
@@ -1901,6 +1917,8 @@ cwc_service_destroy(th_descrambler_t *td)
   ecm_pid_t *ep;
   int i;
 
+  descrambler_close_pid(ct->cs_opaque.mux, &ct->cs_opaque, ct->cs_pid);
+
   while((ep = LIST_FIRST(&ct->cs_pids)) != NULL) {
     for(i = 0; i < 256; i++)
       free(ep->ep_sections[i]);
@@ -1916,25 +1934,6 @@ cwc_service_destroy(th_descrambler_t *td)
   free(ct);
 }
 
-/**
- *
- */
-static inline elementary_stream_t *
-cwc_find_stream_by_caid(service_t *t, const short caid)
-{
-  elementary_stream_t *st;
-  caid_t *c;
-
-  TAILQ_FOREACH(st, &t->s_components, es_link) {
-    LIST_FOREACH(c, &st->es_caids, link) {
-      if(c->caid == caid)
-             return st;
-    }
-  }
-  return NULL;
-}
-
-
 /**
  * Check if our CAID's matches, and if so, link
  *
@@ -1946,6 +1945,8 @@ cwc_service_start(service_t *t)
   cwc_t *cwc;
   cwc_service_t *ct;
   th_descrambler_t *td;
+  elementary_stream_t *st;
+  caid_t *c;
   struct cs_card_data *pcard;
 
   extern const idclass_t mpegts_service_class;
@@ -1958,9 +1959,16 @@ cwc_service_start(service_t *t)
       if (ct->td_service == t && ct->cs_cwc == cwc)
         break;
     }
-    LIST_FOREACH(pcard,&cwc->cwc_cards, cs_card) {
-      if((pcard->cwc_caid != 0) && cwc_find_stream_by_caid(t, pcard->cwc_caid))
-        break;
+    LIST_FOREACH(pcard, &cwc->cwc_cards, cs_card) {
+      if (pcard->cwc_caid == 0) continue;
+      TAILQ_FOREACH(st, &t->s_components, es_link) {
+        LIST_FOREACH(c, &st->es_caids, link) {
+          if (c->caid == pcard->cwc_caid)
+            break;
+        }
+        if (c) break;
+      }
+      if (st) break;
     }
     if (!pcard) {
       if (ct) cwc_service_destroy((th_descrambler_t*)ct);
@@ -1969,22 +1977,26 @@ cwc_service_start(service_t *t)
 
     if (ct) continue;
 
-    mpegts_table_register_caid(((mpegts_service_t *)t)->s_dvb_mux, pcard->cwc_caid);
-
     ct                   = calloc(1, sizeof(cwc_service_t));
     ct->cs_cwc           = cwc;
     ct->cs_channel       = -1;
+    ct->cs_pid           = st->es_pid;
+    ct->cs_opaque.service = ct;
+    ct->cs_opaque.estream = st;
+    ct->cs_opaque.mux    = ((mpegts_service_t *)t)->s_dvb_mux;
     ct->ecm_state        = ECM_INIT;
 
     td                   = (th_descrambler_t *)ct;
     tvhcsa_init(td->td_csa = &ct->cs_csa);
     td->td_service       = t;
     td->td_stop          = cwc_service_destroy;
-    td->td_table         = cwc_table_input;
     LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link);
 
     LIST_INSERT_HEAD(&cwc->cwc_services, ct, cs_link);
 
+    descrambler_open_pid(ct->cs_opaque.mux, &ct->cs_opaque,
+                         ct->cs_pid, cwc_table_input);
+
     tvhlog(LOG_DEBUG, "cwc", "%s using CWC %s:%d",
           service_nicename(t), cwc->cwc_hostname, cwc->cwc_port);
 
index 83a9a7251b372eff2f529cc950401def43039e8e..6cd9bb4bbbd8b71a015d662c7a3e8be521f97abc 100755 (executable)
@@ -20,7 +20,7 @@
 #include "cwc.h"
 #include "capmt.h"
 #include "ffdecsa/FFdecsa.h"
-#include "service.h"
+#include "input.h"
 #include "tvhcsa.h"
 
 static struct strtab caidnametab[] = {
@@ -149,6 +149,17 @@ descrambler_service_stop ( service_t *t )
     td->td_stop(td);
 }
 
+void
+descrambler_caid_changed ( service_t *t )
+{
+  th_descrambler_t *td;
+
+  LIST_FOREACH(td, &t->s_descramblers, td_service_link) {
+    if (td->td_caid_change)
+      td->td_caid_change(td);
+  }
+}
+
 int
 descrambler_descramble ( service_t *t,
                          elementary_stream_t *st,
@@ -173,14 +184,98 @@ descrambler_descramble ( service_t *t,
   return count == failed ? -1 : 0;
 }
 
+static int
+descrambler_table_callback
+  (mpegts_table_t *mt, const uint8_t *ptr, int len, int tableid)
+{
+  descrambler_table_t *dt = mt->mt_opaque;
+  descrambler_section_t *ds;
+
+  pthread_mutex_lock(&mt->mt_mux->mm_descrambler_lock);
+  TAILQ_FOREACH(ds, &dt->sections, link)
+    ds->callback(ds->opaque, mt->mt_pid, ptr, len);
+  pthread_mutex_unlock(&mt->mt_mux->mm_descrambler_lock);
+  return 0;
+}
+
+int
+descrambler_open_pid( mpegts_mux_t *mux, void *opaque, int pid,
+                      descrambler_section_callback_t callback )
+{
+  descrambler_table_t *dt;
+  descrambler_section_t *ds;
+
+  pthread_mutex_lock(&mux->mm_descrambler_lock);
+  TAILQ_FOREACH(dt, &mux->mm_descrambler_tables, link) {
+    if (dt->table->mt_pid == pid) {
+      TAILQ_FOREACH(ds, &dt->sections, link) {
+        if (ds->opaque == opaque) {
+          pthread_mutex_unlock(&mux->mm_descrambler_lock);
+          return 0;
+        }
+      }
+    }
+  }
+  if (!dt) {
+    dt = calloc(1, sizeof(*dt));
+    TAILQ_INIT(&dt->sections);
+    dt->table = mpegts_table_add(mux, 0, 0, descrambler_table_callback,
+                                 dt, "descrambler", MT_FULL, pid);
+    TAILQ_INSERT_TAIL(&mux->mm_descrambler_tables, dt, link);
+  }
+  ds = calloc(1, sizeof(*ds));
+  ds->callback    = callback;
+  ds->opaque      = opaque;
+  TAILQ_INSERT_TAIL(&dt->sections, ds, link);
+  pthread_mutex_unlock(&mux->mm_descrambler_lock);
+  return 1;
+}
+
+int
+descrambler_close_pid( mpegts_mux_t *mux, void *opaque, int pid )
+{
+  descrambler_table_t *dt;
+  descrambler_section_t *ds;
+
+  pthread_mutex_lock(&mux->mm_descrambler_lock);
+  TAILQ_FOREACH(dt, &mux->mm_descrambler_tables, link) {
+    if (dt->table->mt_pid == pid) {
+      TAILQ_FOREACH(ds, &dt->sections, link) {
+        if (ds->opaque == opaque) {
+          TAILQ_REMOVE(&dt->sections, ds, link);
+          free(ds);
+          if (TAILQ_FIRST(&dt->sections) == NULL) {
+            TAILQ_REMOVE(&mux->mm_descrambler_tables, dt, link);
+            mpegts_table_destroy(dt->table);
+            free(dt);
+          }
+          pthread_mutex_unlock(&mux->mm_descrambler_lock);
+          return 1;
+        }
+      }
+    }
+  }
+  pthread_mutex_unlock(&mux->mm_descrambler_lock);
+  return 0;
+}
+
 void
-descrambler_ca_section( elementary_stream_t *st,
-                        const uint8_t *data, size_t len )
+descrambler_flush_tables( mpegts_mux_t *mux )
 {
-  th_descrambler_t *td;
+  descrambler_table_t *dt;
+  descrambler_section_t *ds;
 
-  LIST_FOREACH(td, &st->es_service->s_descramblers, td_service_link)
-    td->td_table(td, st, data, len);
+  pthread_mutex_lock(&mux->mm_descrambler_lock);
+  while ((dt = TAILQ_FIRST(&mux->mm_descrambler_tables)) != NULL) {
+    while ((ds = TAILQ_FIRST(&dt->sections)) != NULL) {
+      TAILQ_REMOVE(&dt->sections, ds, link);
+      free(ds);
+    }
+    TAILQ_REMOVE(&mux->mm_descrambler_tables, dt, link);
+    mpegts_table_destroy(dt->table);
+    free(dt);
+  }
+  pthread_mutex_unlock(&mux->mm_descrambler_lock);
 }
 
 // TODO: might actually put const char* into caid_t
index 086f972e8c9ecf2fa4946141f8d6651417608ba5..a20ab9dbb1f0e8cf7cd1b41f161bf25a5060a880 100644 (file)
@@ -347,6 +347,9 @@ struct mpegts_mux
   LIST_HEAD(, mpegts_table)   mm_tables;
   TAILQ_HEAD(, mpegts_table)  mm_table_queue;
 
+  TAILQ_HEAD(, descrambler_table) mm_descrambler_tables;
+  pthread_mutex_t             mm_descrambler_lock;
+
   /*
    * Functions
    */
@@ -729,7 +732,6 @@ mpegts_table_t *mpegts_table_add
 void mpegts_table_flush_all
   (mpegts_mux_t *mm);
 void mpegts_table_destroy ( mpegts_table_t *mt );
-void mpegts_table_register_caid ( mpegts_mux_t *mm, uint16_t caid );
 
 mpegts_service_t *mpegts_service_create0
   ( mpegts_service_t *ms, const idclass_t *class, const char *uuid,
index 21521d73de783f49d9909ccb262e37512a46fa22..41878d2d8b7859211ddf2653757f12c325805a7c 100644 (file)
@@ -1561,6 +1561,10 @@ psi_parse_pmt
       if(t->s_status == SERVICE_RUNNING)
         ret = 1;
     }
+    
+    // notify descrambler that we found another CAIDs
+    if (update & PMT_UPDATE_NEW_CAID)
+      descrambler_caid_changed((service_t *)t);
   }
   return ret;
 }
index 456bdaab2f1067b0cb15e4cb6fede37529e6f2dd..d42e61754e5c4b682776f21fd30dc69a975c61c7 100644 (file)
@@ -314,8 +314,10 @@ mpegts_input_open_service ( mpegts_input_t *mi, mpegts_service_t *s, int init )
   pthread_mutex_lock(&s->s_stream_mutex);
   mi->mi_open_pid(mi, s->s_dvb_mux, s->s_pmt_pid, MPS_STREAM, s);
   mi->mi_open_pid(mi, s->s_dvb_mux, s->s_pcr_pid, MPS_STREAM, s);
-  TAILQ_FOREACH(st, &s->s_components, es_link)
-    mi->mi_open_pid(mi, s->s_dvb_mux, st->es_pid, MPS_STREAM, s);
+  TAILQ_FOREACH(st, &s->s_components, es_link) {
+    if (st->es_type != SCT_CA)
+      mi->mi_open_pid(mi, s->s_dvb_mux, st->es_pid, MPS_STREAM, s);
+  }
 
   pthread_mutex_unlock(&s->s_stream_mutex);
   pthread_mutex_unlock(&mi->mi_output_lock);
index c7fb2f09698a1d2142568f977185b27975ad914b..cfdbe4cd7c865c943ca48c685e812a64cdc3162f 100644 (file)
@@ -769,6 +769,8 @@ mpegts_mux_create0
   mm->mm_open_table          = mpegts_mux_open_table;
   mm->mm_close_table         = mpegts_mux_close_table;
   TAILQ_INIT(&mm->mm_table_queue);
+  TAILQ_INIT(&mm->mm_descrambler_tables);
+  pthread_mutex_init(&mm->mm_descrambler_lock, NULL);
 
   mm->mm_last_pid            = -1;
 
index 773e0d09735e7e2cc9453521621288ef2a5beb18..6f1f11b72fba82eabce7820bcdc6e3b000e66d58 100644 (file)
@@ -200,20 +200,11 @@ void
 mpegts_table_flush_all ( mpegts_mux_t *mm )
 {
   mpegts_table_t        *mt;
+  descrambler_flush_tables(mm);
   while ((mt = LIST_FIRST(&mm->mm_tables)))
     mpegts_table_destroy(mt);
 }
 
-/**
- * Register wanted CAID
- */
-void
-mpegts_table_register_caid ( mpegts_mux_t *mm, uint16_t caid )
-{
-  uintptr_t ca = caid;
-  mpegts_table_add(mm, 0, 0, NULL, (void *)ca, "ca", MT_FULL, -1);
-}
-
 /*
  * Section assembly
  */
index 7f22ae2a313d35a3809cb7568f595b6b798a0537..621a4bfef5b5d98dbf9dfba6a506d58d96fbd3d7 100644 (file)
 
 static void ts_remux(mpegts_service_t *t, const uint8_t *tsb);
 
-/**
- * Code for dealing with a complete section
- */
-static void
-got_ca_section(const uint8_t *data, size_t len, void *opaque)
-{
-  elementary_stream_t *st = opaque;
-  assert(st->es_service->s_source_type == S_MPEG_TS);
-  descrambler_ca_section(st, data, len);
-}
-
 /**
  * Continue processing of transport stream packets
  */
@@ -62,7 +51,7 @@ static void
 ts_recv_packet0
   (mpegts_service_t *t, elementary_stream_t *st, const uint8_t *tsb)
 {
-  int off, pusi, cc, error, ccerr;
+  int off, pusi, cc, error;
 
   service_set_streaming_status_flags((service_t*)t, TSS_MUX_PACKETS);
 
@@ -72,7 +61,6 @@ ts_recv_packet0
   if (!st)
     return;
 
-  ccerr = 0;
   error = !!(tsb[1] & 0x80);
   pusi  = !!(tsb[1] & 0x40);
 
@@ -81,7 +69,6 @@ ts_recv_packet0
   if(tsb[3] & 0x10) {
     cc = tsb[3] & 0xf;
     if(st->es_cc != -1 && cc != st->es_cc) {
-      ccerr = 1;
       /* Incorrect CC */
       limitedlog(&st->es_loglimit_cc, "TS", service_component_nicename(st),
      "Continuity counter error");
@@ -100,10 +87,6 @@ ts_recv_packet0
   switch(st->es_type) {
 
   case SCT_CA:
-    if(st->es_section == NULL)
-      st->es_section = calloc(1, sizeof(mpegts_psi_section_t));
-    mpegts_psi_section_reassemble(st->es_section, tsb, 0, ccerr,
-                                  got_ca_section, st);
     break;
 
   default: