diff --git a/src/cwc.c b/src/cwc.c index 51b8f2e7..52a4489e 100644 --- a/src/cwc.c +++ b/src/cwc.c @@ -27,7 +27,6 @@ #include #include #include - #include "tvheadend.h" #include "tcp.h" #include "psi.h" @@ -38,7 +37,7 @@ #include "atomic.h" #include "dtable.h" #include "subscriptions.h" - +#include "service.h" #include /** @@ -754,9 +753,9 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg, int len, int seq) { service_t *t = ct->cs_service; + ecm_pid_t *ep, *epn; cwc_service_t *ct2; cwc_t *cwc2; - ecm_pid_t *ep; char chaninfo[32]; int i; int64_t delay = (getmonoclock() - es->es_time) / 1000LL; // in ms @@ -773,9 +772,6 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg, /* ERROR */ - if(ct->cs_okchannel == es->es_channel) - ct->cs_okchannel = -1; - if (es->es_nok < 3) es->es_nok++; @@ -829,6 +825,11 @@ forbid: } else { ct->cs_okchannel = es->es_channel; + tvhlog(LOG_DEBUG, "cwc", "es->es_nok %d t->tht_prefcapid %d", es->es_nok, t->s_prefcapid); + if(es->es_nok == 1 || t->s_prefcapid == 0) { + t->s_prefcapid = ct->cs_okchannel; + service_request_save(t, 0); + } es->es_nok = 0; tvhlog(LOG_DEBUG, "cwc", @@ -865,6 +866,22 @@ forbid: ct->cs_keystate = CS_RESOLVED; memcpy(ct->cs_cw, msg + 3, 16); ct->cs_pending_cw_update = 1; + + ep = LIST_FIRST(&ct->cs_pids); + while(ep != NULL) { + if (ct->cs_okchannel == ep->ep_pid) { + ep = LIST_NEXT(ep, ep_link); + } + else { + epn = LIST_NEXT(ep, ep_link); + for(i = 0; i < 256; i++) + free(ep->ep_sections[i]); + LIST_REMOVE(ep, ep_link); + tvhlog(LOG_WARNING, "cwc", "Delete ECMpid %d", ep->ep_pid); + free(ep); + ep = epn; + } + } } } @@ -902,6 +919,10 @@ cwc_running_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len) } } tvhlog(LOG_WARNING, "cwc", "Got unexpected ECM reply (seqno: %d)", seq); + LIST_FOREACH(ct, &cwc->cwc_services, cs_link) { + tvhlog(LOG_DEBUG, "cwc", "After got unexpected (ct->cs_okchannel: %d)", ct->cs_okchannel); + if (ct->cs_okchannel == -3) ct->cs_okchannel = -2; + } break; } return 0; @@ -1592,9 +1613,28 @@ cwc_table_input(struct th_descrambler *td, struct service *t, } if(ep == NULL) { - ep = calloc(1, sizeof(ecm_pid_t)); - ep->ep_pid = st->es_pid; - LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link); + if (ct->cs_okchannel == -2) { + t->s_prefcapid = 0; + ct->cs_okchannel = -1; + tvhlog(LOG_DEBUG, "cwc", "Insert after unexpected reply"); + } + + if (ct->cs_okchannel == -3 && t->s_prefcapid == st->es_pid) { + ep = calloc(1, sizeof(ecm_pid_t)); + ep->ep_pid = t->s_prefcapid; + LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link); + tvhlog(LOG_DEBUG, "cwc", "Insert only one new ECM channel %d for service id %d", t->s_prefcapid, sid); + } + + if (ct->cs_okchannel == -1 || (ct->cs_okchannel == -3 && t->s_prefcapid == 0)) { + ep = calloc(1, sizeof(ecm_pid_t)); + ep->ep_pid = st->es_pid; + LIST_INSERT_HEAD(&ct->cs_pids, ep, ep_link); + tvhlog(LOG_DEBUG, "cwc", "Insert new ECM channel %d", st->es_pid); + } + else { + return; + } } @@ -1626,6 +1666,9 @@ cwc_table_input(struct th_descrambler *td, struct service *t, section = 0; } + channel = st->es_pid; + snprintf(chaninfo, sizeof(chaninfo), " (channel %d)", channel); + if(ep->ep_sections[section] == NULL) ep->ep_sections[section] = calloc(1, sizeof(ecm_section_t)); @@ -1650,7 +1693,7 @@ cwc_table_input(struct th_descrambler *td, struct service *t, memcpy(es->es_ecm, data, len); es->es_ecmsize = len; - if(ct->cs_okchannel != -1 && channel != -1 && + if(ct->cs_okchannel >= 0 && channel != -1 && ct->cs_okchannel != channel) { tvhlog(LOG_DEBUG, "cwc", "Filtering ECM channel %d", channel); return; @@ -1988,7 +2031,7 @@ cwc_service_start(service_t *t) ct->cs_keys = get_key_struct(); ct->cs_cwc = cwc; ct->cs_service = t; - ct->cs_okchannel = -1; + ct->cs_okchannel = -3; td = &ct->cs_head; td->td_stop = cwc_service_destroy; diff --git a/src/dvb/dvb_service.c b/src/dvb/dvb_service.c index 82621227..65b7fbf5 100644 --- a/src/dvb/dvb_service.c +++ b/src/dvb/dvb_service.c @@ -259,6 +259,10 @@ dvb_service_load(th_dvb_mux_instance_t *tdmi, const char *tdmi_identifier) if(s && u32) service_map_channel(t, channel_find_by_name(s, 1, 0), 0); + if(htsmsg_get_u32(c, "prefcapid", &u32)) + u32 = 0; + t->s_prefcapid = u32; + /* HACK - force save for old config */ if(old) dvb_service_save(t); @@ -471,6 +475,8 @@ dvb_service_build_msg(service_t *t) htsmsg_add_u32(m, "dvb_eit_enable", t->s_dvb_eit_enable); + htsmsg_add_u32(m, "prefcapid", t->s_prefcapid); + return m; } diff --git a/src/service.c b/src/service.c index 6548f104..e189ae1d 100644 --- a/src/service.c +++ b/src/service.c @@ -933,6 +933,15 @@ service_set_enable(service_t *t, int enabled) subscription_reschedule(); } +void +service_set_prefcapid(service_t *t, uint32_t prefcapid) +{ + if(t->s_prefcapid == prefcapid) + return; + + t->s_prefcapid = prefcapid; + t->s_config_save(t); +} static pthread_mutex_t pending_save_mutex; static pthread_cond_t pending_save_cond; diff --git a/src/service.h b/src/service.h index 11e39b5d..b6463fc0 100644 --- a/src/service.h +++ b/src/service.h @@ -474,6 +474,7 @@ typedef struct service { int s_scrambled; int s_scrambled_seen; int s_caid; + uint16_t s_prefcapid; /** * PCR drift compensation. This should really be per-packet. @@ -597,6 +598,8 @@ void service_set_dvb_charset(service_t *t, const char *dvb_charset); void service_set_dvb_eit_enable(service_t *t, int dvb_eit_enable); +void service_set_prefcapid(service_t *t, uint32_t prefcapid); + int service_is_primary_epg (service_t *t); htsmsg_t *servicetype_list (void); diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 10829e2e..6355e236 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -1469,6 +1469,9 @@ service_update(htsmsg_t *in) if((chname = htsmsg_get_str(c, "channelname")) != NULL) service_map_channel(t, channel_find_by_name(chname, 1, 0), 1); + if(!htsmsg_get_u32(c, "prefcapid", &u32)) + service_set_prefcapid(t, u32); + if((dvb_charset = htsmsg_get_str(c, "dvb_charset")) != NULL) service_set_dvb_charset(t, dvb_charset); @@ -1800,6 +1803,9 @@ extjs_service_update(htsmsg_t *in) if(!htsmsg_get_u32(c, "enabled", &u32)) service_set_enable(t, u32); + if(!htsmsg_get_u32(c, "prefcapid", &u32)) + service_set_prefcapid(t, u32); + if((chname = htsmsg_get_str(c, "channelname")) != NULL) service_map_channel(t, channel_find_by_name(chname, 1, 0), 1); diff --git a/src/webui/static/app/dvb.js b/src/webui/static/app/dvb.js index 746ac7d6..0f1b836f 100644 --- a/src/webui/static/app/dvb.js +++ b/src/webui/static/app/dvb.js @@ -506,6 +506,11 @@ tvheadend.dvb_services = function(adapterId) { dataIndex : 'sid', width : 50, hidden : true + }, { + header: "Preffered CA pid", + dataIndex: 'prefcapid', + width: 50, + editor: new fm.TextField({allowBlank: true}) }, { header : "PMT PID", dataIndex : 'pmt', @@ -521,7 +526,7 @@ tvheadend.dvb_services = function(adapterId) { var store = new Ext.data.JsonStore({ root : 'entries', fields : Ext.data.Record.create([ 'id', 'enabled', 'type', 'sid', 'pmt', - 'pcr', 'svcname', 'network', 'provider', 'mux', 'channelname', + 'pcr', 'svcname', 'network', 'provider', 'mux', 'channelname', 'prefcapid', 'dvb_charset', 'dvb_eit_enable' ]), url : "dvb/services/" + adapterId, autoLoad : true,