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