Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Introduce DVB CA support
  • Loading branch information
dmarion authored and perexg committed Apr 16, 2015
1 parent b1b9b42 commit f358286
Show file tree
Hide file tree
Showing 9 changed files with 842 additions and 0 deletions.
5 changes: 5 additions & 0 deletions Makefile
Expand Up @@ -337,6 +337,11 @@ SRCS-${CONFIG_CAPMT} += \
SRCS-${CONFIG_CONSTCW} += \
src/descrambler/constcw.c

# DVB CAM
SRCS-${CONFIG_LINUXDVB_CA} += \
src/input/mpegts/linuxdvb/linuxdvb_ca.c \
src/descrambler/dvbcam.c

# TSDEBUGCW
SRCS-${CONFIG_TSDEBUG} += \
src/descrambler/tsdebugcw.c
Expand Down
19 changes: 19 additions & 0 deletions configure
Expand Up @@ -43,6 +43,7 @@ OPTIONS=(
"tvhcsa:auto"
"bundle:no"
"dvbcsa:no"
"libdvben50221:auto"
"kqueue:no"
"dbus_1:auto"
"android:no"
Expand Down Expand Up @@ -196,6 +197,16 @@ int test(void)
}
' -liconv

check_cc_snippet libdvben50221 '
#include <libdvben50221/en50221_session.h>
#define TEST test
int test(void)
{
struct en50221_transport_layer *tl = en50221_tl_create(5, 32);
return 0;
}
' '-ldvben50221 -ldvbapi -lucsi'

#
# Python
#
Expand Down Expand Up @@ -432,6 +443,14 @@ if enabled cwc || enabled capmt || enabled constcw; then
fi
fi

#
# libdvben50221
#
if enabled_or_auto libdvben50221; then
LDFLAGS="$LDFLAGS -ldvben50221 -ldvbapi -lucsi"
enable linuxdvb_ca
fi

#
# Icon caching
#
Expand Down
12 changes: 12 additions & 0 deletions src/descrambler/descrambler.c
Expand Up @@ -22,6 +22,7 @@
#include "ffdecsa/FFdecsa.h"
#include "input.h"
#include "input/mpegts/tsdemux.h"
#include "dvbcam.h"

struct caid_tab {
const char *name;
Expand Down Expand Up @@ -84,6 +85,9 @@ descrambler_init ( void )
ffdecsa_init();
#endif
caclient_init();
#if ENABLE_LINUXDVB_CA
dvbcam_init();
#endif
}

void
Expand Down Expand Up @@ -123,6 +127,10 @@ descrambler_service_start ( service_t *t )
tvhcsa_init(&dr->dr_csa);
}
caclient_start(t);

#if ENABLE_LINUXDVB_CA
dvbcam_service_start(t);
#endif
}

void
Expand All @@ -131,6 +139,10 @@ descrambler_service_stop ( service_t *t )
th_descrambler_t *td;
th_descrambler_runtime_t *dr = t->s_descramble;

#if ENABLE_LINUXDVB_CA
dvbcam_service_stop(t);
#endif

while ((td = LIST_FIRST(&t->s_descramblers)) != NULL)
td->td_stop(td);
t->s_descramble = NULL;
Expand Down
222 changes: 222 additions & 0 deletions src/descrambler/dvbcam.c
@@ -0,0 +1,222 @@
/*
* tvheadend, DVB CAM interface
* Copyright (C) 2014 Damjan Marion
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <ctype.h>
#include "tvheadend.h"
#include "caclient.h"
#include "service.h"
#include "input.h"

#include "dvbcam.h"
#include "input/mpegts/linuxdvb/linuxdvb_private.h"

#if ENABLE_LINUXDVB_CA

#define CAIDS_PER_CA_SLOT 16

typedef struct dvbcam_active_service {
TAILQ_ENTRY(dvbcam_active_service) link;
service_t *t;
uint8_t *last_pmt;
int last_pmt_len;
linuxdvb_ca_t *ca;
uint8_t slot;
} dvbcam_active_service_t;

typedef struct dvbcam_active_caid {
TAILQ_ENTRY(dvbcam_active_caid) link;
uint16_t caids[CAIDS_PER_CA_SLOT];
int num_caids;
linuxdvb_ca_t *ca;
uint8_t slot;
} dvbcam_active_caid_t;

TAILQ_HEAD(,dvbcam_active_service) dvbcam_active_services;
TAILQ_HEAD(,dvbcam_active_caid) dvbcam_active_caids;

pthread_mutex_t dvbcam_mutex;

void
dvbcam_register_cam(linuxdvb_ca_t * lca, uint8_t slot, uint16_t * caids,
int num_caids)
{
dvbcam_active_caid_t *ac;

num_caids = MIN(CAIDS_PER_CA_SLOT, num_caids);

if ((ac = malloc(sizeof(*ac))) == NULL)
return;

ac->ca = lca;
ac->slot = slot;
memcpy(ac->caids, caids, num_caids * sizeof(uint16_t));
ac->num_caids = num_caids;

pthread_mutex_lock(&dvbcam_mutex);

TAILQ_INSERT_TAIL(&dvbcam_active_caids, ac, link);

pthread_mutex_unlock(&dvbcam_mutex);
}

void
dvbcam_unregister_cam(linuxdvb_ca_t * lca, uint8_t slot)
{
dvbcam_active_caid_t *ac, *ac_tmp;
dvbcam_active_service_t *as;

pthread_mutex_lock(&dvbcam_mutex);

/* remove pointer to this CAM in all active services */
TAILQ_FOREACH(as, &dvbcam_active_services, link)
if (as->ca == lca && as->slot == slot)
as->ca = NULL;

