struct elementary_stream *st,
const uint8_t *tsb );
int descrambler_open_pid ( struct mpegts_mux *mux, void *opaque, int pid,
- descrambler_section_callback_t callback );
+ descrambler_section_callback_t callback,
+ struct service *service );
int descrambler_close_pid ( struct mpegts_mux *mux, void *opaque, int pid );
void descrambler_flush_tables ( struct mpegts_mux *mux );
void descrambler_cat_data ( struct mpegts_mux *mux, const uint8_t *data, int len );
uint8_t mode[DMX_FILTER_SIZE];
} dmx_filter_t;
-typedef struct dmx_sct_filter_params {
- uint16_t pid;
- dmx_filter_t filter;
- uint32_t timeout;
- uint32_t flags;
-#define DMX_CHECK_CRC 1
-#define DMX_ONESHOT 2
-#define DMX_IMMEDIATE_START 4
-#define DMX_KERNEL_CLIENT 0x8000
-} dmx_filter_params_t;
-
#define CA_SET_DESCR 0x40106f86
#define CA_SET_DESCR_X 0x866f1040
#define CA_SET_PID 0x40086f87
/**
**
*/
+typedef struct capmt_dmx {
+ dmx_filter_t filter;
+ uint16_t pid;
+ uint32_t flags;
+} capmt_dmx_t;
+
typedef struct capmt_filters {
int max;
int adapter;
- dmx_filter_params_t dmx[MAX_FILTER];
+ capmt_dmx_t dmx[MAX_FILTER];
} capmt_filters_t;
typedef struct capmt_demuxes {
}
static void
-capmt_pid_add(capmt_t *capmt, int adapter, int pid)
+capmt_pid_add(capmt_t *capmt, int adapter, int pid, mpegts_service_t *s)
{
capmt_adapter_t *ca = &capmt->capmt_adapters[adapter];
capmt_opaque_t *o = NULL, *t;
o->adapter = adapter;
o->pid = pid;
mmi = LIST_FIRST(&capmt->capmt_adapters[adapter].ca_tuner->mi_mux_active);
- descrambler_open_pid(mmi->mmi_mux, o, pid, capmt_table_input);
+ descrambler_open_pid(mmi->mmi_mux, o,
+ s ? DESCRAMBLER_ECM_PID(pid) : pid,
+ capmt_table_input, (service_t *)s);
}
}
uint8_t demux_index = sbuf_peek_u8 (sb, offset + 4);
uint8_t filter_index = sbuf_peek_u8 (sb, offset + 5);
uint16_t pid = sbuf_peek_u16(sb, offset + 6);
- dmx_filter_params_t *filter;
- dmx_filter_params_t *params = (dmx_filter_params_t *)sbuf_peek(sb, offset + 6);
+ capmt_dmx_t *filter;
capmt_filters_t *cf;
capmt_service_t *ct;
mpegts_service_t *t;
cf->adapter = adapter;
filter = &cf->dmx[filter_index];
filter->pid = pid;
- capmt_pid_add(capmt, adapter, pid);
- memcpy(&filter->filter, ¶ms->filter, sizeof(params->filter));
- filter->timeout = 0;
+ memcpy(&filter->filter, sbuf_peek(sb, offset + 10), sizeof(filter->filter));
filter->flags = 0;
/* ECM messages have the higher priority */
+ t = NULL;
LIST_FOREACH(ct, &capmt->capmt_services, ct_link) {
t = (mpegts_service_t *)ct->td_service;
pthread_mutex_lock(&t->s_stream_mutex);
pthread_mutex_unlock(&t->s_stream_mutex);
if (st) break;
}
+ capmt_pid_add(capmt, adapter, pid, t);
/* Update the max values */
if (capmt->capmt_demuxes.max <= demux_index)
capmt->capmt_demuxes.max = demux_index + 1;
uint8_t demux_index = sbuf_peek_u8 (sb, offset + 4);
uint8_t filter_index = sbuf_peek_u8 (sb, offset + 5);
int16_t pid = sbuf_peek_s16le(sb, offset + 6);
- dmx_filter_params_t *filter;
+ capmt_dmx_t *filter;
capmt_filters_t *cf;
tvhtrace("capmt", "stopping filter: adapter=%d, demux=%d, filter=%d, pid=%d",
else if (cmd == CA_SET_DESCR)
return 4 + 16;
else if (oscam_new && cmd == DMX_SET_FILTER)
- return 4 + 2 + sizeof(dmx_filter_params_t);
+ return 4 + 2 + 60;
else if (oscam_new && cmd == DMX_STOP)
return 4 + 4;
else {
pthread_mutex_unlock(&global_lock);
+ if (!capmt->capmt_running) continue;
+
/* open connection to camd.socket */
capmt_connect(capmt, 0);
if (capmt->capmt_adapters[i].ca_sock >= 0)
close(capmt->capmt_adapters[i].ca_sock);
- if (!capmt->capmt_running)
- break;
+ if (!capmt->capmt_running) continue;
/* schedule reconnection */
if(subscriptions_active() && !fatal) {
descrambler_open_pid(ct->cs_mux, ct,
DESCRAMBLER_ECM_PID(ct->cs_estream->es_pid),
- cwc_table_input);
+ cwc_table_input, t);
tvhlog(LOG_DEBUG, "cwc", "%s using CWC %s:%d",
service_nicename(t), cwc->cwc_hostname, cwc->cwc_port);
void
descrambler_service_start ( service_t *t )
{
+ t->s_descramble_key = 0;
#if ENABLE_CWC
cwc_service_start(t);
#endif
#if ENABLE_CAPMT
capmt_service_start(t);
#endif
+ t->s_descramble_buf = calloc(1, sizeof(sbuf_t));
+ sbuf_init(t->s_descramble_buf);
}
void
while ((td = LIST_FIRST(&t->s_descramblers)) != NULL)
td->td_stop(td);
+ if (t->s_descramble_buf) {
+ sbuf_free(t->s_descramble_buf);
+ t->s_descramble_buf = NULL;
+ }
}
void
const uint8_t *tsb )
{
th_descrambler_t *td;
- int count, failed;
+ int count, failed, off, size;
+ count = failed = 0;
LIST_FOREACH(td, &t->s_descramblers, td_service_link) {
count++;
if (td->td_keystate == DS_FORBIDDEN) {
}
if (td->td_keystate != DS_RESOLVED)
continue;
+ if (t->s_descramble_buf) {
+ for (off = 0, size = t->s_descramble_buf->sb_ptr; off < size; off += 188)
+ tvhcsa_descramble(td->td_csa,
+ (mpegts_service_t *)td->td_service,
+ st, t->s_descramble_buf->sb_data + off);
+ sbuf_free(t->s_descramble_buf);
+ free(t->s_descramble_buf);
+ t->s_descramble_buf = NULL;
+ }
tvhcsa_descramble(td->td_csa,
- (struct mpegts_service *)td->td_service,
+ (mpegts_service_t *)td->td_service,
st, tsb);
return 1;
}
- return count == failed ? -1 : 0;
+ if (t->s_descramble_key && count != failed) {
+ /*
+ * Fill a temporary buffer until the keys are known to make
+ * streaming faster.
+ */
+ if (t->s_descramble_buf == NULL) {
+ t->s_descramble_buf = calloc(1, sizeof(sbuf_t));
+ if (t->s_descramble_buf)
+ sbuf_init(t->s_descramble_buf);
+ }
+ if (t->s_descramble_buf) {
+ if (t->s_descramble_buf->sb_ptr >= 3000 * 188)
+ sbuf_cut(t->s_descramble_buf, 300 * 188);
+ sbuf_append(t->s_descramble_buf, tsb, 188);
+ }
+ }
+ return count && count == failed ? -1 : count;
}
static int
ds->last_data_len = 0;
}
ds->callback(ds->opaque, mt->mt_pid, ptr, len);
+ if ((mt->mt_flags & MT_FAST) != 0) { /* ECM */
+ if (mt->mt_service) {
+ /* The keys are requested from this moment */
+ mt->mt_service->s_descramble_key |= 1;
+ }
+ }
}
pthread_mutex_unlock(&mt->mt_mux->mm_descrambler_lock);
return 0;
static int
descrambler_open_pid_( mpegts_mux_t *mux, void *opaque, int pid,
- descrambler_section_callback_t callback )
+ descrambler_section_callback_t callback,
+ service_t *service )
{
descrambler_table_t *dt;
descrambler_section_t *ds;
TAILQ_INIT(&dt->sections);
dt->table = mpegts_table_add(mux, 0, 0, descrambler_table_callback,
dt, "descrambler", MT_FULL | flags, pid);
+ if (dt->table)
+ dt->table->mt_service = (mpegts_service_t *)service;
TAILQ_INSERT_TAIL(&mux->mm_descrambler_tables, dt, link);
}
ds = calloc(1, sizeof(*ds));
int
descrambler_open_pid( mpegts_mux_t *mux, void *opaque, int pid,
- descrambler_section_callback_t callback )
+ descrambler_section_callback_t callback,
+ service_t *service )
{
int res;
pthread_mutex_lock(&mux->mm_descrambler_lock);
- res = descrambler_open_pid_(mux, opaque, pid, callback);
+ res = descrambler_open_pid_(mux, opaque, pid, callback, service);
pthread_mutex_unlock(&mux->mm_descrambler_lock);
return res;
}
}
}
if (emm)
- descrambler_open_pid_(mux, opaque, pid, callback);
+ descrambler_open_pid_(mux, opaque, pid, callback, NULL);
pthread_mutex_unlock(&mux->mm_descrambler_lock);
next:
data += dlen;
tvhtrace("descrambler",
"attach emm caid %04X (%i) pid %04X (%i) - direct",
caid, caid, pid, pid);
- descrambler_open_pid_(mux, opaque, pid, callback);
+ descrambler_open_pid_(mux, opaque, pid, callback, NULL);
}
pthread_mutex_unlock(&mux->mm_descrambler_lock);
return 1;
mpegts_psi_section_t mt_sect;
struct mpegts_table_mux_cb *mt_mux_cb;
+
+ mpegts_service_t *mt_service;
void (*mt_destroy) (mpegts_table_t *mt); // Allow customisable destroy hook
// useful for dynamic allocation of
*/
struct th_descrambler_list s_descramblers;
- int s_scrambled_seen;
+ uint16_t s_scrambled_seen;
+ uint16_t s_descramble_key;
+ sbuf_t *s_descramble_buf;
/**
* List of all and filtered components.