I am trying to use libdvben50221 from linuxtv-dvb-apps (version 20070114
from Gentoo) to drive the CI/CA/CAM for some encrypted channels. I get
some printouts on the console, but it doesn't work, the channel is not
decrypted.
CAM supports the following ca system ids:
0x1702
0x1722
0x1762
0x4a20
0x0500
CAM Application type: 01
CAM Application manufacturer: 4a20
CAM Manufacturer code: 4a20
CAM Menu string: AlphaCrypt Light
I sometimes also get
Received new PMT - sending to CAM...
between the "0x0500" and "CAM Application type: 01", which is promising,
but decryption still doesn't work. I also don't know why I sometimes get
that line and sometimes not.
The same card and CI/CAM works with MythTV. zap also seems to work.
Most likely I'm doing something wrong, but I don't know what I am
supposed to do, as there is absolutely no documentation / howto. I used
the zap code as example (and use the unchanged zap_ca.* files), but
still I must be doing something wrong.
I'm at a loss here.
Can somebody please give some hints on how to debug this, and/or
describe what I'm supposed to do?
Relevant source attached.
Thanks in advance,
Ben
P.S. Sometimes, at the first tune(s), I also get, before that:
en50221_tl_handle_sb: Received T_SB for connection not in T_STATE_ACTIVE
from module on slot 00
en50221_stdcam_llci_poll: Error reported by stack:-7
I don't remember whether I get this particular error with the normal
DVB-S card and driver or only with the SkyStar HD DVB-S2 card and the
multiprotocol branch which I use currently.
/**
* This listens to the DVB stream for the PAT/PMT and time,
* which is unfortunately needed as input for the CA.
*
* You call either ca_start_in_new_thread() or
* (if you create the thread yourself) ca_start() and later
* ca_stop_thread() / ca_stop().
*
* Uses open()/close(), poll() and ioctl() system calls.
*
* Based on zap_dvb.c and zap_ca.c
*
* Copyright (C) 2007 Ben Bucksch
* Copyright (C) 2004, 2005 Manu Abraham ([EMAIL PROTECTED])
* Copyright (C) 2006 Andrew de Quincey ([EMAIL PROTECTED])
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "poll.h"
#include "zap_ca.h"
#include <jni.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <fcntl.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
#include <libucsi/mpeg/section.h>
#include <libucsi/dvb/section.h>
#include <iostream>
#include <string>
static void process_pat(int pat_fd, const char* demuxDeviceFilename, int channel_service_id, int *pmt_fd, struct pollfd *pollfd);
static void process_tdt(int tdt_fd);
static void process_pmt(int pmt_fd, int channel_service_id);
static void* ca_start_run(void* params);
static int create_filter(const char* demuxDeviceFilename, uint16_t pid, uint8_t table_id);
/////////////////////////////////////////////////////////////
// Thread
/////////////////////////////////////////////////////////////
class CAThread
{
public:
int myAdapterNo;
int myChannelServiceID;
bool myStopSignal;
JNIEnv* myEnv; // only temporary
pthread_t myThreadID;
};
static int pat_version = -1; // TODO move to CAThread?
static int ca_pmt_version = -1;
/**
* Creates a thread and starts ca_start()
*/
CAThread* ca_start_in_new_thread(int adapterNo, int channelServiceID, JNIEnv* env)
{
CAThread* thread = new CAThread();
thread->myAdapterNo = adapterNo;
thread->myChannelServiceID = channelServiceID;
thread->myEnv = env;
thread->myStopSignal = false;
pthread_create(&(thread->myThreadID), NULL, ca_start_run, (void*) thread);
return thread;
}
// callback, for use in ca_start_in_new_thread() only
// starting point of thread
static void* ca_start_run(void* param)
{
CAThread* thread = (CAThread*) param;
ca_start(thread->myAdapterNo, thread->myChannelServiceID, &(thread->myStopSignal), thread->myEnv);
thread->myEnv = 0;
return 0;
}
void ca_stop_thread(CAThread* thread)
{
ca_stop(&(thread->myStopSignal));
pthread_join(thread->myThreadID, NULL);
delete thread;
}
/////////////////////////////////////////////////////////////
// ca_start(), incl. setup and poll()
/////////////////////////////////////////////////////////////
void ca_stop(bool* stopSignal)
{
(*stopSignal) = true;
zap_ca_stop();
}
#define ERROR_INCASTART(test, message) \
{ \
if (test) \
{ \
delete[] demuxDeviceFilename; \
if (pat_fd > 0) close(pat_fd); \
if (pmt_fd > 0) close(pmt_fd); \
if (tdt_fd > 0) close(tdt_fd); \
jclass eClass = env->FindClass("org/bucksch/zeipis/recorder/CantUseTVCard"); \
if (eClass == 0) \
return; \
env->ThrowNew(eClass, message); \
return; \
} \
}
/**
* Sets up the CA for the tuned transponder
* Call XXX before/after tuning
*
* You must call this in a thread, because it will block,
* in fact it will loop infinitely until you call ca_stop().
*
* @param adapterNo E.g. 0 for "/dev/dvb/adapter0/"
* @param channel_service_id ID for channel
*/
void ca_start(int adapterNo, int channelServiceID, bool* stopSignal, JNIEnv* env)
{
std::string adapter = "/dev/dvb/adapter0/";
adapter[adapter.size() - 2] = 48 + adapterNo;
std::string demuxDeviceFilenameStr = adapter + "demux0";
const char* demuxDeviceFilename = demuxDeviceFilenameStr.c_str();
//std::cout << "Using adapter " << adapterNo << " " << adapter << " with " << demuxDeviceFilename
// << " . Service ID " << channelServiceID << std::endl;
struct zap_ca_params zap_ca_params1;
zap_ca_params1.adapter_id = adapterNo;
zap_ca_params1.caslot_num = 0; // TODO support several CAMs per DVB card
zap_ca_params1.moveca = 0;
zap_ca_start(&zap_ca_params1); // TODO creates yet another pthread :-(
struct pollfd pollfds[3];
int pat_fd = -1;
int pmt_fd = -1;
int tdt_fd = -1;
// Create PAT filter
pat_fd = create_filter(demuxDeviceFilename, TRANSPORT_PAT_PID, 0x00); // stag_mpeg_program_association
ERROR_INCASTART(pat_fd < 0, "Failed to create PAT section filter");
pollfds[0].fd = pat_fd;
pollfds[0].events = POLLIN|POLLPRI|POLLERR;
// Create TDT filter
tdt_fd = create_filter(demuxDeviceFilename, TRANSPORT_TDT_PID, 0x70); // stag_dvb_time_date
ERROR_INCASTART(tdt_fd < 0, "Failed to create TDT section filter");
pollfds[1].fd = tdt_fd;
pollfds[1].events = POLLIN|POLLPRI|POLLERR;
// Zero PMT filter for now, will be filled in later by process_pat()
pollfds[2].fd = 0;
pollfds[2].events = 0;
// Infinite loop until ca_stop is called
// to get PMT/PAT for CA
while(!(*stopSignal))
{
// is there SI data?
int count = poll(pollfds, 3, 100); // system call to efficiently wait for new data
ERROR_INCASTART(count < 0, "Poll error");
if (count == 0)
continue;
if (pollfds[0].revents & (POLLIN|POLLPRI)) // PAT
process_pat(pat_fd, demuxDeviceFilename, channelServiceID, &pmt_fd, &pollfds[2]);
if (pollfds[1].revents & (POLLIN|POLLPRI)) // TDT
process_tdt(tdt_fd);
if (pollfds[2].revents & (POLLIN|POLLPRI)) // PMT
process_pmt(pmt_fd, channelServiceID);
}
close(pat_fd);
close(pmt_fd);
close(tdt_fd);
}
static int create_filter(const char* demuxDeviceFilename, uint16_t pid, uint8_t table_id)
{
int demux_fd = open(demuxDeviceFilename, O_RDWR|O_NONBLOCK);
if (demux_fd < 0)
{
return -1;
}
struct dmx_sct_filter_params sctfilter;
memset(&sctfilter, 0, sizeof(sctfilter));
sctfilter.pid = pid;
sctfilter.filter.filter[0] = table_id;
sctfilter.filter.mask[0] = 0xFF;
sctfilter.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
int rv = ioctl(demux_fd, DMX_SET_FILTER, &sctfilter);
if (rv < 0)
{
close(demux_fd);
return -1;
}
return demux_fd;
}
/////////////////////////////////////////////////////////////
// Process
/////////////////////////////////////////////////////////////
static void process_pat(int pat_fd, const char* demuxDeviceFilename, int channel_service_id, int *pmt_fd, struct pollfd *pollfd)
{
int size;
uint8_t sibuf[4096];
// read the section
if ((size = read(pat_fd, sibuf, sizeof(sibuf))) < 0) {
return;
}
// parse section
struct section *section = section_codec(sibuf, size);
if (section == NULL) {
return;
}
// parse section_ext
struct section_ext *section_ext = section_ext_decode(section, 0);
if (section_ext == NULL) {
return;
}
if (pat_version == section_ext->version_number) {
return;
}
// parse PAT
struct mpeg_pat_section *pat = mpeg_pat_section_codec(section_ext);
if (pat == NULL) {
return;
}
// try and find the requested program
struct mpeg_pat_program *cur_program;
mpeg_pat_section_programs_for_each(pat, cur_program) {
if (cur_program->program_number == channel_service_id) {
// close old PMT fd
if (*pmt_fd != -1)
close(*pmt_fd);
// create PMT filter
if ((*pmt_fd = create_filter(demuxDeviceFilename,
cur_program->pid, stag_mpeg_program_map)) < 0) {
return;
}
pollfd->fd = *pmt_fd;
pollfd->events = POLLIN|POLLPRI|POLLERR;
// we have a new PMT pid
ca_pmt_version = -1;
break;
}
}
// remember the PAT version
pat_version = section_ext->version_number;
}
static void process_tdt(int tdt_fd)
{
int size;
uint8_t sibuf[4096];
// read the section
if ((size = read(tdt_fd, sibuf, sizeof(sibuf))) < 0) {
return;
}
// parse section
struct section *section = section_codec(sibuf, size);
if (section == NULL) {
return;
}
// parse TDT
struct dvb_tdt_section *tdt = dvb_tdt_section_codec(section);
if (tdt == NULL) {
return;
}
// done
zap_ca_new_dvbtime(dvbdate_to_unixtime(tdt->utc_time));
}
static void process_pmt(int pmt_fd, int channel_service_id)
{
int size;
uint8_t sibuf[4096];
// read the section
if ((size = read(pmt_fd, sibuf, sizeof(sibuf))) < 0) {
return;
}
// parse section
struct section *section = section_codec(sibuf, size);
if (section == NULL) {
return;
}
// parse section_ext
struct section_ext *section_ext = section_ext_decode(section, 0);
if (section_ext == NULL) {
return;
}
if ((section_ext->table_id_ext != channel_service_id) ||
(section_ext->version_number == ca_pmt_version)) {
return;
}
// parse PMT
struct mpeg_pmt_section *pmt = mpeg_pmt_section_codec(section_ext);
if (pmt == NULL) {
return;
}
//std::cout << "Send new PMT to zap_ca" << std::endl;
// do ca handling
if (zap_ca_new_pmt(pmt) == 1)
ca_pmt_version = pmt->head.version_number;
}
#include <pthread.h>
#include <jni.h>
class CAThread;
CAThread* ca_start_in_new_thread(int adapterNo, int channelServiceID, JNIEnv* env);
void ca_stop_thread(CAThread* thread);
void ca_start(int adapterNo, int channelServiceID, bool* stopSignal, JNIEnv* env);
void ca_stop(bool* stopSignal);
/*
ZAP utility CA functions
Copyright (C) 2004, 2005 Manu Abraham ([EMAIL PROTECTED])
Copyright (C) 2006 Andrew de Quincey ([EMAIL PROTECTED])
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef ZAP_CA_H
#define ZAP_CA_H 1
#ifdef __cplusplus
extern "C" {
#endif
struct zap_ca_params {
int adapter_id;
int caslot_num;
int moveca;
};
extern void zap_ca_start(struct zap_ca_params *params);
extern void zap_ca_stop(void);
extern int zap_ca_new_pmt(struct mpeg_pmt_section *pmt);
extern void zap_ca_new_dvbtime(time_t dvb_time);
#ifdef __cplusplus
}
#endif
#endif
_______________________________________________
linux-dvb mailing list
[email protected]
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb