From f0b284065def370cbd248a2fd2f32b63c5541147 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 7 Jul 2014 11:47:34 +0200 Subject: [PATCH] descrambler: improve the ECM handling - for constcw (CAID 2600) do not expect any key change - when the stream is broken, try to issue new ECM request Note: The TS data might be wrong (which may cause the ECM late situations). This patch tries to ask for new ECM to be sure that the keys are correct. The constcw specific code is just an optimization. The new ECM request is not required for it. --- src/descrambler.h | 1 + src/descrambler/capmt.c | 15 ++++++++++++++ src/descrambler/cwc.c | 13 ++++++++++++ src/descrambler/descrambler.c | 39 +++++++++++++++++++++++++++++------ 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/descrambler.h b/src/descrambler.h index dadc8441..9d3981b5 100755 --- a/src/descrambler.h +++ b/src/descrambler.h @@ -51,6 +51,7 @@ typedef struct th_descrambler { void (*td_stop) (struct th_descrambler *d); void (*td_caid_change)(struct th_descrambler *d); + int (*td_ecm_reset) (struct th_descrambler *d); } th_descrambler_t; diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index 8b11664b..64cd7a20 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -182,6 +182,7 @@ typedef struct capmt_service { /* list of used ca-systems with ids and last ecm */ struct capmt_caid_ecm_list ct_caid_ecm; + int ct_constcw; /* fast flag */ tvhcsa_t ct_csa; @@ -935,6 +936,17 @@ capmt_abort(capmt_t *capmt, int keystate) } #endif +static int +capmt_ecm_reset(th_descrambler_t *th) +{ + capmt_service_t *ct = (capmt_service_t *)th; + + if (ct->ct_constcw) + return 1; /* keys will not change */ + ct->td_keystate = DS_UNKNOWN; + return 0; +} + static void capmt_process_key(capmt_t *capmt, uint8_t adapter, uint16_t seq, const uint8_t *even, const uint8_t *odd, @@ -1538,6 +1550,7 @@ capmt_caid_change(th_descrambler_t *td) cce->cce_ecmpid = st->es_pid; cce->cce_providerid = c->providerid; LIST_INSERT_HEAD(&ct->ct_caid_ecm, cce, cce_link); + ct->ct_constcw |= c->caid == 0x2600 ? 1 : 0; change = 1; } } @@ -1812,6 +1825,7 @@ capmt_service_start(service_t *s) cce->cce_ecmpid = st->es_pid; cce->cce_providerid = c->providerid; LIST_INSERT_HEAD(&ct->ct_caid_ecm, cce, cce_link); + ct->ct_constcw |= c->caid == 0x2600 ? 1 : 0; change = 1; } } @@ -1826,6 +1840,7 @@ capmt_service_start(service_t *s) td->td_service = s; td->td_stop = capmt_service_destroy; td->td_caid_change = capmt_caid_change; + td->td_ecm_reset = capmt_ecm_reset; LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link); LIST_INSERT_HEAD(&capmt->capmt_services, ct, ct_link); diff --git a/src/descrambler/cwc.c b/src/descrambler/cwc.c index 0f249061..a4ff0065 100755 --- a/src/descrambler/cwc.c +++ b/src/descrambler/cwc.c @@ -147,6 +147,7 @@ typedef struct cwc_service { tvhcsa_t cs_csa; LIST_HEAD(, ecm_pid) cs_pids; + int cs_constcw; } cwc_service_t; @@ -692,7 +693,17 @@ cwc_send_login(cwc_t *cwc) return 0; } +static int +cwc_ecm_reset(th_descrambler_t *th) +{ + cwc_service_t *ct = (cwc_service_t *)th; + if (ct->cs_constcw) + return 1; /* keys will not change */ + ct->td_keystate = DS_UNKNOWN; + ct->ecm_state = ECM_RESET; + return 0; +} static void handle_ecm_reply(cwc_service_t *ct, ecm_section_t *es, uint8_t *msg, @@ -1991,6 +2002,7 @@ cwc_service_start(service_t *t) ct->cs_channel = -1; ct->cs_mux = ((mpegts_service_t *)t)->s_dvb_mux; ct->ecm_state = ECM_INIT; + ct->cs_constcw = pcard->cwc_caid == 0x2600; td = (th_descrambler_t *)ct; tvhcsa_init(td->td_csa = &ct->cs_csa); @@ -1998,6 +2010,7 @@ cwc_service_start(service_t *t) td->td_nicename = strdup(buf); td->td_service = t; td->td_stop = cwc_service_destroy; + td->td_ecm_reset = cwc_ecm_reset; LIST_INSERT_HEAD(&t->s_descramblers, td, td_service_link); LIST_INSERT_HEAD(&cwc->cwc_services, ct, cs_link); diff --git a/src/descrambler/descrambler.c b/src/descrambler/descrambler.c index 5408dc0d..ecbdda7e 100755 --- a/src/descrambler/descrambler.c +++ b/src/descrambler/descrambler.c @@ -222,6 +222,30 @@ fin: pthread_mutex_unlock(&t->s_stream_mutex); } +static void +descrambler_flush_table_data( service_t *t ) +{ + mpegts_service_t *ms = (mpegts_service_t *)t; + mpegts_mux_t *mux = ms->s_dvb_mux; + descrambler_table_t *dt; + descrambler_section_t *ds; + + if (mux == NULL) + return; + tvhtrace("descrabler", "flush table data for service \"%s\"", ms->s_dvb_svcname); + pthread_mutex_lock(&mux->mm_descrambler_lock); + TAILQ_FOREACH(dt, &mux->mm_descrambler_tables, link) { + if (dt->table == NULL || dt->table->mt_service != ms) + continue; + TAILQ_FOREACH(ds, &dt->sections, link) { + free(ds->last_data); + ds->last_data = NULL; + ds->last_data_len = 0; + } + } + pthread_mutex_unlock(&mux->mm_descrambler_lock); +} + static inline void key_update( th_descrambler_runtime_t *dr, uint8_t key ) { @@ -238,7 +262,7 @@ descrambler_descramble ( service_t *t, #define KEY_MASK(k) (((k) & 0x40) + 0x40) /* 0x40 (for even) or 0x80 (for odd) */ th_descrambler_t *td; th_descrambler_runtime_t *dr = t->s_descramble; - int count, failed, off, size; + int count, failed, off, size, flush_data = 0; uint8_t *tsb2, ki; lock_assert(&t->s_stream_mutex); @@ -270,7 +294,8 @@ descrambler_descramble ( service_t *t, ((mpegts_service_t *)t)->s_dvb_svcname); if (dr->dr_ecm_key_time + 2 < dr->dr_key_start) { sbuf_cut(&dr->dr_buf, off); - goto idle; + if (!td->td_ecm_reset(td)) + goto next; } key_update(dr, ki); } @@ -300,7 +325,8 @@ descrambler_descramble ( service_t *t, tvhtrace("descrambler", "ECM late (%ld seconds) for service \"%s\"", dispatch_clock - dr->dr_ecm_key_time, ((mpegts_service_t *)t)->s_dvb_svcname); - goto idle; + if (!td->td_ecm_reset(td)) + goto next; } key_update(dr, ki); } @@ -310,9 +336,8 @@ descrambler_descramble ( service_t *t, tsb); dr->dr_last_descramble = dispatch_clock; return 1; -idle: - td->td_keystate = DS_IDLE; - failed++; +next: + flush_data = 1; continue; } if (dr->dr_ecm_start) { /* ECM sent */ @@ -344,6 +369,8 @@ idle: sbuf_append(&dr->dr_buf, tsb, 188); } } + if (flush_data) + descrambler_flush_table_data(t); if (dr->dr_last_descramble + 25 < dispatch_clock) return -1; if (count && count == failed)