#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
/**
*
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;
+
/**
*
*/
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;
/* 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);
/**
*
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;
+ }
+ }
+ }
+}
+
/**
*
*/
*
*/
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);
}
/**
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);
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));
}
}
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);
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
{
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;
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)
cf->adapter = adapter;
filter = &cf->dmx[filter_index];
filter->pid = pid;
+ capmt_pid_add(capmt, adapter, pid);
memcpy(&filter->filter, ¶ms->filter, sizeof(params->filter));
filter->timeout = filter->flags = 0;
if (capmt->capmt_demuxes.max <= demux_index)
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)
}
}
+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,
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;
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;
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);
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);
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;
if (adapter >= MAX_CA)
continue;
- recvsock = capmt->capmt_sock_ca0[adapter];
+ recvsock = capmt->capmt_adapters[adapter].ca_sock;
if (recvsock <= 0)
continue;
close(recvsock);
capmt_poll_rem(capmt, recvsock);
- capmt->capmt_sock_ca0[adapter] = -1;
+ capmt->capmt_adapters[adapter].ca_sock = -1;
continue;
}
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') {
tvhpoll_destroy(capmt->capmt_poll);
capmt->capmt_poll = NULL;
}
-
#if CONFIG_LINUXDVB
static void
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");
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,
}
}
+ capmt_abort(capmt, DS_UNKNOWN);
tvhlog(LOG_INFO, "capmt", "connection from client closed ...");
}
#endif
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;
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 {
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);
/* 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;
*
*/
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)
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)
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;
}
"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));
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;
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);
} 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;
+
+
/**
*
*/
LIST_ENTRY(cwc_service) cs_link;
int cs_channel;
+ int cs_pid;
+ cwc_opaque_t cs_opaque;
/**
* ECM Status
* 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;
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;
}
}
- 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);
}
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;
section = 0;
}
- channel = st->es_pid;
+ channel = pid;
snprintf(chaninfo, sizeof(chaninfo), " (PID %d)", channel);
if(ep->ep_sections[section] == NULL)
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]);
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
*
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;
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);
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);
#include "cwc.h"
#include "capmt.h"
#include "ffdecsa/FFdecsa.h"
-#include "service.h"
+#include "input.h"
#include "tvhcsa.h"
static struct strtab caidnametab[] = {
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,
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