DS_READY,
DS_RESOLVED,
DS_FORBIDDEN,
+ DS_FATAL,
DS_IDLE
} th_descrambler_keystate_t;
int dr_ca_count;
int dr_ca_resolved;
int dr_ca_failed;
+ int dr_ca_fatal;
uint32_t dr_external:1;
uint32_t dr_skip:1;
uint32_t dr_quick_ecm:1;
/* Elementary stream types */
uint8_t ct_types[MAX_PIDS];
uint8_t ct_type_sok[MAX_PIDS];
+
+ /* OK flag - seems that descrambling is going on */
+ uint8_t ct_ok_flag;
+ mtimer_t ct_ok_timer;
} capmt_service_t;
/**
"%s: Removing CAPMT Server from service \"%s\" on adapter %d",
capmt_name(capmt), s->s_dvb_svcname, ct->ct_adapter);
+ mtimer_disarm(&ct->ct_ok_timer);
+
pthread_mutex_lock(&capmt->capmt_mutex);
/* send stop to client */
if (cce->cce_ecmpid == pid) {
flags = CAPMT_MSG_FAST;
t = cce->cce_service;
- break;
+ goto service_found;
}
- if (t) break;
}
+service_found:
if (t) {
dmx_filter_t *pf = (dmx_filter_t *)sbuf_peek(sb, offset + 4);
/* OK, probably ECM, but sometimes, it's shared */
if (i < DMX_FILTER_SIZE ||
pf->mode[0] ||
(pf->filter[0] & 0xf0) != 0x80 ||
- (pf->mask[0] & 0xf0) != 0xf0)
+ (pf->mask[0] & 0xf0) != 0xf0) {
t = NULL;
+ flags = 0;
+ }
}
+ if (t)
+ ct->ct_ok_flag = 1;
cf->adapter = adapter;
filter = &cf->dmx[filter_index];
if (pid == 0) break;
if (pid == pids[i]) {
if (multipid) {
+ ct->ct_ok_flag = 1;
descrambler_keys((th_descrambler_t *)ct, type, pid, even, odd);
continue;
} else if (ct->ct_type_sok[j])
continue;
found:
+ ct->ct_ok_flag = 1;
descrambler_keys((th_descrambler_t *)ct, type, pid, even, odd);
}
pthread_mutex_unlock(&capmt->capmt_mutex);
capmt_notify_server(capmt, ct, 1);
}
+static void
+capmt_ok_timer_cb(void *aux)
+{
+ capmt_service_t *ct = aux;
+
+ if (!ct->ct_ok_flag)
+ descrambler_change_keystate((th_descrambler_t *)ct, DS_FATAL, 1);
+}
+
static void
capmt_send_request(capmt_service_t *ct, int lm)
{
capmt_name(capmt), t->s_dvb_svcname);
capmt_queue_msg(capmt, adapter_num, sid, buf, pos, 0);
+
+ mtimer_arm_rel(&ct->ct_ok_timer, capmt_ok_timer_cb, ct, sec2mono(3)/2);
}
static void
{ "READY", DS_READY },
{ "RESOLVED", DS_RESOLVED },
{ "FORBIDDEN", DS_FORBIDDEN },
+ { "FATAL", DS_FATAL },
{ "IDLE", DS_IDLE },
};
{
service_t *t = td->td_service;
th_descrambler_runtime_t *dr;
- int count = 0, failed = 0, resolved = 0;
+ int count = 0, fatal = 0, failed = 0, resolved = 0;
if (td->td_keystate == keystate)
return;
LIST_FOREACH(td, &t->s_descramblers, td_service_link) {
count++;
switch (td->td_keystate) {
+ case DS_FATAL: fatal++; break;
case DS_FORBIDDEN: failed++; break;
case DS_RESOLVED : resolved++; break;
default: break;
dr->dr_ca_count = count;
dr->dr_ca_resolved = resolved;
dr->dr_ca_failed = failed;
- tvhtrace(LS_DESCRAMBLER, "service \"%s\": %d descramblers (%d ok %d failed)",
- t->s_nicename, count, resolved, failed);
+ dr->dr_ca_fatal = fatal;
+ tvhtrace(LS_DESCRAMBLER, "service \"%s\": %d descramblers (%d ok %d failed %d fatal)",
+ t->s_nicename, count, resolved, failed, fatal);
if (lock)
pthread_mutex_unlock(&t->s_stream_mutex);
}
descrambler_flush_table_data(t);
end:
debug2("%p: end, %s", dr, keystr(tsb));
- if (dr->dr_ca_count > 0 && dr->dr_ca_count == dr->dr_ca_failed)
- return -1;
+ if (dr->dr_ca_count > 0) {
+ if (dr->dr_ca_count == dr->dr_ca_fatal)
+ return 0;
+ if (dr->dr_ca_count == dr->dr_ca_failed)
+ return -1;
+ }
return dr->dr_ca_count;
}
mpegts_apids_t pids;
const uint8_t *data1;
int len1;
+ uint8_t dtag;
uint8_t dlen;
uint16_t caid;
uint16_t pid;
int
tss2errcode(int tss)
{
+ if(tss & TSS_NO_DESCRAMBLER)
+ return SM_CODE_NO_DESCRAMBLER;
+
if(tss & TSS_NO_ACCESS)
return SM_CODE_NO_ACCESS;
if(tss & TSS_TUNING)
return SM_CODE_TUNING_FAILED;
- if(tss & TSS_NO_DESCRAMBLER)
- return SM_CODE_NO_DESCRAMBLER;
-
if(tss & (TSS_GRACEPERIOD|TSS_TIMEOUT))
return SM_CODE_NO_INPUT;
}
if (sm->sm_type == SMT_SERVICE_STATUS &&
- (sm->sm_code & (TSS_TUNING|TSS_TIMEOUT|TSS_CA_CHECK))) {
+ (sm->sm_code & (TSS_TUNING|TSS_TIMEOUT|TSS_NO_DESCRAMBLER|TSS_CA_CHECK))) {
error = tss2errcode(sm->sm_code);
if (error != SM_CODE_OK)
if (error != SM_CODE_NO_ACCESS ||