libdvben50221 docs and debuging

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 (manu@xxxxxxxxxxx)
 * Copyright (C) 2006 Andrew de Quincey (adq_dvb@xxxxxxxxxxxxx)
 *
 * 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 (manu@xxxxxxxxxxx)
	Copyright (C) 2006 Andrew de Quincey (adq_dvb@xxxxxxxxxxxxx)

	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
linux-dvb@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linux-dvb

[Index of Archives]     [Linux Media]     [Video 4 Linux]     [Asterisk]     [Samba]     [Xorg]     [Xfree86]     [Linux USB]

  Powered by Linux