diff --git a/src/capmt.c b/src/capmt.c index bf6af52d..b98f5a4e 100644 --- a/src/capmt.c +++ b/src/capmt.c @@ -411,6 +411,12 @@ capmt_table_input(struct th_descrambler *td, struct th_transport *t, capmt_t *capmt = ct->ct_capmt; int adapter_num = t->tht_dvb_mux_instance->tdmi_adapter->tda_adapter_num; + caid_t *c; + + c = LIST_FIRST(&st->st_caids); + if(c == NULL) + return; + if(len > 4096) return; @@ -420,9 +426,9 @@ capmt_table_input(struct th_descrambler *td, struct th_transport *t, { /* ECM */ if (ct->ct_caid_last == -1) - ct->ct_caid_last = st->st_caid; + ct->ct_caid_last = c->caid; - uint16_t caid = st->st_caid; + uint16_t caid = c->caid; /* search ecmpid in list */ capmt_caid_ecm_t *cce, *cce2; LIST_FOREACH(cce, &ct->ct_caid_ecm, cce_link) @@ -432,11 +438,11 @@ capmt_table_input(struct th_descrambler *td, struct th_transport *t, if (!cce) { tvhlog(LOG_DEBUG, "capmt", - "New caid 0x%04X for service \"%s\"", st->st_caid, t->tht_svcname); + "New caid 0x%04X for service \"%s\"", c->caid, t->tht_svcname); /* ecmpid not already seen, add it to list */ cce = calloc(1, sizeof(capmt_caid_ecm_t)); - cce->cce_caid = st->st_caid; + cce->cce_caid = c->caid; cce->cce_ecmpid = st->st_pid; LIST_INSERT_HEAD(&ct->ct_caid_ecm, cce, cce_link); } @@ -619,15 +625,16 @@ capmt_transport_start(th_transport_t *t) ct->ct_seq = capmt->capmt_seq++; LIST_FOREACH(st, &t->tht_components, st_link) { - if (st->st_caid == 0) - continue; + caid_t *c = LIST_FIRST(&st->st_caids); + if(c == NULL) + continue; tvhlog(LOG_DEBUG, "capmt", - "New caid 0x%04X for service \"%s\"", st->st_caid, t->tht_svcname); + "New caid 0x%04X for service \"%s\"", c->caid, t->tht_svcname); /* add it to list */ cce = calloc(1, sizeof(capmt_caid_ecm_t)); - cce->cce_caid = st->st_caid; + cce->cce_caid = c->caid; cce->cce_ecmpid = st->st_pid; LIST_INSERT_HEAD(&ct->ct_caid_ecm, cce, cce_link); diff --git a/src/cwc.c b/src/cwc.c index 910dc863..5e40e614 100644 --- a/src/cwc.c +++ b/src/cwc.c @@ -1063,19 +1063,25 @@ cwc_table_input(struct th_descrambler *td, struct th_transport *t, int section; ecm_section_t *es; char chaninfo[32]; + caid_t *c; if(len > 4096) return; - if(cwc->cwc_caid != st->st_caid) - return; - - if(!verify_provider(cwc, st->st_providerid)) - return; - if((data[0] & 0xf0) != 0x80) return; + LIST_FOREACH(c, &st->st_caids, link) { + if(cwc->cwc_caid != c->caid) + break; + } + + if(c == NULL) + return; + + if(!verify_provider(cwc, c->providerid)) + return; + switch(data[0]) { case 0x80: case 0x81: @@ -1216,10 +1222,13 @@ static inline th_stream_t * cwc_find_stream_by_caid(th_transport_t *t, int caid) { th_stream_t *st; + caid_t *c; LIST_FOREACH(st, &t->tht_components, st_link) { - if(st->st_caid == caid) - return st; + LIST_FOREACH(c, &st->st_caids, link) { + if(c->caid == caid) + return st; + } } return NULL; } diff --git a/src/dvb/dvb_multiplex.c b/src/dvb/dvb_multiplex.c index b6359568..2d2b379e 100644 --- a/src/dvb/dvb_multiplex.c +++ b/src/dvb/dvb_multiplex.c @@ -1076,6 +1076,7 @@ dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src) th_dvb_mux_instance_t *tdmi_dst; th_transport_t *t_src, *t_dst; th_stream_t *st_src, *st_dst; + caid_t *caid_src, *caid_dst; tdmi_dst = dvb_mux_create(dst, &tdmi_src->tdmi_conf, @@ -1120,7 +1121,15 @@ dvb_mux_copy(th_dvb_adapter_t *dst, th_dvb_mux_instance_t *tdmi_src) memcpy(st_dst->st_lang, st_src->st_lang, 4); st_dst->st_frame_duration = st_src->st_frame_duration; - st_dst->st_caid = st_src->st_caid; + + LIST_FOREACH(caid_src, &st_src->st_caids, link) { + caid_dst = malloc(sizeof(caid_t)); + + caid_dst->caid = caid_src->caid; + caid_dst->providerid = caid_src->providerid; + caid_dst->delete_me = 0; + LIST_INSERT_HEAD(&st_dst->st_caids, caid_dst, link); + } } pthread_mutex_unlock(&t_dst->tht_stream_mutex); diff --git a/src/psi.c b/src/psi.c index 8c2f08d9..112c0c7d 100644 --- a/src/psi.c +++ b/src/psi.c @@ -221,7 +221,7 @@ psi_build_pat(th_transport_t *t, uint8_t *buf, int maxlen, int pmtpid) #define PMT_UPDATE_NEW_CAID 0x100 #define PMT_UPDATE_CA_PROVIDER_CHANGE 0x200 #define PMT_UPDATE_PARENT_PID 0x400 - +#define PMT_UPDATE_CAID_DELETED 0x800 /** * Add a CA descriptor @@ -230,6 +230,7 @@ static int psi_desc_add_ca(th_transport_t *t, uint16_t caid, uint32_t provid, uint16_t pid) { th_stream_t *st; + caid_t *c; int r = 0; if((st = transport_stream_find(t, pid)) == NULL) { @@ -239,16 +240,26 @@ psi_desc_add_ca(th_transport_t *t, uint16_t caid, uint32_t provid, uint16_t pid) st->st_delete_me = 0; - if(st->st_caid != caid) { - st->st_caid = caid; - r |= PMT_UPDATE_NEW_CAID; + LIST_FOREACH(c, &st->st_caids, link) { + if(c->caid == caid) { + c->delete_me = 0; + + if(c->providerid != provid) { + c->providerid = provid; + r |= PMT_UPDATE_CA_PROVIDER_CHANGE; + } + return r; + } } - if(st->st_providerid != provid) { - st->st_providerid = provid; - r |= PMT_UPDATE_CA_PROVIDER_CHANGE; - } + c = malloc(sizeof(caid_t)); + c->caid = caid; + c->providerid = provid; + + c->delete_me = 0; + LIST_INSERT_HEAD(&st->st_caids, c, link); + r |= PMT_UPDATE_NEW_CAID; return r; } @@ -259,11 +270,18 @@ static int psi_desc_ca(th_transport_t *t, const uint8_t *buffer, int size) { int r = 0; - int i = 0; + int i; uint32_t provid = 0; uint16_t caid = (buffer[0] << 8) | buffer[1]; uint16_t pid = ((buffer[2]&0x1F) << 8) | buffer[3]; +#if 0 + printf("CA_DESC: "); + for(i = 0; i < size; i++) + printf("%02x.", buffer[i]); + printf("\n"); +#endif + switch (caid & 0xFF00) { case 0x0100: // SECA/Mediaguard provid = (buffer[4] << 8) | buffer[5]; @@ -365,6 +383,7 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, int composition_id; int ancillary_id; int version; + caid_t *c, *cn; if(len < 9) return -1; @@ -396,10 +415,16 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, len -= 9; /* Mark all streams for deletion */ - if(delete) - LIST_FOREACH(st, &t->tht_components, st_link) + if(delete) { + LIST_FOREACH(st, &t->tht_components, st_link) { st->st_delete_me = 1; + LIST_FOREACH(c, &st->st_caids, link) + c->delete_me = 1; + + } + } + while(dllen > 1) { dtag = ptr[0]; dlen = ptr[1]; @@ -555,6 +580,17 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, /* Scan again to see if any streams should be deleted */ for(st = LIST_FIRST(&t->tht_components); st != NULL; st = next) { next = LIST_NEXT(st, st_link); + + for(c = LIST_FIRST(&st->st_caids); c != NULL; c = cn) { + cn = LIST_NEXT(c, link); + if(c->delete_me) { + LIST_REMOVE(c, link); + free(c); + update |= PMT_UPDATE_CAID_DELETED; + } + } + + if(st->st_delete_me) { transport_stream_destroy(t, st); update |= PMT_UPDATE_STREAM_DELETED; @@ -563,7 +599,7 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, if(update) { tvhlog(LOG_DEBUG, "PSI", "Transport \"%s\" PMT (version %d) updated" - "%s%s%s%s%s%s%s%s%s%s%s", + "%s%s%s%s%s%s%s%s%s%s%s%s", transport_nicename(t), version, update&PMT_UPDATE_PCR ? ", PCR PID changed":"", update&PMT_UPDATE_NEW_STREAM ? ", New elementary stream":"", @@ -575,11 +611,19 @@ psi_parse_pmt(th_transport_t *t, const uint8_t *ptr, int len, int chksvcid, update&PMT_UPDATE_NEW_CA_STREAM ? ", New CA stream":"", update&PMT_UPDATE_NEW_CAID ? ", New CAID":"", update&PMT_UPDATE_CA_PROVIDER_CHANGE? ", CA provider changed":"", - update&PMT_UPDATE_PARENT_PID ? ", Parent PID changed":""); + update&PMT_UPDATE_PARENT_PID ? ", Parent PID changed":"", + update&PMT_UPDATE_CAID_DELETED ? ", CAID deleted":""); transport_request_save(t); - if(t->tht_status == TRANSPORT_RUNNING) - transport_restart(t, had_components); + + // Only restart if something that our clients worry about did change + if(update & !(PMT_UPDATE_NEW_CA_STREAM | + PMT_UPDATE_NEW_CAID | + PMT_UPDATE_CA_PROVIDER_CHANGE | + PMT_UPDATE_CAID_DELETED)) { + if(t->tht_status == TRANSPORT_RUNNING) + transport_restart(t, had_components); + } } return 0; } @@ -848,11 +892,20 @@ psi_save_transport_settings(htsmsg_t *m, th_transport_t *t) htsmsg_add_str(sub, "language", st->st_lang); if(st->st_type == SCT_CA) { - htsmsg_add_str(sub, "caid", psi_caid2name(st->st_caid)); - htsmsg_add_u32(sub, "caidnum", st->st_caid); - if(st->st_providerid) - htsmsg_add_u32(sub, "caproviderid", st->st_providerid); + caid_t *c; + htsmsg_t *v = htsmsg_create_list(); + + LIST_FOREACH(c, &st->st_caids, link) { + htsmsg_t *caid = htsmsg_create_map(); + + htsmsg_add_u32(caid, "caid", c->caid); + if(c->providerid) + htsmsg_add_u32(caid, "providerid", c->providerid); + htsmsg_add_msg(v, NULL, caid); + } + + htsmsg_add_msg(sub, "caidlist", v); } if(st->st_type == SCT_DVBSUB) { @@ -871,6 +924,74 @@ psi_save_transport_settings(htsmsg_t *m, th_transport_t *t) } +/** + * + */ +static void +add_caid(th_stream_t *st, uint16_t caid, uint32_t providerid) +{ + caid_t *c = malloc(sizeof(caid_t)); + c->caid = caid; + c->providerid = providerid; + c->delete_me = 0; + LIST_INSERT_HEAD(&st->st_caids, c, link); +} + + +/** + * + */ +static void +load_legacy_caid(htsmsg_t *c, th_stream_t *st) +{ + uint32_t a, b; + const char *v; + + if(htsmsg_get_u32(c, "caproviderid", &b)) + b = 0; + + if(htsmsg_get_u32(c, "caidnum", &a)) { + if((v = htsmsg_get_str(c, "caid")) != NULL) { + int i = str2val(v, caidnametab); + a = i < 0 ? strtol(v, NULL, 0) : i; + } else { + return; + } + } + + add_caid(st, a, b); +} + + +/** + * + */ +static void +load_caid(htsmsg_t *m, th_stream_t *st) +{ + htsmsg_field_t *f; + htsmsg_t *c, *v = htsmsg_get_list(m, "caidlist"); + uint32_t a, b; + + if(v == NULL) + return; + + HTSMSG_FOREACH(f, v) { + if((c = htsmsg_get_map_by_field(f)) == NULL) + continue; + + if(htsmsg_get_u32(c, "caid", &a)) + continue; + + if(htsmsg_get_u32(c, "providerid", &b)) + b = 0; + + add_caid(st, a, b); + } +} + + + /** * Load transport info from htsmsg */ @@ -879,11 +1000,10 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t) { htsmsg_t *c; htsmsg_field_t *f; - uint32_t u32; + uint32_t u32, pid; th_stream_t *st; streaming_component_type_t type; const char *v; - uint32_t pid; if(!htsmsg_get_u32(m, "pcr", &u32)) t->tht_pcr_pid = u32; @@ -919,14 +1039,9 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t) if(!htsmsg_get_u32(c, "frameduration", &u32)) st->st_frame_duration = u32; - if(!htsmsg_get_u32(c, "caidnum", &u32)) { - st->st_caid = u32; - } else if((v = htsmsg_get_str(c, "caid")) != NULL) { - int i = str2val(v, caidnametab); - st->st_caid = i < 0 ? strtol(v, NULL, 0) : i; - } - - htsmsg_get_u32(c, "caproviderid", &st->st_providerid); + + load_legacy_caid(c, st); + load_caid(c, st); if(type == SCT_DVBSUB) { if(!htsmsg_get_u32(c, "compositionid", &u32)) diff --git a/src/tvhead.h b/src/tvhead.h index d300e726..c7c9bdcf 100644 --- a/src/tvhead.h +++ b/src/tvhead.h @@ -330,6 +330,19 @@ typedef void (pid_section_callback_t)(struct th_transport *t, struct th_stream *pi, const uint8_t *section, int section_len); +LIST_HEAD(caid_list, caid); +/** + * + */ +typedef struct caid { + LIST_ENTRY(caid) link; + + uint8_t delete_me; + uint16_t caid; + uint32_t providerid; + +} caid_t; + /* * Stream, one media component for a transport. * @@ -419,10 +432,8 @@ typedef struct th_stream { struct th_pktref_queue st_durationq; - /* ca id for this stream */ - - uint16_t st_caid; - uint32_t st_providerid; + /* CA ID's on this stream */ + struct caid_list st_caids; /* Remuxing information */ AVRational st_tb; diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 12f4fa47..c81c3cd8 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -1053,7 +1053,8 @@ extjs_servicedetails(http_connection_t *hc, htsmsg_t *out, *streams, *c; th_transport_t *t; th_stream_t *st; - char buf[40]; + caid_t *caid; + char buf[128]; pthread_mutex_lock(&global_lock); @@ -1077,8 +1078,14 @@ extjs_servicedetails(http_connection_t *hc, break; case SCT_CA: - snprintf(buf, sizeof(buf), "%s (0x%04x)", - psi_caid2name(st->st_caid), st->st_caid); + buf[0] = 0; + + LIST_FOREACH(caid, &st->st_caids, link) { + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + "%s (0x%04x) ", + psi_caid2name(caid->caid), caid->caid); + } + htsmsg_add_str(c, "details", buf); break; diff --git a/src/webui/statedump.c b/src/webui/statedump.c index 6bfa937d..2e819309 100644 --- a/src/webui/statedump.c +++ b/src/webui/statedump.c @@ -29,6 +29,7 @@ #include "access.h" #include "epg.h" #include "xmltv.h" +#include "psi.h" #if ENABLE_LINUXDVB #include "dvr/dvr.h" #include "dvb/dvb.h" @@ -106,13 +107,18 @@ dumptransports(htsbuf_queue_t *hq, struct th_transport_list *l, int indent) indent + 4, ""); LIST_FOREACH(st, &t->tht_components, st_link) { - htsbuf_qprintf(hq, "%*.s%-16s %-5d %-5d %-5s %04x %08x\n", indent + 4, "", + caid_t *caid; + htsbuf_qprintf(hq, "%*.s%-16s %-5d %-5d %-5s\n", indent + 4, "", streaming_component_type2txt(st->st_type), st->st_index, st->st_pid, - st->st_lang[0] ? st->st_lang : "", - st->st_caid, - st->st_providerid); + st->st_lang[0] ? st->st_lang : ""); + LIST_FOREACH(caid, &st->st_caids, link) { + htsbuf_qprintf(hq, "%*.sCAID %04x (%s) %08x\n", indent + 6, "", + caid->caid, + psi_caid2name(caid->caid), + caid->providerid); + } } htsbuf_qprintf(hq, "\n");