/* delete entry */
for (ac = TAILQ_FIRST(&dvbcam_active_caids); ac != NULL; ac = ac_tmp) {
ac_tmp = TAILQ_NEXT(ac, link);
if(ac && ac->ca == lca && ac->slot == slot) {
TAILQ_REMOVE(&dvbcam_active_caids, ac, link);
free(ac);
}
}

pthread_mutex_unlock(&dvbcam_mutex);
}

void
dvbcam_pmt_data(mpegts_service_t *s, const uint8_t *ptr, int len)
{
linuxdvb_frontend_t *lfe;
dvbcam_active_caid_t *ac;
dvbcam_active_service_t *as = NULL, *as2;
int i, l;
uint8_t *p;

lfe = (linuxdvb_frontend_t*) s->s_dvb_active_input;

if (!lfe)
return;

pthread_mutex_lock(&dvbcam_mutex);

TAILQ_FOREACH(as2, &dvbcam_active_services, link)
if (as2->t == (service_t *) s) {
as = as2;
break;
}

pthread_mutex_unlock(&dvbcam_mutex);

if (!as)
return;

if(as->last_pmt)
free(as->last_pmt);

as->last_pmt = malloc(len + 3);
memcpy(as->last_pmt, ptr-3, len + 3);
as->last_pmt_len = len + 3;
as->ca = NULL;

l = (ptr[7] & 0x03 )| ptr[8];
p = (uint8_t *) ptr + 9;

while (l > 0 ) {
uint8_t desc_tag = p[0];
uint8_t desc_len = p[1];

if (desc_tag == DVB_DESC_CA) {
uint16_t caid = (p[2] << 8) | p[3];

pthread_mutex_lock(&dvbcam_mutex);

TAILQ_FOREACH(ac, &dvbcam_active_caids, link) {
for(i=0;i<ac->num_caids;i++) {
if(ac->ca && ac->ca->lca_adapter == lfe->lfe_adapter &&
ac->caids[i] == caid)
{
as->ca = ac->ca;
as->slot = ac->slot;
break;
}
}
}
pthread_mutex_unlock(&dvbcam_mutex);
}
p += desc_len + 2;
l -= desc_len + 2;
}

/* this service doesn't have assigned CAM */
if (!as->ca)
return;

linuxdvb_ca_send_capmt(as->ca, as->slot, as->last_pmt, as->last_pmt_len);
}

void
dvbcam_service_start(service_t *t)
{
dvbcam_active_service_t *as;

TAILQ_FOREACH(as, &dvbcam_active_services, link)
if (as->t == t)
return;

if ((as = malloc(sizeof(*as))) == NULL)
return;

as->t = t;
as->last_pmt = NULL;
as->last_pmt_len = 0;

pthread_mutex_lock(&dvbcam_mutex);
TAILQ_INSERT_TAIL(&dvbcam_active_services, as, link);
pthread_mutex_unlock(&dvbcam_mutex);
}

void
dvbcam_service_stop(service_t *t)
{
dvbcam_active_service_t *as, *as_tmp;

pthread_mutex_lock(&dvbcam_mutex);

for (as = TAILQ_FIRST(&dvbcam_active_services); as != NULL; as = as_tmp) {
as_tmp = TAILQ_NEXT(as, link);
if(as && as->t == t) {
TAILQ_REMOVE(&dvbcam_active_services, as, link);
if(as->last_pmt)
free(as->last_pmt);
free(as);
}
}

pthread_mutex_unlock(&dvbcam_mutex);
}

void
dvbcam_init(void)
{
pthread_mutex_init(&dvbcam_mutex, NULL);
TAILQ_INIT(&dvbcam_active_services);
TAILQ_INIT(&dvbcam_active_caids);
}

#endif /* ENABLE_LINUXDVB_CA */
37 changes: 37 additions & 0 deletions src/descrambler/dvbcam.h
@@ -0,0 +1,37 @@
/*
* tvheadend - CSA wrapper
* Copyright (C) 2013 Adam Sutton
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __DVBCAM_H__
#define __DVBCAM_H__

struct mpegts_service;
struct elementary_stream;

#if ENABLE_LINUXDVB_CA

typedef struct linuxdvb_ca linuxdvb_ca_t;
void dvbcam_init(void);
void dvbcam_service_start(struct service *t);
void dvbcam_service_stop(struct service *t);
void dvbcam_register_cam(linuxdvb_ca_t * lca, uint8_t slot, uint16_t * caids, int num_caids);
void dvbcam_unregister_cam(linuxdvb_ca_t * lca, uint8_t slot);
void dvbcam_pmt_data(mpegts_service_t *s, const uint8_t *ptr, int len);

#endif

#endif /* __DVBCAM_H__ */
5 changes: 5 additions & 0 deletions src/input/mpegts/dvb_psi.c
Expand Up @@ -26,6 +26,7 @@
#include "dvb_charset.h"
#include "bouquet.h"
#include "fastscan.h"
#include "descrambler/dvbcam.h"

#include <assert.h>
#include <stdio.h>
Expand Down Expand Up @@ -985,6 +986,10 @@ dvb_pmt_callback
if (s->s_dvb_service_id == sid) break;
if (!s) return -1;

#if ENABLE_LINUXDVB_CA
dvbcam_pmt_data(s, ptr, len);
#endif

/* Process */
tvhdebug("pmt", "sid %04X (%d)", sid, sid);
pthread_mutex_lock(&s->s_stream_mutex);
Expand Down

0 comments on commit f358286

Please sign in to comment.