Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
linuxdvb_ca: improve CAPMT sending to CAM, support multiple services
  • Loading branch information
dmarion authored and perexg committed May 18, 2015
1 parent 36c638b commit 61eeb38
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 60 deletions.
123 changes: 86 additions & 37 deletions src/descrambler/dvbcam.c
Expand Up @@ -38,28 +38,32 @@ typedef struct dvbcam_active_service {
uint8_t slot;
} dvbcam_active_service_t;

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

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

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;
dvbcam_active_cam_t *ac;

tvhtrace("dvbcam", "register cam ca %p slot %u num_caids %u",
lca, slot, num_caids);

num_caids = MIN(CAIDS_PER_CA_SLOT, num_caids);

if ((ac = malloc(sizeof(*ac))) == NULL)
if ((ac = calloc(1, sizeof(*ac))) == NULL)
return;

ac->ca = lca;
Expand All @@ -69,17 +73,19 @@ dvbcam_register_cam(linuxdvb_ca_t * lca, uint8_t slot, uint16_t * caids,

pthread_mutex_lock(&dvbcam_mutex);

TAILQ_INSERT_TAIL(&dvbcam_active_caids, ac, link);
TAILQ_INSERT_TAIL(&dvbcam_active_cams, 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_cam_t *ac, *ac_tmp;
dvbcam_active_service_t *as;

tvhtrace("dvbcam", "unregister cam lca %p slot %u", lca, slot);

pthread_mutex_lock(&dvbcam_mutex);

/* remove pointer to this CAM in all active services */
Expand All @@ -88,10 +94,10 @@ dvbcam_unregister_cam(linuxdvb_ca_t * lca, uint8_t slot)
as->ca = NULL;

/* delete entry */
for (ac = TAILQ_FIRST(&dvbcam_active_caids); ac != NULL; ac = ac_tmp) {
for (ac = TAILQ_FIRST(&dvbcam_active_cams); 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);
TAILQ_REMOVE(&dvbcam_active_cams, ac, link);
free(ac);
}
}
Expand All @@ -103,76 +109,101 @@ 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_cam_t *ac = NULL, *ac2;
dvbcam_active_service_t *as = NULL, *as2;
elementary_stream_t *st;
caid_t *c;
uint8_t list_mgmt;
int is_update = 0;
int i;

lfe = (linuxdvb_frontend_t*) s->s_dvb_active_input;
lfe = (linuxdvb_frontend_t*) s->s_dvb_active_input;

if (!lfe)
return;

pthread_mutex_lock(&dvbcam_mutex);

/* find this service in the list of active services */
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) {
tvhtrace("dvbcam", "cannot find active service entry");
goto done;
}

if(as->last_pmt)
if(as->last_pmt) {
free(as->last_pmt);
is_update = 1;
}

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

pthread_mutex_lock(&dvbcam_mutex);
/*if this is update just send updated CAPMT to CAM */
if (is_update) {

/* check all ellementary streams for CAIDs, if any send PMT to CAM */
tvhtrace("dvbcam", "CAPMT sent to CAM (update)");
list_mgmt = CA_LIST_MANAGEMENT_UPDATE;
goto enqueue;
}

/* check all ellementary streams for CAIDs and find CAM */
TAILQ_FOREACH(st, &s->s_components, es_link) {
LIST_FOREACH(c, &st->es_caids, link) {
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] == c->caid)
TAILQ_FOREACH(ac2, &dvbcam_active_cams, link) {
for(i=0;i<ac2->num_caids;i++) {
if(ac2->ca && ac2->ca->lca_adapter == lfe->lfe_adapter &&
ac2->caids[i] == c->caid)
{
as->ca = ac->ca;
as->slot = ac->slot;
break;
as->ca = ac2->ca;
as->slot = ac2->slot;
ac = ac2;
goto end_of_search_for_cam;
}
}
}
}
}

pthread_mutex_unlock(&dvbcam_mutex);

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

linuxdvb_ca_send_capmt(as->ca, as->slot, as->last_pmt, as->last_pmt_len);
if (!ac) {
tvhtrace("dvbcam", "cannot find active cam entry");
goto done;
}
tvhtrace("dvbcam", "found active cam entry");

if (ac->active_programs++)
list_mgmt = CA_LIST_MANAGEMENT_ADD;
else
list_mgmt = CA_LIST_MANAGEMENT_ONLY;

enqueue:
if (as->ca)
linuxdvb_ca_enqueue_capmt(as->ca, as->slot, as->last_pmt, as->last_pmt_len,
list_mgmt, CA_PMT_CMD_ID_OK_DESCRAMBLING);
done:
pthread_mutex_unlock(&dvbcam_mutex);
}

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

tvhtrace("dvbcam", "start service %p", t);

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

if ((as = malloc(sizeof(*as))) == NULL)
if ((as = calloc(1, sizeof(*as))) == NULL)
return;

as->t = t;
Expand All @@ -188,19 +219,37 @@ void
dvbcam_service_stop(service_t *t)
{
dvbcam_active_service_t *as, *as_tmp;
linuxdvb_ca_t *ca = NULL;
dvbcam_active_cam_t *ac2;
uint8_t slot;

tvhtrace("dvbcam", "stop service %p", t);

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)
if(as->last_pmt) {
linuxdvb_ca_enqueue_capmt(as->ca, as->slot, as->last_pmt,
as->last_pmt_len,
CA_LIST_MANAGEMENT_UPDATE,
CA_PMT_CMD_ID_NOT_SELECTED);
free(as->last_pmt);
}
slot = as->slot;
ca = as->ca;
TAILQ_REMOVE(&dvbcam_active_services, as, link);
free(as);
}
}

if (ca)
TAILQ_FOREACH(ac2, &dvbcam_active_cams, link)
if (ac2->slot == slot && ac2->ca == ca) {
ac2->active_programs--;
}

pthread_mutex_unlock(&dvbcam_mutex);
}

Expand All @@ -209,7 +258,7 @@ dvbcam_init(void)
{
pthread_mutex_init(&dvbcam_mutex, NULL);
TAILQ_INIT(&dvbcam_active_services);
TAILQ_INIT(&dvbcam_active_caids);
TAILQ_INIT(&dvbcam_active_cams);
}

#endif /* ENABLE_LINUXDVB_CA */

0 comments on commit 61eeb38

Please sign in to comment.