diff --git a/docs/html/config_services.html b/docs/html/config_services.html
index 7975687e..d48355cc 100644
--- a/docs/html/config_services.html
+++ b/docs/html/config_services.html
@@ -51,6 +51,17 @@
Pref. CA PID
The Preferred Conditional Access Packet Identifier. Used for decrypting scrambled streams.
+ Lock Pref. CA PID
+ The locking mechanism selection for The Preferred Conditional Access Packet Identifier.
+
+ - Off
+
- Automatic Preferred Conditional Access Packet Identifier selection.
+
- On
+
- Keep Preferred Conditional Access Packet Identifier selection (no automatic modifications allowed).
+
- Only Pref. CA PID
+
- Filter mode - use only Preferred Conditional Access Packet Identifier for the streams decryption.
+
+
Character Set
The character encoding for this service (e.g. UTF-8).
diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c
index e60ce7a4..babd1a81 100644
--- a/src/descrambler/capmt.c
+++ b/src/descrambler/capmt.c
@@ -1530,6 +1530,9 @@ capmt_caid_change(th_descrambler_t *td)
lock_assert(&t->s_stream_mutex);
TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
+ if (t->s_dvb_prefcapid_lock == 2 &&
+ t->s_dvb_prefcapid != st->es_pid)
+ continue;
LIST_FOREACH(c, &st->es_caids, link) {
/* search ecmpid in list */
LIST_FOREACH(cce, &ct->ct_caid_ecm, cce_link)
@@ -1809,6 +1812,9 @@ capmt_service_start(service_t *s)
pthread_mutex_lock(&t->s_stream_mutex);
TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
caid_t *c;
+ if (t->s_dvb_prefcapid_lock == 2 &&
+ t->s_dvb_prefcapid != st->es_pid)
+ continue;
LIST_FOREACH(c, &st->es_caids, link) {
if(c == NULL || c->use == 0)
continue;
diff --git a/src/descrambler/cwc.c b/src/descrambler/cwc.c
index 36d70cea..af9f64c4 100755
--- a/src/descrambler/cwc.c
+++ b/src/descrambler/cwc.c
@@ -101,6 +101,7 @@ typedef struct ecm_section {
uint16_t es_seq;
char es_nok;
char es_pending;
+ char es_resolved;
int64_t es_time; // time request was sent
size_t es_ecmsize;
uint8_t es_ecm[4070];
@@ -711,10 +712,12 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
{
mpegts_service_t *t = (mpegts_service_t *)ct->td_service;
th_descrambler_t *td;
- ecm_pid_t *ep, *epn;
+ ecm_pid_t *ep;
+ ecm_section_t *es2;
char chaninfo[32];
- int i;
+ int i, j;
int64_t delay = (getmonoclock() - es->es_time) / 1000LL; // in ms
+
es->es_pending = 0;
snprintf(chaninfo, sizeof(chaninfo), " (PID %d)", es->es_channel);
@@ -749,17 +752,20 @@ handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg,
"Req delay: %"PRId64" ms)", t->s_dvb_svcname, chaninfo, seq, delay);
forbid:
+ j = 0;
LIST_FOREACH(ep, &ct->cs_pids, ep_link) {
- for(i = 0; i <= ep->ep_last_section; i++)
- if(ep->ep_sections[i] == NULL) {
- if(es->es_nok < 2) /* only first hit is allowed */
- return;
- } else {
- if(ep->ep_sections[i]->es_pending ||
- ep->ep_sections[i]->es_nok == 0)
+ for(i = 0; i <= ep->ep_last_section; i++) {
+ es2 = ep->ep_sections[i];
+ if(es2 && es2 != es && es2->es_nok == 0) {
+ if (es2->es_pending)
return;
+ j++;
}
+ }
}
+ if (j && es->es_nok < 2) /* only first hit is allowed */
+ return;
+
tvhlog(LOG_ERR, "cwc",
"Can not descramble service \"%s\", access denied (seqno: %d "
"Req delay: %"PRId64" ms) from %s",
@@ -776,7 +782,9 @@ forbid:
ct->cs_channel = es->es_channel;
ct->ecm_state = ECM_VALID;
- if(t->s_dvb_prefcapid == 0 || t->s_dvb_prefcapid != ct->cs_channel) {
+ if(t->s_dvb_prefcapid == 0 ||
+ (t->s_dvb_prefcapid != ct->cs_channel &&
+ t->s_dvb_prefcapid_lock == 0)) {
t->s_dvb_prefcapid = ct->cs_channel;
tvhlog(LOG_DEBUG, "cwc", "Saving prefered PID %d for %s",
t->s_dvb_prefcapid, ct->td_nicename);
@@ -802,20 +810,13 @@ forbid:
descrambler_keys((th_descrambler_t *)ct, msg + 3, msg + 3 + 8);
- ep = LIST_FIRST(&ct->cs_pids);
- while(ep != NULL) {
- if (ct->cs_channel == 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 ECM (PID %d) for service \"%s\" from %s",
- ep->ep_pid, t->s_dvb_svcname, ct->td_nicename);
- free(ep);
- ep = epn;
+ LIST_FOREACH(ep, &ct->cs_pids, ep_link) {
+ for(i = 0; i < ep->ep_last_section; i++) {
+ es2 = ep->ep_sections[i];
+ if (es2) {
+ es2->es_resolved = 1;
+ es2->es_pending = 0;
+ }
}
}
}
@@ -848,9 +849,19 @@ cwc_running_reply(cwc_t *cwc, uint8_t msgtype, uint8_t *msg, int len)
for(i = 0; i <= ep->ep_last_section; i++) {
es = ep->ep_sections[i];
if(es != NULL) {
- if(es->es_seq == seq && es->es_pending) {
- handle_ecm_reply(ct, es, msg, len, seq);
- return 0;
+ if(es->es_seq == seq) {
+ if (es->es_resolved) {
+ mpegts_service_t *t = (mpegts_service_t *)ct->td_service;
+ tvhlog(LOG_WARNING, "cwc",
+ "Ignore %sECM (PID %d) for service \"%s\" from %s (seq %i)",
+ es->es_pending ? "duplicate " : "",
+ ep->ep_pid, t->s_dvb_svcname, ct->td_nicename, es->es_seq);
+ return 0;
+ }
+ if (es->es_pending) {
+ handle_ecm_reply(ct, es, msg, len, seq);
+ return 0;
+ }
}
}
}
@@ -1194,8 +1205,8 @@ cwc_thread(void *aux)
ts.tv_nsec = 0;
tvhlog(LOG_INFO, "cwc",
- "%s:%i: Automatic connection attempt in in %d seconds",
- cwc->cwc_hostname, cwc->cwc_port, d);
+ "%s:%i: Automatic connection attempt in %d seconds",
+ cwc->cwc_hostname, cwc->cwc_port, d-1);
pthread_cond_timedwait(&cwc_config_changed, &cwc_mutex, &ts);
}
@@ -1735,6 +1746,7 @@ cwc_table_input(void *opaque, int pid, const uint8_t *data, int len)
es->es_channel = channel;
es->es_section = section;
es->es_pending = 1;
+ es->es_resolved = 0;
memcpy(es->es_ecm, data, len);
es->es_ecmsize = len;
@@ -1980,6 +1992,9 @@ cwc_service_start(service_t *t)
LIST_FOREACH(pcard, &cwc->cwc_cards, cs_card) {
if (pcard->cwc_caid == 0) continue;
TAILQ_FOREACH(st, &t->s_filt_components, es_filt_link) {
+ if (((mpegts_service_t *)t)->s_dvb_prefcapid_lock == 2 &&
+ ((mpegts_service_t *)t)->s_dvb_prefcapid != st->es_pid)
+ continue;
LIST_FOREACH(c, &st->es_caids, link) {
if (c->use && c->caid == pcard->cwc_caid)
break;
diff --git a/src/input/mpegts.h b/src/input/mpegts.h
index 292d2527..791e56be 100644
--- a/src/input/mpegts.h
+++ b/src/input/mpegts.h
@@ -428,6 +428,7 @@ struct mpegts_service
uint16_t s_dvb_servicetype;
char *s_dvb_charset;
uint16_t s_dvb_prefcapid;
+ int s_dvb_prefcapid_lock;
/*
* EIT/EPG control
diff --git a/src/input/mpegts/mpegts_service.c b/src/input/mpegts/mpegts_service.c
index ed41eaf6..e4dc026b 100644
--- a/src/input/mpegts/mpegts_service.c
+++ b/src/input/mpegts/mpegts_service.c
@@ -55,6 +55,17 @@ mpegts_service_class_get_network ( void *ptr )
return &s;
}
+static htsmsg_t *
+mpegts_service_pref_capid_lock_list ( void *o )
+{
+ static const struct strtab tab[] = {
+ { "Off", 0 },
+ { "On", 1 },
+ { "Only Pref. CA PID", 2 },
+ };
+ return strtab2htsmsg(tab);
+}
+
const idclass_t mpegts_service_class =
{
.ic_super = &service_class,
@@ -133,6 +144,14 @@ const idclass_t mpegts_service_class =
.off = offsetof(mpegts_service_t, s_dvb_prefcapid),
.opts = PO_ADVANCED,
},
+ {
+ .type = PT_INT,
+ .id = "prefcapid_lock",
+ .name = "Lock Pref. CA PID",
+ .off = offsetof(mpegts_service_t, s_dvb_prefcapid_lock),
+ .opts = PO_ADVANCED,
+ .list = mpegts_service_pref_capid_lock_list,
+ },
{},
}
};
diff --git a/src/service.c b/src/service.c
index 65be059f..d1d1dcfb 100644
--- a/src/service.c
+++ b/src/service.c
@@ -405,9 +405,9 @@ filter:
ca = NULL;
if ((esf->esf_caid != (uint16_t)-1 || esf->esf_caprovider != -1)) {
LIST_FOREACH(ca, &st->es_caids, link) {
- if (esf->esf_caid != -1 && ca->caid != esf->esf_caid)
+ if (esf->esf_caid != (uint16_t)-1 && ca->caid != esf->esf_caid)
continue;
- if (esf->esf_caprovider != -1 && ca->providerid != esf->esf_caprovider)
+ if (esf->esf_caprovider != (uint32_t)-1 && ca->providerid != esf->esf_caprovider)
continue;
break;
}